github.com/niedbalski/juju@v0.0.0-20190215020005-8ff100488e47/provider/azure/upgrades.go (about) 1 // Copyright 2017 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package azure 5 6 import ( 7 stdcontext "context" 8 "strings" 9 10 "github.com/Azure/azure-sdk-for-go/services/compute/mgmt/2018-10-01/compute" 11 "github.com/Azure/azure-sdk-for-go/services/network/mgmt/2018-08-01/network" 12 "github.com/Azure/go-autorest/autorest/to" 13 "github.com/juju/errors" 14 15 "github.com/juju/juju/environs" 16 "github.com/juju/juju/environs/context" 17 "github.com/juju/juju/environs/tags" 18 "github.com/juju/juju/provider/azure/internal/errorutils" 19 ) 20 21 // UpgradeOperations is part of the upgrades.OperationSource interface. 22 func (env *azureEnviron) UpgradeOperations(context.ProviderCallContext, environs.UpgradeOperationsParams) []environs.UpgradeOperation { 23 return []environs.UpgradeOperation{{ 24 providerVersion1, 25 []environs.UpgradeStep{ 26 commonDeploymentUpgradeStep{env}, 27 }, 28 }} 29 } 30 31 // commonDeploymentUpgradeStep adds a "common" deployment to each 32 // Environ corresponding to non-controller models. 33 type commonDeploymentUpgradeStep struct { 34 env *azureEnviron 35 } 36 37 // Description is part of the environs.UpgradeStep interface. 38 func (commonDeploymentUpgradeStep) Description() string { 39 return "Create common resource deployment" 40 } 41 42 // Run is part of the environs.UpgradeStep interface. 43 func (step commonDeploymentUpgradeStep) Run(ctx context.ProviderCallContext) error { 44 env := step.env 45 isControllerEnviron, err := isControllerEnviron(env, ctx) 46 if err != nil { 47 return errors.Trace(err) 48 } 49 if isControllerEnviron { 50 // We only need to create the deployment for 51 // non-controller Environs. 52 return nil 53 } 54 55 // Identify the network security rules that exist already. 56 // We will add these, excluding the SSH/API rules, to the 57 // network security group template created in the deployment 58 // below. 59 nsgClient := network.SecurityGroupsClient{ 60 BaseClient: env.network, 61 } 62 allRules, err := networkSecurityRules(nsgClient, env.resourceGroup) 63 if errors.IsNotFound(err) { 64 allRules = nil 65 } else if err != nil { 66 return errors.Trace(err) 67 } 68 rules := make([]network.SecurityRule, 0, len(allRules)) 69 for _, rule := range allRules { 70 name := to.String(rule.Name) 71 if name == sshSecurityRuleName || strings.HasPrefix(name, apiSecurityRulePrefix) { 72 continue 73 } 74 rules = append(rules, rule) 75 } 76 77 env.mu.Lock() 78 storageAccountType := env.config.storageAccountType 79 env.mu.Unlock() 80 return env.createCommonResourceDeployment(ctx, nil, rules, storageAccountTemplateResource( 81 env.location, nil, 82 env.storageAccountName, 83 storageAccountType, 84 )) 85 } 86 87 func isControllerEnviron(env *azureEnviron, ctx context.ProviderCallContext) (bool, error) { 88 // Look for a machine with the "juju-is-controller" tag set to "true". 89 client := compute.VirtualMachinesClient{env.compute} 90 sdkCtx := stdcontext.Background() 91 result, err := client.ListComplete(sdkCtx, env.resourceGroup) 92 if err != nil { 93 return false, errorutils.HandleCredentialError(errors.Annotate(err, "listing virtual machines"), ctx) 94 } 95 96 if result.Response().IsEmpty() { 97 // No machines implies this is not the controller model, as 98 // there must be a controller machine for the upgrades to be 99 // running! 100 return false, nil 101 } 102 103 for ; result.NotDone(); err = result.NextWithContext(sdkCtx) { 104 if err != nil { 105 return false, errors.Annotate(err, "iterating machines") 106 } 107 vm := result.Value() 108 if to.String(vm.Tags[tags.JujuIsController]) == "true" { 109 return true, nil 110 } 111 } 112 return false, nil 113 }