I'm trying to contribute for terraform related Azure implementation. In this case, the most important thing is to understand Azure SDK for Go. I'd like to share my learning.
On this blog, I'd like to explain using Log Analytics API as an example.
Import
You need to import not only Azure Go SDK its self, but also, Azure Go Autorest. The autorest is the OpenAPI specification code generator. Azure Go SDK is created top on it. adal means Active Directory Authentication Library. You can't import whole Azure Go SDK. You need to pick some packages under /arm .
import( : "github.com/Azure/azure-sdk-for-go/arm/operationalinsights" "github.com/Azure/go-autorest/autorest" "github.com/Azure/go-autorest/autorest/adal" "github.com/Azure/go-autorest/autorest/azure" )
Service Principal Token
If you want to access REST API of Azure, you need to request an access token. If you try to contribute terraform, all you need it to understand the way to get an access token by a Service Principal. If you don't have a service principal, please read this article.
Once you've got a service principal, you can write code like this. Using ADAL, you can get the Service Principal Token. However, in this point, the service principal has not retrieved yet.
func main() { spt, err := NewServicePrincipalTokenFromCredentials(c, azure.PublicCloud.ResourceManagerEndpoint) if err != nil { log.Fatalf("Err: %v", err) return } : } func NewServicePrincipalTokenFromCredentials(c map[string]string, scope string) (*adal.ServicePrincipalToken, error) { oauthConfig, err := adal.NewOAuthConfig(azure.PublicCloud.ActiveDirectoryEndpoint, c["AZURE_TENANT_ID"]) if err != nil { panic(err) } return adal.NewServicePrincipalToken(*oauthConfig, c["AZURE_CLIENT_ID"], c["AZURE_CLIENT_SECRET"], scope) }
Configure the Azure SDK Client
Then you need configure an client for Azure SDK for go. You can find a lot of clients under the /arm packages. In this example, I use LogAnalytics workspace client. Just add an Service Principal Token to the client.
client := operationalinsights.NewWorkspacesClient(c["AZURE_SUBSCRIPTION_ID"]) client.Authorizer = autorest.NewBearerAuthorizer(spt)
type ManagementClient struct { autorest.Client BaseURI string SubscriptionID string }
type WorkspacesClient struct { ManagementClient }
Operate Azure
Now you are ready to operate Azure using Azure SDK for go. For example, I tried the CreateOrUpdate function for Workspace.
parameter := operationalinsights.Workspace{ Location: ToAddress("eastus"), } cancel := make(chan struct{}) receive, error := client.CreateOrUpdate(resourceGroup, name, parameter, cancel)
workspace := <-receive err = <-error if err != nil { log.Fatalf("Error: %v", err) }
The ToAddress method is like this. We need to avoid nil panic.
func ToAddress(str string) *string { return &str }
type Workspace struct { autorest.Response `json:"-"` ID *string `json:"id,omitempty"` Name *string `json:"name,omitempty"` Type *string `json:"type,omitempty"` Location *string `json:"location,omitempty"` Tags *map[string]*string `json:"tags,omitempty"` *WorkspaceProperties `json:"properties,omitempty"` ETag *string `json:"eTag,omitempty"` }
Getting Result
You can see the all result. Unfortunately, The Azure SDK for go doesn't explain which value can we use for it. What does it mean? Then you can refer the REST API documentation.
NOTE: You might notice some has no "*" in case of dereferences. e.g. workspace.Sku.Name . If you try *workspace.Sku.Name, you will get Invalid Indirect.
log.Printf("ID: %s", *workspace.ID) log.Printf("Name: %s", *workspace.Name) log.Printf("Type: %s", *workspace.Type) log.Printf("Location: %s", *workspace.Location) if workspace.Tags != nil { for key, value := range *workspace.Tags { log.Print("[Tags]: key: ", key, "value: ", value) } } switch workspace.ProvisioningState { case operationalinsights.Canceled: log.Printf("ProvisioningState: Canceled") case operationalinsights.Creating: log.Printf("ProvisioningState: Creating") case operationalinsights.Deleting: log.Printf("ProvisioningState: Deleting") case operationalinsights.Failed: log.Printf("ProvisioningState: Failed") case operationalinsights.ProvisioningAccount: log.Printf("ProvisioningState: ProvisioningAccount") case operationalinsights.Succeeded: log.Printf("ProvisioningState: Succeeded") } log.Printf("Source: %s", *workspace.Source) log.Printf("CustomerID: %s", *workspace.CustomerID) // a.k.a. Workspace ID log.Printf("PortalURL: %s", *workspace.PortalURL) log.Printf("Sku: %s", workspace.Sku.Name) log.Printf("RetentionInDays %d", *workspace.RetentionInDays)
Also you can get the Shared Key for the work space.
sharedKeys, err := client.GetSharedKeys(resourceGroup, name) if err != nil { log.Fatalf("Error: %v", err) } log.Printf("SharedKey: Primary Shared Key: ", *sharedKeys.PrimarySharedKey) log.Printf("SharedKey: Shared Secondary Key: ", *sharedKeys.SecondarySharedKey)
This is the result.
$ go run cmd/client/main.go 2017/09/06 08:43:49 ID: /subscriptions/{YOUR_SUBSCRIPTION}/resourcegroups/spikeoms/providers/microsoft.operationalinsights/workspaces/spikesaoms¥n 2017/09/06 08:43:49 Name: spikesaoms¥n 2017/09/06 08:43:49 Type: Microsoft.OperationalInsights/workspaces¥n 2017/09/06 08:43:49 Location: eastus¥n 2017/09/06 08:43:49 ProvisioningState: Succeeded 2017/09/06 08:43:49 Source: Azure¥n 2017/09/06 08:43:49 CustomerID: {YOUR_WORKSPACE_ID}¥n 2017/09/06 08:43:49 PortalURL: https://eus.mms.microsoft.com/Account?tenant={YOUR_TENANT_ID}&resource=%2fsubscriptions%2f{YOUR_SUBSCRIPTION_ID}%2fresourcegroups%2fspikeoms%2fproviders%2fmicrosoft.operationalinsights%2fworkspaces%2fspikesaoms¥n 2017/09/06 08:43:49 Sku: free¥n 2017/09/06 08:43:49 RetentionInDays 0¥n 2017/09/06 08:43:49 SharedKey: Primary Shared Key: 9RSV......QUOFRi7w== 2017/09/06 08:43:49 SharedKey: Shared Secondary Key: Bqd9Ozk.....0zbomeyQ==
Now you are ready for contribute the terraform!
Resource
You can find whole source code on the gist.
GitHubGist: TsuyoshiUshio/main.go