From ecd105de274097d204f3b23a9f7e98b2ac568907 Mon Sep 17 00:00:00 2001 From: Josh Gavant Date: Thu, 12 Jul 2018 08:16:53 -0700 Subject: [PATCH] replace config system Removes `helpers` and `iam` packages in favor of internal packages to manage configuration and authorizers. Adjusts `resources` and `network` packages for new setup. --- .env.tpl | 11 +- Gopkg.lock | 17 ++ README.md | 89 +++---- helpers/parse_args.go | 260 -------------------- iam/oauth.go | 209 ---------------- internal/config/canary.go | 57 +++++ internal/config/config.go | 146 +++++++++++ internal/config/env.go | 65 +++++ internal/config/flags.go | 19 ++ internal/iam/authorizers.go | 210 ++++++++++++++++ helpers/helpers.go => internal/util/util.go | 16 +- network/hybrid/network.go | 103 ++++---- network/hybrid/network_test.go | 90 ++++--- network/network.go | 125 +++++----- network/network_test.go | 150 +++++++---- resources/cleanup.go | 6 +- resources/deployment.go | 17 +- resources/deployment_test.go | 26 +- resources/groups.go | 37 +-- resources/hybrid/cleanup.go | 4 +- resources/hybrid/groups.go | 46 ++-- resources/hybrid/resources_test.go | 46 +++- resources/provider.go | 13 +- resources/resources.go | 15 +- resources/resources_test.go | 70 ++++-- 25 files changed, 1007 insertions(+), 840 deletions(-) delete mode 100644 helpers/parse_args.go delete mode 100644 iam/oauth.go create mode 100644 internal/config/canary.go create mode 100644 internal/config/config.go create mode 100644 internal/config/env.go create mode 100644 internal/config/flags.go create mode 100644 internal/iam/authorizers.go rename helpers/helpers.go => internal/util/util.go (58%) diff --git a/.env.tpl b/.env.tpl index 606936b7a..c0caa3a16 100644 --- a/.env.tpl +++ b/.env.tpl @@ -1,9 +1,10 @@ -AZURE_SUBSCRIPTION_ID= -AZURE_RESOURCE_GROUP_NAME= -AZURE_LOCATION= +AZURE_BASE_GROUP_NAME=az-samples-go +AZURE_LOCATION_DEFAULT=westus2 +AZURE_SAMPLES_KEEP_RESOURCES=0 + AZURE_TENANT_ID= AZURE_CLIENT_ID= AZURE_CLIENT_SECRET= -AZURE_SAMPLES_KEEP_RESOURCES=0 +AZURE_SUBSCRIPTION_ID= -AZURE_STORAGE_ACCOUNT_NAME= \ No newline at end of file +AZURE_AUTH_LOCATION=$HOME/.azure/sdk_auth.json diff --git a/Gopkg.lock b/Gopkg.lock index 20cc31458..594dbe78b 100644 --- a/Gopkg.lock +++ b/Gopkg.lock @@ -163,6 +163,22 @@ pruneopts = "" revision = "113d3961e7311526535a1ef7042196563d442761" +[[projects]] + digest = "1:f23957829bec661c8e4c3cd421383c8270b4e01c93cf2046bb8844532ac0022c" + name = "github.com/gobuffalo/envy" + packages = ["."] + pruneopts = "" + revision = "2d0f467653f3d961ce9ada4d32a230bdcb3bfe11" + version = "v1.6.3" + +[[projects]] + digest = "1:9e2d3c77cfb28d97073016bdc42d70e73d84876d8bacd4436f613dfbf93f8eda" + name = "github.com/joho/godotenv" + packages = ["."] + pruneopts = "" + revision = "a79fa1e548e2c689c241d10173efd51e5d689d5b" + version = "v1.2.0" + [[projects]] digest = "1:a0cb5f41e61664683912f073ec14760a9f60b432d75afa01f64e1db5443a5539" name = "github.com/marstr/collection" @@ -304,6 +320,7 @@ "github.com/denisenkom/go-mssqldb", "github.com/globalsign/mgo", "github.com/globalsign/mgo/bson", + "github.com/gobuffalo/envy", "github.com/marstr/randname", "github.com/satori/go.uuid", "github.com/subosito/gotenv", diff --git a/README.md b/README.md index 1348760d1..2d9d869f1 100644 --- a/README.md +++ b/README.md @@ -1,66 +1,43 @@ -# Azure SDK for Go - Samples +# Azure SDK for Go Samples -azure-sdk-for-go-samples provides easy-to-understand, continuously-tested samples for using Azure services via [Azure/azure-sdk-for-go][]. These are currently targeting -Go SDK For Azure **v14.0.0**. +azure-sdk-for-go-samples is a collection of sample usages of the +[Azure/azure-sdk-for-go][]. [![Build Status](https://travis-ci.org/Azure-Samples/azure-sdk-for-go-samples.svg?branch=master)](https://travis-ci.org/Azure-Samples/azure-sdk-for-go-samples) -The goal of this project is to provide a library of code snippets for common -and not-so-common operations in Azure via the Go SDK. Code is organized by -services as well as snippet type. The repo will continue to be testable to -ensure our samples reflect current recommendations and best practices! - -Read the [main SDK README][] for more help getting started with the Go SDK. +For general SDK help, start with the [main SDK README][]. ## To run tests -1. Set the following environment variables. Use the following instructions to find or create these values if necessary. - - * `AZURE_SUBSCRIPTION_ID` * - * `AZURE_TENANT_ID` * - * `AZURE_CLIENT_ID` * - * `AZURE_CLIENT_SECRET` * - * `AZURE_NATIVE_CLIENT_ID` ** - * `AZURE_SP_OBJECT_ID` - * `AZURE_LOCATION` - * `AZURE_RESOURCE_GROUP_PREFIX` - * `AZURE_KEEP_SAMPLE_RESOURCES` - - (* are required for service principal authentication) - - (** is required for device flow authentication) - - Using [the Azure CLI][azure-cli], you can get your subscription ID and tenant ID by running `az account - show`. - - For service principal authentication, get a client ID and secret by - running `az ad sp create-for-rbac -n ""`. - - For device flow authentication, get your client ID running `az ad app create --display-name "" --native-app --requiredResourceAccess @manifest.json`. - - If `AZURE_RESOURCE_GROUP_PREFIX` isn't specified, `azure-samples-go` will be used. - - If `AZURE_LOCATION` isn't specified `westus2` will be used. - - If `AZURE_KEEP_SAMPLE_RESOURCES` is set to `1` tests won't clean up resources - they create when done. This can be helpful if you want to further experiment - with those resources. - - `AZURE_SP_OBJECT_ID` represents a service principal ObjectID. It is needed to run the Create VM with encrypted managed disks sample. - - **NOTE:** the environment variables are listed in [.env.tpl](./.env.tpl) - so you can copy that to .env (e.g. `cp .env.tpl .env`) and update for - convenience. The samples pick up environment variables from .env files - automatically. - -1. Run `dep ensure` to get dependencies. -1. Run tests with `go test` as follows: - - 1. To run individual samples, refer to that folder, e.g. `go test ./storage/`, `go test ./network/`. - * If you use a .env file, copy it into the folder first, e.g. `cp .env ./network/`. - 1. If you're feeling lucky and want to test all the samples, try `go test ./...` - * This only requires the root .env file. - 1. To run tests with device flow authentication, add the `--deviceFlow` flag. +1. set up authentication (see following) +1. `dep ensure` +1. `go test -v ./network/` (or any package) + +To run all tests: `make test`. + +To use service principal authentication, create a principal by running `az ad +sp create-for-rbac -n ""` and set the following environment +variables. You can copy `.env.tpl` to a `.env` file in each package for ease of use. + +```bash +export AZURE_SUBSCRIPTION_ID= +export AZURE_TENANT_ID= +export AZURE_CLIENT_ID= +export AZURE_CLIENT_SECRET= + +export AZURE_LOCATION_DEFAULT=westus2 +export AZURE_BASE_GROUP_NAME=azure-samples-go +export AZURE_KEEP_SAMPLE_RESOURCES=0 +``` + +For device flow authentication, create a "native" app by running `az ad app +create --display-name "" --native-app --requiredResourceAccess +@manifest.json`; and specify the `-useDeviceFlow` flag when running tests. + +## Other notes + +`AZURE_SP_OBJECT_ID` represents a service principal ObjectID. It is needed to +run the Create VM with encrypted managed disks sample. # Resources diff --git a/helpers/parse_args.go b/helpers/parse_args.go deleted file mode 100644 index 169e1309d..000000000 --- a/helpers/parse_args.go +++ /dev/null @@ -1,260 +0,0 @@ -// Copyright (c) Microsoft and contributors. All rights reserved. -// -// This source code is licensed under the MIT license found in the -// LICENSE file in the root directory of this source tree. - -package helpers - -import ( - "errors" - "flag" - "fmt" - "log" - "os" - "strings" - - "github.com/Azure/go-autorest/autorest/azure" - "github.com/Azure/go-autorest/autorest/to" - "github.com/marstr/randname" - "github.com/subosito/gotenv" -) - -var ( - targetEnv = azure.PublicCloud.Name - resourceGroupNamePrefix string - resourceGroupName string - location string - subscriptionID string - servicePrincipalObjectID string - keepResourcesPtr *bool - deviceFlow *bool - - allLocations = []string{ - "eastasia", - "southeastasia", - "centralus", - "eastus", - "eastus2", - "westus", - "northcentralus", - "southcentralus", - "northeurope", - "westeurope", - "japanwest", - "japaneast", - "brazilsouth", - "australiaeast", - "australiasoutheast", - "southindia", - "centralindia", - "westindia", - "canadacentral", - "canadaeast", - "uksouth", - "ukwest", - "westcentralus", - "westus2", - "koreacentral", - "koreasouth", - } - - locationOverrideTemplate = "Using location %s on this sample, because this service is not yet available on specified location %s\n" -) - -// ParseArgs picks up shared env vars and flags and finishes parsing flags -// Other packages should declare their flags then call helpers.ParseArgs() -func ParseArgs() error { - err := ParseSubscriptionID() - if err != nil { - return err - } - - err = ParseDeviceFlow() - if err != nil { - return err - } - - // flags are prioritized over env vars, - // so read from env vars first, then check flags - err = ReadEnvFile() - if err != nil { - return err - } - - servicePrincipalObjectID = os.Getenv("AZURE_SP_OBJECT_ID") - - // flags override envvars - if resourceGroupNamePrefix == "" { - resourceGroupNamePrefix = os.Getenv("AZURE_RESOURCE_GROUP_PREFIX") - flag.StringVar(&resourceGroupNamePrefix, "groupPrefix", GroupPrefix(), "Specify prefix name of resource group for sample resources.") - } - - if location == "" { - location = os.Getenv("AZURE_LOCATION") - if location == "" { - location = "westus2" // lots of space, most new features - } - flag.StringVar(&location, "location", location, "Provide the Azure location where the resources will be be created.") - } - - if keepResourcesPtr == nil { - keepResources := false - if os.Getenv("AZURE_SAMPLES_KEEP_RESOURCES") == "1" { - keepResources = true - } - flag.BoolVar(&keepResources, "keepResources", keepResources, "Keep resources created by samples.") - keepResourcesPtr = &keepResources - } - - if targetEnv == "" { - targetEnv = os.Getenv("AZURE_ENVIRONMENT") - if targetEnv == "" { - targetEnv = azure.PublicCloud.Name - } - flag.StringVar(&targetEnv, "environment", targetEnv, "Azure environment.") - } - - flag.Parse() - return nil -} - -// ParseSubscriptionID gets the subscription id from either an env var, .env file or flag -// The caller should do flag.Parse() -func ParseSubscriptionID() error { - if subscriptionID != "" { - return nil - } - err := ReadEnvFile() - if err != nil { - return err - } - - subscriptionID = os.Getenv("AZURE_SUBSCRIPTION_ID") - flag.StringVar(&subscriptionID, "subscription", subscriptionID, "Subscription to use for deployment.") - - if !(len(subscriptionID) > 0) { - return errors.New("subscription ID must be specified in env var, .env file or flag") - } - return nil -} - -// ParseDeviceFlow parses the auth grant type to be used -// The caller should do flag.Parse() -func ParseDeviceFlow() error { - if deviceFlow != nil { - return nil - } - err := ReadEnvFile() - if err != nil { - return err - } - - deviceFlow = to.BoolPtr(false) - - if os.Getenv("AZURE_AUTH_DEVICEFLOW") != "" { - deviceFlow = to.BoolPtr(true) - } - flag.BoolVar(deviceFlow, "deviceFlow", *deviceFlow, "Use device flow for authentication. This flag should be used with -v flag. Default authentication is service principal.") - return nil -} - -// getters - -// KeepResources indicates whether resources created by samples should be retained. -func KeepResources() bool { - if keepResourcesPtr == nil { - return false - } - return *keepResourcesPtr -} - -// SubscriptionID returns the ID of the subscription to use. -func SubscriptionID() string { - return subscriptionID -} - -// ServicePrincipalObjectID returns the object ID of the service principal in use. -func ServicePrincipalObjectID() string { - return servicePrincipalObjectID -} - -// ResourceGroupName returns the name of the resource group to use. -func ResourceGroupName() string { - return resourceGroupName -} - -// Location specifies the Azure region to use. -func Location() string { - return location -} - -// GroupPrefix specifies the prefix sample resource groups should have -func GroupPrefix() string { - if resourceGroupNamePrefix == "" { - return "azure-samples-go" - } - return resourceGroupNamePrefix -} - -// DeviceFlow returns if device flow has been set as auth grant type -func DeviceFlow() bool { - if deviceFlow == nil { - return false - } - return *deviceFlow -} - -// Environment gets the Azure environment -func Environment() azure.Environment { - env, err := azure.EnvironmentFromName(targetEnv) - if err != nil { - log.Fatalf("failed to get environment from name (defaulting to Public Cloud): %s\n", err) - return azure.PublicCloud - } - return env -} - -// ArmEndpoint specifies resource manager URI -func ArmEndpoint() string { - return Environment().ResourceManagerEndpoint -} - -// end getters - -// SetPrefix sets a prefix for resource group names -func SetPrefix(prefix string) { - resourceGroupNamePrefix = prefix -} - -// SetResourceGroupName sets a name for the resource group. It takes into account the -// resource group prefix, and adds some random letters to ensure uniqueness -func SetResourceGroupName(suffix string) { - resourceGroupName = randname.GenerateWithPrefix(fmt.Sprintf("%s-%s-", GroupPrefix(), suffix), 5) -} - -// OverrideCanaryLocation ovverrides the specified canary location where to create Azure resources. -func OverrideCanaryLocation(usableLocation string) { - if strings.HasSuffix(location, "euap") { - log.Printf(locationOverrideTemplate, usableLocation, location) - location = usableLocation - } -} - -// OverrideLocation ovverrides the specified location where to create Azure resources. -// This can be used when the selection location does not have the desired resource provider available yet -func OverrideLocation(available []string) { - // If location is not listed on all locations, don't override it. It might be a canary location - if contains(allLocations, location) && !contains(available, location) && len(available) > 0 { - log.Printf(locationOverrideTemplate, available[0], location) - location = available[0] - } -} - -// ReadEnvFile reads the .env file and loads its environment variables. -func ReadEnvFile() error { - err := gotenv.Load() // to allow use of .env file - if err != nil && !strings.HasPrefix(err.Error(), "open .env:") { - return err - } - return nil -} diff --git a/iam/oauth.go b/iam/oauth.go deleted file mode 100644 index 6b7c9ca24..000000000 --- a/iam/oauth.go +++ /dev/null @@ -1,209 +0,0 @@ -// Copyright (c) Microsoft and contributors. All rights reserved. -// -// This source code is licensed under the MIT license found in the -// LICENSE file in the root directory of this source tree. - -package iam - -import ( - "log" - "net/url" - "os" - "strings" - - "github.com/Azure-Samples/azure-sdk-for-go-samples/helpers" - "github.com/Azure/go-autorest/autorest" - "github.com/Azure/go-autorest/autorest/adal" - "github.com/Azure/go-autorest/autorest/azure/auth" -) - -var ( - // for service principal and device - oauthConfig *adal.OAuthConfig - armAuthorizer autorest.Authorizer - batchAuthorizer autorest.Authorizer - graphAuthorizer autorest.Authorizer - keyvaultAuthorizer autorest.Authorizer - - // for service principal - subscriptionID string - tenantID string - clientID string - clientSecret string - - // for device - nativeClientID string -) - -// OAuthGrantType specifies which grant type to use. -type OAuthGrantType int - -const ( - // OAuthGrantTypeServicePrincipal for client credentials flow - OAuthGrantTypeServicePrincipal OAuthGrantType = iota - // OAuthGrantTypeDeviceFlow for device-auth flow - OAuthGrantTypeDeviceFlow -) - -// ParseArgs picks up shared env vars -// Other packages should use this func after helpers.ParseArgs() -func ParseArgs() error { - err := helpers.ParseArgs() - if err != nil { - log.Fatalf("failed to parse args: %v\n", err) - } - - err = helpers.ReadEnvFile() - if err != nil { - return err - } - - tenantID = os.Getenv("AZURE_TENANT_ID") - clientID = os.Getenv("AZURE_CLIENT_ID") - clientSecret = os.Getenv("AZURE_CLIENT_SECRET") - nativeClientID = os.Getenv("AZURE_NATIVE_CLIENT_ID") - - oauthConfig, err = adal.NewOAuthConfig(helpers.Environment().ActiveDirectoryEndpoint, tenantID) - return err -} - -// ClientID gets the client ID -func ClientID() string { - return clientID -} - -// TenantID gets the client ID -func TenantID() string { - return tenantID -} - -// ClientSecret gets the client secret -func ClientSecret() string { - return clientSecret -} - -// AuthGrantType returns what kind of authentication is going to be used: device flow or service principal -func AuthGrantType() OAuthGrantType { - if helpers.DeviceFlow() { - return OAuthGrantTypeDeviceFlow - } - return OAuthGrantTypeServicePrincipal -} - -// GetResourceManagementAuthorizer gets an OAuth token for managing resources using the specified grant type. -func GetResourceManagementAuthorizer(grantType OAuthGrantType) (a autorest.Authorizer, err error) { - if armAuthorizer != nil { - return armAuthorizer, nil - } - - switch grantType { - case OAuthGrantTypeServicePrincipal: - a, err = auth.NewAuthorizerFromEnvironment() - case OAuthGrantTypeDeviceFlow: - config := auth.NewDeviceFlowConfig(nativeClientID, tenantID) - a, err = config.Authorizer() - default: - log.Fatalln("invalid token type specified") - } - - if err == nil { - armAuthorizer = a - } - return -} - -// GetBatchAuthorizer gets an authorizer for Azure batch using the specified grant type. -func GetBatchAuthorizer(grantType OAuthGrantType) (a autorest.Authorizer, err error) { - if batchAuthorizer != nil { - return batchAuthorizer, nil - } - - a, err = getAuthorizer(grantType, helpers.Environment().BatchManagementEndpoint) - if err == nil { - batchAuthorizer = a - } - - return -} - -// GetGraphAuthorizer gets an authorizer for the graphrbac API using the specified grant type. -func GetGraphAuthorizer(grantType OAuthGrantType) (a autorest.Authorizer, err error) { - if graphAuthorizer != nil { - return graphAuthorizer, nil - } - - a, err = getAuthorizer(grantType, helpers.Environment().GraphEndpoint) - if err == nil { - graphAuthorizer = a - } - - return -} - -// GetResourceManagementTokenHybrid retrieves auth token for hybrid environment -func GetResourceManagementTokenHybrid(activeDirectoryEndpoint, tokenAudience string) (adal.OAuthTokenProvider, error) { - var token adal.OAuthTokenProvider - oauthConfig, err := adal.NewOAuthConfig(activeDirectoryEndpoint, tenantID) - token, err = adal.NewServicePrincipalToken( - *oauthConfig, - clientID, - clientSecret, - tokenAudience) - - return token, err -} - -func getAuthorizer(grantType OAuthGrantType, endpoint string) (a autorest.Authorizer, err error) { - switch grantType { - case OAuthGrantTypeServicePrincipal: - token, err := adal.NewServicePrincipalToken(*oauthConfig, clientID, clientSecret, endpoint) - if err != nil { - return a, err - } - a = autorest.NewBearerAuthorizer(token) - case OAuthGrantTypeDeviceFlow: - config := auth.NewDeviceFlowConfig(nativeClientID, tenantID) - config.Resource = endpoint - a, err = config.Authorizer() - default: - log.Fatalln("invalid token type specified") - } - return -} - -// GetKeyvaultAuthorizer gets an authorizer for the keyvault dataplane -func GetKeyvaultAuthorizer(grantType OAuthGrantType) (a autorest.Authorizer, err error) { - if keyvaultAuthorizer != nil { - return keyvaultAuthorizer, nil - } - - vaultEndpoint := strings.TrimSuffix(helpers.Environment().KeyVaultEndpoint, "/") - config, err := adal.NewOAuthConfig(helpers.Environment().ActiveDirectoryEndpoint, tenantID) - updatedAuthorizeEndpoint, err := url.Parse("https://login.windows.net/" + tenantID + "/oauth2/token") - config.AuthorizeEndpoint = *updatedAuthorizeEndpoint - if err != nil { - return - } - - switch grantType { - case OAuthGrantTypeServicePrincipal: - token, err := adal.NewServicePrincipalToken(*config, clientID, clientSecret, vaultEndpoint) - if err != nil { - return a, err - } - a = autorest.NewBearerAuthorizer(token) - case OAuthGrantTypeDeviceFlow: - deviceConfig := auth.NewDeviceFlowConfig(nativeClientID, tenantID) - deviceConfig.Resource = vaultEndpoint - deviceConfig.AADEndpoint = updatedAuthorizeEndpoint.String() - a, err = deviceConfig.Authorizer() - default: - log.Fatalln("invalid token type specified") - } - - if err == nil { - keyvaultAuthorizer = a - } - - return -} diff --git a/internal/config/canary.go b/internal/config/canary.go new file mode 100644 index 000000000..2ee2a703c --- /dev/null +++ b/internal/config/canary.go @@ -0,0 +1,57 @@ +package config + +import ( + "log" + "strings" + + "github.com/Azure-Samples/azure-sdk-for-go-samples/internal/util" +) + +var allLocations = []string{ + "eastasia", + "southeastasia", + "centralus", + "eastus", + "eastus2", + "westus", + "northcentralus", + "southcentralus", + "northeurope", + "westeurope", + "japanwest", + "japaneast", + "brazilsouth", + "australiaeast", + "australiasoutheast", + "southindia", + "centralindia", + "westindia", + "canadacentral", + "canadaeast", + "uksouth", + "ukwest", + "westcentralus", + "westus2", + "koreacentral", + "koreasouth", +} + +var locationOverrideTemplate = "overriding default location %s for this package because service is not available there. using location %s instead.\n" + +// OverrideCanaryLocation overrides the specified canary location where to create Azure resources. +func OverrideCanaryLocation(usableLocation string) { + if strings.HasSuffix(location, "euap") { + log.Printf(locationOverrideTemplate, usableLocation, location) + location = usableLocation + } +} + +// OverrideLocation overrides the specified location where to create Azure resources. +// This can be used when the selection location does not have the desired resource provider available yet +func OverrideLocation(available []string) { + // If location is not listed on all locations, don't override it. It might be a canary location + if util.Contains(allLocations, location) && !util.Contains(available, location) && len(available) > 0 { + log.Printf(locationOverrideTemplate, available[0], location) + location = available[0] + } +} diff --git a/internal/config/config.go b/internal/config/config.go new file mode 100644 index 000000000..85ec7a54a --- /dev/null +++ b/internal/config/config.go @@ -0,0 +1,146 @@ +// package config manages loading configuration from environment and command-line params +// Some of these should be considered base names and defaults rather than exact +// settings. +package config + +import ( + "fmt" + "strings" + + "github.com/Azure/go-autorest/autorest/azure" + "github.com/marstr/randname" +) + +var ( + // these are our *global* config settings, to be shared by all packages. + // each has corresponding public accessors below. + // if anything requires a `Set` accessor, that indicates it perhaps + // shouldn't be set here, because mutable vars shouldn't be global. + clientID string + clientSecret string + tenantID string + subscriptionID string + location string + resourceURL string + authorizationServerURL string + cloudName string = "AzurePublicCloud" + useDeviceFlow bool + keepResources bool + groupName string // deprecated, use baseGroupName instead + baseGroupName string + userAgent string +) + +// ClientID is the OAuth client ID. +func ClientID() string { + return clientID +} + +// ClientSecret is the OAuth client secret. +func ClientSecret() string { + return clientSecret +} + +// TenantID is the AAD tenant to which this client belongs. +func TenantID() string { + return tenantID +} + +// TODO: shouldn't be global. deprecate and manage within packages. +// ResourceURL is the URL of a resource for which access is to be requested via +// OAuth. +func ResourceURL() string { + return resourceURL +} + +// SubscriptionID is a target subscription for Azure resources. +func SubscriptionID() string { + return subscriptionID +} + +// deprecated: use DefaultLocation() instead +// Location returns the Azure location to be utilized. +func Location() string { + return location +} + +// DefaultLocation() returns the default location wherein to create new resources. +// Some resource types are not available in all locations so another location might need +// to be chosen. +func DefaultLocation() string { + return location +} + +// AuthorizationServerURL is the OAuth authorization server URL. +// Q: Can this be gotten from the `azure.Environment` in `Environment()`? +func AuthorizationServerURL() string { + return authorizationServerURL +} + +// UseDeviceFlow() specifies if interactive auth should be used. Interactive +// auth uses the OAuth Device Flow grant type. +func UseDeviceFlow() bool { + return useDeviceFlow +} + +// deprecated: do not use global group names +// utilize `BaseGroupName()` for a shared prefix +func GroupName() string { + return groupName +} + +// deprecated: we have to set this because we use a global for group names +// once that's fixed this should be removed +func SetGroupName(name string) { + groupName = name +} + +// BaseGroupName() returns a prefix for new groups. +func BaseGroupName() string { + return baseGroupName +} + +// KeepResources() specifies whether to keep resources created by samples. +func KeepResources() bool { + return keepResources +} + +// UserAgent() specifies a string to append to the agent identifier. +func UserAgent() string { + if len(userAgent) > 0 { + return userAgent + } + return "sdk-samples" +} + +// cache +var environment *azure.Environment + +// Environment() returns an `azure.Environment{...}` for the current cloud. +func Environment() *azure.Environment { + if environment != nil { + return environment + } + env, err := azure.EnvironmentFromName(cloudName) + if err != nil { + // TODO: move to initialization of var + panic(fmt.Sprintf( + "invalid cloud name '%s' specified, cannot continue\n", cloudName)) + } + environment = &env + return environment +} + +// GenerateGroupName leverages BaseGroupName() to return a more detailed name, +// helping to avoid collisions. It appends each of the `affixes` to +// BaseGroupName() separated by dashes, and adds a 5-character random string. +func GenerateGroupName(affixes ...string) string { + var b strings.Builder + b.WriteString(BaseGroupName()) + b.WriteRune('-') + for _, affix := range affixes { + b.WriteString(affix) + b.WriteRune('-') + } + return randname.GenerateWithPrefix(b.String(), 5) +} diff --git a/internal/config/env.go b/internal/config/env.go new file mode 100644 index 000000000..93ff43e95 --- /dev/null +++ b/internal/config/env.go @@ -0,0 +1,65 @@ +package config + +import ( + "fmt" + "log" + "strconv" + + "github.com/Azure/go-autorest/autorest/azure" + "github.com/gobuffalo/envy" +) + +// ParseEnvironment loads a sibling `.env` file then looks through all environment +// variables to set global configuration. +func ParseEnvironment() error { + envy.Load() + azureEnv, _ := azure.EnvironmentFromName("AzurePublicCloud") // shouldn't fail + authorizationServerURL = azureEnv.ActiveDirectoryEndpoint + + // AZURE_GROUP_NAME and `config.GroupName()` are deprecated. + // Use AZURE_BASE_GROUP_NAME and `config.GenerateGroupName()` instead. + groupName = envy.Get("AZURE_GROUP_NAME", "azure-go-samples") + baseGroupName = envy.Get("AZURE_BASE_GROUP_NAME", groupName) + + resourceURL = envy.Get("AZURE_RESOURCE_URL", azureEnv.ResourceManagerEndpoint) + location = envy.Get("AZURE_LOCATION_DEFAULT", "westus2") + + var err error + useDeviceFlow, err = strconv.ParseBool(envy.Get("AZURE_USE_DEVICEFLOW", "0")) + if err != nil { + log.Printf("invalid value specified for AZURE_USE_DEVICEFLOW, disabling\n") + useDeviceFlow = false + } + keepResources, err = strconv.ParseBool(envy.Get("AZURE_SAMPLES_KEEP_RESOURCES", "0")) + if err != nil { + log.Printf("invalid value specified for AZURE_SAMPLES_KEEP_RESOURCES, discarding\n") + keepResources = false + } + + // these must be provided by environment + // clientID + clientID, err = envy.MustGet("AZURE_CLIENT_ID") + if err != nil { + return fmt.Errorf("expected env vars not provided: %s\n", err) + } + + // clientSecret + clientSecret, err = envy.MustGet("AZURE_CLIENT_SECRET") + if err != nil && useDeviceFlow != true { // don't need a secret for device flow + return fmt.Errorf("expected env vars not provided: %s\n", err) + } + + // tenantID (AAD) + tenantID, err = envy.MustGet("AZURE_TENANT_ID") + if err != nil { + return fmt.Errorf("expected env vars not provided: %s\n", err) + } + + // subscriptionID (ARM) + subscriptionID, err = envy.MustGet("AZURE_SUBSCRIPTION_ID") + if err != nil { + return fmt.Errorf("expected env vars not provided: %s\n", err) + } + + return nil +} diff --git a/internal/config/flags.go b/internal/config/flags.go new file mode 100644 index 000000000..453b16cca --- /dev/null +++ b/internal/config/flags.go @@ -0,0 +1,19 @@ +package config + +import ( + "flag" +) + +// AddFlags adds flags applicable to all services. +// Remember to call `flag.Parse()` in your main or TestMain. +func AddFlags() error { + flag.StringVar(&subscriptionID, "subscription", subscriptionID, "Subscription for tests.") + flag.StringVar(&location, "location", location, "Default location for tests.") + flag.StringVar(&cloudName, "cloud", cloudName, "Name of Azure cloud.") + flag.StringVar(&baseGroupName, "baseGroupName", BaseGroupName(), "Specify prefix name of resource group for sample resources.") + + flag.BoolVar(&useDeviceFlow, "useDeviceFlow", useDeviceFlow, "Use device-flow grant type rather than client credentials.") + flag.BoolVar(&keepResources, "keepResources", keepResources, "Keep resources created by samples.") + + return nil +} diff --git a/internal/iam/authorizers.go b/internal/iam/authorizers.go new file mode 100644 index 000000000..e947c05a1 --- /dev/null +++ b/internal/iam/authorizers.go @@ -0,0 +1,210 @@ +// Copyright (c) Microsoft and contributors. All rights reserved. +// +// This source code is licensed under the MIT license found in the +// LICENSE file in the root directory of this source tree. + +package iam + +import ( + "fmt" + "net/url" + "strings" + + "github.com/Azure-Samples/azure-sdk-for-go-samples/internal/config" + + "github.com/Azure/go-autorest/autorest" + "github.com/Azure/go-autorest/autorest/adal" + "github.com/Azure/go-autorest/autorest/azure/auth" +) + +var ( + armAuthorizer autorest.Authorizer + batchAuthorizer autorest.Authorizer + graphAuthorizer autorest.Authorizer + keyvaultAuthorizer autorest.Authorizer +) + +// OAuthGrantType specifies which grant type to use. +type OAuthGrantType int + +const ( + // OAuthGrantTypeServicePrincipal for client credentials flow + OAuthGrantTypeServicePrincipal OAuthGrantType = iota + // OAuthGrantTypeDeviceFlow for device flow + OAuthGrantTypeDeviceFlow +) + +// GrantType returns what grant type has been configured. +func grantType() OAuthGrantType { + if config.UseDeviceFlow() { + return OAuthGrantTypeDeviceFlow + } + return OAuthGrantTypeServicePrincipal +} + +// GetResourceManagementAuthorizer gets an OAuthTokenAuthorizer for Azure Resource Manager +func GetResourceManagementAuthorizer() (autorest.Authorizer, error) { + if armAuthorizer != nil { + return armAuthorizer, nil + } + + var a autorest.Authorizer + var err error + + a, err = getAuthorizerForResource( + grantType(), config.Environment().ResourceManagerEndpoint) + + if err == nil { + // cache + armAuthorizer = a + } else { + // clear cache + armAuthorizer = nil + } + return armAuthorizer, err +} + +// GetBatchAuthorizer gets an OAuthTokenAuthorizer for Azure Batch. +func GetBatchAuthorizer() (autorest.Authorizer, error) { + if batchAuthorizer != nil { + return batchAuthorizer, nil + } + + var a autorest.Authorizer + var err error + + a, err = getAuthorizerForResource( + grantType(), config.Environment().BatchManagementEndpoint) + + if err == nil { + // cache + batchAuthorizer = a + } else { + // clear cache + batchAuthorizer = nil + } + + return batchAuthorizer, err +} + +// GetGraphAuthorizer gets an OAuthTokenAuthorizer for graphrbac API. +func GetGraphAuthorizer() (autorest.Authorizer, error) { + if graphAuthorizer != nil { + return graphAuthorizer, nil + } + + var a autorest.Authorizer + var err error + + a, err = getAuthorizerForResource(grantType(), config.Environment().GraphEndpoint) + + if err == nil { + // cache + graphAuthorizer = a + } else { + graphAuthorizer = nil + } + + return graphAuthorizer, err +} + +// GetKeyvaultAuthorizer gets an OAuthTokenAuthorizer for use with Key Vault +// keys and secrets. Note that Key Vault *Vaults* are managed by Azure Resource +// Manager. +func GetKeyvaultAuthorizer() (autorest.Authorizer, error) { + if keyvaultAuthorizer != nil { + return keyvaultAuthorizer, nil + } + + // BUG: default value for KeyVaultEndpoint is wrong + vaultEndpoint := strings.TrimSuffix(config.Environment().KeyVaultEndpoint, "/") + // BUG: alternateEndpoint replaces other endpoints in the configs below + alternateEndpoint, _ := url.Parse( + "https://login.windows.net/" + config.TenantID() + "/oauth2/token") + + var a autorest.Authorizer + var err error + + switch grantType() { + case OAuthGrantTypeServicePrincipal: + oauthconfig, err := adal.NewOAuthConfig( + config.Environment().ActiveDirectoryEndpoint, config.TenantID()) + if err != nil { + return a, err + } + oauthconfig.AuthorizeEndpoint = *alternateEndpoint + + token, err := adal.NewServicePrincipalToken( + *oauthconfig, config.ClientID(), config.ClientSecret(), vaultEndpoint) + if err != nil { + return a, err + } + + a = autorest.NewBearerAuthorizer(token) + + case OAuthGrantTypeDeviceFlow: + deviceConfig := auth.NewDeviceFlowConfig(config.ClientID(), config.TenantID()) + deviceConfig.Resource = vaultEndpoint + deviceConfig.AADEndpoint = alternateEndpoint.String() + a, err = deviceConfig.Authorizer() + default: + return a, fmt.Errorf("invalid grant type specified: %s\n", grantType) + } + + if err == nil { + keyvaultAuthorizer = a + } else { + keyvaultAuthorizer = nil + } + + return keyvaultAuthorizer, err +} + +func getAuthorizerForResource(grantType OAuthGrantType, resource string) (autorest.Authorizer, error) { + + var a autorest.Authorizer + var err error + + switch grantType { + + case OAuthGrantTypeServicePrincipal: + oauthConfig, err := adal.NewOAuthConfig( + config.Environment().ActiveDirectoryEndpoint, config.TenantID()) + if err != nil { + return nil, err + } + + token, err := adal.NewServicePrincipalToken( + *oauthConfig, config.ClientID(), config.ClientSecret(), resource) + if err != nil { + return nil, err + } + a = autorest.NewBearerAuthorizer(token) + + case OAuthGrantTypeDeviceFlow: + deviceconfig := auth.NewDeviceFlowConfig(config.ClientID(), config.TenantID()) + deviceconfig.Resource = resource + a, err = deviceconfig.Authorizer() + if err != nil { + return nil, err + } + + default: + return a, fmt.Errorf("invalid grant type specified: %s\n", grantType) + } + + return a, err +} + +// GetResourceManagementTokenHybrid retrieves auth token for hybrid environment +func GetResourceManagementTokenHybrid(activeDirectoryEndpoint, tokenAudience string) (adal.OAuthTokenProvider, error) { + var tokenProvider adal.OAuthTokenProvider + oauthConfig, err := adal.NewOAuthConfig(activeDirectoryEndpoint, config.TenantID()) + tokenProvider, err = adal.NewServicePrincipalToken( + *oauthConfig, + config.ClientID(), + config.ClientSecret(), + tokenAudience) + + return tokenProvider, err +} diff --git a/helpers/helpers.go b/internal/util/util.go similarity index 58% rename from helpers/helpers.go rename to internal/util/util.go index 326e3b094..c3877db15 100644 --- a/helpers/helpers.go +++ b/internal/util/util.go @@ -1,17 +1,10 @@ -// Copyright (c) Microsoft and contributors. All rights reserved. -// -// This source code is licensed under the MIT license found in the -// LICENSE file in the root directory of this source tree. - -package helpers +package util import ( "encoding/json" "fmt" "io/ioutil" "log" - - "github.com/Azure/go-autorest/autorest/utils" ) // PrintAndLog writes to stdout and to a logger. @@ -20,7 +13,7 @@ func PrintAndLog(message string) { fmt.Println(message) } -func contains(array []string, element string) bool { +func Contains(array []string, element string) bool { for _, e := range array { if e == element { return true @@ -29,11 +22,6 @@ func contains(array []string, element string) bool { return false } -// UserAgent return the string to be appended to user agent header -func UserAgent() string { - return "samples " + utils.GetCommit() -} - // ReadJSON reads a json file, and unmashals it. // Very useful for template deployments. func ReadJSON(path string) (*map[string]interface{}, error) { diff --git a/network/hybrid/network.go b/network/hybrid/network.go index 5662a875c..36e0705e7 100644 --- a/network/hybrid/network.go +++ b/network/hybrid/network.go @@ -10,12 +10,13 @@ import ( "fmt" "log" - "github.com/Azure-Samples/azure-sdk-for-go-samples/helpers" - "github.com/Azure-Samples/azure-sdk-for-go-samples/iam" "github.com/Azure/azure-sdk-for-go/profiles/2017-03-09/network/mgmt/network" "github.com/Azure/go-autorest/autorest" "github.com/Azure/go-autorest/autorest/azure" "github.com/Azure/go-autorest/autorest/to" + + "github.com/Azure-Samples/azure-sdk-for-go-samples/internal/config" + "github.com/Azure-Samples/azure-sdk-for-go-samples/internal/iam" ) const ( @@ -27,9 +28,9 @@ func getVnetClient(activeDirectoryEndpoint, tokenAudience string) network.Virtua if err != nil { log.Fatal(fmt.Sprintf(errorPrefix, "virtual network", fmt.Sprintf("Cannot generate token. Error details: %v.", err))) } - vnetClient := network.NewVirtualNetworksClientWithBaseURI(helpers.ArmEndpoint(), helpers.SubscriptionID()) + vnetClient := network.NewVirtualNetworksClientWithBaseURI(config.Environment().ResourceManagerEndpoint, config.SubscriptionID()) vnetClient.Authorizer = autorest.NewBearerAuthorizer(token) - vnetClient.AddToUserAgent(helpers.UserAgent()) + vnetClient.AddToUserAgent(config.UserAgent()) return vnetClient } @@ -38,9 +39,9 @@ func getNsgClient(activeDirectoryEndpoint, tokenAudience string) network.Securit if err != nil { log.Fatal(fmt.Sprintf(errorPrefix, "security group", fmt.Sprintf("Cannot generate token. Error details: %v.", err))) } - nsgClient := network.NewSecurityGroupsClientWithBaseURI(helpers.ArmEndpoint(), helpers.SubscriptionID()) + nsgClient := network.NewSecurityGroupsClientWithBaseURI(config.Environment().ResourceManagerEndpoint, config.SubscriptionID()) nsgClient.Authorizer = autorest.NewBearerAuthorizer(token) - nsgClient.AddToUserAgent(helpers.UserAgent()) + nsgClient.AddToUserAgent(config.UserAgent()) return nsgClient } @@ -49,9 +50,9 @@ func getIPClient(activeDirectoryEndpoint, tokenAudience string) network.PublicIP if err != nil { log.Fatal(fmt.Sprintf(errorPrefix, "public IP address", fmt.Sprintf("Cannot generate token. Error details: %v.", err))) } - ipClient := network.NewPublicIPAddressesClientWithBaseURI(helpers.ArmEndpoint(), helpers.SubscriptionID()) + ipClient := network.NewPublicIPAddressesClientWithBaseURI(config.Environment().ResourceManagerEndpoint, config.SubscriptionID()) ipClient.Authorizer = autorest.NewBearerAuthorizer(token) - ipClient.AddToUserAgent(helpers.UserAgent()) + ipClient.AddToUserAgent(config.UserAgent()) return ipClient } @@ -60,9 +61,9 @@ func getNicClient(activeDirectoryEndpoint, tokenAudience string) network.Interfa if err != nil { log.Fatal(fmt.Sprintf(errorPrefix, "network interface", fmt.Sprintf("Cannot generate token. Error details: %v.", err))) } - nicClient := network.NewInterfacesClientWithBaseURI(helpers.ArmEndpoint(), helpers.SubscriptionID()) + nicClient := network.NewInterfacesClientWithBaseURI(config.Environment().ResourceManagerEndpoint, config.SubscriptionID()) nicClient.Authorizer = autorest.NewBearerAuthorizer(token) - nicClient.AddToUserAgent(helpers.UserAgent()) + nicClient.AddToUserAgent(config.UserAgent()) return nicClient } @@ -71,23 +72,23 @@ func getSubnetsClient(activeDirectoryEndpoint, tokenAudience string) network.Sub if err != nil { log.Fatal(fmt.Sprintf(errorPrefix, "subnet", fmt.Sprintf("Cannot generate token. Error details: %v.", err))) } - subnetsClient := network.NewSubnetsClientWithBaseURI(helpers.ArmEndpoint(), helpers.SubscriptionID()) + subnetsClient := network.NewSubnetsClientWithBaseURI(config.Environment().ResourceManagerEndpoint, config.SubscriptionID()) subnetsClient.Authorizer = autorest.NewBearerAuthorizer(token) - subnetsClient.AddToUserAgent(helpers.UserAgent()) + subnetsClient.AddToUserAgent(config.UserAgent()) return subnetsClient } // CreateVirtualNetworkAndSubnets creates a virtual network with one subnet -func CreateVirtualNetworkAndSubnets(cntx context.Context, vnetName, subnetName string) (vnet network.VirtualNetwork, err error) { +func CreateVirtualNetworkAndSubnets(ctx context.Context, vnetName, subnetName string) (vnet network.VirtualNetwork, err error) { resourceName := "virtual network and subnet" - environment, _ := azure.EnvironmentFromURL(helpers.ArmEndpoint()) + environment := config.Environment() vnetClient := getVnetClient(environment.ActiveDirectoryEndpoint, environment.TokenAudience) future, err := vnetClient.CreateOrUpdate( - cntx, - helpers.ResourceGroupName(), + ctx, + config.GroupName(), vnetName, network.VirtualNetwork{ - Location: to.StringPtr(helpers.Location()), + Location: to.StringPtr(config.Location()), VirtualNetworkPropertiesFormat: &network.VirtualNetworkPropertiesFormat{ AddressSpace: &network.AddressSpace{ AddressPrefixes: &[]string{"10.0.0.0/8"}, @@ -107,7 +108,7 @@ func CreateVirtualNetworkAndSubnets(cntx context.Context, vnetName, subnetName s return vnet, fmt.Errorf(fmt.Sprintf(errorPrefix, resourceName, err)) } - err = future.WaitForCompletion(cntx, vnetClient.Client) + err = future.WaitForCompletion(ctx, vnetClient.Client) if err != nil { return vnet, fmt.Errorf(fmt.Sprintf(errorPrefix, resourceName, fmt.Sprintf("cannot get the vnet create or update future response: %v", err))) } @@ -116,16 +117,16 @@ func CreateVirtualNetworkAndSubnets(cntx context.Context, vnetName, subnetName s } // CreateNetworkSecurityGroup creates a new network security group -func CreateNetworkSecurityGroup(cntx context.Context, nsgName string) (nsg network.SecurityGroup, err error) { +func CreateNetworkSecurityGroup(ctx context.Context, nsgName string) (nsg network.SecurityGroup, err error) { resourceName := "security group" - environment, _ := azure.EnvironmentFromURL(helpers.ArmEndpoint()) + environment := config.Environment() nsgClient := getNsgClient(environment.ActiveDirectoryEndpoint, environment.TokenAudience) future, err := nsgClient.CreateOrUpdate( - cntx, - helpers.ResourceGroupName(), + ctx, + config.GroupName(), nsgName, network.SecurityGroup{ - Location: to.StringPtr(helpers.Location()), + Location: to.StringPtr(config.Location()), SecurityGroupPropertiesFormat: &network.SecurityGroupPropertiesFormat{ SecurityRules: &[]network.SecurityRule{ { @@ -163,7 +164,7 @@ func CreateNetworkSecurityGroup(cntx context.Context, nsgName string) (nsg netwo return nsg, fmt.Errorf(fmt.Sprintf(errorPrefix, resourceName, err)) } - err = future.WaitForCompletion(cntx, nsgClient.Client) + err = future.WaitForCompletion(ctx, nsgClient.Client) if err != nil { return nsg, fmt.Errorf(fmt.Sprintf(errorPrefix, resourceName, fmt.Sprintf("cannot get nsg create or update future response: %v", err))) } @@ -172,17 +173,17 @@ func CreateNetworkSecurityGroup(cntx context.Context, nsgName string) (nsg netwo } // CreatePublicIP creates a new public IP -func CreatePublicIP(cntx context.Context, ipName string) (ip network.PublicIPAddress, err error) { +func CreatePublicIP(ctx context.Context, ipName string) (ip network.PublicIPAddress, err error) { resourceName := "public IP" - environment, _ := azure.EnvironmentFromURL(helpers.ArmEndpoint()) + environment, _ := azure.EnvironmentFromURL(config.Environment().ResourceManagerEndpoint) ipClient := getIPClient(environment.ActiveDirectoryEndpoint, environment.TokenAudience) future, err := ipClient.CreateOrUpdate( - cntx, - helpers.ResourceGroupName(), + ctx, + config.GroupName(), ipName, network.PublicIPAddress{ Name: to.StringPtr(ipName), - Location: to.StringPtr(helpers.Location()), + Location: to.StringPtr(config.Location()), PublicIPAddressPropertiesFormat: &network.PublicIPAddressPropertiesFormat{ PublicIPAllocationMethod: network.Static, }, @@ -193,7 +194,7 @@ func CreatePublicIP(cntx context.Context, ipName string) (ip network.PublicIPAdd return ip, fmt.Errorf(fmt.Sprintf(errorPrefix, resourceName, err)) } - err = future.WaitForCompletion(cntx, ipClient.Client) + err = future.WaitForCompletion(ctx, ipClient.Client) if err != nil { return ip, fmt.Errorf(fmt.Sprintf(errorPrefix, resourceName, fmt.Sprintf("cannot get public ip address create or update future response: %v", err))) } @@ -201,29 +202,29 @@ func CreatePublicIP(cntx context.Context, ipName string) (ip network.PublicIPAdd } // CreateNetworkInterface creates a new network interface -func CreateNetworkInterface(cntx context.Context, netInterfaceName, nsgName, vnetName, subnetName, ipName string) (nic network.Interface, err error) { +func CreateNetworkInterface(ctx context.Context, netInterfaceName, nsgName, vnetName, subnetName, ipName string) (nic network.Interface, err error) { resourceName := "network interface" - nsg, err := GetNetworkSecurityGroup(cntx, nsgName) + nsg, err := GetNetworkSecurityGroup(ctx, nsgName) if err != nil { return nic, fmt.Errorf(fmt.Sprintf(errorPrefix, resourceName, fmt.Sprintf("failed to get netwrok security group: %v", err))) } - subnet, err := GetVirtualNetworkSubnet(cntx, vnetName, subnetName) + subnet, err := GetVirtualNetworkSubnet(ctx, vnetName, subnetName) if err != nil { return nic, fmt.Errorf(fmt.Sprintf(errorPrefix, resourceName, fmt.Sprintf("failed to get subnet: %v", err))) } - ip, err := GetPublicIP(cntx, ipName) + ip, err := GetPublicIP(ctx, ipName) if err != nil { return nic, fmt.Errorf(fmt.Sprintf(errorPrefix, resourceName, fmt.Sprintf("failed to get ip address: %v", err))) } - environment, _ := azure.EnvironmentFromURL(helpers.ArmEndpoint()) + environment := config.Environment() nicClient := getNicClient(environment.ActiveDirectoryEndpoint, environment.TokenAudience) future, err := nicClient.CreateOrUpdate( - cntx, - helpers.ResourceGroupName(), + ctx, + config.GroupName(), netInterfaceName, network.Interface{ Name: to.StringPtr(netInterfaceName), - Location: to.StringPtr(helpers.Location()), + Location: to.StringPtr(config.Location()), InterfacePropertiesFormat: &network.InterfacePropertiesFormat{ NetworkSecurityGroup: &nsg, IPConfigurations: &[]network.InterfaceIPConfiguration{ @@ -242,7 +243,7 @@ func CreateNetworkInterface(cntx context.Context, netInterfaceName, nsgName, vne if err != nil { return nic, fmt.Errorf(fmt.Sprintf(errorPrefix, resourceName, err)) } - err = future.WaitForCompletion(cntx, nicClient.Client) + err = future.WaitForCompletion(ctx, nicClient.Client) if err != nil { return nic, fmt.Errorf(fmt.Sprintf(errorPrefix, resourceName, fmt.Sprintf("cannot get nic create or update future response: %v", err))) } @@ -250,29 +251,29 @@ func CreateNetworkInterface(cntx context.Context, netInterfaceName, nsgName, vne } // GetNetworkSecurityGroup retrieves a netwrok resource group by its name -func GetNetworkSecurityGroup(cntx context.Context, nsgName string) (network.SecurityGroup, error) { - environment, _ := azure.EnvironmentFromURL(helpers.ArmEndpoint()) +func GetNetworkSecurityGroup(ctx context.Context, nsgName string) (network.SecurityGroup, error) { + environment := config.Environment() nsgClient := getNsgClient(environment.ActiveDirectoryEndpoint, environment.TokenAudience) - return nsgClient.Get(cntx, helpers.ResourceGroupName(), nsgName, "") + return nsgClient.Get(ctx, config.GroupName(), nsgName, "") } // GetVirtualNetworkSubnet retrieves a virtual netwrok subnet by its name -func GetVirtualNetworkSubnet(cntx context.Context, vnetName string, subnetName string) (network.Subnet, error) { - environment, _ := azure.EnvironmentFromURL(helpers.ArmEndpoint()) +func GetVirtualNetworkSubnet(ctx context.Context, vnetName string, subnetName string) (network.Subnet, error) { + environment := config.Environment() subnetsClient := getSubnetsClient(environment.ActiveDirectoryEndpoint, environment.TokenAudience) - return subnetsClient.Get(cntx, helpers.ResourceGroupName(), vnetName, subnetName, "") + return subnetsClient.Get(ctx, config.GroupName(), vnetName, subnetName, "") } // GetPublicIP retrieves a public IP by its name -func GetPublicIP(cntx context.Context, ipName string) (network.PublicIPAddress, error) { - environment, _ := azure.EnvironmentFromURL(helpers.ArmEndpoint()) +func GetPublicIP(ctx context.Context, ipName string) (network.PublicIPAddress, error) { + environment := config.Environment() ipClient := getIPClient(environment.ActiveDirectoryEndpoint, environment.TokenAudience) - return ipClient.Get(cntx, helpers.ResourceGroupName(), ipName, "") + return ipClient.Get(ctx, config.GroupName(), ipName, "") } // GetNic retrieves a network interface by its name -func GetNic(cntx context.Context, nicName string) (network.Interface, error) { - environment, _ := azure.EnvironmentFromURL(helpers.ArmEndpoint()) +func GetNic(ctx context.Context, nicName string) (network.Interface, error) { + environment := config.Environment() nicClient := getNicClient(environment.ActiveDirectoryEndpoint, environment.TokenAudience) - return nicClient.Get(cntx, helpers.ResourceGroupName(), nicName, "") + return nicClient.Get(ctx, config.GroupName(), nicName, "") } diff --git a/network/hybrid/network_test.go b/network/hybrid/network_test.go index 1bb312245..1fbb52591 100644 --- a/network/hybrid/network_test.go +++ b/network/hybrid/network_test.go @@ -7,14 +7,17 @@ package network import ( "context" + "flag" "fmt" "log" "os" "testing" + "time" - "github.com/Azure-Samples/azure-sdk-for-go-samples/helpers" - "github.com/Azure-Samples/azure-sdk-for-go-samples/iam" hybridresources "github.com/Azure-Samples/azure-sdk-for-go-samples/resources/hybrid" + + "github.com/Azure-Samples/azure-sdk-for-go-samples/internal/config" + "github.com/Azure-Samples/azure-sdk-for-go-samples/internal/util" ) var ( @@ -26,45 +29,65 @@ var ( networkInterfaceName = "netinterface1" ) -func TestMain(m *testing.M) { - err := helpers.ParseArgs() - if err != nil { - log.Fatalf("failed to parse network args: %v\n", err) - } +func setupEnvironment() error { + err1 := config.ParseEnvironment() + err2 := config.AddFlags() + err3 := addLocalConfig() - err = iam.ParseArgs() - if err != nil { - log.Fatalln("failed to parse IAM args") + for _, err := range []error{err1, err2, err3} { + if err != nil { + return err + } } - os.Exit(m.Run()) + flag.Parse() + return nil } -func ExampleCreateVirtualNetworkAndSubnets() { - ctx := context.Background() +func addLocalConfig() error { + vnetNameFromEnv := os.Getenv("AZURE_VNET_NAME") + if len(vnetNameFromEnv) > 0 { + virtualNetworkName = vnetNameFromEnv + } + flag.StringVar(&virtualNetworkName, "vnetName", virtualNetworkName, "Name for the VNET.") + return nil +} + +func TestNetwork(t *testing.T) { + err := setupEnvironment() + if err != nil { + t.Fatalf("could not set up environment: %v\n", err) + } + + groupName := config.GenerateGroupName("network-test") + config.SetGroupName(groupName) // TODO: don't use globals + ctx, cancel := context.WithTimeout(context.Background(), 300*time.Second) + defer cancel() defer hybridresources.Cleanup(ctx) - _, err := hybridresources.CreateGroup(ctx) + + _, err = hybridresources.CreateGroup(ctx) if err != nil { - helpers.PrintAndLog(err.Error()) + t.Fatalf("could not create group %v\n", err.Error()) } _, err = CreateVirtualNetworkAndSubnets(context.Background(), virtualNetworkName, subnetName) if err != nil { - log.Fatal(fmt.Sprintf("Cannot create virtual network. Error details: %s", err.Error())) + t.Fatalf("could not create vnet: %v\n", err.Error()) } - fmt.Println("VNET created") - - // Output: - // VNET created + t.Logf("created vnet") } func ExampleCreateNetworkSecurityGroup() { - ctx := context.Background() + groupName := config.GenerateGroupName("CreateNetworkSecurityGroup") + config.SetGroupName(groupName) // TODO: don't use globals + ctx, cancel := context.WithTimeout(context.Background(), 300*time.Second) + defer cancel() defer hybridresources.Cleanup(ctx) + _, err := hybridresources.CreateGroup(ctx) if err != nil { - helpers.PrintAndLog(err.Error()) + util.PrintAndLog(err.Error()) } - _, err = CreateNetworkSecurityGroup(context.Background(), nsgName) + _, err = CreateNetworkSecurityGroup(ctx, nsgName) if err != nil { log.Fatal(fmt.Sprintf("Cannot create network security group. Error details: %s", err.Error())) } @@ -75,13 +98,17 @@ func ExampleCreateNetworkSecurityGroup() { } func ExampleCreatePublicIP() { - ctx := context.Background() + groupName := config.GenerateGroupName("CreatePublicIP") + config.SetGroupName(groupName) // TODO: don't use globals + ctx, cancel := context.WithTimeout(context.Background(), 300*time.Second) + defer cancel() defer hybridresources.Cleanup(ctx) + _, err := hybridresources.CreateGroup(ctx) if err != nil { - helpers.PrintAndLog(err.Error()) + util.PrintAndLog(err.Error()) } - _, err = CreatePublicIP(context.Background(), ipName) + _, err = CreatePublicIP(ctx, ipName) if err != nil { log.Fatal(fmt.Sprintf("Cannot create public IP. Error details: %s", err.Error())) } @@ -92,13 +119,18 @@ func ExampleCreatePublicIP() { } func ExampleCreateNetworkInterface() { - ctx := context.Background() + groupName := config.GenerateGroupName("CreateNIC") + config.SetGroupName(groupName) // TODO: don't use globals + ctx, cancel := context.WithTimeout(context.Background(), 300*time.Second) + defer cancel() defer hybridresources.Cleanup(ctx) + _, err := hybridresources.CreateGroup(ctx) if err != nil { - helpers.PrintAndLog(err.Error()) + util.PrintAndLog(err.Error()) } - _, err = CreateNetworkInterface(context.Background(), networkInterfaceName, nsgName, virtualNetworkName, subnetName, ipName) + + _, err = CreateNetworkInterface(ctx, networkInterfaceName, nsgName, virtualNetworkName, subnetName, ipName) if err != nil { log.Fatal(fmt.Sprintf("Cannot create network interface. Error details: %s", err.Error())) } diff --git a/network/network.go b/network/network.go index ef779743d..bb8665e83 100644 --- a/network/network.go +++ b/network/network.go @@ -10,19 +10,20 @@ import ( "fmt" "log" - "github.com/Azure-Samples/azure-sdk-for-go-samples/helpers" - "github.com/Azure-Samples/azure-sdk-for-go-samples/iam" "github.com/Azure/azure-sdk-for-go/services/network/mgmt/2017-09-01/network" "github.com/Azure/go-autorest/autorest/to" + + "github.com/Azure-Samples/azure-sdk-for-go-samples/internal/config" + "github.com/Azure-Samples/azure-sdk-for-go-samples/internal/iam" ) // Vnets func getVnetClient() network.VirtualNetworksClient { - vnetClient := network.NewVirtualNetworksClient(helpers.SubscriptionID()) - auth, _ := iam.GetResourceManagementAuthorizer(iam.AuthGrantType()) - vnetClient.Authorizer = auth - vnetClient.AddToUserAgent(helpers.UserAgent()) + vnetClient := network.NewVirtualNetworksClient(config.SubscriptionID()) + a, _ := iam.GetResourceManagementAuthorizer() + vnetClient.Authorizer = a + vnetClient.AddToUserAgent(config.UserAgent()) return vnetClient } @@ -31,10 +32,10 @@ func CreateVirtualNetwork(ctx context.Context, vnetName string) (vnet network.Vi vnetClient := getVnetClient() future, err := vnetClient.CreateOrUpdate( ctx, - helpers.ResourceGroupName(), + config.GroupName(), vnetName, network.VirtualNetwork{ - Location: to.StringPtr(helpers.Location()), + Location: to.StringPtr(config.Location()), VirtualNetworkPropertiesFormat: &network.VirtualNetworkPropertiesFormat{ AddressSpace: &network.AddressSpace{ AddressPrefixes: &[]string{"10.0.0.0/8"}, @@ -59,10 +60,10 @@ func CreateVirtualNetworkAndSubnets(ctx context.Context, vnetName, subnet1Name, vnetClient := getVnetClient() future, err := vnetClient.CreateOrUpdate( ctx, - helpers.ResourceGroupName(), + config.GroupName(), vnetName, network.VirtualNetwork{ - Location: to.StringPtr(helpers.Location()), + Location: to.StringPtr(config.Location()), VirtualNetworkPropertiesFormat: &network.VirtualNetworkPropertiesFormat{ AddressSpace: &network.AddressSpace{ AddressPrefixes: &[]string{"10.0.0.0/8"}, @@ -99,16 +100,16 @@ func CreateVirtualNetworkAndSubnets(ctx context.Context, vnetName, subnet1Name, // DeleteVirtualNetwork deletes a virtual network given an existing virtual network func DeleteVirtualNetwork(ctx context.Context, vnetName string) (result network.VirtualNetworksDeleteFuture, err error) { vnetClient := getVnetClient() - return vnetClient.Delete(ctx, helpers.ResourceGroupName(), vnetName) + return vnetClient.Delete(ctx, config.GroupName(), vnetName) } // VNet Subnets func getSubnetsClient() network.SubnetsClient { - subnetsClient := network.NewSubnetsClient(helpers.SubscriptionID()) - auth, _ := iam.GetResourceManagementAuthorizer(iam.AuthGrantType()) - subnetsClient.Authorizer = auth - subnetsClient.AddToUserAgent(helpers.UserAgent()) + subnetsClient := network.NewSubnetsClient(config.SubscriptionID()) + a, _ := iam.GetResourceManagementAuthorizer() + subnetsClient.Authorizer = a + subnetsClient.AddToUserAgent(config.UserAgent()) return subnetsClient } @@ -118,7 +119,7 @@ func CreateVirtualNetworkSubnet(ctx context.Context, vnetName, subnetName string future, err := subnetsClient.CreateOrUpdate( ctx, - helpers.ResourceGroupName(), + config.GroupName(), vnetName, subnetName, network.Subnet{ @@ -148,7 +149,7 @@ func CreateSubnetWithNetowrkSecurityGroup(ctx context.Context, vnetName, subnetN subnetsClient := getSubnetsClient() future, err := subnetsClient.CreateOrUpdate( ctx, - helpers.ResourceGroupName(), + config.GroupName(), vnetName, subnetName, network.Subnet{ @@ -175,16 +176,16 @@ func DeleteVirtualNetworkSubnet() {} // GetVirtualNetworkSubnet returns an existing subnet from a virtual network func GetVirtualNetworkSubnet(ctx context.Context, vnetName string, subnetName string) (network.Subnet, error) { subnetsClient := getSubnetsClient() - return subnetsClient.Get(ctx, helpers.ResourceGroupName(), vnetName, subnetName, "") + return subnetsClient.Get(ctx, config.GroupName(), vnetName, subnetName, "") } // Network Security Groups func getNsgClient() network.SecurityGroupsClient { - nsgClient := network.NewSecurityGroupsClient(helpers.SubscriptionID()) - auth, _ := iam.GetResourceManagementAuthorizer(iam.AuthGrantType()) - nsgClient.Authorizer = auth - nsgClient.AddToUserAgent(helpers.UserAgent()) + nsgClient := network.NewSecurityGroupsClient(config.SubscriptionID()) + a, _ := iam.GetResourceManagementAuthorizer() + nsgClient.Authorizer = a + nsgClient.AddToUserAgent(config.UserAgent()) return nsgClient } @@ -193,10 +194,10 @@ func CreateNetworkSecurityGroup(ctx context.Context, nsgName string) (nsg networ nsgClient := getNsgClient() future, err := nsgClient.CreateOrUpdate( ctx, - helpers.ResourceGroupName(), + config.GroupName(), nsgName, network.SecurityGroup{ - Location: to.StringPtr(helpers.Location()), + Location: to.StringPtr(config.Location()), SecurityGroupPropertiesFormat: &network.SecurityGroupPropertiesFormat{ SecurityRules: &[]network.SecurityRule{ { @@ -247,10 +248,10 @@ func CreateSimpleNetworkSecurityGroup(ctx context.Context, nsgName string) (nsg nsgClient := getNsgClient() future, err := nsgClient.CreateOrUpdate( ctx, - helpers.ResourceGroupName(), + config.GroupName(), nsgName, network.SecurityGroup{ - Location: to.StringPtr(helpers.Location()), + Location: to.StringPtr(config.Location()), }, ) @@ -269,13 +270,13 @@ func CreateSimpleNetworkSecurityGroup(ctx context.Context, nsgName string) (nsg // DeleteNetworkSecurityGroup deletes an existing network security group func DeleteNetworkSecurityGroup(ctx context.Context, nsgName string) (result network.SecurityGroupsDeleteFuture, err error) { nsgClient := getNsgClient() - return nsgClient.Delete(ctx, helpers.ResourceGroupName(), nsgName) + return nsgClient.Delete(ctx, config.GroupName(), nsgName) } // GetNetworkSecurityGroup returns an existing network security group func GetNetworkSecurityGroup(ctx context.Context, nsgName string) (network.SecurityGroup, error) { nsgClient := getNsgClient() - return nsgClient.Get(ctx, helpers.ResourceGroupName(), nsgName, "") + return nsgClient.Get(ctx, config.GroupName(), nsgName, "") } // Network Security Group Rules @@ -289,10 +290,10 @@ func DeleteNetworkSecurityGroupRule() {} // Network Interfaces (NIC's) func getNicClient() network.InterfacesClient { - nicClient := network.NewInterfacesClient(helpers.SubscriptionID()) - auth, _ := iam.GetResourceManagementAuthorizer(iam.AuthGrantType()) - nicClient.Authorizer = auth - nicClient.AddToUserAgent(helpers.UserAgent()) + nicClient := network.NewInterfacesClient(config.SubscriptionID()) + a, _ := iam.GetResourceManagementAuthorizer() + nicClient.Authorizer = a + nicClient.AddToUserAgent(config.UserAgent()) return nicClient } @@ -310,7 +311,7 @@ func CreateNIC(ctx context.Context, vnetName, subnetName, nsgName, ipName, nicNa nicParams := network.Interface{ Name: to.StringPtr(nicName), - Location: to.StringPtr(helpers.Location()), + Location: to.StringPtr(config.Location()), InterfacePropertiesFormat: &network.InterfacePropertiesFormat{ IPConfigurations: &[]network.InterfaceIPConfiguration{ { @@ -334,7 +335,7 @@ func CreateNIC(ctx context.Context, vnetName, subnetName, nsgName, ipName, nicNa } nicClient := getNicClient() - future, err := nicClient.CreateOrUpdate(ctx, helpers.ResourceGroupName(), nicName, nicParams) + future, err := nicClient.CreateOrUpdate(ctx, config.GroupName(), nicName, nicParams) if err != nil { return nic, fmt.Errorf("cannot create nic: %v", err) } @@ -361,10 +362,10 @@ func CreateNICWithLoadBalancer(ctx context.Context, lbName, vnetName, subnetName nicClient := getNicClient() future, err := nicClient.CreateOrUpdate(ctx, - helpers.ResourceGroupName(), + config.GroupName(), nicName, network.Interface{ - Location: to.StringPtr(helpers.Location()), + Location: to.StringPtr(config.Location()), InterfacePropertiesFormat: &network.InterfacePropertiesFormat{ IPConfigurations: &[]network.InterfaceIPConfiguration{ { @@ -403,22 +404,22 @@ func CreateNICWithLoadBalancer(ctx context.Context, lbName, vnetName, subnetName // GetNic returns an existing network interface func GetNic(ctx context.Context, nicName string) (network.Interface, error) { nicClient := getNicClient() - return nicClient.Get(ctx, helpers.ResourceGroupName(), nicName, "") + return nicClient.Get(ctx, config.GroupName(), nicName, "") } // DeleteNic deletes an existing network interface func DeleteNic(ctx context.Context, nic string) (result network.InterfacesDeleteFuture, err error) { nicClient := getNicClient() - return nicClient.Delete(ctx, helpers.ResourceGroupName(), nic) + return nicClient.Delete(ctx, config.GroupName(), nic) } // Public IP Addresses func getIPClient() network.PublicIPAddressesClient { - ipClient := network.NewPublicIPAddressesClient(helpers.SubscriptionID()) - auth, _ := iam.GetResourceManagementAuthorizer(iam.AuthGrantType()) - ipClient.Authorizer = auth - ipClient.AddToUserAgent(helpers.UserAgent()) + ipClient := network.NewPublicIPAddressesClient(config.SubscriptionID()) + a, _ := iam.GetResourceManagementAuthorizer() + ipClient.Authorizer = a + ipClient.AddToUserAgent(config.UserAgent()) return ipClient } @@ -427,11 +428,11 @@ func CreatePublicIP(ctx context.Context, ipName string) (ip network.PublicIPAddr ipClient := getIPClient() future, err := ipClient.CreateOrUpdate( ctx, - helpers.ResourceGroupName(), + config.GroupName(), ipName, network.PublicIPAddress{ Name: to.StringPtr(ipName), - Location: to.StringPtr(helpers.Location()), + Location: to.StringPtr(config.Location()), PublicIPAddressPropertiesFormat: &network.PublicIPAddressPropertiesFormat{ PublicIPAddressVersion: network.IPv4, PublicIPAllocationMethod: network.Static, @@ -454,20 +455,20 @@ func CreatePublicIP(ctx context.Context, ipName string) (ip network.PublicIPAddr // GetPublicIP returns an existing public IP func GetPublicIP(ctx context.Context, ipName string) (network.PublicIPAddress, error) { ipClient := getIPClient() - return ipClient.Get(ctx, helpers.ResourceGroupName(), ipName, "") + return ipClient.Get(ctx, config.GroupName(), ipName, "") } // DeletePublicIP deletes an existing public IP func DeletePublicIP(ctx context.Context, ipName string) (result network.PublicIPAddressesDeleteFuture, err error) { ipClient := getIPClient() - return ipClient.Delete(ctx, helpers.ResourceGroupName(), ipName) + return ipClient.Delete(ctx, config.GroupName(), ipName) } func getSecurityRulesClient() network.SecurityRulesClient { - rulesClient := network.NewSecurityRulesClient(helpers.SubscriptionID()) - auth, _ := iam.GetResourceManagementAuthorizer(iam.AuthGrantType()) - rulesClient.Authorizer = auth - rulesClient.AddToUserAgent(helpers.UserAgent()) + rulesClient := network.NewSecurityRulesClient(config.SubscriptionID()) + a, _ := iam.GetResourceManagementAuthorizer() + rulesClient.Authorizer = a + rulesClient.AddToUserAgent(config.UserAgent()) return rulesClient } @@ -475,7 +476,7 @@ func getSecurityRulesClient() network.SecurityRulesClient { func CreateSSHRule(ctx context.Context, nsgName string) (rule network.SecurityRule, err error) { rulesClient := getSecurityRulesClient() future, err := rulesClient.CreateOrUpdate(ctx, - helpers.ResourceGroupName(), + config.GroupName(), nsgName, "ALLOW-SSH", network.SecurityRule{ @@ -507,7 +508,7 @@ func CreateSSHRule(ctx context.Context, nsgName string) (rule network.SecurityRu func CreateHTTPRule(ctx context.Context, nsgName string) (rule network.SecurityRule, err error) { rulesClient := getSecurityRulesClient() future, err := rulesClient.CreateOrUpdate(ctx, - helpers.ResourceGroupName(), + config.GroupName(), nsgName, "ALLOW-HTTP", network.SecurityRule{ @@ -539,7 +540,7 @@ func CreateHTTPRule(ctx context.Context, nsgName string) (rule network.SecurityR func CreateSQLRule(ctx context.Context, nsgName, frontEndAddressPrefix string) (rule network.SecurityRule, err error) { rulesClient := getSecurityRulesClient() future, err := rulesClient.CreateOrUpdate(ctx, - helpers.ResourceGroupName(), + config.GroupName(), nsgName, "ALLOW-SQL", network.SecurityRule{ @@ -571,7 +572,7 @@ func CreateSQLRule(ctx context.Context, nsgName, frontEndAddressPrefix string) ( func CreateDenyOutRule(ctx context.Context, nsgName string) (rule network.SecurityRule, err error) { rulesClient := getSecurityRulesClient() future, err := rulesClient.CreateOrUpdate(ctx, - helpers.ResourceGroupName(), + config.GroupName(), nsgName, "DENY-OUT", network.SecurityRule{ @@ -602,17 +603,17 @@ func CreateDenyOutRule(ctx context.Context, nsgName string) (rule network.Securi // Load balancers func getLBClient() network.LoadBalancersClient { - lbClient := network.NewLoadBalancersClient(helpers.SubscriptionID()) - auth, _ := iam.GetResourceManagementAuthorizer(iam.AuthGrantType()) - lbClient.Authorizer = auth - lbClient.AddToUserAgent(helpers.UserAgent()) + lbClient := network.NewLoadBalancersClient(config.SubscriptionID()) + a, _ := iam.GetResourceManagementAuthorizer() + lbClient.Authorizer = a + lbClient.AddToUserAgent(config.UserAgent()) return lbClient } // GetLoadBalancer gets info on a loadbalancer func GetLoadBalancer(ctx context.Context, lbName string) (network.LoadBalancer, error) { lbClient := getLBClient() - return lbClient.Get(ctx, helpers.ResourceGroupName(), lbName, "") + return lbClient.Get(ctx, config.GroupName(), lbName, "") } // CreateLoadBalancer creates a load balancer with 2 inbound NAT rules. @@ -620,7 +621,7 @@ func CreateLoadBalancer(ctx context.Context, lbName, pipName string) (lb network probeName := "probe" frontEndIPConfigName := "fip" backEndAddressPoolName := "backEndPool" - idPrefix := fmt.Sprintf("/subscriptions/%s/resourceGroups/%s/providers/Microsoft.Network/loadBalancers", helpers.SubscriptionID(), helpers.ResourceGroupName()) + idPrefix := fmt.Sprintf("/subscriptions/%s/resourceGroups/%s/providers/Microsoft.Network/loadBalancers", config.SubscriptionID(), config.GroupName()) pip, err := GetPublicIP(ctx, pipName) if err != nil { @@ -629,10 +630,10 @@ func CreateLoadBalancer(ctx context.Context, lbName, pipName string) (lb network lbClient := getLBClient() future, err := lbClient.CreateOrUpdate(ctx, - helpers.ResourceGroupName(), + config.GroupName(), lbName, network.LoadBalancer{ - Location: to.StringPtr(helpers.Location()), + Location: to.StringPtr(config.Location()), LoadBalancerPropertiesFormat: &network.LoadBalancerPropertiesFormat{ FrontendIPConfigurations: &[]network.FrontendIPConfiguration{ { diff --git a/network/network_test.go b/network/network_test.go index f464a08c8..5b0ad4ed3 100644 --- a/network/network_test.go +++ b/network/network_test.go @@ -11,11 +11,11 @@ import ( "log" "os" "testing" + "time" - "github.com/subosito/gotenv" + "github.com/Azure-Samples/azure-sdk-for-go-samples/internal/config" + "github.com/Azure-Samples/azure-sdk-for-go-samples/internal/util" - "github.com/Azure-Samples/azure-sdk-for-go-samples/helpers" - "github.com/Azure-Samples/azure-sdk-for-go-samples/iam" "github.com/Azure-Samples/azure-sdk-for-go-samples/resources" ) @@ -29,64 +29,111 @@ var ( ) func TestMain(m *testing.M) { - err := parseArgs() + err := setupEnvironment() if err != nil { - log.Fatalf("failed to parse network args: %v\n", err) + log.Fatalf("could not set up environment: %v\n", err) } - err = iam.ParseArgs() - if err != nil { - log.Fatalln("failed to parse IAM args") + os.Exit(m.Run()) +} + +func setupEnvironment() error { + err1 := config.ParseEnvironment() + err2 := config.AddFlags() + err3 := addLocalConfig() + + for _, err := range []error{err1, err2, err3} { + if err != nil { + return err + } } - os.Exit(m.Run()) + flag.Parse() + return nil } -func parseArgs() error { - gotenv.Load() +func addLocalConfig() error { + vnetNameFromEnv := os.Getenv("AZURE_VNET_NAME") + if len(vnetNameFromEnv) > 0 { + virtualNetworkName = vnetNameFromEnv + } + flag.StringVar(&virtualNetworkName, "vnetName", virtualNetworkName, "Name for the VNET.") + return nil +} - virtualNetworkName = os.Getenv("AZURE_VNET_NAME") - flag.StringVar(&virtualNetworkName, "vnetName", virtualNetworkName, "Specify a name for the vnet.") +func TestNetwork(t *testing.T) { + groupName := config.GenerateGroupName("network-test") + config.SetGroupName(groupName) // TODO: don't use globals + ctx, cancel := context.WithTimeout(context.Background(), 300*time.Second) + defer cancel() + defer resources.Cleanup(ctx) - if !(len(virtualNetworkName) > 0) { - virtualNetworkName = "vnet1" + _, err := resources.CreateGroup(ctx, groupName) + if err != nil { + t.Fatalf("failed to create group: %v\n", err.Error()) } + t.Logf("created group %s\n", groupName) - return nil + _, err = CreateVirtualNetworkAndSubnets(ctx, virtualNetworkName, subnet1Name, subnet2Name) + if err != nil { + t.Fatalf("failed to create vnet: %v\n", err.Error()) + } + t.Logf("created vnet with 2 subnets") + + _, err = CreateNetworkSecurityGroup(ctx, nsgName) + if err != nil { + t.Fatalf("failed to create NSG: %v\n", err.Error()) + } + t.Logf("created network security group") + + _, err = CreatePublicIP(ctx, ipName) + if err != nil { + t.Fatalf("failed to create public IP: %v\n", err.Error()) + } + t.Logf("created public IP") + + _, err = CreateNIC(ctx, virtualNetworkName, subnet1Name, nsgName, ipName, nicName) + if err != nil { + t.Fatalf("failed to create NIC: %v\n", err.Error()) + } + t.Logf("created nic") } func ExampleCreateNIC() { - helpers.SetResourceGroupName("CreateNIC") - ctx := context.Background() + groupName := config.GenerateGroupName("CreateNIC") + config.SetGroupName(groupName) // TODO: don't use globals + ctx, cancel := context.WithTimeout(context.Background(), 300*time.Second) + defer cancel() defer resources.Cleanup(ctx) - _, err := resources.CreateGroup(ctx, helpers.ResourceGroupName()) + + _, err := resources.CreateGroup(ctx, config.GroupName()) if err != nil { - helpers.PrintAndLog(err.Error()) + util.PrintAndLog(err.Error()) } _, err = CreateVirtualNetworkAndSubnets(ctx, virtualNetworkName, subnet1Name, subnet2Name) if err != nil { - helpers.PrintAndLog(err.Error()) + util.PrintAndLog(err.Error()) } - helpers.PrintAndLog("created vnet and 2 subnets") + util.PrintAndLog("created vnet and 2 subnets") _, err = CreateNetworkSecurityGroup(ctx, nsgName) if err != nil { - helpers.PrintAndLog(err.Error()) + util.PrintAndLog(err.Error()) } - helpers.PrintAndLog("created network security group") + util.PrintAndLog("created network security group") _, err = CreatePublicIP(ctx, ipName) if err != nil { - helpers.PrintAndLog(err.Error()) + util.PrintAndLog(err.Error()) } - helpers.PrintAndLog("created public IP") + util.PrintAndLog("created public IP") _, err = CreateNIC(ctx, virtualNetworkName, subnet1Name, nsgName, ipName, nicName) if err != nil { - helpers.PrintAndLog(err.Error()) + util.PrintAndLog(err.Error()) } - helpers.PrintAndLog("created nic") + util.PrintAndLog("created nic") // Output: // created vnet and 2 subnets @@ -96,71 +143,74 @@ func ExampleCreateNIC() { } func ExampleCreateNetworkSecurityGroup() { - helpers.SetResourceGroupName("CreateNSG") - ctx := context.Background() + groupName := config.GenerateGroupName("CreateNSG") + config.SetGroupName(groupName) // TODO: don't use globals + ctx, cancel := context.WithTimeout(context.Background(), 300*time.Second) + defer cancel() defer resources.Cleanup(ctx) - _, err := resources.CreateGroup(ctx, helpers.ResourceGroupName()) + + _, err := resources.CreateGroup(ctx, config.GroupName()) if err != nil { - helpers.PrintAndLog(err.Error()) + util.PrintAndLog(err.Error()) } _, err = CreateVirtualNetwork(ctx, virtualNetworkName) if err != nil { - helpers.PrintAndLog(err.Error()) + util.PrintAndLog(err.Error()) } - helpers.PrintAndLog("created vnet") + util.PrintAndLog("created vnet") frontNSGName := "frontend" backNSGName := "backend" _, err = CreateNetworkSecurityGroup(ctx, frontNSGName) if err != nil { - helpers.PrintAndLog(err.Error()) + util.PrintAndLog(err.Error()) } - helpers.PrintAndLog("created frontend network security group") + util.PrintAndLog("created frontend network security group") _, err = CreateNetworkSecurityGroup(ctx, backNSGName) if err != nil { - helpers.PrintAndLog(err.Error()) + util.PrintAndLog(err.Error()) } - helpers.PrintAndLog("created backend network security group") + util.PrintAndLog("created backend network security group") frontEndAddressPrefix := "10.0.0.0/16" _, err = CreateSubnetWithNetowrkSecurityGroup(ctx, virtualNetworkName, "frontend", frontEndAddressPrefix, frontNSGName) if err != nil { - helpers.PrintAndLog(err.Error()) + util.PrintAndLog(err.Error()) } - helpers.PrintAndLog("created subnet with frontend network security group") + util.PrintAndLog("created subnet with frontend network security group") _, err = CreateSubnetWithNetowrkSecurityGroup(ctx, virtualNetworkName, "backend", "10.1.0.0/16", backNSGName) if err != nil { - helpers.PrintAndLog(err.Error()) + util.PrintAndLog(err.Error()) } - helpers.PrintAndLog("created subnet with backend network security group") + util.PrintAndLog("created subnet with backend network security group") _, err = CreateSSHRule(ctx, frontNSGName) if err != nil { - helpers.PrintAndLog(err.Error()) + util.PrintAndLog(err.Error()) } - helpers.PrintAndLog("created frontend SSH security rule") + util.PrintAndLog("created frontend SSH security rule") _, err = CreateHTTPRule(ctx, frontNSGName) if err != nil { - helpers.PrintAndLog(err.Error()) + util.PrintAndLog(err.Error()) } - helpers.PrintAndLog("created frontend HTTP security rule") + util.PrintAndLog("created frontend HTTP security rule") _, err = CreateSQLRule(ctx, frontNSGName, frontEndAddressPrefix) if err != nil { - helpers.PrintAndLog(err.Error()) + util.PrintAndLog(err.Error()) } - helpers.PrintAndLog("created frontend SQL security rule") + util.PrintAndLog("created frontend SQL security rule") _, err = CreateDenyOutRule(ctx, backNSGName) if err != nil { - helpers.PrintAndLog(err.Error()) + util.PrintAndLog(err.Error()) } - helpers.PrintAndLog("created backend deny out security rule") + util.PrintAndLog("created backend deny out security rule") // Output: // created vnet diff --git a/resources/cleanup.go b/resources/cleanup.go index e2b8b1fa1..f54c8b904 100644 --- a/resources/cleanup.go +++ b/resources/cleanup.go @@ -9,16 +9,16 @@ import ( "context" "log" - "github.com/Azure-Samples/azure-sdk-for-go-samples/helpers" + "github.com/Azure-Samples/azure-sdk-for-go-samples/internal/config" ) // Cleanup deletes the rescource group created for the sample func Cleanup(ctx context.Context) error { - if helpers.KeepResources() { + if config.KeepResources() { log.Println("keeping resources") return nil } log.Println("deleting resources") - _, err := DeleteGroup(ctx, helpers.ResourceGroupName()) + _, err := DeleteGroup(ctx, config.GroupName()) return err } diff --git a/resources/deployment.go b/resources/deployment.go index 35d33d98f..fa67a0aeb 100644 --- a/resources/deployment.go +++ b/resources/deployment.go @@ -9,16 +9,17 @@ import ( "context" "fmt" - "github.com/Azure-Samples/azure-sdk-for-go-samples/helpers" - "github.com/Azure-Samples/azure-sdk-for-go-samples/iam" "github.com/Azure/azure-sdk-for-go/services/resources/mgmt/2017-05-10/resources" + + "github.com/Azure-Samples/azure-sdk-for-go-samples/internal/config" + "github.com/Azure-Samples/azure-sdk-for-go-samples/internal/iam" ) func getDeploymentsClient() resources.DeploymentsClient { - deployClient := resources.NewDeploymentsClient(helpers.SubscriptionID()) - auth, _ := iam.GetResourceManagementAuthorizer(iam.AuthGrantType()) - deployClient.Authorizer = auth - deployClient.AddToUserAgent(helpers.UserAgent()) + deployClient := resources.NewDeploymentsClient(config.SubscriptionID()) + a, _ := iam.GetResourceManagementAuthorizer() + deployClient.Authorizer = a + deployClient.AddToUserAgent(config.UserAgent()) return deployClient } @@ -28,7 +29,7 @@ func CreateDeployment(ctx context.Context, deploymentName string, template, para deployClient := getDeploymentsClient() future, err := deployClient.CreateOrUpdate( ctx, - helpers.ResourceGroupName(), + config.GroupName(), deploymentName, resources.Deployment{ Properties: &resources.DeploymentProperties{ @@ -55,7 +56,7 @@ func CreateDeployment(ctx context.Context, deploymentName string, template, para func ValidateDeployment(ctx context.Context, deploymentName string, template, params *map[string]interface{}) (valid resources.DeploymentValidateResult, err error) { deployClient := getDeploymentsClient() return deployClient.Validate(ctx, - helpers.ResourceGroupName(), + config.GroupName(), deploymentName, resources.Deployment{ Properties: &resources.DeploymentProperties{ diff --git a/resources/deployment_test.go b/resources/deployment_test.go index 6fa9b1007..5fa2dc9b8 100644 --- a/resources/deployment_test.go +++ b/resources/deployment_test.go @@ -11,16 +11,18 @@ import ( "log" "path/filepath" - "github.com/Azure-Samples/azure-sdk-for-go-samples/helpers" + "github.com/Azure-Samples/azure-sdk-for-go-samples/internal/config" + "github.com/Azure-Samples/azure-sdk-for-go-samples/internal/util" ) func ExampleCreateTemplateDeployment() { - helpers.SetResourceGroupName("CreateTemplateDeploy") + config.SetGroupName("CreateTemplateDeploy") ctx := context.Background() defer Cleanup(ctx) - _, err := CreateGroup(ctx, helpers.ResourceGroupName()) + + _, err := CreateGroup(ctx, config.GroupName()) if err != nil { - helpers.PrintAndLog(err.Error()) + util.PrintAndLog(err.Error()) } gopath := build.Default.GOPATH @@ -29,26 +31,26 @@ func ExampleCreateTemplateDeployment() { parametersFile := filepath.Join(gopath, "src", repo, "resources", "testdata", "parameters.json") deployName := "VMdeploy" - template, err := helpers.ReadJSON(templateFile) + template, err := util.ReadJSON(templateFile) if err != nil { return } - params, err := helpers.ReadJSON(parametersFile) + params, err := util.ReadJSON(parametersFile) if err != nil { return } _, err = ValidateDeployment(ctx, deployName, template, params) if err != nil { - helpers.PrintAndLog(err.Error()) + util.PrintAndLog(err.Error()) } - helpers.PrintAndLog("validated VM template deployment") + util.PrintAndLog("validated VM template deployment") _, err = CreateDeployment(ctx, deployName, template, params) if err != nil { - helpers.PrintAndLog(err.Error()) + util.PrintAndLog(err.Error()) } - helpers.PrintAndLog("created VM template deployment") + util.PrintAndLog("created VM template deployment") ipName := (*params)["publicIPAddresses_QuickstartVM_ip_name"].(map[string]interface{})["value"].(string) vmUser := (*params)["vm_user"].(map[string]interface{})["value"].(string) @@ -60,9 +62,9 @@ func ExampleCreateTemplateDeployment() { ipName, "2018-01-01") if err != nil { - helpers.PrintAndLog(err.Error()) + util.PrintAndLog(err.Error()) } - helpers.PrintAndLog("got public IP info via get generic resource") + util.PrintAndLog("got public IP info via get generic resource") log.Printf("Log in with ssh: %s@%s, password: %s", vmUser, diff --git a/resources/groups.go b/resources/groups.go index 61d691529..9476ba3f3 100644 --- a/resources/groups.go +++ b/resources/groups.go @@ -12,38 +12,43 @@ import ( "strings" "sync" - "github.com/Azure-Samples/azure-sdk-for-go-samples/helpers" - "github.com/Azure-Samples/azure-sdk-for-go-samples/iam" "github.com/Azure/azure-sdk-for-go/services/resources/mgmt/2017-05-10/resources" + "github.com/Azure/go-autorest/autorest/azure/auth" "github.com/Azure/go-autorest/autorest/to" + + "github.com/Azure-Samples/azure-sdk-for-go-samples/internal/config" + "github.com/Azure-Samples/azure-sdk-for-go-samples/internal/iam" ) func getGroupsClient() resources.GroupsClient { - groupsClient := resources.NewGroupsClient(helpers.SubscriptionID()) - auth, _ := iam.GetResourceManagementAuthorizer(iam.AuthGrantType()) - groupsClient.Authorizer = auth - groupsClient.AddToUserAgent(helpers.UserAgent()) + groupsClient := resources.NewGroupsClient(config.SubscriptionID()) + a, err := iam.GetResourceManagementAuthorizer() + if err != nil { + log.Fatalf("failed to initialize authorizer: %v\n", err) + } + groupsClient.Authorizer = a + groupsClient.AddToUserAgent(config.UserAgent()) return groupsClient } func getGroupsClientFromAuthFile() resources.GroupsClient { - groupsClient := resources.NewGroupsClient(helpers.SubscriptionID()) - auth, _ := auth.NewAuthorizerFromFile(groupsClient.BaseURI) - groupsClient.Authorizer = auth - groupsClient.AddToUserAgent(helpers.UserAgent()) + groupsClient := resources.NewGroupsClient(config.SubscriptionID()) + a, _ := auth.NewAuthorizerFromFile(groupsClient.BaseURI) + groupsClient.Authorizer = a + groupsClient.AddToUserAgent(config.UserAgent()) return groupsClient } // CreateGroup creates a new resource group named by env var func CreateGroup(ctx context.Context, groupName string) (resources.Group, error) { groupsClient := getGroupsClient() - log.Println(fmt.Sprintf("creating resource group '%s' on location: %v", groupName, helpers.Location())) + log.Println(fmt.Sprintf("creating resource group '%s' on location: %v", groupName, config.Location())) return groupsClient.CreateOrUpdate( ctx, groupName, resources.Group{ - Location: to.StringPtr(helpers.Location()), + Location: to.StringPtr(config.Location()), }) } @@ -51,12 +56,12 @@ func CreateGroup(ctx context.Context, groupName string) (resources.Group, error) // is set up based on an auth file created using the Azure CLI. func CreateGroupWithAuthFile(ctx context.Context, groupName string) (resources.Group, error) { groupsClient := getGroupsClientFromAuthFile() - log.Println(fmt.Sprintf("creating resource group '%s' on location: %v", groupName, helpers.Location())) + log.Println(fmt.Sprintf("creating resource group '%s' on location: %v", groupName, config.Location())) return groupsClient.CreateOrUpdate( ctx, groupName, resources.Group{ - Location: to.StringPtr(helpers.Location()), + Location: to.StringPtr(config.Location()), }) } @@ -75,12 +80,12 @@ func ListGroups(ctx context.Context) (resources.GroupListResultIterator, error) // GetGroup gets info on the resource group in use func GetGroup(ctx context.Context) (resources.Group, error) { groupsClient := getGroupsClient() - return groupsClient.Get(ctx, helpers.ResourceGroupName()) + return groupsClient.Get(ctx, config.GroupName()) } // DeleteAllGroupsWithPrefix deletes all rescource groups that start with a certain prefix func DeleteAllGroupsWithPrefix(ctx context.Context, prefix string) (futures []resources.GroupsDeleteFuture, groups []string) { - if helpers.KeepResources() { + if config.KeepResources() { log.Println("keeping resource groups") return } diff --git a/resources/hybrid/cleanup.go b/resources/hybrid/cleanup.go index 0693a8991..af55f5ffb 100644 --- a/resources/hybrid/cleanup.go +++ b/resources/hybrid/cleanup.go @@ -9,12 +9,12 @@ import ( "context" "log" - "github.com/Azure-Samples/azure-sdk-for-go-samples/helpers" + "github.com/Azure-Samples/azure-sdk-for-go-samples/internal/config" ) // Cleanup deletes the rescource group created for the sample func Cleanup(ctx context.Context) error { - if helpers.KeepResources() { + if config.KeepResources() { log.Println("Hybrid resources cleanup: keeping resources") return nil } diff --git a/resources/hybrid/groups.go b/resources/hybrid/groups.go index 8cad982fd..4faf005e7 100644 --- a/resources/hybrid/groups.go +++ b/resources/hybrid/groups.go @@ -7,14 +7,14 @@ package resources import ( "context" - "fmt" "log" - "github.com/Azure-Samples/azure-sdk-for-go-samples/helpers" - "github.com/Azure-Samples/azure-sdk-for-go-samples/iam" "github.com/Azure/azure-sdk-for-go/profiles/2017-03-09/resources/mgmt/resources" "github.com/Azure/go-autorest/autorest" - "github.com/Azure/go-autorest/autorest/azure" + "github.com/Azure/go-autorest/autorest/to" + + "github.com/Azure-Samples/azure-sdk-for-go-samples/internal/config" + "github.com/Azure-Samples/azure-sdk-for-go-samples/internal/iam" ) const ( @@ -22,29 +22,39 @@ const ( ) func getGroupsClient(activeDirectoryEndpoint, tokenAudience string) resources.GroupsClient { - token, err := iam.GetResourceManagementTokenHybrid(activeDirectoryEndpoint, tokenAudience) + token, err := iam.GetResourceManagementTokenHybrid( + activeDirectoryEndpoint, tokenAudience) if err != nil { - log.Fatal(fmt.Sprintf(errorPrefix, fmt.Sprintf("Cannot generate token. Error details: %v.", err))) + log.Fatalf("failed to get token: %v\n", err) } - groupsClient := resources.NewGroupsClientWithBaseURI(helpers.ArmEndpoint(), helpers.SubscriptionID()) + + groupsClient := resources.NewGroupsClientWithBaseURI( + config.Environment().ResourceManagerEndpoint, + config.SubscriptionID()) groupsClient.Authorizer = autorest.NewBearerAuthorizer(token) - groupsClient.AddToUserAgent(helpers.UserAgent()) + groupsClient.AddToUserAgent(config.UserAgent()) return groupsClient } // CreateGroup creates a new resource group named by env var -func CreateGroup(cntx context.Context) (resources.Group, error) { - environment, _ := azure.EnvironmentFromURL(helpers.ArmEndpoint()) - groupClient := getGroupsClient(environment.ActiveDirectoryEndpoint, environment.TokenAudience) - location := helpers.Location() - helpers.SetResourceGroupName("hybridResourceGroup") - return groupClient.CreateOrUpdate(cntx, helpers.ResourceGroupName(), resources.Group{Location: &location}) +func CreateGroup(ctx context.Context) (resources.Group, error) { + groupClient := getGroupsClient( + config.Environment().ActiveDirectoryEndpoint, + config.Environment().TokenAudience) + + return groupClient.CreateOrUpdate(ctx, + config.GroupName(), + resources.Group{ + Location: to.StringPtr(config.Location()), + }, + ) } // DeleteGroup removes the resource group named by env var func DeleteGroup(ctx context.Context) (result resources.GroupsDeleteFuture, err error) { - environment, _ := azure.EnvironmentFromURL(helpers.ArmEndpoint()) - groupsClient := getGroupsClient(environment.ActiveDirectoryEndpoint, environment.TokenAudience) - helpers.SetResourceGroupName("hybridResourceGroup") - return groupsClient.Delete(ctx, helpers.ResourceGroupName()) + groupsClient := getGroupsClient( + config.Environment().ActiveDirectoryEndpoint, + config.Environment().TokenAudience) + + return groupsClient.Delete(ctx, config.GroupName()) } diff --git a/resources/hybrid/resources_test.go b/resources/hybrid/resources_test.go index 6a57d49a4..254e477c6 100644 --- a/resources/hybrid/resources_test.go +++ b/resources/hybrid/resources_test.go @@ -7,24 +7,50 @@ package resources import ( "context" - "log" + "flag" + "testing" + "time" - "github.com/Azure-Samples/azure-sdk-for-go-samples/helpers" - "github.com/Azure-Samples/azure-sdk-for-go-samples/iam" + "github.com/Azure-Samples/azure-sdk-for-go-samples/internal/config" + "github.com/Azure-Samples/azure-sdk-for-go-samples/internal/util" ) -func ExampleCreateGroup() { - err := iam.ParseArgs() +func setupEnvironment() error { + err1 := config.ParseEnvironment() + err2 := config.AddFlags() + err3 := addLocalConfig() + + for _, err := range []error{err1, err2, err3} { + if err != nil { + return err + } + } + + flag.Parse() + return nil +} + +func addLocalConfig() error { + return nil +} + +func TestGroupsHybrid(t *testing.T) { + err := setupEnvironment() if err != nil { - log.Fatalln("failed to parse IAM args") + t.Fatalf("could not set up environment: %v\n", err) } - defer Cleanup(context.Background()) - _, err = CreateGroup(context.Background()) + groupName := config.GenerateGroupName("resource-groups-hybrid") + config.SetGroupName(groupName) // TODO: don't rely on globals + ctx, cancel := context.WithTimeout(context.Background(), 300*time.Second) + defer cancel() + defer Cleanup(ctx) + + _, err = CreateGroup(ctx) if err != nil { - helpers.PrintAndLog(err.Error()) + util.PrintAndLog(err.Error()) } - helpers.PrintAndLog("resource group created") + util.PrintAndLog("resource group created") // Output: // resource group created diff --git a/resources/provider.go b/resources/provider.go index e190ad4e7..59d9e7235 100644 --- a/resources/provider.go +++ b/resources/provider.go @@ -8,16 +8,17 @@ package resources import ( "context" - "github.com/Azure-Samples/azure-sdk-for-go-samples/helpers" - "github.com/Azure-Samples/azure-sdk-for-go-samples/iam" "github.com/Azure/azure-sdk-for-go/services/resources/mgmt/2017-05-10/resources" + + "github.com/Azure-Samples/azure-sdk-for-go-samples/internal/config" + "github.com/Azure-Samples/azure-sdk-for-go-samples/internal/iam" ) func getProviderClient() resources.ProvidersClient { - providerClient := resources.NewProvidersClient(helpers.SubscriptionID()) - auth, _ := iam.GetResourceManagementAuthorizer(iam.AuthGrantType()) - providerClient.Authorizer = auth - providerClient.AddToUserAgent(helpers.UserAgent()) + providerClient := resources.NewProvidersClient(config.SubscriptionID()) + a, _ := iam.GetResourceManagementAuthorizer() + providerClient.Authorizer = a + providerClient.AddToUserAgent(config.UserAgent()) return providerClient } diff --git a/resources/resources.go b/resources/resources.go index cca4579b1..28098275d 100644 --- a/resources/resources.go +++ b/resources/resources.go @@ -10,17 +10,18 @@ import ( "net/http" "net/url" - "github.com/Azure-Samples/azure-sdk-for-go-samples/helpers" - "github.com/Azure-Samples/azure-sdk-for-go-samples/iam" "github.com/Azure/azure-sdk-for-go/services/resources/mgmt/2017-05-10/resources" "github.com/Azure/go-autorest/autorest" + + "github.com/Azure-Samples/azure-sdk-for-go-samples/internal/config" + "github.com/Azure-Samples/azure-sdk-for-go-samples/internal/iam" ) func getResourcesClient() resources.Client { - resourcesClient := resources.NewClient(helpers.SubscriptionID()) - auth, _ := iam.GetResourceManagementAuthorizer(iam.AuthGrantType()) - resourcesClient.Authorizer = auth - resourcesClient.AddToUserAgent(helpers.UserAgent()) + resourcesClient := resources.NewClient(config.SubscriptionID()) + a, _ := iam.GetResourceManagementAuthorizer() + resourcesClient.Authorizer = a + resourcesClient.AddToUserAgent(config.UserAgent()) return resourcesClient } @@ -54,7 +55,7 @@ func GetResource(ctx context.Context, resourceProvider, resourceType, resourceNa return resourcesClient.Get( ctx, - helpers.ResourceGroupName(), + config.GroupName(), resourceProvider, "", resourceType, diff --git a/resources/resources_test.go b/resources/resources_test.go index b19acd7e3..dd0352c72 100644 --- a/resources/resources_test.go +++ b/resources/resources_test.go @@ -7,43 +7,69 @@ package resources import ( "context" + "flag" "log" + "os" + "testing" + "time" - "github.com/Azure-Samples/azure-sdk-for-go-samples/helpers" - "github.com/Azure-Samples/azure-sdk-for-go-samples/iam" + "github.com/Azure-Samples/azure-sdk-for-go-samples/internal/config" ) -func init() { - err := iam.ParseArgs() +func TestMain(m *testing.M) { + err := setupEnvironment() if err != nil { - log.Fatalln("failed to parse IAM args") + log.Fatalf("could not set up environment: %v\n", err) } + + os.Exit(m.Run()) } -func ExampleCreateGroup() { - helpers.SetResourceGroupName("CreateGroup") - defer Cleanup(context.Background()) +func setupEnvironment() error { + err1 := config.ParseEnvironment() + err2 := config.AddFlags() + err3 := addLocalConfig() - _, err := CreateGroup(context.Background(), helpers.ResourceGroupName()) - if err != nil { - helpers.PrintAndLog(err.Error()) + for _, err := range []error{err1, err2, err3} { + if err != nil { + return err + } } - helpers.PrintAndLog("resource group created") - // Output: - // resource group created + flag.Parse() + return nil +} + +func addLocalConfig() error { + return nil } -func ExampleCreateGroupWithAuthFile() { - helpers.SetResourceGroupName("CreateGroupWithAuthFile") - defer Cleanup(context.Background()) +func TestGroups(t *testing.T) { + groupName := config.GenerateGroupName("resource-groups") + config.SetGroupName(groupName) // TODO: don't rely on globals + ctx, cancel := context.WithTimeout(context.Background(), 300*time.Second) + defer cancel() + defer Cleanup(ctx) - _, err := CreateGroupWithAuthFile(context.Background(), helpers.ResourceGroupName()) + var err error + _, err = CreateGroup(ctx, config.GroupName()) if err != nil { - helpers.PrintAndLog(err.Error()) + t.Fatalf("failed to create group: %v\n", err.Error()) } - helpers.PrintAndLog("resource group created, authentication was set up with an Azure CLI auth file") + t.Logf("created group: %s\n", config.GroupName()) +} + +func TestGroupsWithAuthFile(t *testing.T) { + groupName := config.GenerateGroupName("resource-groups-authfile") + config.SetGroupName(groupName) // TODO: don't rely on globals + ctx, cancel := context.WithTimeout(context.Background(), 300*time.Second) + defer cancel() + defer Cleanup(ctx) - // Output: - // resource group created, authentication was set up with an Azure CLI auth file + var err error + _, err = CreateGroupWithAuthFile(ctx, config.GroupName()) + if err != nil { + t.Fatalf("failed to create group: %v\n", err.Error()) + } + t.Logf("created group with auth file: %s\n", config.GroupName()) }