// InstanceTags returns the minimum set of tags that should be set on a // machine instance, if the provider supports them. func InstanceTags(cfg *config.Config, jobs []multiwatcher.MachineJob) map[string]string { instanceTags := tags.ResourceTags(names.NewModelTag(cfg.UUID()), cfg) if multiwatcher.AnyJobNeedsState(jobs...) { instanceTags[tags.JujuController] = "true" } return instanceTags }
// InstanceTags returns the minimum set of tags that should be set on a // machine instance, if the provider supports them. func InstanceTags(cfg *config.Config, jobs []multiwatcher.MachineJob) map[string]string { uuid, _ := cfg.UUID() instanceTags := tags.ResourceTags(names.NewEnvironTag(uuid), cfg) if multiwatcher.AnyJobNeedsState(jobs...) { instanceTags[tags.JujuStateServer] = "true" } return instanceTags }
// InstanceTags returns the minimum set of tags that should be set on a // machine instance, if the provider supports them. func InstanceTags(modelUUID, controllerUUID string, tagger tags.ResourceTagger, jobs []multiwatcher.MachineJob) map[string]string { instanceTags := tags.ResourceTags( names.NewModelTag(modelUUID), names.NewControllerTag(controllerUUID), tagger, ) if multiwatcher.AnyJobNeedsState(jobs...) { instanceTags[tags.JujuIsController] = "true" } return instanceTags }
// storageTags returns the tags that should be set on a volume or filesystem, // if the provider supports them. func storageTags( storageInstance state.StorageInstance, cfg *config.Config, ) (map[string]string, error) { storageTags := tags.ResourceTags(names.NewModelTag(cfg.UUID()), cfg) if storageInstance != nil { storageTags[tags.JujuStorageInstance] = storageInstance.Tag().Id() storageTags[tags.JujuStorageOwner] = storageInstance.Owner().Id() } return storageTags, nil }
// initResourceGroup creates and initialises a resource group for this // environment. The resource group will have a storage account and a // subnet associated with it (but not necessarily contained within: // see subnet creation). func (env *azureEnviron) initResourceGroup() (*config.Config, error) { location := env.config.location tags := tags.ResourceTags( names.NewModelTag(env.config.Config.UUID()), names.NewModelTag(env.config.Config.ControllerUUID()), env.config, ) resourceGroupsClient := resources.GroupsClient{env.resources} logger.Debugf("creating resource group %q", env.resourceGroup) _, err := resourceGroupsClient.CreateOrUpdate(env.resourceGroup, resources.Group{ Location: to.StringPtr(location), Tags: toTagsPtr(tags), }) if err != nil { return nil, errors.Annotate(err, "creating resource group") } // Create an internal network for all VMs in the // resource group to connect to. vnetPtr, err := createInternalVirtualNetwork( env.network, env.resourceGroup, location, tags, ) if err != nil { return nil, errors.Annotate(err, "creating virtual network") } _, err = createInternalSubnet( env.network, env.resourceGroup, vnetPtr, location, tags, ) if err != nil { return nil, errors.Annotate(err, "creating subnet") } // Create a storage account for the resource group. storageAccountsClient := storage.AccountsClient{env.storage} storageAccountName, storageAccountKey, err := createStorageAccount( storageAccountsClient, env.config.storageAccountType, env.resourceGroup, location, tags, env.provider.config.StorageAccountNameGenerator, ) if err != nil { return nil, errors.Annotate(err, "creating storage account") } return env.config.Config.Apply(map[string]interface{}{ configAttrStorageAccount: storageAccountName, configAttrStorageAccountKey: storageAccountKey, }) }
// storageTags returns the tags that should be set on a volume or filesystem, // if the provider supports them. func storageTags( storageInstance state.StorageInstance, modelUUID, controllerUUID string, tagger tags.ResourceTagger, ) (map[string]string, error) { storageTags := tags.ResourceTags( names.NewModelTag(modelUUID), names.NewControllerTag(controllerUUID), tagger, ) if storageInstance != nil { storageTags[tags.JujuStorageInstance] = storageInstance.Tag().Id() storageTags[tags.JujuStorageOwner] = storageInstance.Owner().Id() } return storageTags, nil }
// initResourceGroup creates a resource group for this environment. func (env *azureEnviron) initResourceGroup(controllerUUID string) error { location := env.location resourceGroupsClient := resources.GroupsClient{env.resources} env.mu.Lock() tags := tags.ResourceTags( names.NewModelTag(env.config.Config.UUID()), names.NewControllerTag(controllerUUID), env.config, ) env.mu.Unlock() logger.Debugf("creating resource group %q", env.resourceGroup) err := env.callAPI(func() (autorest.Response, error) { group, err := resourceGroupsClient.CreateOrUpdate(env.resourceGroup, resources.ResourceGroup{ Location: to.StringPtr(location), Tags: to.StringMapPtr(tags), }) return group.Response, err }) return errors.Annotate(err, "creating resource group") }
func testResourceTags(c *gc.C, tag names.EnvironTag, taggers []tags.ResourceTagger, expectTags map[string]string) { tags := tags.ResourceTags(tag, taggers...) c.Assert(tags, jc.DeepEquals, expectTags) }
func testResourceTags(c *gc.C, model, controller names.ModelTag, taggers []tags.ResourceTagger, expectTags map[string]string) { tags := tags.ResourceTags(model, controller, taggers...) c.Assert(tags, jc.DeepEquals, expectTags) }
// StartInstance is specified in the InstanceBroker interface. func (env *azureEnviron) StartInstance(args environs.StartInstanceParams) (*environs.StartInstanceResult, error) { if args.ControllerUUID == "" { return nil, errors.New("missing controller UUID") } // Get the required configuration and config-dependent information // required to create the instance. We take the lock just once, to // ensure we obtain all information based on the same configuration. env.mu.Lock() envTags := tags.ResourceTags( names.NewModelTag(env.config.Config.UUID()), names.NewControllerTag(args.ControllerUUID), env.config, ) storageAccountType := env.config.storageAccountType imageStream := env.config.ImageStream() instanceTypes, err := env.getInstanceTypesLocked() if err != nil { env.mu.Unlock() return nil, errors.Trace(err) } env.mu.Unlock() // If the user has not specified a root-disk size, then // set a sensible default. var rootDisk uint64 if args.Constraints.RootDisk != nil { rootDisk = *args.Constraints.RootDisk } else { rootDisk = defaultRootDiskSize args.Constraints.RootDisk = &rootDisk } // Identify the instance type and image to provision. series := args.Tools.OneSeries() instanceSpec, err := findInstanceSpec( compute.VirtualMachineImagesClient{env.compute}, instanceTypes, &instances.InstanceConstraint{ Region: env.location, Series: series, Arches: args.Tools.Arches(), Constraints: args.Constraints, }, imageStream, ) if err != nil { return nil, err } if rootDisk < uint64(instanceSpec.InstanceType.RootDisk) { // The InstanceType's RootDisk is set to the maximum // OS disk size; override it with the user-specified // or default root disk size. instanceSpec.InstanceType.RootDisk = rootDisk } // Windows images are 127GiB, and cannot be made smaller. const windowsMinRootDiskMB = 127 * 1024 seriesOS, err := jujuseries.GetOSFromSeries(series) if err != nil { return nil, errors.Trace(err) } if seriesOS == os.Windows { if instanceSpec.InstanceType.RootDisk < windowsMinRootDiskMB { instanceSpec.InstanceType.RootDisk = windowsMinRootDiskMB } } // Pick tools by filtering the available tools down to the architecture of // the image that will be provisioned. selectedTools, err := args.Tools.Match(tools.Filter{ Arch: instanceSpec.Image.Arch, }) if err != nil { return nil, errors.Trace(err) } logger.Infof("picked tools %q", selectedTools[0].Version) // Finalize the instance config, which we'll render to CustomData below. if err := args.InstanceConfig.SetTools(selectedTools); err != nil { return nil, errors.Trace(err) } if err := instancecfg.FinishInstanceConfig( args.InstanceConfig, env.Config(), ); err != nil { return nil, err } machineTag := names.NewMachineTag(args.InstanceConfig.MachineId) vmName := resourceName(machineTag) vmTags := make(map[string]string) for k, v := range args.InstanceConfig.Tags { vmTags[k] = v } // jujuMachineNameTag identifies the VM name, in which is encoded // the Juju machine name. We tag all resources related to the // machine with this. vmTags[jujuMachineNameTag] = vmName if err := env.createVirtualMachine( vmName, vmTags, envTags, instanceSpec, args.InstanceConfig, storageAccountType, ); err != nil { logger.Errorf("creating instance failed, destroying: %v", err) if err := env.StopInstances(instance.Id(vmName)); err != nil { logger.Errorf("could not destroy failed virtual machine: %v", err) } return nil, errors.Annotatef(err, "creating virtual machine %q", vmName) } // Note: the instance is initialised without addresses to keep the // API chatter down. We will refresh the instance if we need to know // the addresses. inst := &azureInstance{vmName, "Creating", env, nil, nil} amd64 := arch.AMD64 hc := &instance.HardwareCharacteristics{ Arch: &amd64, Mem: &instanceSpec.InstanceType.Mem, RootDisk: &instanceSpec.InstanceType.RootDisk, CpuCores: &instanceSpec.InstanceType.CpuCores, } return &environs.StartInstanceResult{ Instance: inst, Hardware: hc, }, nil }
// StartInstance is specified in the InstanceBroker interface. func (env *azureEnviron) StartInstance(args environs.StartInstanceParams) (*environs.StartInstanceResult, error) { // Get the required configuration and config-dependent information // required to create the instance. We take the lock just once, to // ensure we obtain all information based on the same configuration. env.mu.Lock() location := env.config.location envTags := tags.ResourceTags( names.NewModelTag(env.config.Config.UUID()), names.NewModelTag(env.config.Config.ControllerUUID()), env.config, ) apiPort := env.config.APIPort() vmClient := compute.VirtualMachinesClient{env.compute} availabilitySetClient := compute.AvailabilitySetsClient{env.compute} networkClient := env.network vmImagesClient := compute.VirtualMachineImagesClient{env.compute} vmExtensionClient := compute.VirtualMachineExtensionsClient{env.compute} imageStream := env.config.ImageStream() storageEndpoint := env.config.storageEndpoint storageAccountName := env.config.storageAccount instanceTypes, err := env.getInstanceTypesLocked() if err != nil { env.mu.Unlock() return nil, errors.Trace(err) } internalNetworkSubnet, err := env.getInternalSubnetLocked() if err != nil { env.mu.Unlock() return nil, errors.Trace(err) } env.mu.Unlock() // Identify the instance type and image to provision. instanceSpec, err := findInstanceSpec( vmImagesClient, instanceTypes, &instances.InstanceConstraint{ Region: location, Series: args.Tools.OneSeries(), Arches: args.Tools.Arches(), Constraints: args.Constraints, }, imageStream, ) if err != nil { return nil, err } // Pick tools by filtering the available tools down to the architecture of // the image that will be provisioned. selectedTools, err := args.Tools.Match(tools.Filter{ Arch: instanceSpec.Image.Arch, }) if err != nil { return nil, errors.Trace(err) } logger.Infof("picked tools %q", selectedTools[0].Version) // Finalize the instance config, which we'll render to CustomData below. if err := args.InstanceConfig.SetTools(selectedTools); err != nil { return nil, errors.Trace(err) } if err := instancecfg.FinishInstanceConfig( args.InstanceConfig, env.Config(), ); err != nil { return nil, err } machineTag := names.NewMachineTag(args.InstanceConfig.MachineId) vmName := resourceName(machineTag) vmTags := make(map[string]string) for k, v := range args.InstanceConfig.Tags { vmTags[k] = v } // jujuMachineNameTag identifies the VM name, in which is encoded // the Juju machine name. We tag all resources related to the // machine with this. vmTags[jujuMachineNameTag] = vmName // If the machine will run a controller, then we need to open the // API port for it. var apiPortPtr *int if multiwatcher.AnyJobNeedsState(args.InstanceConfig.Jobs...) { apiPortPtr = &apiPort } vm, err := createVirtualMachine( env.resourceGroup, location, vmName, vmTags, envTags, instanceSpec, args.InstanceConfig, args.DistributionGroup, env.Instances, apiPortPtr, internalNetworkSubnet, storageEndpoint, storageAccountName, networkClient, vmClient, availabilitySetClient, vmExtensionClient, ) if err != nil { logger.Errorf("creating instance failed, destroying: %v", err) if err := env.StopInstances(instance.Id(vmName)); err != nil { logger.Errorf("could not destroy failed virtual machine: %v", err) } return nil, errors.Annotatef(err, "creating virtual machine %q", vmName) } // Note: the instance is initialised without addresses to keep the // API chatter down. We will refresh the instance if we need to know // the addresses. inst := &azureInstance{vm, env, nil, nil} amd64 := arch.AMD64 hc := &instance.HardwareCharacteristics{ Arch: &amd64, Mem: &instanceSpec.InstanceType.Mem, RootDisk: &instanceSpec.InstanceType.RootDisk, CpuCores: &instanceSpec.InstanceType.CpuCores, } return &environs.StartInstanceResult{ Instance: inst, Hardware: hc, }, nil }