diff --git a/builder/azure/arm/artifact.go b/builder/azure/arm/artifact.go index 5de9f90e1..eade5017b 100644 --- a/builder/azure/arm/artifact.go +++ b/builder/azure/arm/artifact.go @@ -16,11 +16,25 @@ const ( ) type Artifact struct { + // VHD StorageAccountLocation string OSDiskUri string TemplateUri string OSDiskUriReadOnlySas string TemplateUriReadOnlySas string + + // Managed Image + ManagedImageResourceGroupName string + ManagedImageName string + ManagedImageLocation string +} + +func NewManagedImageArtifact(resourceGroup, name, location string) (*Artifact, error) { + return &Artifact{ + ManagedImageResourceGroupName: resourceGroup, + ManagedImageName: name, + ManagedImageLocation: location, + }, nil } func NewArtifact(template *CaptureTemplate, getSasUrl func(name string) string) (*Artifact, error) { @@ -78,6 +92,10 @@ func storageUriToTemplateUri(su *url.URL) (*url.URL, error) { return url.Parse(strings.Replace(su.String(), filename, templateFilename, 1)) } +func (a *Artifact) isMangedImage() bool { + return a.ManagedImageResourceGroupName != "" +} + func (*Artifact) BuilderId() string { return BuilderId } @@ -103,11 +121,17 @@ func (a *Artifact) String() string { var buf bytes.Buffer buf.WriteString(fmt.Sprintf("%s:\n\n", a.BuilderId())) - buf.WriteString(fmt.Sprintf("StorageAccountLocation: %s\n", a.StorageAccountLocation)) - buf.WriteString(fmt.Sprintf("OSDiskUri: %s\n", a.OSDiskUri)) - buf.WriteString(fmt.Sprintf("OSDiskUriReadOnlySas: %s\n", a.OSDiskUriReadOnlySas)) - buf.WriteString(fmt.Sprintf("TemplateUri: %s\n", a.TemplateUri)) - buf.WriteString(fmt.Sprintf("TemplateUriReadOnlySas: %s\n", a.TemplateUriReadOnlySas)) + if a.isMangedImage() { + buf.WriteString(fmt.Sprintf("ManagedImageResourceGroupName: %s\n", a.ManagedImageResourceGroupName)) + buf.WriteString(fmt.Sprintf("ManagedImageName: %s\n", a.ManagedImageName)) + buf.WriteString(fmt.Sprintf("ManagedImageLocation: %s\n", a.ManagedImageLocation)) + } else { + buf.WriteString(fmt.Sprintf("StorageAccountLocation: %s\n", a.StorageAccountLocation)) + buf.WriteString(fmt.Sprintf("OSDiskUri: %s\n", a.OSDiskUri)) + buf.WriteString(fmt.Sprintf("OSDiskUriReadOnlySas: %s\n", a.OSDiskUriReadOnlySas)) + buf.WriteString(fmt.Sprintf("TemplateUri: %s\n", a.TemplateUri)) + buf.WriteString(fmt.Sprintf("TemplateUriReadOnlySas: %s\n", a.TemplateUriReadOnlySas)) + } return buf.String() } diff --git a/builder/azure/arm/azure_client.go b/builder/azure/arm/azure_client.go index 10e3d42c0..88a6990af 100644 --- a/builder/azure/arm/azure_client.go +++ b/builder/azure/arm/azure_client.go @@ -180,23 +180,27 @@ func NewAzureClient(subscriptionID, resourceGroupName, storageAccountName string azureClient.VaultClient.ResponseInspector = byInspecting(maxlen) azureClient.VaultClient.UserAgent += packerUserAgent - accountKeys, err := azureClient.AccountsClient.ListKeys(resourceGroupName, storageAccountName) - if err != nil { - return nil, err + // If this is a managed disk build, this should be ignored. + if resourceGroupName != "" && storageAccountName != "" { + accountKeys, err := azureClient.AccountsClient.ListKeys(resourceGroupName, storageAccountName) + if err != nil { + return nil, err + } + + storageClient, err := storage.NewClient( + storageAccountName, + *(*accountKeys.Keys)[0].Value, + cloud.StorageEndpointSuffix, + storage.DefaultAPIVersion, + true /*useHttps*/) + + if err != nil { + return nil, err + } + + azureClient.BlobStorageClient = storageClient.GetBlobService() } - storageClient, err := storage.NewClient( - storageAccountName, - *(*accountKeys.Keys)[0].Value, - cloud.StorageEndpointSuffix, - storage.DefaultAPIVersion, - true /*useHttps*/) - - if err != nil { - return nil, err - } - - azureClient.BlobStorageClient = storageClient.GetBlobService() return azureClient, nil } diff --git a/builder/azure/arm/builder.go b/builder/azure/arm/builder.go index ef92f4cbc..a9a435a22 100644 --- a/builder/azure/arm/builder.go +++ b/builder/azure/arm/builder.go @@ -104,14 +104,16 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe } } - account, err := b.getBlobAccount(azureClient, b.config.ResourceGroupName, b.config.StorageAccount) - if err != nil { - return nil, err - } - b.config.storageAccountBlobEndpoint = *account.AccountProperties.PrimaryEndpoints.Blob + if b.config.StorageAccount != "" { + account, err := b.getBlobAccount(azureClient, b.config.ResourceGroupName, b.config.StorageAccount) + if err != nil { + return nil, err + } + b.config.storageAccountBlobEndpoint = *account.AccountProperties.PrimaryEndpoints.Blob - if !b.config.isManagedImage() && equalLocation(*account.Location, b.config.Location) == false { - return nil, fmt.Errorf("The storage account is located in %s, but the build will take place in %s. The locations must be identical", *account.Location, b.config.Location) + if !equalLocation(*account.Location, b.config.Location) { + return nil, fmt.Errorf("The storage account is located in %s, but the build will take place in %s. The locations must be identical", *account.Location, b.config.Location) + } } endpointConnectType := PublicEndpoint @@ -197,7 +199,9 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe return nil, errors.New("Build was halted.") } - if template, ok := b.stateBag.GetOk(constants.ArmCaptureTemplate); ok { + if b.config.isManagedImage() { + return NewManagedImageArtifact(b.config.ManagedImageResourceGroupName, b.config.ManagedImageName, b.config.manageImageLocation) + } else if template, ok := b.stateBag.GetOk(constants.ArmCaptureTemplate); ok { return NewArtifact( template.(*CaptureTemplate), func(name string) string { diff --git a/builder/azure/arm/config.go b/builder/azure/arm/config.go index 0f42f6511..ee3d124f1 100644 --- a/builder/azure/arm/config.go +++ b/builder/azure/arm/config.go @@ -470,39 +470,61 @@ func assertRequiredParametersSet(c *Config, errs *packer.MultiError) { ///////////////////////////////////////////// // Capture - if c.CaptureContainerName == "" { - errs = packer.MultiErrorAppend(errs, fmt.Errorf("A capture_container_name must be specified")) + if c.CaptureContainerName == "" && c.ManagedImageName == "" { + errs = packer.MultiErrorAppend(errs, fmt.Errorf("A capture_container_name or managed_image_name must be specified")) } - if !reCaptureContainerName.MatchString(c.CaptureContainerName) { - errs = packer.MultiErrorAppend(errs, fmt.Errorf("A capture_container_name must satisfy the regular expression %q.", reCaptureContainerName.String())) + if c.CaptureNamePrefix == "" && c.ManagedImageResourceGroupName == "" { + errs = packer.MultiErrorAppend(errs, fmt.Errorf("A capture_name_prefix or managed_image_resource_group_name must be specified")) } - if strings.HasSuffix(c.CaptureContainerName, "-") { - errs = packer.MultiErrorAppend(errs, fmt.Errorf("A capture_container_name must not end with a hyphen, e.g. '-'.")) + if (c.CaptureNamePrefix != "" || c.CaptureContainerName != "") && (c.ManagedImageResourceGroupName != "" || c.ManagedImageName != "") { + errs = packer.MultiErrorAppend(errs, fmt.Errorf("Either a VHD or a managed image can be built, but not both. Please specify either capture_container_name and capture_name_prefix or managed_image_resource_group_name and managed_image_name.")) } - if strings.Contains(c.CaptureContainerName, "--") { - errs = packer.MultiErrorAppend(errs, fmt.Errorf("A capture_container_name must not contain consecutive hyphens, e.g. '--'.")) - } + if c.CaptureContainerName != "" { + if !reCaptureContainerName.MatchString(c.CaptureContainerName) { + errs = packer.MultiErrorAppend(errs, fmt.Errorf("A capture_container_name must satisfy the regular expression %q.", reCaptureContainerName.String())) + } - if c.CaptureNamePrefix == "" { - errs = packer.MultiErrorAppend(errs, fmt.Errorf("A capture_name_prefix must be specified")) - } + if strings.HasSuffix(c.CaptureContainerName, "-") { + errs = packer.MultiErrorAppend(errs, fmt.Errorf("A capture_container_name must not end with a hyphen, e.g. '-'.")) + } - if !reCaptureNamePrefix.MatchString(c.CaptureNamePrefix) { - errs = packer.MultiErrorAppend(errs, fmt.Errorf("A capture_name_prefix must satisfy the regular expression %q.", reCaptureNamePrefix.String())) - } + if strings.Contains(c.CaptureContainerName, "--") { + errs = packer.MultiErrorAppend(errs, fmt.Errorf("A capture_container_name must not contain consecutive hyphens, e.g. '--'.")) + } - if strings.HasSuffix(c.CaptureNamePrefix, "-") || strings.HasSuffix(c.CaptureNamePrefix, ".") { - errs = packer.MultiErrorAppend(errs, fmt.Errorf("A capture_name_prefix must not end with a hyphen or period.")) + if c.CaptureNamePrefix == "" { + errs = packer.MultiErrorAppend(errs, fmt.Errorf("A capture_name_prefix must be specified")) + } + + if !reCaptureNamePrefix.MatchString(c.CaptureNamePrefix) { + errs = packer.MultiErrorAppend(errs, fmt.Errorf("A capture_name_prefix must satisfy the regular expression %q.", reCaptureNamePrefix.String())) + } + + if strings.HasSuffix(c.CaptureNamePrefix, "-") || strings.HasSuffix(c.CaptureNamePrefix, ".") { + errs = packer.MultiErrorAppend(errs, fmt.Errorf("A capture_name_prefix must not end with a hyphen or period.")) + } } ///////////////////////////////////////////// // Compute - if c.ImageUrl != "" && - (c.CustomManagedImageName != "" || c.CustomManagedImageResourceGroupName != "") && - (c.ImagePublisher != "" || c.ImageOffer != "" || c.ImageSku != "") { + toInt := func(b bool) int { + if b { + return 1 + } else { + return 0 + } + } + + isImageUrl := c.ImageUrl != "" + isCustomManagedImage := c.CustomManagedImageName != "" || c.CustomManagedImageResourceGroupName != "" + isPlatformImage := c.ImagePublisher != "" || c.ImageOffer != "" || c.ImageSku != "" + + countSourceInputs := toInt(isImageUrl) + toInt(isCustomManagedImage) + toInt(isPlatformImage) + + if countSourceInputs > 1 { errs = packer.MultiErrorAppend(errs, fmt.Errorf("Specify either a VHD (image_url), Image Reference (image_publisher, image_offer, image_sku) or a Managed Disk (custom_managed_disk_image_name, custom_managed_disk_resource_group_name")) } @@ -541,12 +563,23 @@ func assertRequiredParametersSet(c *Config, errs *packer.MultiError) { ///////////////////////////////////////////// // Deployment - if c.StorageAccount == "" { - errs = packer.MultiErrorAppend(errs, fmt.Errorf("A storage_account must be specified")) + xor := func(a, b bool) bool { + return (a || b) && !(a && b) } - if c.ResourceGroupName == "" { - errs = packer.MultiErrorAppend(errs, fmt.Errorf("A resource_group_name must be specified")) + + if !xor((c.StorageAccount != "" || c.ResourceGroupName != ""), (c.ManagedImageName != "" || c.ManagedImageResourceGroupName != "")) { + errs = packer.MultiErrorAppend(errs, fmt.Errorf("Specify either a VHD (storage_account and resource_group_name) or Managed Image (managed_image_resource_group_name and managed_image_name) output")) } + + if c.ManagedImageName == "" && c.ManagedImageResourceGroupName == "" { + if c.StorageAccount == "" { + errs = packer.MultiErrorAppend(errs, fmt.Errorf("A storage_account must be specified")) + } + if c.ResourceGroupName == "" { + errs = packer.MultiErrorAppend(errs, fmt.Errorf("A resource_group_name must be specified")) + } + } + if c.VirtualNetworkName == "" && c.VirtualNetworkResourceGroupName != "" { errs = packer.MultiErrorAppend(errs, fmt.Errorf("If virtual_network_resource_group_name is specified, so must virtual_network_name")) } diff --git a/builder/azure/arm/config_test.go b/builder/azure/arm/config_test.go index 1d859d014..835454718 100644 --- a/builder/azure/arm/config_test.go +++ b/builder/azure/arm/config_test.go @@ -737,6 +737,95 @@ func TestConfigShouldRejectMissingCustomDataFile(t *testing.T) { } } +func TestConfigShouldAcceptPlatformManagedImageBuild(t *testing.T) { + config := map[string]interface{}{ + "image_offer": "ignore", + "image_publisher": "ignore", + "image_sku": "ignore", + "location": "ignore", + "subscription_id": "ignore", + "communicator": "none", + "managed_image_resource_group_name": "ignore", + "managed_image_name": "ignore", + + // Does not matter for this test case, just pick one. + "os_type": constants.Target_Linux, + } + + _, _, err := newConfig(config, getPackerConfiguration()) + if err != nil { + t.Fatal("expected config to accept platform managed image build") + } +} + +// If the user specified a build for a VHD and a Managed Image it should be rejected. +func TestConfigShouldRejectVhdAndManagedImageOutput(t *testing.T) { + config := map[string]interface{}{ + "image_offer": "ignore", + "image_publisher": "ignore", + "image_sku": "ignore", + "location": "ignore", + "subscription_id": "ignore", + "communicator": "none", + "capture_container_name": "ignore", + "capture_name_prefix": "ignore", + "managed_image_resource_group_name": "ignore", + "managed_image_name": "ignore", + + // Does not matter for this test case, just pick one. + "os_type": constants.Target_Linux, + } + + _, _, err := newConfig(config, getPackerConfiguration()) + if err == nil { + t.Fatal("expected config to reject VHD and Managed Image build") + } +} + +func TestConfigShouldRejectCustomAndPlatformManagedImageBuild(t *testing.T) { + config := map[string]interface{}{ + "custom_managed_image_resource_group_name": "ignore", + "custom_managed_image_name": "ignore", + "image_offer": "ignore", + "image_publisher": "ignore", + "image_sku": "ignore", + "location": "ignore", + "subscription_id": "ignore", + "communicator": "none", + "managed_image_resource_group_name": "ignore", + "managed_image_name": "ignore", + + // Does not matter for this test case, just pick one. + "os_type": constants.Target_Linux, + } + + _, _, err := newConfig(config, getPackerConfiguration()) + if err == nil { + t.Fatal("expected config to reject custom and platform input for a managed image build") + } +} + +func TestConfigShouldRejectCustomAndImageUrlForManagedImageBuild(t *testing.T) { + config := map[string]interface{}{ + "image_url": "ignore", + "custom_managed_image_resource_group_name": "ignore", + "custom_managed_image_name": "ignore", + "location": "ignore", + "subscription_id": "ignore", + "communicator": "none", + "managed_image_resource_group_name": "ignore", + "managed_image_name": "ignore", + + // Does not matter for this test case, just pick one. + "os_type": constants.Target_Linux, + } + + _, _, err := newConfig(config, getPackerConfiguration()) + if err == nil { + t.Fatal("expected config to reject custom and platform input for a managed image build") + } +} + func getArmBuilderConfiguration() map[string]string { m := make(map[string]string) for _, v := range requiredConfigValues { diff --git a/builder/azure/arm/template_factory_test.go b/builder/azure/arm/template_factory_test.go index 0301b1012..8a6e0c650 100644 --- a/builder/azure/arm/template_factory_test.go +++ b/builder/azure/arm/template_factory_test.go @@ -261,11 +261,7 @@ growpart: // Ensure the VM template is correct when building from a custom managed image. func TestVirtualMachineDeployment08(t *testing.T) { config := map[string]interface{}{ - "capture_name_prefix": "ignore", - "capture_container_name": "ignore", "location": "ignore", - "resource_group_name": "ignore", - "storage_account": "ignore", "subscription_id": "ignore", "os_type": constants.Target_Linux, "communicator": "none", @@ -294,11 +290,7 @@ func TestVirtualMachineDeployment08(t *testing.T) { // Ensure the VM template is correct when building from a platform managed image. func TestVirtualMachineDeployment09(t *testing.T) { config := map[string]interface{}{ - "capture_name_prefix": "ignore", - "capture_container_name": "ignore", "location": "ignore", - "resource_group_name": "ignore", - "storage_account": "ignore", "subscription_id": "ignore", "os_type": constants.Target_Linux, "communicator": "none", diff --git a/examples/azure/centos.json b/examples/azure/centos.json index 26538467f..1b0e7a633 100644 --- a/examples/azure/centos.json +++ b/examples/azure/centos.json @@ -28,12 +28,12 @@ "os_type": "Linux", "image_publisher": "OpenLogic", "image_offer": "CentOS", - "image_sku": "7.2", + "image_sku": "7.3", "image_version": "latest", "ssh_pty": "true", "location": "South Central US", - "vm_size": "Standard_A2" + "vm_size": "Standard_DS2_v2" }], "provisioners": [{ "execute_command": "echo '{{user `ssh_pass`}}' | {{ .Vars }} sudo -S -E sh '{{ .Path }}'", diff --git a/examples/azure/debian.json b/examples/azure/debian.json index 3e313a48f..112ca4993 100644 --- a/examples/azure/debian.json +++ b/examples/azure/debian.json @@ -30,7 +30,7 @@ "ssh_pty": "true", "location": "South Central US", - "vm_size": "Standard_A2" + "vm_size": "Standard_DS2_v2" }], "provisioners": [{ "execute_command": "echo '{{user `ssh_pass`}}' | {{ .Vars }} sudo -S -E sh '{{ .Path }}'", diff --git a/examples/azure/linux_custom_image.json b/examples/azure/linux_custom_image.json index 4f4be6ca4..efbd3bef0 100644 --- a/examples/azure/linux_custom_image.json +++ b/examples/azure/linux_custom_image.json @@ -28,7 +28,7 @@ }, "location": "West US", - "vm_size": "Standard_A2" + "vm_size": "Standard_DS2_v2" } ], "provisioners": [{ diff --git a/examples/azure/linux_custom_managed_image.json b/examples/azure/linux_custom_managed_image.json index 62269b0ee..79dcc4d26 100644 --- a/examples/azure/linux_custom_managed_image.json +++ b/examples/azure/linux_custom_managed_image.json @@ -2,8 +2,6 @@ "variables": { "client_id": "{{env `ARM_CLIENT_ID`}}", "client_secret": "{{env `ARM_CLIENT_SECRET`}}", - "resource_group": "{{env `ARM_RESOURCE_GROUP`}}", - "storage_account": "{{env `ARM_STORAGE_ACCOUNT`}}", "subscription_id": "{{env `ARM_SUBSCRIPTION_ID`}}" }, "builders": [ @@ -12,13 +10,8 @@ "client_id": "{{user `client_id`}}", "client_secret": "{{user `client_secret`}}", - "resource_group_name": "{{user `resource_group`}}", - "storage_account": "{{user `storage_account`}}", "subscription_id": "{{user `subscription_id`}}", - "capture_container_name": "images", - "capture_name_prefix": "packer", - "os_type": "Linux", "custom_managed_image_resource_group_name": "MyResourceGroup", "custom_managed_image_name": "MyImage", @@ -31,7 +24,7 @@ }, "location": "West US", - "vm_size": "Standard_A2" + "vm_size": "Standard_DS2_v2" } ], "provisioners": [{ diff --git a/examples/azure/rhel.json b/examples/azure/rhel.json new file mode 100644 index 000000000..7c4160268 --- /dev/null +++ b/examples/azure/rhel.json @@ -0,0 +1,48 @@ +{ + "variables": { + "client_id": "{{env `ARM_CLIENT_ID`}}", + "client_secret": "{{env `ARM_CLIENT_SECRET`}}", + "resource_group": "{{env `ARM_RESOURCE_GROUP`}}", + "storage_account": "{{env `ARM_STORAGE_ACCOUNT`}}", + "subscription_id": "{{env `ARM_SUBSCRIPTION_ID`}}", + "tenant_id": "{{env `ARM_TENANT_ID`}}", + "ssh_user": "centos", + "ssh_pass": null + }, + "builders": [{ + "type": "azure-arm", + + "client_id": "{{user `client_id`}}", + "client_secret": "{{user `client_secret`}}", + "resource_group_name": "{{user `resource_group`}}", + "storage_account": "{{user `storage_account`}}", + "subscription_id": "{{user `subscription_id`}}", + "tenant_id": "{{user `tenant_id`}}", + + "capture_container_name": "images", + "capture_name_prefix": "packer", + + "ssh_username": "{{user `ssh_user`}}", + "ssh_password": "{{user `ssh_pass`}}", + + "os_type": "Linux", + "image_publisher": "RedHat", + "image_offer": "RHEL", + "image_sku": "7.3", + "image_version": "latest", + "ssh_pty": "true", + + "location": "South Central US", + "vm_size": "Standard_DS2_v2" + }], + "provisioners": [{ + "execute_command": "echo '{{user `ssh_pass`}}' | {{ .Vars }} sudo -S -E sh '{{ .Path }}'", + "inline": [ + "yum update -y", + "/usr/sbin/waagent -force -deprovision+user && export HISTSIZE=0 && sync" + ], + "inline_shebang": "/bin/sh -x", + "type": "shell", + "skip_clean": true + }] +} diff --git a/examples/azure/opensuse.json b/examples/azure/suse.json similarity index 93% rename from examples/azure/opensuse.json rename to examples/azure/suse.json index 2bb462191..c99b364ec 100644 --- a/examples/azure/opensuse.json +++ b/examples/azure/suse.json @@ -25,12 +25,12 @@ "os_type": "Linux", "image_publisher": "SUSE", - "image_offer": "openSUSE", - "image_sku": "13.2", + "image_offer": "SLES", + "image_sku": "12-SP2", "ssh_pty": "true", "location": "South Central US", - "vm_size": "Standard_A2" + "vm_size": "Standard_DS2_v2" }], "provisioners": [{ "execute_command": "echo '{{user `ssh_pass`}}' | {{ .Vars }} sudo -S -E sh '{{ .Path }}'", diff --git a/examples/azure/ubuntu.json b/examples/azure/ubuntu.json index e90ab8ede..a9c657d06 100644 --- a/examples/azure/ubuntu.json +++ b/examples/azure/ubuntu.json @@ -21,7 +21,7 @@ "os_type": "Linux", "image_publisher": "Canonical", "image_offer": "UbuntuServer", - "image_sku": "16.04.0-LTS", + "image_sku": "16.04-LTS", "azure_tags": { "dept": "engineering", @@ -29,7 +29,7 @@ }, "location": "West US", - "vm_size": "Standard_A2" + "vm_size": "Standard_DS2_v2" }], "provisioners": [{ "execute_command": "chmod +x {{ .Path }}; {{ .Vars }} sudo -E sh '{{ .Path }}'", diff --git a/examples/azure/ubuntu_managed_image.json b/examples/azure/ubuntu_managed_image.json index b8e480ba4..ddb4a49c9 100644 --- a/examples/azure/ubuntu_managed_image.json +++ b/examples/azure/ubuntu_managed_image.json @@ -2,8 +2,6 @@ "variables": { "client_id": "{{env `ARM_CLIENT_ID`}}", "client_secret": "{{env `ARM_CLIENT_SECRET`}}", - "resource_group": "{{env `ARM_RESOURCE_GROUP`}}", - "storage_account": "{{env `ARM_STORAGE_ACCOUNT`}}", "subscription_id": "{{env `ARM_SUBSCRIPTION_ID`}}" }, "builders": [{ @@ -11,13 +9,8 @@ "client_id": "{{user `client_id`}}", "client_secret": "{{user `client_secret`}}", - "resource_group_name": "{{user `resource_group`}}", - "storage_account": "{{user `storage_account`}}", "subscription_id": "{{user `subscription_id`}}", - "capture_container_name": "images", - "capture_name_prefix": "packer", - "os_type": "Linux", "image_publisher": "Canonical", "image_offer": "UbuntuServer", @@ -32,7 +25,7 @@ }, "location": "West US", - "vm_size": "Standard_A2" + "vm_size": "Standard_DS2_v2" }], "provisioners": [{ "execute_command": "chmod +x {{ .Path }}; {{ .Vars }} sudo -E sh '{{ .Path }}'", diff --git a/examples/azure/ubuntu_quickstart.json b/examples/azure/ubuntu_quickstart.json index 22bc210c6..15166d131 100644 --- a/examples/azure/ubuntu_quickstart.json +++ b/examples/azure/ubuntu_quickstart.json @@ -20,7 +20,7 @@ "image_sku": "16.04-LTS", "location": "West US", - "vm_size": "Standard_DS1_v2" + "vm_size": "Standard_DS2_v2" }], "provisioners": [{ "execute_command": "chmod +x {{ .Path }}; {{ .Vars }} sudo -E sh '{{ .Path }}'", diff --git a/examples/azure/windows.json b/examples/azure/windows.json index b96f06559..8493f82cb 100644 --- a/examples/azure/windows.json +++ b/examples/azure/windows.json @@ -32,7 +32,7 @@ "winrm_username": "packer", "location": "West US", - "vm_size": "Standard_A2" + "vm_size": "Standard_DS2_v2" }], "provisioners": [{ "type": "powershell", diff --git a/examples/azure/windows_custom_image.json b/examples/azure/windows_custom_image.json index f8d95136d..b411555a7 100644 --- a/examples/azure/windows_custom_image.json +++ b/examples/azure/windows_custom_image.json @@ -28,7 +28,7 @@ }, "location": "West US", - "vm_size": "Standard_A2" + "vm_size": "Standard_DS2_v2" } ], "provisioners": [{ diff --git a/website/source/docs/builders/azure.html.md b/website/source/docs/builders/azure.html.md index adb0a4a2b..750a2fe66 100644 --- a/website/source/docs/builders/azure.html.md +++ b/website/source/docs/builders/azure.html.md @@ -29,15 +29,8 @@ builder. - `client_secret` (string) The password or secret for your service principal. -- `resource_group_name` (string) Resource group under which the final artifact will be stored. - -- `storage_account` (string) Storage account under which the final artifact will be stored. - - `subscription_id` (string) Subscription under which the build will be performed. **The service principal specified in `client_id` must have full access to this subscription.** - -- `capture_container_name` (string) Destination container name. Essentially the "directory" where your VHD will be organized in Azure. The captured VHD's URL will be .blob.core.windows.net/system/Microsoft.Compute/Images//.xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx.vhd. - -- `capture_name_prefix` (string) VHD prefix. The final artifacts will be named `PREFIX-osDisk.UUID` and `PREFIX-vmTemplate.UUID`. +- `capture_container_name` (string) Destination container name. Essentially the "directory" where your VHD will be organized in Azure. The captured VHD's URL will be https://.blob.core.windows.net/system/Microsoft.Compute/Images//.xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx.vhd. - `image_publisher` (string) PublisherName for your base image. See [documentation](https://azure.microsoft.com/en-us/documentation/articles/resource-groups-vm-searching/) for details. @@ -54,6 +47,32 @@ builder. - `location` (string) Azure datacenter in which your VM will build. CLI example `azure location list` + +#### VHD or Managed Image + +The Azure builder can create either a VHD, or a managed image. When creating a VHD the following two options are required. + +- `capture_container_name` (string) Destination container name. Essentially the "directory" where your VHD will be + organized in Azure. The captured VHD's URL will be https://.blob.core.windows.net/system/Microsoft.Compute/Images//.xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx.vhd. + +- `capture_name_prefix` (string) VHD prefix. The final artifacts will be named `PREFIX-osDisk.UUID` and + `PREFIX-vmTemplate.UUID`. + +- `resource_group_name` (string) Resource group under which the final artifact will be stored. + +- `storage_account` (string) Storage account under which the final artifact will be stored. + +When creating a managed image the following two options are required. + +- `managed_image_name` (string) Specify the managed image name where the result of the Packer build will be saved. The + image name must not exist ahead of time, and will not be overwritten. If this value is set, the value + `managed_image_resource_group_name` must also be set. See [documentation](https://docs.microsoft.com/en-us/azure/storage/storage-managed-disks-overview#images) + to learn more about managed images. + +- `managed_image_resource_group_name` (string) Specify the managed image resource group name where the result of the Packer build will be + saved. The resource group must already exist. If this value is set, the value `managed_image_name` must also be + set. See [documentation](https://docs.microsoft.com/en-us/azure/storage/storage-managed-disks-overview#images) to + learn more about managed images. ### Optional: @@ -89,16 +108,7 @@ builder. - `image_url` (string) Specify a custom VHD to use. If this value is set, do not set image\_publisher, image\_offer, image\_sku, or image\_version. -- `managed_image_name` (string) Specify the managed image name where the result of the Packer build will be saved. The - image name must not exist ahead of time, and will not be overwritten. If this value is set, the value - `managed_image_resource_group_name` must also be set. See [documentation](https://docs.microsoft.com/en-us/azure/storage/storage-managed-disks-overview#images) - to learn more about managed images. - -- `managed_image_resource_group_name` (string) Specify the managed image resource group name where the result of the Packer build will be - saved. The resource group must already exist. If this value is set, the value `managed_image_name` must also be - set. See [documentation](https://docs.microsoft.com/en-us/azure/storage/storage-managed-disks-overview#images) to - learn more about managed images. - + - `object_id` (string) Specify an OAuth Object ID to protect WinRM certificates created at runtime. This variable is required when creating images based on Windows; this variable is not used by non-Windows builds. See `Windows`