github.com/niedbalski/juju@v0.0.0-20190215020005-8ff100488e47/provider/azure/utils.go (about) 1 // Copyright 2015 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package azure 5 6 import ( 7 stdcontext "context" 8 "math/rand" 9 "net/http" 10 "time" 11 12 "github.com/Azure/azure-sdk-for-go/services/resources/mgmt/2018-05-01/resources" 13 "github.com/Azure/go-autorest/autorest" 14 "github.com/Azure/go-autorest/autorest/to" 15 "github.com/juju/errors" 16 "github.com/juju/utils" 17 18 "github.com/juju/juju/environs/context" 19 "github.com/juju/juju/provider/azure/internal/errorutils" 20 ) 21 22 const ( 23 retryDelay = 5 * time.Second 24 maxRetryDelay = 1 * time.Minute 25 maxRetryDuration = 5 * time.Minute 26 ) 27 28 func toTags(tags *map[string]*string) map[string]string { 29 if tags == nil { 30 return nil 31 } 32 return to.StringMap(*tags) 33 } 34 35 // randomAdminPassword returns a random administrator password for 36 // Windows machines. 37 func randomAdminPassword() string { 38 // We want at least one each of lower-alpha, upper-alpha, and digit. 39 // Allocate 16 of each (randomly), and then the remaining characters 40 // will be randomly chosen from the full set. 41 validRunes := append(utils.LowerAlpha, utils.Digits...) 42 validRunes = append(validRunes, utils.UpperAlpha...) 43 44 lowerAlpha := utils.RandomString(16, utils.LowerAlpha) 45 upperAlpha := utils.RandomString(16, utils.UpperAlpha) 46 digits := utils.RandomString(16, utils.Digits) 47 mixed := utils.RandomString(16, validRunes) 48 password := []rune(lowerAlpha + upperAlpha + digits + mixed) 49 for i := len(password) - 1; i >= 1; i-- { 50 j := rand.Intn(i + 1) 51 password[i], password[j] = password[j], password[i] 52 } 53 return string(password) 54 } 55 56 func isNotFoundResponse(resp *http.Response) bool { 57 return isNotFoundResult(autorest.Response{resp}) 58 } 59 60 func isNotFoundResult(resp autorest.Response) bool { 61 if resp.Response != nil && resp.StatusCode == http.StatusNotFound { 62 return true 63 } 64 return false 65 } 66 67 // collectAPIVersions returns a map of the latest API version for each 68 // possible resource type. This is needed to use the Azure Resource 69 // Management API, because the API version requested must match the 70 // type of the resource being manipulated through the API, rather than 71 // the API version specified statically in the resource client code. 72 func collectAPIVersions(ctx context.ProviderCallContext, sdkCtx stdcontext.Context, client resources.ProvidersClient) (map[string]string, error) { 73 result := make(map[string]string) 74 75 var res resources.ProviderListResultIterator 76 res, err := client.ListComplete(sdkCtx, nil, "") 77 if err != nil { 78 return result, errorutils.HandleCredentialError(errors.Trace(err), ctx) 79 } 80 for ; res.NotDone(); err = res.NextWithContext(sdkCtx) { 81 if err != nil { 82 return map[string]string{}, errorutils.HandleCredentialError(errors.Trace(err), ctx) 83 } 84 85 provider := res.Value() 86 if provider.ResourceTypes == nil { 87 continue 88 } 89 90 for _, resourceType := range *provider.ResourceTypes { 91 key := to.String(provider.Namespace) + "/" + to.String(resourceType.ResourceType) 92 versions := to.StringSlice(resourceType.APIVersions) 93 if len(versions) == 0 { 94 continue 95 } 96 // The versions are newest-first. 97 result[key] = versions[0] 98 } 99 } 100 return result, nil 101 }