Go + Azure: Calling a method return undefined - azure

Am trying to use Go Azure SDK to call the notification hub api
I have installed the SDK and imported to the GO file :
package hub
import (
"fmt"
"github.com/Azure/azure-sdk-for-go/arm/notificationhubs"
)
func GetHub() {
if resourceType, err := notificationhubs.Get("sourceGroupName", "NameSpaceValue", "NameOfTheHub"); err != nil {
fmt.Println("Error occured")
return
}
fmt.Println("Success")
}
However when am trying to runt he code i got this error
undefined: notificationhubs.Get
And am not sure what it means since my IDE don't complain about importing the Azure SDK so am assuming the SDK is imported correctly.

The function you're trying to use doesn't exist (https://godoc.org/github.com/Azure/azure-sdk-for-go/arm/notificationhubs).
You're probably trying to use the function GroupClient.Get; if that's the case, you need to get an object of type GroupClient and then call the function Get on it.

#cd1 is correct! The Get method doesn't belong directly to namespace that you've imported, but rather a client that exists in that namespace. In order to interact with NotificationsHub in this manner, instantiate a GroupClient then run a Get command.
import (
hubs "github.com/Azure/azure-sdk-for-go/arm/notificationshub"
)
func main() {
// Implementation details of your program ...
client := hubs.NewGroupClient("<YOUR SUBSCRIPTION ID>")
client.Authorizer = // Your initialized Service Principal Token
results, err := client.Get("<RESOURCE GROUP NAME>", "<NAMESPACE NAME>", "<NOTIFICATION HUB NAME>")
if err != nil {
return
}
}

Related

How can I use d.IsNewResource() when importing a resource in Terraform?

Context: I'm writing a Terraform Provider
A typical pattern (#1) in resource implementations in the Create/CreateContext function is to return the Read/ReadContext function at the end to fill in the Terraform State for all attributes.
Another typical pattern (#2) in resource implementations in the Read/ReadContext function is to remove the resource from the Terraform State if the remote system returns an error or status that indicates the remote resource no longer exists by explicitly calling d.SetId("") and returning no error. If the remote system is not strongly read-after-write consistent (eventually consistent), this means the resource creation can return no error and also return no resource state.
Official HashiCorp's tutorial supports #2 pattern:
When you create something in Terraform but delete it manually,
Terraform should gracefully handle it. If the API returns an error
when the resource doesn't exist, the read function should check to see
if the resource is available first. If the resource isn't available,
the function should set the ID to an empty string so Terraform
"destroys" the resource in state. The following code snippet is an
example of how this can be implemented; you do not need to add this to
your configuration for this tutorial.
if resourceDoesntExist {
d.SetID("")
return
}
Here's a minimal working code sample that displays usage of both #1 and #2 patterns:
func resourceServiceThingCreate(d *schema.ResourceData, meta interface{}) error {
/* ... */
return resourceServiceThingRead(d, meta)
}
func resourceServiceThingRead(d *schema.ResourceData, meta interface{}) error {
/* ... */
output, err := conn.DescribeServiceThing(input)
if !d.IsNewResource() && ErrCodeEquals(err, 404) {
log.Printf("[WARN] {Service} {Thing} (%s) not found, removing from state", d.Id())
d.SetId("")
return nil
}
if err != nil {
return fmt.Errorf("error reading {Service} {Thing} (%s): %w", d.Id(), err)
}
/* ... */
}
The problem is when I add an importer to the resource using
Importer: &schema.ResourceImporter{
StateContext: schema.ImportStatePassthroughContext,
},
that basically calls resourceServiceThingRead(d, meta) and if conn.DescribeServiceThing(input) returns 404 (e.g., there was a typo and the user used wrong ID that caused 404 status code) TF provider will print no errors:
terraform import resource_foo.example-2 foo-1234
resource_foo.example-2: Importing from ID "foo-1234"...
resource_foo.example-2: Import prepared!
Prepared resource_foo for import
resource_foo.example-2: Refreshing state... [id=foo-1234]
Import successful!
# but the client actually received 404 error that it ignored
since
if !d.IsNewResource() && ErrCodeEquals(err, 404) {
log.Printf("[WARN] {Service} {Thing} (%s) not found, removing from state", d.Id())
d.SetId("")
// print out no error and confuse a user
return nil
}
// instead of going here
if err != nil { // print out & return descriptive error }
piece of code will be executed. Is there a way to mark imported resource as new or something so I'd be able to print out the real 404 error for a failed attempt of importing a resource?
Otherwise it looks like we'll have to remove schema.ImportStatePassthroughContext and use copy pasted resourceServiceThingRead_2() that excludes d.SetId("") check to support showing descriptive 404 errors for imports.

Is retry handled from go client library for azure service bus?

I'm referencing to the client library in https://github.com/Azure/azure-service-bus-go. I was able to write a simple client which listens to a subscription and read the messages. If I drop the network, after a few seconds I could see the receive loop exiting with the error message "context canceled". I was hoping the client library will do some kind of retry mechanism and handle any connection issues or any server timeouts etc. Do we need to handle this our selves ? Also do we get any exceptions which we could identify and use it for this retrying mechanism ? Any sample code would be highly appreciated.
below is the sample code I tried (only including the vital parts).
err = subscription.Receive(ctx, servicebus.HandlerFunc(func(ctx context.Context, message *servicebus.Message) error {
fmt.Println(string(message.Data))
return message.Complete(ctx)
}))
if err != nil {
fmt.Println("FATAL: ", err)
return
}
Unfortunately, the older library doesn't do a good job of retrying, so you'll need to wrap the code in your own retry loop.
func demoReceiveWithRecovery(ns *servicebus.Namespace) {
parentCtx := context.TODO()
for {
q, err := ns.NewQueue(queueName)
if err != nil {
panic(err)
}
defer q.Close(parentCtx)
handler := servicebus.HandlerFunc(func(c context.Context, m *servicebus.Message) error {
log.Printf("Received message")
return m.Complete(c)
})
err = q.Receive(parentCtx, handler)
// check for potential recoverable situation
if err != nil && errors.Is(err, context.Canceled) {
// This workaround distinguishes between the handler cancelling because the
// library has disconnected vs the parent context (passed in by you) being cancelled.
if parentCtx.Err() != nil {
// our parent context cancelled, which caused the entire operation to be canceled
log.Printf("Cancelled by parent context")
return
} else {
// cancelled internally due to an error, we can restart the queue
log.Printf("Error occurred, restarting")
_ = q.Close(parentCtx)
continue
}
} else {
log.Printf("Other error, closing client and restarting: %s", err.Error())
_ = q.Close(parentCtx)
}
}
}
NOTE: This library was deprecated recently, but it was deprecated after you posted your question. The new package is here if you want to try it - azservicebus with a migration guide here to make things easier: migrationguide.md
The new package should recover properly in this scenario for receiving. There is an open bug in the new package I'm working on for the sending side to do recovery #16695.
If you want to ask further questions or have some feature requests you can submit those in the github issues for https://github.com/Azure/azure-sdk-for-go.

Calling WCF endpoint from Azure Function

I have a v2 Azure function written in dotnet core. I want to call in to a legacy WCF endpoint like this:
basicHttpBinding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Basic;
var factory = new ChannelFactory<IMyWcfService>(basicHttpBinding, null);
factory.Credentials.UserName.UserName = "foo";
factory.Credentials.UserName.Password = "bar";
IMyWcfService myWcfService = factory.CreateChannel(new EndpointAddress(new Uri(endpointUri)));
ICommunicationObject communicationObject = myWcfService as ICommunicationObject;
if ( communicationObject != null)
communicationObject.Open();
try
{
return await myWcfService.GetValueAsync());
}
finally
{
if (communicationObject != null)
communicationObject.Close();
factory.Close();
}
This works when I call it from a unit test, so I know the code is fine running on Windows 10. However, when I debug in the func host, I get missing dependency exceptions. I copied two dlls : System.Private.Runtime and System.Runtime.WindowsRuntime into the in directory, but have reached the end of the line with the exception
Could not load type 'System.Threading.Tasks.AsyncCausalityTracer' from assembly 'mscorlib'
This seems like a runtime rabbit hole that I don't want to go down. Has anyone successfully called a Wcf service from an Azure function? Which dependencies should I add to get the call to work?

Error when retrieving message from Service Bus queue

I trying to pull messages from azure service bus queue using Go, but I got an error when running the code. Here is my code.
func Example_queue_receive() {
ctx, cancel :=context.WithTimeout(context.Background(),10*time.Second)
defer cancel()
connectionString :="Endpoint=sb://{my_service_name}.servicebus.windows.net/;SharedAccessKeyName = RootManageSharedAccessKey;SharedAccessKey={my_shared_access_key_value}"
// Create a client to communicate with a Service Bus Namespace.
ns, err := servicebus.NewNamespace(servicebus.NamespaceWithConnectionString(connectionString))
if err != nil {
fmt.Println(err)
}
// Create a client to communicate with the queue.
q, err := ns.NewQueue("MyQueueName")
if err != nil {
fmt.Println("FATAL: ", err)
}
err = q.ReceiveOne(ctx, servicebus.HandlerFunc(func(ctx context.Context, message *servicebus.Message) servicebus.DispositionAction {
fmt.Println(string(message.Data))
return message.Complete()
}))
if err != nil {
fmt.Println("FATAL: ", err)
}
}
This is the error:
link detached, reason: *Error{Condition: amqp:not-found}
I searched for the error information in the Github repo, and I found the code ErrorNotFound MessageErrorCondition = "amqp:not-found", but there is not any explaination for the error.
I compared it with Exception types in C# from the offical document Service Bus messaging exceptions and my testing, I think it's the same as below.
In my environment go version go1.11.3 windows/amd64, I run the similar code without an existing queue MyQueueName, I got the similar error below.
FATAL: unhandled error link xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxxx: status code 404 and description: The messaging entity 'sb://.servicebus.windows.net/MyQueueName' could not be found. TrackingId:f9fc309d-xxxx-xxxx-xxxx-8fccd694f266_G42, SystemTracker:.servicebus.windows.MyQueueName, Timestamp:2019-01-25T09:45:28
So I think the error means your Queue MyQueueName in your code is not existing in your Azure Service Bus, you should create it first before to use.
Meanwhile, as #JerryLiu said, your code below has some mistakes.
err = q.ReceiveOne(ctx, servicebus.HandlerFunc(func(ctx context.Context, message *servicebus.Message) servicebus.DispositionAction {
fmt.Println(string(message.Data))
return message.Complete()
}))
According to the godoc for azure-service-bus-go, the parameter type of servicebus.HanderFunc method must be HandlerFunc which is a function return error, not servicebus.DispositionAction in your code.
And the method message.Complete should be passed a parameter ctx (a context object) and return error that not match servicebus.DispositionAction. The message.CompleteAction method return servicebus.DispositionAction , but not suitable in the reciving message code.
Please refer to the example of godoc Example (QueueSendAndReceive) to modify your code.

go websockets eof

I'm trying to make a simple command forwarder to connect my home computer to a server I own, so that I can push commands to my server and my home pc gets it. Those commands are simple pause/resume for my downloader. My design is, that on a server, I run a hub instance, which creates a window for passing commands and a window for backend to pass those commands to my pc. I'm bounding those two "windows" with a channel, they run a server. When a client connects and sends a message to the hub, it gets streamed through a channel to backend window and then to the real backend (on my home pc). When backend responds to the backend window on the hub, the hub prints the result back to the client.
With this approach, only the first message passes and works with my downloader. I have to reconnect the backend from my home pc with the hub each time I get a message to get this working properly. I don't think that's the proper way with websockets, so here I am. After one successful request (when the backend finishes it's work and replies the result), it gets looped forever with EOF error.
The important parts of the code are:
main executable
hub handlers
backend connector
If you put the source in your GOPATH (i'm developing it for the tip version of go to support modern websockets), to compile it:
go build gosab/cmd, to run it:
./cmd -mode="hub" hub
./cmd -mode="backend" --address="localhost:8082" backend
To pass messages to the hub, use this javascript:
var s = new WebSocket("ws://localhost:8082")
s.send("1 5")
So how do I handle it? Are channels a good way to communicate between two different requests?
I'm surprised you haven't received an answer to this.
What you need to do is something like the code below. When you receive an incoming websocket connection, a new goroutine is spawned for that connection. If you let that goroutine end, it'll disconnect the websocket client.
I'm making an assumption that you're not necessarily going to be running the client and server on the same computer. If you always are, then it'd be better to do the communication internally via channels or such instead of using websockets or a network port. I only mention this because I'm not completely sure what you're using this for. I just hope I answered the right part of your question.
package main
import (
"code.google.com/p/go.net/websocket"
"flag"
"fmt"
"net/http"
"os"
"time"
)
type Message struct {
RequestID int
Command string
SomeOtherThing string
Success bool
}
var mode *string = flag.String("mode", "<nil>", "Mode: server or client")
var address *string = flag.String("address", "localhost:8080", "Bind address:port")
func main() {
flag.Parse()
switch *mode {
case "server":
RunServer()
case "client":
RunClient()
default:
flag.Usage()
}
}
func RunServer() {
http.Handle("/", http.FileServer(http.Dir("www")))
http.Handle("/server", websocket.Handler(WSHandler))
fmt.Println("Starting Server")
err := http.ListenAndServe(*address, nil)
if err != nil {
fmt.Printf("HTTP failed: %s\n", err.Error())
os.Exit(1)
}
}
func WSHandler(ws *websocket.Conn) {
defer ws.Close()
fmt.Println("Client Connected")
for {
var message Message
err := websocket.JSON.Receive(ws, &message)
if err != nil {
fmt.Printf("Error: %s\n", err.Error())
return
}
fmt.Println(message)
// do something useful here...
response := new(Message)
response.RequestID = message.RequestID
response.Success = true
response.SomeOtherThing = "The hot dog left the castle as requested."
err = websocket.JSON.Send(ws, response)
if err != nil {
fmt.Printf("Send failed: %s\n", err.Error())
os.Exit(1)
}
}
}
func RunClient() {
fmt.Println("Starting Client")
ws, err := websocket.Dial(fmt.Sprintf("ws://%s/server", *address), "", fmt.Sprintf("http://%s/", *address))
if err != nil {
fmt.Printf("Dial failed: %s\n", err.Error())
os.Exit(1)
}
incomingMessages := make(chan Message)
go readClientMessages(ws, incomingMessages)
i := 0
for {
select {
case <-time.After(time.Duration(2e9)):
i++
response := new(Message)
response.RequestID = i
response.Command = "Eject the hot dog."
err = websocket.JSON.Send(ws, response)
if err != nil {
fmt.Printf("Send failed: %s\n", err.Error())
os.Exit(1)
}
case message := <-incomingMessages:
fmt.Println(message)
}
}
}
func readClientMessages(ws *websocket.Conn, incomingMessages chan Message) {
for {
var message Message
err := websocket.JSON.Receive(ws, &message)
if err != nil {
fmt.Printf("Error: %s\n", err.Error())
return
}
incomingMessages <- message
}
}

Resources