// Create creates the virtual machine. func (d *Driver) Create() error { // NOTE(ahmetalpbalkan): We can probably parallelize the sh*t out of this. // However that would lead to a concurrency logic and while creation of a // resource fails, other ones would be kicked off, which could lead to a // resource leak. This is slower but safer. c, err := d.newAzureClient() if err != nil { return err } var customData string if d.CustomDataFile != "" { buf, err := ioutil.ReadFile(d.CustomDataFile) if err != nil { return err } customData = base64.StdEncoding.EncodeToString(buf) } if err := c.CreateResourceGroup(d.ResourceGroup, d.Location); err != nil { return err } if err := c.CreateAvailabilitySetIfNotExists(d.ctx, d.ResourceGroup, d.AvailabilitySet, d.Location); err != nil { return err } if err := c.CreateNetworkSecurityGroup(d.ctx, d.ResourceGroup, d.naming().NSG(), d.Location, d.ctx.FirewallRules); err != nil { return err } vnetResourceGroup, vNetName := parseVirtualNetwork(d.VirtualNetwork, d.ResourceGroup) if err := c.CreateVirtualNetworkIfNotExists(vnetResourceGroup, vNetName, d.Location); err != nil { return err } if err := c.CreateSubnet(d.ctx, vnetResourceGroup, vNetName, d.SubnetName, d.SubnetPrefix); err != nil { return err } if d.NoPublicIP { log.Info("Not creating a public IP address.") } else { if err := c.CreatePublicIPAddress(d.ctx, d.ResourceGroup, d.naming().IP(), d.Location, d.StaticPublicIP, d.DNSLabel); err != nil { return err } } if err := c.CreateNetworkInterface(d.ctx, d.ResourceGroup, d.naming().NIC(), d.Location, d.ctx.PublicIPAddressID, d.ctx.SubnetID, d.ctx.NetworkSecurityGroupID, d.PrivateIPAddr); err != nil { return err } if err := c.CreateStorageAccount(d.ctx, d.ResourceGroup, d.Location, storage.SkuName(d.StorageType)); err != nil { return err } if err := d.generateSSHKey(d.ctx); err != nil { return err } if err := c.CreateVirtualMachine(d.ResourceGroup, d.naming().VM(), d.Location, d.Size, d.ctx.AvailabilitySetID, d.ctx.NetworkInterfaceID, d.BaseDriver.SSHUser, d.ctx.SSHPublicKey, d.Image, customData, d.ctx.StorageAccount); err != nil { return err } return nil }
func resourceArmStorageAccountCreate(d *schema.ResourceData, meta interface{}) error { client := meta.(*ArmClient) storageClient := client.storageServiceClient resourceGroupName := d.Get("resource_group_name").(string) storageAccountName := d.Get("name").(string) accountType := d.Get("account_type").(string) location := d.Get("location").(string) tags := d.Get("tags").(map[string]interface{}) sku := storage.Sku{ Name: storage.SkuName(accountType), } opts := storage.AccountCreateParameters{ Location: &location, Sku: &sku, Tags: expandTags(tags), } _, err := storageClient.Create(resourceGroupName, storageAccountName, opts, make(chan struct{})) if err != nil { return fmt.Errorf("Error creating Azure Storage Account '%s': %s", storageAccountName, err) } // The only way to get the ID back apparently is to read the resource again read, err := storageClient.GetProperties(resourceGroupName, storageAccountName) if err != nil { return err } if read.ID == nil { return fmt.Errorf("Cannot read Storage Account %s (resource group %s) ID", storageAccountName, resourceGroupName) } log.Printf("[DEBUG] Waiting for Storage Account (%s) to become available", storageAccountName) stateConf := &resource.StateChangeConf{ Pending: []string{"Updating", "Creating"}, Target: []string{"Succeeded"}, Refresh: storageAccountStateRefreshFunc(client, resourceGroupName, storageAccountName), Timeout: 30 * time.Minute, MinTimeout: 15 * time.Second, } if _, err := stateConf.WaitForState(); err != nil { return fmt.Errorf("Error waiting for Storage Account (%s) to become available: %s", storageAccountName, err) } d.SetId(*read.ID) return resourceArmStorageAccountRead(d, meta) }
// storageAccountTemplateResource returns a template resource definition // for creating a storage account. func storageAccountTemplateResource( location string, envTags map[string]string, accountName, accountType string, ) armtemplates.Resource { return armtemplates.Resource{ APIVersion: armstorage.APIVersion, Type: "Microsoft.Storage/storageAccounts", Name: accountName, Location: location, Tags: envTags, StorageSku: &armstorage.Sku{ Name: armstorage.SkuName(accountType), }, } }
// resourceArmStorageAccountUpdate is unusual in the ARM API where most resources have a combined // and idempotent operation for CreateOrUpdate. In particular updating all of the parameters // available requires a call to Update per parameter... func resourceArmStorageAccountUpdate(d *schema.ResourceData, meta interface{}) error { client := meta.(*ArmClient).storageServiceClient id, err := parseAzureResourceID(d.Id()) if err != nil { return err } storageAccountName := id.Path["storageAccounts"] resourceGroupName := id.ResourceGroup d.Partial(true) if d.HasChange("account_type") { accountType := d.Get("account_type").(string) sku := storage.Sku{ Name: storage.SkuName(accountType), } opts := storage.AccountUpdateParameters{ Sku: &sku, } _, err := client.Update(resourceGroupName, storageAccountName, opts) if err != nil { return fmt.Errorf("Error updating Azure Storage Account type %q: %s", storageAccountName, err) } d.SetPartial("account_type") } if d.HasChange("tags") { tags := d.Get("tags").(map[string]interface{}) opts := storage.AccountUpdateParameters{ Tags: expandTags(tags), } _, err := client.Update(resourceGroupName, storageAccountName, opts) if err != nil { return fmt.Errorf("Error updating Azure Storage Account tags %q: %s", storageAccountName, err) } d.SetPartial("tags") } d.Partial(false) return nil }
func resourceArmStorageAccountCreate(d *schema.ResourceData, meta interface{}) error { client := meta.(*ArmClient).storageServiceClient resourceGroupName := d.Get("resource_group_name").(string) storageAccountName := d.Get("name").(string) accountType := d.Get("account_type").(string) location := d.Get("location").(string) tags := d.Get("tags").(map[string]interface{}) sku := storage.Sku{ Name: storage.SkuName(accountType), } opts := storage.AccountCreateParameters{ Location: &location, Sku: &sku, Tags: expandTags(tags), } _, err := client.Create(resourceGroupName, storageAccountName, opts, make(chan struct{})) if err != nil { return fmt.Errorf("Error creating Azure Storage Account '%s': %s", storageAccountName, err) } // The only way to get the ID back apparently is to read the resource again read, err := client.GetProperties(resourceGroupName, storageAccountName) if err != nil { return err } if read.ID == nil { return fmt.Errorf("Cannot read Storage Account %s (resource group %s) ID", storageAccountName, resourceGroupName) } d.SetId(*read.ID) return resourceArmStorageAccountRead(d, meta) }
func (s *environSuite) assertStartInstanceRequests( c *gc.C, requests []*http.Request, args assertStartInstanceRequestsParams, ) startInstanceRequests { nsgId := `[resourceId('Microsoft.Network/networkSecurityGroups', 'juju-internal-nsg')]` securityRules := []network.SecurityRule{{ Name: to.StringPtr("SSHInbound"), Properties: &network.SecurityRulePropertiesFormat{ Description: to.StringPtr("Allow SSH access to all machines"), Protocol: network.TCP, SourceAddressPrefix: to.StringPtr("*"), SourcePortRange: to.StringPtr("*"), DestinationAddressPrefix: to.StringPtr("*"), DestinationPortRange: to.StringPtr("22"), Access: network.Allow, Priority: to.Int32Ptr(100), Direction: network.Inbound, }, }, { Name: to.StringPtr("JujuAPIInbound"), Properties: &network.SecurityRulePropertiesFormat{ Description: to.StringPtr("Allow API connections to controller machines"), Protocol: network.TCP, SourceAddressPrefix: to.StringPtr("*"), SourcePortRange: to.StringPtr("*"), DestinationAddressPrefix: to.StringPtr("192.168.16.0/20"), DestinationPortRange: to.StringPtr("17777"), Access: network.Allow, Priority: to.Int32Ptr(101), Direction: network.Inbound, }, }} subnets := []network.Subnet{{ Name: to.StringPtr("juju-internal-subnet"), Properties: &network.SubnetPropertiesFormat{ AddressPrefix: to.StringPtr("192.168.0.0/20"), NetworkSecurityGroup: &network.SecurityGroup{ ID: to.StringPtr(nsgId), }, }, }, { Name: to.StringPtr("juju-controller-subnet"), Properties: &network.SubnetPropertiesFormat{ AddressPrefix: to.StringPtr("192.168.16.0/20"), NetworkSecurityGroup: &network.SecurityGroup{ ID: to.StringPtr(nsgId), }, }, }} subnetName := "juju-internal-subnet" privateIPAddress := "192.168.0.4" if args.availabilitySetName == "juju-controller" { subnetName = "juju-controller-subnet" privateIPAddress = "192.168.16.4" } subnetId := fmt.Sprintf( `[concat(resourceId('Microsoft.Network/virtualNetworks', 'juju-internal-network'), '/subnets/%s')]`, subnetName, ) publicIPAddressId := `[resourceId('Microsoft.Network/publicIPAddresses', 'machine-0-public-ip')]` ipConfigurations := []network.InterfaceIPConfiguration{{ Name: to.StringPtr("primary"), Properties: &network.InterfaceIPConfigurationPropertiesFormat{ Primary: to.BoolPtr(true), PrivateIPAddress: to.StringPtr(privateIPAddress), PrivateIPAllocationMethod: network.Static, Subnet: &network.Subnet{ID: to.StringPtr(subnetId)}, PublicIPAddress: &network.PublicIPAddress{ ID: to.StringPtr(publicIPAddressId), }, }, }} nicId := `[resourceId('Microsoft.Network/networkInterfaces', 'machine-0-primary')]` nics := []compute.NetworkInterfaceReference{{ ID: to.StringPtr(nicId), Properties: &compute.NetworkInterfaceReferenceProperties{ Primary: to.BoolPtr(true), }, }} vmDependsOn := []string{ nicId, `[resourceId('Microsoft.Storage/storageAccounts', '` + storageAccountName + `')]`, } addressPrefixes := []string{"192.168.0.0/20", "192.168.16.0/20"} templateResources := []armtemplates.Resource{{ APIVersion: network.APIVersion, Type: "Microsoft.Network/networkSecurityGroups", Name: "juju-internal-nsg", Location: "westus", Tags: to.StringMap(s.envTags), Properties: &network.SecurityGroupPropertiesFormat{ SecurityRules: &securityRules, }, }, { APIVersion: network.APIVersion, Type: "Microsoft.Network/virtualNetworks", Name: "juju-internal-network", Location: "westus", Tags: to.StringMap(s.envTags), Properties: &network.VirtualNetworkPropertiesFormat{ AddressSpace: &network.AddressSpace{&addressPrefixes}, Subnets: &subnets, }, DependsOn: []string{nsgId}, }, { APIVersion: storage.APIVersion, Type: "Microsoft.Storage/storageAccounts", Name: storageAccountName, Location: "westus", Tags: to.StringMap(s.envTags), StorageSku: &storage.Sku{ Name: storage.SkuName("Standard_LRS"), }, }} var availabilitySetSubResource *compute.SubResource if args.availabilitySetName != "" { availabilitySetId := fmt.Sprintf( `[resourceId('Microsoft.Compute/availabilitySets','%s')]`, args.availabilitySetName, ) templateResources = append(templateResources, armtemplates.Resource{ APIVersion: compute.APIVersion, Type: "Microsoft.Compute/availabilitySets", Name: args.availabilitySetName, Location: "westus", Tags: to.StringMap(s.envTags), }) availabilitySetSubResource = &compute.SubResource{ ID: to.StringPtr(availabilitySetId), } vmDependsOn = append([]string{availabilitySetId}, vmDependsOn...) } templateResources = append(templateResources, []armtemplates.Resource{{ APIVersion: network.APIVersion, Type: "Microsoft.Network/publicIPAddresses", Name: "machine-0-public-ip", Location: "westus", Tags: to.StringMap(s.vmTags), Properties: &network.PublicIPAddressPropertiesFormat{ PublicIPAllocationMethod: network.Dynamic, }, }, { APIVersion: network.APIVersion, Type: "Microsoft.Network/networkInterfaces", Name: "machine-0-primary", Location: "westus", Tags: to.StringMap(s.vmTags), Properties: &network.InterfacePropertiesFormat{ IPConfigurations: &ipConfigurations, }, DependsOn: []string{ publicIPAddressId, `[resourceId('Microsoft.Network/virtualNetworks', 'juju-internal-network')]`, }, }, { APIVersion: compute.APIVersion, Type: "Microsoft.Compute/virtualMachines", Name: "machine-0", Location: "westus", Tags: to.StringMap(s.vmTags), Properties: &compute.VirtualMachineProperties{ HardwareProfile: &compute.HardwareProfile{ VMSize: "Standard_D1", }, StorageProfile: &compute.StorageProfile{ ImageReference: args.imageReference, OsDisk: &compute.OSDisk{ Name: to.StringPtr("machine-0"), CreateOption: compute.FromImage, Caching: compute.ReadWrite, Vhd: &compute.VirtualHardDisk{ URI: to.StringPtr(fmt.Sprintf( `[concat(reference(resourceId('Microsoft.Storage/storageAccounts', '%s'), '%s').primaryEndpoints.blob, 'osvhds/machine-0.vhd')]`, storageAccountName, storage.APIVersion, )), }, DiskSizeGB: to.Int32Ptr(int32(args.diskSizeGB)), }, }, OsProfile: args.osProfile, NetworkProfile: &compute.NetworkProfile{&nics}, AvailabilitySet: availabilitySetSubResource, }, DependsOn: vmDependsOn, }}...) if args.vmExtension != nil { templateResources = append(templateResources, armtemplates.Resource{ APIVersion: compute.APIVersion, Type: "Microsoft.Compute/virtualMachines/extensions", Name: "machine-0/JujuCustomScriptExtension", Location: "westus", Tags: to.StringMap(s.vmTags), Properties: args.vmExtension, DependsOn: []string{"Microsoft.Compute/virtualMachines/machine-0"}, }) } templateMap := map[string]interface{}{ "$schema": "http://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#", "contentVersion": "1.0.0.0", "resources": templateResources, } deployment := &resources.Deployment{ &resources.DeploymentProperties{ Template: &templateMap, Mode: resources.Incremental, }, } // Validate HTTP request bodies. var startInstanceRequests startInstanceRequests if args.vmExtension != nil { // It must be Windows or CentOS, so // there should be no image query. c.Assert(requests, gc.HasLen, numExpectedStartInstanceRequests-1) c.Assert(requests[0].Method, gc.Equals, "GET") // vmSizes c.Assert(requests[1].Method, gc.Equals, "PUT") // create deployment startInstanceRequests.vmSizes = requests[0] startInstanceRequests.deployment = requests[1] } else { c.Assert(requests, gc.HasLen, numExpectedStartInstanceRequests) c.Assert(requests[0].Method, gc.Equals, "GET") // vmSizes c.Assert(requests[1].Method, gc.Equals, "GET") // skus c.Assert(requests[2].Method, gc.Equals, "PUT") // create deployment startInstanceRequests.vmSizes = requests[0] startInstanceRequests.skus = requests[1] startInstanceRequests.deployment = requests[2] } // Marshal/unmarshal the deployment we expect, so it's in map form. var expected resources.Deployment data, err := json.Marshal(&deployment) c.Assert(err, jc.ErrorIsNil) err = json.Unmarshal(data, &expected) c.Assert(err, jc.ErrorIsNil) // Check that we send what we expect. CustomData is non-deterministic, // so don't compare it. // TODO(axw) shouldn't CustomData be deterministic? Look into this. var actual resources.Deployment unmarshalRequestBody(c, startInstanceRequests.deployment, &actual) c.Assert(actual.Properties, gc.NotNil) c.Assert(actual.Properties.Template, gc.NotNil) resources := (*actual.Properties.Template)["resources"].([]interface{}) c.Assert(resources, gc.HasLen, len(templateResources)) vmResourceIndex := len(resources) - 1 if args.vmExtension != nil { vmResourceIndex-- } vmResource := resources[vmResourceIndex].(map[string]interface{}) vmResourceProperties := vmResource["properties"].(map[string]interface{}) osProfile := vmResourceProperties["osProfile"].(map[string]interface{}) osProfile["customData"] = "<juju-goes-here>" c.Assert(actual, jc.DeepEquals, expected) return startInstanceRequests }
func resourceArmStorageAccountCreate(d *schema.ResourceData, meta interface{}) error { client := meta.(*ArmClient) storageClient := client.storageServiceClient resourceGroupName := d.Get("resource_group_name").(string) storageAccountName := d.Get("name").(string) accountType := d.Get("account_type").(string) location := d.Get("location").(string) tags := d.Get("tags").(map[string]interface{}) sku := storage.Sku{ Name: storage.SkuName(accountType), } opts := storage.AccountCreateParameters{ Location: &location, Sku: &sku, Tags: expandTags(tags), } // Create the storage account. We wrap this so that it is cancellable // with a Ctrl-C since this can take a LONG time. wrap := signalwrapper.Run(func(cancelCh <-chan struct{}) error { _, err := storageClient.Create(resourceGroupName, storageAccountName, opts, cancelCh) return err }) // Check the result of the wrapped function. var createErr error select { case <-time.After(1 * time.Hour): // An hour is way above the expected P99 for this API call so // we premature cancel and error here. createErr = wrap.Cancel() case createErr = <-wrap.ErrCh: // Successfully ran (but perhaps not successfully completed) // the function. } // The only way to get the ID back apparently is to read the resource again read, err := storageClient.GetProperties(resourceGroupName, storageAccountName) // Set the ID right away if we have one if err == nil && read.ID != nil { log.Printf("[INFO] storage account %q ID: %q", storageAccountName, *read.ID) d.SetId(*read.ID) } // If we had a create error earlier then we return with that error now. // We do this later here so that we can grab the ID above is possible. if createErr != nil { return fmt.Errorf( "Error creating Azure Storage Account '%s': %s", storageAccountName, createErr) } // Check the read error now that we know it would exist without a create err if err != nil { return err } // If we got no ID then the resource group doesn't yet exist if read.ID == nil { return fmt.Errorf("Cannot read Storage Account %s (resource group %s) ID", storageAccountName, resourceGroupName) } log.Printf("[DEBUG] Waiting for Storage Account (%s) to become available", storageAccountName) stateConf := &resource.StateChangeConf{ Pending: []string{"Updating", "Creating"}, Target: []string{"Succeeded"}, Refresh: storageAccountStateRefreshFunc(client, resourceGroupName, storageAccountName), Timeout: 30 * time.Minute, MinTimeout: 15 * time.Second, } if _, err := stateConf.WaitForState(); err != nil { return fmt.Errorf("Error waiting for Storage Account (%s) to become available: %s", storageAccountName, err) } return resourceArmStorageAccountRead(d, meta) }
// resourceArmStorageAccountUpdate is unusual in the ARM API where most resources have a combined // and idempotent operation for CreateOrUpdate. In particular updating all of the parameters // available requires a call to Update per parameter... func resourceArmStorageAccountUpdate(d *schema.ResourceData, meta interface{}) error { client := meta.(*ArmClient).storageServiceClient id, err := parseAzureResourceID(d.Id()) if err != nil { return err } storageAccountName := id.Path["storageAccounts"] resourceGroupName := id.ResourceGroup d.Partial(true) if d.HasChange("account_type") { accountType := d.Get("account_type").(string) sku := storage.Sku{ Name: storage.SkuName(accountType), } opts := storage.AccountUpdateParameters{ Sku: &sku, } _, err := client.Update(resourceGroupName, storageAccountName, opts) if err != nil { return fmt.Errorf("Error updating Azure Storage Account type %q: %s", storageAccountName, err) } d.SetPartial("account_type") } if d.HasChange("access_tier") { accessTier := d.Get("access_tier").(string) opts := storage.AccountUpdateParameters{ Properties: &storage.AccountPropertiesUpdateParameters{ AccessTier: storage.AccessTier(accessTier), }, } _, err := client.Update(resourceGroupName, storageAccountName, opts) if err != nil { return fmt.Errorf("Error updating Azure Storage Account access_tier %q: %s", storageAccountName, err) } d.SetPartial("access_tier") } if d.HasChange("tags") { tags := d.Get("tags").(map[string]interface{}) opts := storage.AccountUpdateParameters{ Tags: expandTags(tags), } _, err := client.Update(resourceGroupName, storageAccountName, opts) if err != nil { return fmt.Errorf("Error updating Azure Storage Account tags %q: %s", storageAccountName, err) } d.SetPartial("tags") } if d.HasChange("enable_blob_encryption") { enableBlobEncryption := d.Get("enable_blob_encryption").(bool) opts := storage.AccountUpdateParameters{ Properties: &storage.AccountPropertiesUpdateParameters{ Encryption: &storage.Encryption{ Services: &storage.EncryptionServices{ Blob: &storage.EncryptionService{ Enabled: &enableBlobEncryption, }, }, KeySource: &storageAccountEncryptionSource, }, }, } _, err := client.Update(resourceGroupName, storageAccountName, opts) if err != nil { return fmt.Errorf("Error updating Azure Storage Account enable_blob_encryption %q: %s", storageAccountName, err) } d.SetPartial("enable_blob_encryption") } d.Partial(false) return nil }
func resourceArmStorageAccountCreate(d *schema.ResourceData, meta interface{}) error { client := meta.(*ArmClient) storageClient := client.storageServiceClient resourceGroupName := d.Get("resource_group_name").(string) storageAccountName := d.Get("name").(string) accountKind := d.Get("account_kind").(string) accountType := d.Get("account_type").(string) location := d.Get("location").(string) tags := d.Get("tags").(map[string]interface{}) enableBlobEncryption := d.Get("enable_blob_encryption").(bool) sku := storage.Sku{ Name: storage.SkuName(accountType), } opts := storage.AccountCreateParameters{ Location: &location, Sku: &sku, Tags: expandTags(tags), Kind: storage.Kind(accountKind), Properties: &storage.AccountPropertiesCreateParameters{ Encryption: &storage.Encryption{ Services: &storage.EncryptionServices{ Blob: &storage.EncryptionService{ Enabled: &enableBlobEncryption, }, }, KeySource: &storageAccountEncryptionSource, }, }, } // AccessTier is only valid for BlobStorage accounts if accountKind == string(storage.BlobStorage) { accessTier, ok := d.GetOk("access_tier") if !ok { // default to "Hot" accessTier = blobStorageAccountDefaultAccessTier } opts.Properties.AccessTier = storage.AccessTier(accessTier.(string)) } // Create cancelCtx, cancelFunc := context.WithTimeout(client.StopContext, 1*time.Hour) _, createErr := storageClient.Create( resourceGroupName, storageAccountName, opts, cancelCtx.Done()) cancelFunc() // The only way to get the ID back apparently is to read the resource again read, err := storageClient.GetProperties(resourceGroupName, storageAccountName) // Set the ID right away if we have one if err == nil && read.ID != nil { log.Printf("[INFO] storage account %q ID: %q", storageAccountName, *read.ID) d.SetId(*read.ID) } // If we had a create error earlier then we return with that error now. // We do this later here so that we can grab the ID above is possible. if createErr != nil { return fmt.Errorf( "Error creating Azure Storage Account '%s': %s", storageAccountName, createErr) } // Check the read error now that we know it would exist without a create err if err != nil { return err } // If we got no ID then the resource group doesn't yet exist if read.ID == nil { return fmt.Errorf("Cannot read Storage Account %s (resource group %s) ID", storageAccountName, resourceGroupName) } log.Printf("[DEBUG] Waiting for Storage Account (%s) to become available", storageAccountName) stateConf := &resource.StateChangeConf{ Pending: []string{"Updating", "Creating"}, Target: []string{"Succeeded"}, Refresh: storageAccountStateRefreshFunc(client, resourceGroupName, storageAccountName), Timeout: 30 * time.Minute, MinTimeout: 15 * time.Second, } if _, err := stateConf.WaitForState(); err != nil { return fmt.Errorf("Error waiting for Storage Account (%s) to become available: %s", storageAccountName, err) } return resourceArmStorageAccountRead(d, meta) }