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  }