github.com/mwhudson/juju@v0.0.0-20160512215208-90ff01f3497f/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  	"math/rand"
     8  	"net/http"
     9  	"time"
    10  
    11  	"github.com/Azure/azure-sdk-for-go/Godeps/_workspace/src/github.com/Azure/go-autorest/autorest"
    12  	"github.com/Azure/azure-sdk-for-go/Godeps/_workspace/src/github.com/Azure/go-autorest/autorest/to"
    13  	"github.com/juju/retry"
    14  	"github.com/juju/utils"
    15  	"github.com/juju/utils/clock"
    16  )
    17  
    18  const (
    19  	retryDelay       = 5 * time.Second
    20  	maxRetryDelay    = 1 * time.Minute
    21  	maxRetryDuration = 5 * time.Minute
    22  )
    23  
    24  func toTagsPtr(tags map[string]string) *map[string]*string {
    25  	stringPtrMap := to.StringMapPtr(tags)
    26  	return &stringPtrMap
    27  }
    28  
    29  func toTags(tags *map[string]*string) map[string]string {
    30  	if tags == nil {
    31  		return nil
    32  	}
    33  	return to.StringMap(*tags)
    34  }
    35  
    36  // randomAdminPassword returns a random administrator password for
    37  // Windows machines.
    38  func randomAdminPassword() string {
    39  	// We want at least one each of lower-alpha, upper-alpha, and digit.
    40  	// Allocate 16 of each (randomly), and then the remaining characters
    41  	// will be randomly chosen from the full set.
    42  	validRunes := append(utils.LowerAlpha, utils.Digits...)
    43  	validRunes = append(validRunes, utils.UpperAlpha...)
    44  
    45  	lowerAlpha := utils.RandomString(16, utils.LowerAlpha)
    46  	upperAlpha := utils.RandomString(16, utils.UpperAlpha)
    47  	digits := utils.RandomString(16, utils.Digits)
    48  	mixed := utils.RandomString(16, validRunes)
    49  	password := []rune(lowerAlpha + upperAlpha + digits + mixed)
    50  	for i := len(password) - 1; i >= 1; i-- {
    51  		j := rand.Intn(i + 1)
    52  		password[i], password[j] = password[j], password[i]
    53  	}
    54  	return string(password)
    55  }
    56  
    57  // callAPIFunc is a function type that should wrap any any
    58  // Azure Resource Manager API calls.
    59  type callAPIFunc func(func() (autorest.Response, error)) error
    60  
    61  // backoffAPIRequestCaller is a type whose "call" method can
    62  // be used as a callAPIFunc.
    63  type backoffAPIRequestCaller struct {
    64  	clock clock.Clock
    65  }
    66  
    67  // call will call the supplied function, with exponential backoff
    68  // as long as the request returns an http.StatusTooManyRequests
    69  // status.
    70  func (c backoffAPIRequestCaller) call(f func() (autorest.Response, error)) error {
    71  	var resp *http.Response
    72  	return retry.Call(retry.CallArgs{
    73  		Func: func() error {
    74  			autorestResp, err := f()
    75  			resp = autorestResp.Response
    76  			return err
    77  		},
    78  		IsFatalError: func(err error) bool {
    79  			return resp == nil || !autorest.ResponseHasStatusCode(resp, http.StatusTooManyRequests)
    80  		},
    81  		NotifyFunc: func(err error, attempt int) {
    82  			logger.Debugf("attempt %d: %v", attempt, err)
    83  		},
    84  		Attempts:    -1,
    85  		Delay:       retryDelay,
    86  		MaxDelay:    maxRetryDelay,
    87  		MaxDuration: maxRetryDuration,
    88  		BackoffFunc: retry.DoubleDelay,
    89  		Clock:       c.clock,
    90  	})
    91  }