From c262467413f05683a73d32e8498c1b4285137269 Mon Sep 17 00:00:00 2001 From: Wilken Rivera Date: Thu, 13 May 2021 16:13:21 -0400 Subject: [PATCH] Extract Azure plugin components from Packer (#10979) * Remove Azure plugin components and docs * Add Azure plugin to vendored_plugins * Updates Azure to use remote plugin docs * Revendor packer-plugin-azure at v0.0.2 * Update to new version of the Packer plugin SDK v0.2.1 * Update to the official version of go-getter@v2.0.0 * Update salt provisioner to use new go-getter API * Update vendored plugins to working versions This changes fixes an issue with the go.sum for the Azure plugin. It also revendors the plugins for puppet, chef, and ansible as v0.0.1 of those plugins where not usable. --- builder/azure/LICENSE | 21 - builder/azure/TODO.md | 16 - ...estVirtualMachineDeployment05.approved.txt | 118 - builder/azure/arm/artifact.go | 261 -- builder/azure/arm/artifact_test.go | 521 ---- builder/azure/arm/azure_client.go | 311 --- builder/azure/arm/azure_error_response.go | 67 - ...tAzureErrorNestedShouldFormat.approved.txt | 4 - ...tAzureErrorSimpleShouldFormat.approved.txt | 1 - .../azure/arm/azure_error_response_test.go | 77 - builder/azure/arm/builder.go | 496 ---- builder/azure/arm/builder_acc_test.go | 513 ---- builder/azure/arm/builder_test.go | 67 - builder/azure/arm/capture_template.go | 84 - builder/azure/arm/capture_template_test.go | 272 -- builder/azure/arm/config.go | 1252 ---------- builder/azure/arm/config.hcl2spec.go | 361 --- builder/azure/arm/config_test.go | 2188 ----------------- builder/azure/arm/inspector.go | 71 - builder/azure/arm/openssh_key_pair.go | 59 - builder/azure/arm/openssh_key_pair_test.go | 37 - builder/azure/arm/resource_resolver.go | 141 -- builder/azure/arm/resource_resolver_test.go | 79 - builder/azure/arm/step.go | 20 - builder/azure/arm/step_capture_image.go | 120 - builder/azure/arm/step_capture_image_test.go | 137 -- .../azure/arm/step_certificate_in_keyvault.go | 45 - .../arm/step_certificate_in_keyvault_test.go | 66 - .../azure/arm/step_create_resource_group.go | 146 -- .../arm/step_create_resource_group_test.go | 251 -- .../azure/arm/step_delete_additional_disks.go | 118 - .../arm/step_delete_additional_disks_test.go | 227 -- builder/azure/arm/step_deploy_template.go | 306 --- .../azure/arm/step_deploy_template_test.go | 209 -- .../azure/arm/step_get_additional_disks.go | 78 - .../arm/step_get_additional_disks_test.go | 131 - builder/azure/arm/step_get_certificate.go | 77 - .../azure/arm/step_get_certificate_test.go | 99 - builder/azure/arm/step_get_ip_address.go | 107 - builder/azure/arm/step_get_ip_address_test.go | 124 - builder/azure/arm/step_get_os_disk.go | 72 - builder/azure/arm/step_get_os_disk_test.go | 123 - builder/azure/arm/step_power_off_compute.go | 56 - .../azure/arm/step_power_off_compute_test.go | 91 - .../step_publish_to_shared_image_gallery.go | 192 -- ...ep_publish_to_shared_image_gallery_test.go | 86 - builder/azure/arm/step_set_certificate.go | 37 - .../azure/arm/step_set_certificate_test.go | 54 - builder/azure/arm/step_snapshot_data_disks.go | 108 - .../arm/step_snapshot_data_disks_test.go | 88 - builder/azure/arm/step_snapshot_os_disk.go | 99 - .../azure/arm/step_snapshot_os_disk_test.go | 89 - builder/azure/arm/step_test.go | 40 - builder/azure/arm/step_validate_template.go | 61 - .../azure/arm/step_validate_template_test.go | 91 - builder/azure/arm/template_factory.go | 213 -- ...est.TestKeyVaultDeployment03.approved.json | 76 - ..._factory_test.TestPlanInfo01.approved.json | 211 -- ..._factory_test.TestPlanInfo02.approved.json | 216 -- ...stVirtualMachineDeployment03.approved.json | 182 -- ...stVirtualMachineDeployment04.approved.json | 180 -- ...stVirtualMachineDeployment05.approved.json | 141 -- ...stVirtualMachineDeployment06.approved.json | 200 -- ...stVirtualMachineDeployment07.approved.json | 181 -- ...stVirtualMachineDeployment08.approved.json | 180 -- ...stVirtualMachineDeployment09.approved.json | 183 -- ...stVirtualMachineDeployment10.approved.json | 161 -- ...stVirtualMachineDeployment11.approved.json | 194 -- ...stVirtualMachineDeployment12.approved.json | 195 -- ...stVirtualMachineDeployment13.approved.json | 230 -- ...stVirtualMachineDeployment14.approved.json | 181 -- builder/azure/arm/template_factory_test.go | 659 ----- builder/azure/arm/tempname.go | 80 - builder/azure/arm/tempname_test.go | 143 -- builder/azure/chroot/builder.go | 622 ----- builder/azure/chroot/builder.hcl2spec.go | 111 - builder/azure/chroot/builder_test.go | 234 -- builder/azure/chroot/const.go | 6 - builder/azure/chroot/diskattacher.go | 190 -- builder/azure/chroot/diskattacher_freebsd.go | 54 - builder/azure/chroot/diskattacher_linux.go | 36 - builder/azure/chroot/diskattacher_other.go | 11 - builder/azure/chroot/diskattacher_test.go | 87 - builder/azure/chroot/diskset.go | 23 - builder/azure/chroot/diskset_test.go | 16 - builder/azure/chroot/metadatastub_test.go | 18 - builder/azure/chroot/packerui_test.go | 19 - .../shared_image_gallery_destination.go | 71 - ...ared_image_gallery_destination.hcl2spec.go | 70 - .../shared_image_gallery_destination_test.go | 158 -- builder/azure/chroot/step_attach_disk.go | 85 - builder/azure/chroot/step_attach_disk_test.go | 131 - builder/azure/chroot/step_create_image.go | 112 - .../azure/chroot/step_create_image_test.go | 137 -- .../azure/chroot/step_create_new_diskset.go | 239 -- .../chroot/step_create_new_diskset_test.go | 247 -- .../step_create_shared_image_version.go | 108 - .../step_create_shared_image_version_test.go | 144 -- .../azure/chroot/step_create_snapshotset.go | 126 - .../chroot/step_create_snapshotset_test.go | 230 -- builder/azure/chroot/step_mount_device.go | 140 -- .../azure/chroot/step_mount_device_test.go | 72 - .../step_resolve_plaform_image_version.go | 45 - ...step_resolve_plaform_image_version_test.go | 62 - .../step_verify_shared_image_destination.go | 119 - ...ep_verify_shared_image_destination_test.go | 186 -- .../chroot/step_verify_shared_image_source.go | 126 - .../step_verify_shared_image_source_test.go | 188 -- .../azure/chroot/step_verify_source_disk.go | 80 - .../chroot/step_verify_source_disk_test.go | 157 -- builder/azure/chroot/template_funcs.go | 37 - builder/azure/common/artifact.go | 104 - builder/azure/common/artifact_test.go | 21 - .../azure/common/client/azure_client_set.go | 138 -- .../common/client/azure_client_set_mock.go | 72 - builder/azure/common/client/config.go | 352 --- .../azure/common/client/config_retriever.go | 37 - .../common/client/config_retriever_test.go | 56 - builder/azure/common/client/config_test.go | 444 ---- builder/azure/common/client/detect_azure.go | 8 - .../azure/common/client/detect_azure_linux.go | 23 - .../common/client/detect_azure_linux_test.go | 29 - builder/azure/common/client/devicelogin.go | 208 -- builder/azure/common/client/metadata.go | 94 - builder/azure/common/client/metadata_test.go | 32 - .../azure/common/client/normalize_location.go | 9 - .../common/client/normalize_location_test.go | 22 - builder/azure/common/client/platform_image.go | 58 - .../common/client/platform_image_test.go | 30 - builder/azure/common/client/resource.go | 125 - builder/azure/common/client/resource_test.go | 188 -- builder/azure/common/client/testclient.go | 30 - builder/azure/common/client/tokenprovider.go | 10 - .../azure/common/client/tokenprovider_cert.go | 165 -- .../azure/common/client/tokenprovider_cli.go | 99 - .../client/tokenprovider_devicewflow.go | 39 - .../azure/common/client/tokenprovider_jwt.go | 43 - .../azure/common/client/tokenprovider_msi.go | 23 - .../common/client/tokenprovider_secret.go | 35 - .../client/tokenprovider_secret_test.go | 40 - builder/azure/common/constants/stateBag.go | 58 - .../azure/common/constants/targetplatforms.go | 7 - builder/azure/common/dump_config.go | 70 - builder/azure/common/dump_config_test.go | 127 - builder/azure/common/gluestrings.go | 19 - builder/azure/common/gluestrings_test.go | 30 - builder/azure/common/lin/ssh.go | 11 - builder/azure/common/logutil/logfields.go | 16 - builder/azure/common/map.go | 10 - builder/azure/common/state_bag.go | 8 - builder/azure/common/strings_contains.go | 13 - builder/azure/common/strings_contains_test.go | 39 - .../template/TestBuildLinux02.approved.txt | 120 - builder/azure/common/template/template.go | 124 - .../azure/common/template/template_builder.go | 756 ------ ...uilder_test.TestBuildLinux00.approved.json | 182 -- ...uilder_test.TestBuildLinux01.approved.json | 180 -- ...uilder_test.TestBuildLinux02.approved.json | 142 -- ...lder_test.TestBuildWindows00.approved.json | 196 -- ...lder_test.TestBuildWindows01.approved.json | 219 -- ...lder_test.TestBuildWindows02.approved.json | 212 -- ...t.TestNetworkSecurityGroup00.approved.json | 215 -- ...ilder_test.TestSetIdentity00.approved.json | 188 -- ...est.TestSharedImageGallery00.approved.json | 177 -- .../common/template/template_builder_test.go | 283 --- .../common/template/template_parameters.go | 39 - .../template/template_parameters_test.go | 112 - builder/azure/common/template_funcs.go | 40 - builder/azure/common/template_funcs_test.go | 49 - builder/azure/common/vault.go | 138 -- builder/azure/common/vault_client_mock.go | 56 - builder/azure/common/vault_test.go | 26 - ...estVirtualMachineDeployment05.approved.txt | 118 - builder/azure/dtl/WindowsMixAndMatch.json | 65 - builder/azure/dtl/WindowsSimple.json | 37 - builder/azure/dtl/acceptancetest.json | 72 - builder/azure/dtl/artifact.go | 199 -- builder/azure/dtl/azure_client.go | 211 -- builder/azure/dtl/azure_error_response.go | 63 - ...tAzureErrorNestedShouldFormat.approved.txt | 4 - ...tAzureErrorSimpleShouldFormat.approved.txt | 1 - .../azure/dtl/azure_error_response_test.go | 77 - builder/azure/dtl/builder.go | 367 --- builder/azure/dtl/builder_acc_test.go | 142 -- builder/azure/dtl/builder_test.go | 33 - builder/azure/dtl/capture_template.go | 84 - builder/azure/dtl/capture_template_test.go | 272 -- builder/azure/dtl/config.go | 767 ------ builder/azure/dtl/config.hcl2spec.go | 349 --- builder/azure/dtl/config_test.go | 543 ---- builder/azure/dtl/inspector.go | 71 - builder/azure/dtl/openssh_key_pair.go | 59 - builder/azure/dtl/openssh_key_pair_test.go | 37 - builder/azure/dtl/resource_resolver.go | 141 -- builder/azure/dtl/step.go | 20 - builder/azure/dtl/step_capture_image.go | 125 - .../azure/dtl/step_delete_virtual_machine.go | 61 - builder/azure/dtl/step_deploy_template.go | 192 -- builder/azure/dtl/step_power_off_compute.go | 61 - .../step_publish_to_shared_image_gallery.go | 126 - builder/azure/dtl/step_save_winrm_password.go | 22 - builder/azure/dtl/step_test.go | 40 - builder/azure/dtl/template_factory.go | 136 - builder/azure/dtl/template_funcs.go | 46 - builder/azure/dtl/template_funcs_test.go | 49 - builder/azure/dtl/tempname.go | 74 - builder/azure/examples/centos.json | 44 - builder/azure/examples/debian-chroot.json | 27 - builder/azure/examples/debian.json | 45 - builder/azure/examples/freebsd-chroot.json | 26 - builder/azure/examples/freebsd.json | 43 - .../azure/examples/linux_custom_image.json | 44 - .../examples/linux_custom_managed_image.json | 40 - .../azure/examples/marketplace_plan_info.json | 47 - builder/azure/examples/rhel.json | 45 - builder/azure/examples/suse.json | 42 - builder/azure/examples/ubuntu-chroot.json | 41 - builder/azure/examples/ubuntu.json | 41 - .../examples/ubuntu_managed_image_sig.json | 46 - builder/azure/examples/ubuntu_quickstart.json | 35 - builder/azure/examples/windows.json | 45 - .../azure/examples/windows_custom_image.json | 49 - .../azure/examples/windows_quickstart.json | 41 - builder/azure/pkcs12/LICENSE | 27 - builder/azure/pkcs12/bmp-string.go | 50 - builder/azure/pkcs12/bmp-string_test.go | 69 - builder/azure/pkcs12/crypto.go | 167 -- builder/azure/pkcs12/crypto_test.go | 168 -- builder/azure/pkcs12/errors.go | 28 - builder/azure/pkcs12/mac.go | 50 - builder/azure/pkcs12/mac_test.go | 42 - builder/azure/pkcs12/pbkdf.go | 170 -- builder/azure/pkcs12/pbkdf_test.go | 34 - builder/azure/pkcs12/pkcs12.go | 530 ---- builder/azure/pkcs12/pkcs12_test.go | 247 -- builder/azure/pkcs12/pkcs8.go | 67 - builder/azure/pkcs12/pkcs8_test.go | 141 -- builder/azure/pkcs12/rc2/bench_test.go | 27 - builder/azure/pkcs12/rc2/rc2.go | 274 --- builder/azure/pkcs12/rc2/rc2_test.go | 93 - builder/azure/pkcs12/safebags.go | 105 - builder/azure/pkcs12/safebags_test.go | 78 - builder/azure/version/version.go | 13 - command/plugin.go | 28 +- command/vendored_plugins.go | 8 + contrib/azure-setup.sh | 268 -- go.mod | 25 +- go.sum | 74 +- provisioner/azure-dtlartifact/provisioner.go | 183 -- .../azure-dtlartifact/provisioner.hcl2spec.go | 133 - .../azure-dtlartifact/version/version.go | 13 - provisioner/salt-masterless/provisioner.go | 2 +- website/content/docs/builders/azure/arm.mdx | 496 ---- .../content/docs/builders/azure/chroot.mdx | 295 --- website/content/docs/builders/azure/index.mdx | 117 - .../builder/azure/arm/Config-not-required.mdx | 309 --- .../builder/azure/arm/Config-required.mdx | 40 - .../arm/PlanInformation-not-required.mdx | 11 - .../arm/SharedImageGallery-not-required.mdx | 17 - ...edImageGalleryDestination-not-required.mdx | 18 - .../azure/chroot/Config-not-required.mdx | 66 - .../builder/azure/chroot/Config-required.mdx | 8 - .../partials/builder/azure/chroot/Config.mdx | 6 - ...edImageGalleryDestination-not-required.mdx | 7 - ...SharedImageGalleryDestination-required.mdx | 11 - .../chroot/SharedImageGalleryDestination.mdx | 6 - .../chroot/TargetRegion-not-required.mdx | 7 - .../azure/chroot/TargetRegion-required.mdx | 5 - .../builder/azure/chroot/TargetRegion.mdx | 5 - .../common/client/Config-not-required.mdx | 36 - .../builder/azure/common/client/Config.mdx | 12 - .../dtl/ArtifactParameter-not-required.mdx | 9 - .../builder/azure/dtl/Config-not-required.mdx | 169 -- .../azure/dtl/DtlArtifact-not-required.mdx | 11 - .../dtl/SharedImageGallery-not-required.mdx | 13 - ...edImageGalleryDestination-not-required.mdx | 13 - website/data/docs-nav-data.json | 17 - website/data/docs-remote-plugins.json | 6 + 278 files changed, 84 insertions(+), 35369 deletions(-) delete mode 100644 builder/azure/LICENSE delete mode 100644 builder/azure/TODO.md delete mode 100644 builder/azure/arm/TestVirtualMachineDeployment05.approved.txt delete mode 100644 builder/azure/arm/artifact.go delete mode 100644 builder/azure/arm/artifact_test.go delete mode 100644 builder/azure/arm/azure_client.go delete mode 100644 builder/azure/arm/azure_error_response.go delete mode 100644 builder/azure/arm/azure_error_response_test.TestAzureErrorNestedShouldFormat.approved.txt delete mode 100644 builder/azure/arm/azure_error_response_test.TestAzureErrorSimpleShouldFormat.approved.txt delete mode 100644 builder/azure/arm/azure_error_response_test.go delete mode 100644 builder/azure/arm/builder.go delete mode 100644 builder/azure/arm/builder_acc_test.go delete mode 100644 builder/azure/arm/builder_test.go delete mode 100644 builder/azure/arm/capture_template.go delete mode 100644 builder/azure/arm/capture_template_test.go delete mode 100644 builder/azure/arm/config.go delete mode 100644 builder/azure/arm/config.hcl2spec.go delete mode 100644 builder/azure/arm/config_test.go delete mode 100644 builder/azure/arm/inspector.go delete mode 100644 builder/azure/arm/openssh_key_pair.go delete mode 100644 builder/azure/arm/openssh_key_pair_test.go delete mode 100644 builder/azure/arm/resource_resolver.go delete mode 100644 builder/azure/arm/resource_resolver_test.go delete mode 100644 builder/azure/arm/step.go delete mode 100644 builder/azure/arm/step_capture_image.go delete mode 100644 builder/azure/arm/step_capture_image_test.go delete mode 100644 builder/azure/arm/step_certificate_in_keyvault.go delete mode 100644 builder/azure/arm/step_certificate_in_keyvault_test.go delete mode 100644 builder/azure/arm/step_create_resource_group.go delete mode 100644 builder/azure/arm/step_create_resource_group_test.go delete mode 100644 builder/azure/arm/step_delete_additional_disks.go delete mode 100644 builder/azure/arm/step_delete_additional_disks_test.go delete mode 100644 builder/azure/arm/step_deploy_template.go delete mode 100644 builder/azure/arm/step_deploy_template_test.go delete mode 100644 builder/azure/arm/step_get_additional_disks.go delete mode 100644 builder/azure/arm/step_get_additional_disks_test.go delete mode 100644 builder/azure/arm/step_get_certificate.go delete mode 100644 builder/azure/arm/step_get_certificate_test.go delete mode 100644 builder/azure/arm/step_get_ip_address.go delete mode 100644 builder/azure/arm/step_get_ip_address_test.go delete mode 100644 builder/azure/arm/step_get_os_disk.go delete mode 100644 builder/azure/arm/step_get_os_disk_test.go delete mode 100644 builder/azure/arm/step_power_off_compute.go delete mode 100644 builder/azure/arm/step_power_off_compute_test.go delete mode 100644 builder/azure/arm/step_publish_to_shared_image_gallery.go delete mode 100644 builder/azure/arm/step_publish_to_shared_image_gallery_test.go delete mode 100644 builder/azure/arm/step_set_certificate.go delete mode 100644 builder/azure/arm/step_set_certificate_test.go delete mode 100644 builder/azure/arm/step_snapshot_data_disks.go delete mode 100644 builder/azure/arm/step_snapshot_data_disks_test.go delete mode 100644 builder/azure/arm/step_snapshot_os_disk.go delete mode 100644 builder/azure/arm/step_snapshot_os_disk_test.go delete mode 100644 builder/azure/arm/step_test.go delete mode 100644 builder/azure/arm/step_validate_template.go delete mode 100644 builder/azure/arm/step_validate_template_test.go delete mode 100644 builder/azure/arm/template_factory.go delete mode 100644 builder/azure/arm/template_factory_test.TestKeyVaultDeployment03.approved.json delete mode 100644 builder/azure/arm/template_factory_test.TestPlanInfo01.approved.json delete mode 100644 builder/azure/arm/template_factory_test.TestPlanInfo02.approved.json delete mode 100644 builder/azure/arm/template_factory_test.TestVirtualMachineDeployment03.approved.json delete mode 100644 builder/azure/arm/template_factory_test.TestVirtualMachineDeployment04.approved.json delete mode 100644 builder/azure/arm/template_factory_test.TestVirtualMachineDeployment05.approved.json delete mode 100644 builder/azure/arm/template_factory_test.TestVirtualMachineDeployment06.approved.json delete mode 100644 builder/azure/arm/template_factory_test.TestVirtualMachineDeployment07.approved.json delete mode 100644 builder/azure/arm/template_factory_test.TestVirtualMachineDeployment08.approved.json delete mode 100644 builder/azure/arm/template_factory_test.TestVirtualMachineDeployment09.approved.json delete mode 100644 builder/azure/arm/template_factory_test.TestVirtualMachineDeployment10.approved.json delete mode 100644 builder/azure/arm/template_factory_test.TestVirtualMachineDeployment11.approved.json delete mode 100644 builder/azure/arm/template_factory_test.TestVirtualMachineDeployment12.approved.json delete mode 100644 builder/azure/arm/template_factory_test.TestVirtualMachineDeployment13.approved.json delete mode 100644 builder/azure/arm/template_factory_test.TestVirtualMachineDeployment14.approved.json delete mode 100644 builder/azure/arm/template_factory_test.go delete mode 100644 builder/azure/arm/tempname.go delete mode 100644 builder/azure/arm/tempname_test.go delete mode 100644 builder/azure/chroot/builder.go delete mode 100644 builder/azure/chroot/builder.hcl2spec.go delete mode 100644 builder/azure/chroot/builder_test.go delete mode 100644 builder/azure/chroot/const.go delete mode 100644 builder/azure/chroot/diskattacher.go delete mode 100644 builder/azure/chroot/diskattacher_freebsd.go delete mode 100644 builder/azure/chroot/diskattacher_linux.go delete mode 100644 builder/azure/chroot/diskattacher_other.go delete mode 100644 builder/azure/chroot/diskattacher_test.go delete mode 100644 builder/azure/chroot/diskset.go delete mode 100644 builder/azure/chroot/diskset_test.go delete mode 100644 builder/azure/chroot/metadatastub_test.go delete mode 100644 builder/azure/chroot/packerui_test.go delete mode 100644 builder/azure/chroot/shared_image_gallery_destination.go delete mode 100644 builder/azure/chroot/shared_image_gallery_destination.hcl2spec.go delete mode 100644 builder/azure/chroot/shared_image_gallery_destination_test.go delete mode 100644 builder/azure/chroot/step_attach_disk.go delete mode 100644 builder/azure/chroot/step_attach_disk_test.go delete mode 100644 builder/azure/chroot/step_create_image.go delete mode 100644 builder/azure/chroot/step_create_image_test.go delete mode 100644 builder/azure/chroot/step_create_new_diskset.go delete mode 100644 builder/azure/chroot/step_create_new_diskset_test.go delete mode 100644 builder/azure/chroot/step_create_shared_image_version.go delete mode 100644 builder/azure/chroot/step_create_shared_image_version_test.go delete mode 100644 builder/azure/chroot/step_create_snapshotset.go delete mode 100644 builder/azure/chroot/step_create_snapshotset_test.go delete mode 100644 builder/azure/chroot/step_mount_device.go delete mode 100644 builder/azure/chroot/step_mount_device_test.go delete mode 100644 builder/azure/chroot/step_resolve_plaform_image_version.go delete mode 100644 builder/azure/chroot/step_resolve_plaform_image_version_test.go delete mode 100644 builder/azure/chroot/step_verify_shared_image_destination.go delete mode 100644 builder/azure/chroot/step_verify_shared_image_destination_test.go delete mode 100644 builder/azure/chroot/step_verify_shared_image_source.go delete mode 100644 builder/azure/chroot/step_verify_shared_image_source_test.go delete mode 100644 builder/azure/chroot/step_verify_source_disk.go delete mode 100644 builder/azure/chroot/step_verify_source_disk_test.go delete mode 100644 builder/azure/chroot/template_funcs.go delete mode 100644 builder/azure/common/artifact.go delete mode 100644 builder/azure/common/artifact_test.go delete mode 100644 builder/azure/common/client/azure_client_set.go delete mode 100644 builder/azure/common/client/azure_client_set_mock.go delete mode 100644 builder/azure/common/client/config.go delete mode 100644 builder/azure/common/client/config_retriever.go delete mode 100644 builder/azure/common/client/config_retriever_test.go delete mode 100644 builder/azure/common/client/config_test.go delete mode 100644 builder/azure/common/client/detect_azure.go delete mode 100644 builder/azure/common/client/detect_azure_linux.go delete mode 100644 builder/azure/common/client/detect_azure_linux_test.go delete mode 100644 builder/azure/common/client/devicelogin.go delete mode 100644 builder/azure/common/client/metadata.go delete mode 100644 builder/azure/common/client/metadata_test.go delete mode 100644 builder/azure/common/client/normalize_location.go delete mode 100644 builder/azure/common/client/normalize_location_test.go delete mode 100644 builder/azure/common/client/platform_image.go delete mode 100644 builder/azure/common/client/platform_image_test.go delete mode 100644 builder/azure/common/client/resource.go delete mode 100644 builder/azure/common/client/resource_test.go delete mode 100644 builder/azure/common/client/testclient.go delete mode 100644 builder/azure/common/client/tokenprovider.go delete mode 100644 builder/azure/common/client/tokenprovider_cert.go delete mode 100644 builder/azure/common/client/tokenprovider_cli.go delete mode 100644 builder/azure/common/client/tokenprovider_devicewflow.go delete mode 100644 builder/azure/common/client/tokenprovider_jwt.go delete mode 100644 builder/azure/common/client/tokenprovider_msi.go delete mode 100644 builder/azure/common/client/tokenprovider_secret.go delete mode 100644 builder/azure/common/client/tokenprovider_secret_test.go delete mode 100644 builder/azure/common/constants/stateBag.go delete mode 100644 builder/azure/common/constants/targetplatforms.go delete mode 100644 builder/azure/common/dump_config.go delete mode 100644 builder/azure/common/dump_config_test.go delete mode 100644 builder/azure/common/gluestrings.go delete mode 100644 builder/azure/common/gluestrings_test.go delete mode 100644 builder/azure/common/lin/ssh.go delete mode 100644 builder/azure/common/logutil/logfields.go delete mode 100644 builder/azure/common/map.go delete mode 100644 builder/azure/common/state_bag.go delete mode 100644 builder/azure/common/strings_contains.go delete mode 100644 builder/azure/common/strings_contains_test.go delete mode 100644 builder/azure/common/template/TestBuildLinux02.approved.txt delete mode 100644 builder/azure/common/template/template.go delete mode 100644 builder/azure/common/template/template_builder.go delete mode 100644 builder/azure/common/template/template_builder_test.TestBuildLinux00.approved.json delete mode 100644 builder/azure/common/template/template_builder_test.TestBuildLinux01.approved.json delete mode 100644 builder/azure/common/template/template_builder_test.TestBuildLinux02.approved.json delete mode 100644 builder/azure/common/template/template_builder_test.TestBuildWindows00.approved.json delete mode 100644 builder/azure/common/template/template_builder_test.TestBuildWindows01.approved.json delete mode 100644 builder/azure/common/template/template_builder_test.TestBuildWindows02.approved.json delete mode 100644 builder/azure/common/template/template_builder_test.TestNetworkSecurityGroup00.approved.json delete mode 100644 builder/azure/common/template/template_builder_test.TestSetIdentity00.approved.json delete mode 100644 builder/azure/common/template/template_builder_test.TestSharedImageGallery00.approved.json delete mode 100644 builder/azure/common/template/template_builder_test.go delete mode 100644 builder/azure/common/template/template_parameters.go delete mode 100644 builder/azure/common/template/template_parameters_test.go delete mode 100644 builder/azure/common/template_funcs.go delete mode 100644 builder/azure/common/template_funcs_test.go delete mode 100644 builder/azure/common/vault.go delete mode 100644 builder/azure/common/vault_client_mock.go delete mode 100644 builder/azure/common/vault_test.go delete mode 100644 builder/azure/dtl/TestVirtualMachineDeployment05.approved.txt delete mode 100644 builder/azure/dtl/WindowsMixAndMatch.json delete mode 100644 builder/azure/dtl/WindowsSimple.json delete mode 100644 builder/azure/dtl/acceptancetest.json delete mode 100644 builder/azure/dtl/artifact.go delete mode 100644 builder/azure/dtl/azure_client.go delete mode 100644 builder/azure/dtl/azure_error_response.go delete mode 100644 builder/azure/dtl/azure_error_response_test.TestAzureErrorNestedShouldFormat.approved.txt delete mode 100644 builder/azure/dtl/azure_error_response_test.TestAzureErrorSimpleShouldFormat.approved.txt delete mode 100644 builder/azure/dtl/azure_error_response_test.go delete mode 100644 builder/azure/dtl/builder.go delete mode 100644 builder/azure/dtl/builder_acc_test.go delete mode 100644 builder/azure/dtl/builder_test.go delete mode 100644 builder/azure/dtl/capture_template.go delete mode 100644 builder/azure/dtl/capture_template_test.go delete mode 100644 builder/azure/dtl/config.go delete mode 100644 builder/azure/dtl/config.hcl2spec.go delete mode 100644 builder/azure/dtl/config_test.go delete mode 100644 builder/azure/dtl/inspector.go delete mode 100644 builder/azure/dtl/openssh_key_pair.go delete mode 100644 builder/azure/dtl/openssh_key_pair_test.go delete mode 100644 builder/azure/dtl/resource_resolver.go delete mode 100644 builder/azure/dtl/step.go delete mode 100644 builder/azure/dtl/step_capture_image.go delete mode 100644 builder/azure/dtl/step_delete_virtual_machine.go delete mode 100644 builder/azure/dtl/step_deploy_template.go delete mode 100644 builder/azure/dtl/step_power_off_compute.go delete mode 100644 builder/azure/dtl/step_publish_to_shared_image_gallery.go delete mode 100644 builder/azure/dtl/step_save_winrm_password.go delete mode 100644 builder/azure/dtl/step_test.go delete mode 100644 builder/azure/dtl/template_factory.go delete mode 100644 builder/azure/dtl/template_funcs.go delete mode 100644 builder/azure/dtl/template_funcs_test.go delete mode 100644 builder/azure/dtl/tempname.go delete mode 100644 builder/azure/examples/centos.json delete mode 100644 builder/azure/examples/debian-chroot.json delete mode 100644 builder/azure/examples/debian.json delete mode 100644 builder/azure/examples/freebsd-chroot.json delete mode 100644 builder/azure/examples/freebsd.json delete mode 100644 builder/azure/examples/linux_custom_image.json delete mode 100644 builder/azure/examples/linux_custom_managed_image.json delete mode 100644 builder/azure/examples/marketplace_plan_info.json delete mode 100644 builder/azure/examples/rhel.json delete mode 100644 builder/azure/examples/suse.json delete mode 100644 builder/azure/examples/ubuntu-chroot.json delete mode 100644 builder/azure/examples/ubuntu.json delete mode 100644 builder/azure/examples/ubuntu_managed_image_sig.json delete mode 100644 builder/azure/examples/ubuntu_quickstart.json delete mode 100644 builder/azure/examples/windows.json delete mode 100644 builder/azure/examples/windows_custom_image.json delete mode 100644 builder/azure/examples/windows_quickstart.json delete mode 100644 builder/azure/pkcs12/LICENSE delete mode 100644 builder/azure/pkcs12/bmp-string.go delete mode 100644 builder/azure/pkcs12/bmp-string_test.go delete mode 100644 builder/azure/pkcs12/crypto.go delete mode 100644 builder/azure/pkcs12/crypto_test.go delete mode 100644 builder/azure/pkcs12/errors.go delete mode 100644 builder/azure/pkcs12/mac.go delete mode 100644 builder/azure/pkcs12/mac_test.go delete mode 100644 builder/azure/pkcs12/pbkdf.go delete mode 100644 builder/azure/pkcs12/pbkdf_test.go delete mode 100644 builder/azure/pkcs12/pkcs12.go delete mode 100644 builder/azure/pkcs12/pkcs12_test.go delete mode 100644 builder/azure/pkcs12/pkcs8.go delete mode 100644 builder/azure/pkcs12/pkcs8_test.go delete mode 100644 builder/azure/pkcs12/rc2/bench_test.go delete mode 100644 builder/azure/pkcs12/rc2/rc2.go delete mode 100644 builder/azure/pkcs12/rc2/rc2_test.go delete mode 100644 builder/azure/pkcs12/safebags.go delete mode 100644 builder/azure/pkcs12/safebags_test.go delete mode 100644 builder/azure/version/version.go delete mode 100755 contrib/azure-setup.sh delete mode 100644 provisioner/azure-dtlartifact/provisioner.go delete mode 100644 provisioner/azure-dtlartifact/provisioner.hcl2spec.go delete mode 100644 provisioner/azure-dtlartifact/version/version.go delete mode 100644 website/content/docs/builders/azure/arm.mdx delete mode 100644 website/content/docs/builders/azure/chroot.mdx delete mode 100644 website/content/docs/builders/azure/index.mdx delete mode 100644 website/content/partials/builder/azure/arm/Config-not-required.mdx delete mode 100644 website/content/partials/builder/azure/arm/Config-required.mdx delete mode 100644 website/content/partials/builder/azure/arm/PlanInformation-not-required.mdx delete mode 100644 website/content/partials/builder/azure/arm/SharedImageGallery-not-required.mdx delete mode 100644 website/content/partials/builder/azure/arm/SharedImageGalleryDestination-not-required.mdx delete mode 100644 website/content/partials/builder/azure/chroot/Config-not-required.mdx delete mode 100644 website/content/partials/builder/azure/chroot/Config-required.mdx delete mode 100644 website/content/partials/builder/azure/chroot/Config.mdx delete mode 100644 website/content/partials/builder/azure/chroot/SharedImageGalleryDestination-not-required.mdx delete mode 100644 website/content/partials/builder/azure/chroot/SharedImageGalleryDestination-required.mdx delete mode 100644 website/content/partials/builder/azure/chroot/SharedImageGalleryDestination.mdx delete mode 100644 website/content/partials/builder/azure/chroot/TargetRegion-not-required.mdx delete mode 100644 website/content/partials/builder/azure/chroot/TargetRegion-required.mdx delete mode 100644 website/content/partials/builder/azure/chroot/TargetRegion.mdx delete mode 100644 website/content/partials/builder/azure/common/client/Config-not-required.mdx delete mode 100644 website/content/partials/builder/azure/common/client/Config.mdx delete mode 100644 website/content/partials/builder/azure/dtl/ArtifactParameter-not-required.mdx delete mode 100644 website/content/partials/builder/azure/dtl/Config-not-required.mdx delete mode 100644 website/content/partials/builder/azure/dtl/DtlArtifact-not-required.mdx delete mode 100644 website/content/partials/builder/azure/dtl/SharedImageGallery-not-required.mdx delete mode 100644 website/content/partials/builder/azure/dtl/SharedImageGalleryDestination-not-required.mdx diff --git a/builder/azure/LICENSE b/builder/azure/LICENSE deleted file mode 100644 index 5ae193c94..000000000 --- a/builder/azure/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -The MIT License (MIT) - -Copyright (c) Microsoft Corporation - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/builder/azure/TODO.md b/builder/azure/TODO.md deleted file mode 100644 index f35a4607b..000000000 --- a/builder/azure/TODO.md +++ /dev/null @@ -1,16 +0,0 @@ -Here's a list of things we like to get done in no particular order: - -- [ ] Blob/image copy post-processor -- [ ] Blob/image rename post-processor -- [ ] SSH to private ip through subnet -- [ ] chroot builder -- [ ] support cross-storage account image source (i.e. pre-build blob copy) -- [ ] look up object id when using device code (graph api /me ?) -- [ ] device flow support for Windows -- [x] look up tenant id in all cases (see device flow code) -- [ ] look up resource group of storage account -- [ ] include all _data_ disks in artifact too -- [ ] windows sysprep provisioner (since it seems to generate a certain issue volume) -- [ ] allow arbitrary json patching for deployment document -- [ ] tag all resources with user-supplied tag -- [ ] managed disk support diff --git a/builder/azure/arm/TestVirtualMachineDeployment05.approved.txt b/builder/azure/arm/TestVirtualMachineDeployment05.approved.txt deleted file mode 100644 index 31532ddbe..000000000 --- a/builder/azure/arm/TestVirtualMachineDeployment05.approved.txt +++ /dev/null @@ -1,118 +0,0 @@ -{ - "$schema": "http://schema.management.azure.com/schemas/2014-04-01-preview/deploymentTemplate.json", - "contentVersion": "1.0.0.0", - "parameters": { - "adminPassword": { - "type": "string" - }, - "adminUsername": { - "type": "string" - }, - "dnsNameForPublicIP": { - "type": "string" - }, - "osDiskName": { - "type": "string" - }, - "storageAccountBlobEndpoint": { - "type": "string" - }, - "vmName": { - "type": "string" - }, - "vmSize": { - "type": "string" - } - }, - "resources": [ - { - "apiVersion": "[variables('apiVersion')]", - "dependsOn": [], - "location": "[variables('location')]", - "name": "[variables('nicName')]", - "properties": { - "ipConfigurations": [ - { - "name": "ipconfig", - "properties": { - "privateIPAllocationMethod": "Dynamic", - "subnet": { - "id": "[variables('subnetRef')]" - } - } - } - ] - }, - "type": "Microsoft.Network/networkInterfaces" - }, - { - "apiVersion": "[variables('apiVersion')]", - "dependsOn": [ - "[concat('Microsoft.Network/networkInterfaces/', variables('nicName'))]" - ], - "location": "[variables('location')]", - "name": "[parameters('vmName')]", - "properties": { - "diagnosticsProfile": { - "bootDiagnostics": { - "enabled": false - } - }, - "hardwareProfile": { - "vmSize": "[parameters('vmSize')]" - }, - "networkProfile": { - "networkInterfaces": [ - { - "id": "[resourceId('Microsoft.Network/networkInterfaces', variables('nicName'))]" - } - ] - }, - "osProfile": { - "adminPassword": "[parameters('adminPassword')]", - "adminUsername": "[parameters('adminUsername')]", - "computerName": "[parameters('vmName')]", - "linuxConfiguration": { - "ssh": { - "publicKeys": [ - { - "keyData": "", - "path": "[variables('sshKeyPath')]" - } - ] - } - } - }, - "storageProfile": { - "osDisk": { - "caching": "ReadWrite", - "createOption": "FromImage", - "image": { - "uri": "https://localhost/custom.vhd" - }, - "name": "[parameters('osDiskName')]", - "osType": "Linux", - "vhd": { - "uri": "[concat(parameters('storageAccountBlobEndpoint'),variables('vmStorageAccountContainerName'),'/', parameters('osDiskName'),'.vhd')]" - } - } - } - }, - "type": "Microsoft.Compute/virtualMachines" - } - ], - "variables": { - "addressPrefix": "10.0.0.0/16", - "apiVersion": "2015-06-15", - "location": "[resourceGroup().location]", - "publicIPAddressType": "Dynamic", - "sshKeyPath": "[concat('/home/',parameters('adminUsername'),'/.ssh/authorized_keys')]", - "subnetAddressPrefix": "10.0.0.0/24", - "subnetName": "ignore", - "subnetRef": "[concat(variables('vnetID'),'/subnets/',variables('subnetName'))]", - "virtualNetworkName": "ignore", - "virtualNetworkResourceGroup": "ignore", - "vmStorageAccountContainerName": "images", - "vnetID": "[resourceId(variables('virtualNetworkResourceGroup'), 'Microsoft.Network/virtualNetworks', variables('virtualNetworkName'))]" - } -} \ No newline at end of file diff --git a/builder/azure/arm/artifact.go b/builder/azure/arm/artifact.go deleted file mode 100644 index 6a3463ec3..000000000 --- a/builder/azure/arm/artifact.go +++ /dev/null @@ -1,261 +0,0 @@ -package arm - -import ( - "bytes" - "fmt" - "log" - "net/url" - "path" - "strings" -) - -const ( - BuilderId = "Azure.ResourceManagement.VMImage" -) - -type AdditionalDiskArtifact struct { - AdditionalDiskUri string - AdditionalDiskUriReadOnlySas string -} - -type Artifact struct { - // OS type: Linux, Windows - OSType string - - // VHD - StorageAccountLocation string - OSDiskUri string - TemplateUri string - OSDiskUriReadOnlySas string - TemplateUriReadOnlySas string - - // Managed Image - ManagedImageResourceGroupName string - ManagedImageName string - ManagedImageLocation string - ManagedImageId string - ManagedImageOSDiskSnapshotName string - ManagedImageDataDiskSnapshotPrefix string - // ARM resource id for Shared Image Gallery - ManagedImageSharedImageGalleryId string - - // Additional Disks - AdditionalDisks *[]AdditionalDiskArtifact - - // StateData should store data such as GeneratedData - // to be shared with post-processors - StateData map[string]interface{} -} - -func NewManagedImageArtifact(osType, resourceGroup, name, location, id, osDiskSnapshotName, dataDiskSnapshotPrefix string, generatedData map[string]interface{}, keepOSDisk bool, template *CaptureTemplate, getSasUrl func(name string) string) (*Artifact, error) { - res := Artifact{ - ManagedImageResourceGroupName: resourceGroup, - ManagedImageName: name, - ManagedImageLocation: location, - ManagedImageId: id, - OSType: osType, - ManagedImageOSDiskSnapshotName: osDiskSnapshotName, - ManagedImageDataDiskSnapshotPrefix: dataDiskSnapshotPrefix, - StateData: generatedData, - } - - if keepOSDisk { - if template == nil { - log.Printf("artifact error: nil capture template") - return &res, nil - } - - if len(template.Resources) != 1 { - log.Printf("artifact error: malformed capture template, expected one resource") - return &res, nil - } - - vhdUri, err := url.Parse(template.Resources[0].Properties.StorageProfile.OSDisk.Image.Uri) - if err != nil { - log.Printf("artifact error: Error parsing osdisk url: %s", err) - return &res, nil - } - - res.OSDiskUri = vhdUri.String() - res.OSDiskUriReadOnlySas = getSasUrl(getStorageUrlPath(vhdUri)) - } - - return &res, nil -} - -func NewManagedImageArtifactWithSIGAsDestination(osType, resourceGroup, name, location, id, osDiskSnapshotName, dataDiskSnapshotPrefix, destinationSharedImageGalleryId string, generatedData map[string]interface{}) (*Artifact, error) { - return &Artifact{ - ManagedImageResourceGroupName: resourceGroup, - ManagedImageName: name, - ManagedImageLocation: location, - ManagedImageId: id, - OSType: osType, - ManagedImageOSDiskSnapshotName: osDiskSnapshotName, - ManagedImageDataDiskSnapshotPrefix: dataDiskSnapshotPrefix, - ManagedImageSharedImageGalleryId: destinationSharedImageGalleryId, - StateData: generatedData, - }, nil -} - -func NewArtifact(template *CaptureTemplate, getSasUrl func(name string) string, osType string, generatedData map[string]interface{}) (*Artifact, error) { - if template == nil { - return nil, fmt.Errorf("nil capture template") - } - - if len(template.Resources) != 1 { - return nil, fmt.Errorf("malformed capture template, expected one resource") - } - - vhdUri, err := url.Parse(template.Resources[0].Properties.StorageProfile.OSDisk.Image.Uri) - if err != nil { - return nil, err - } - - templateUri, err := storageUriToTemplateUri(vhdUri) - if err != nil { - return nil, err - } - - var additional_disks *[]AdditionalDiskArtifact - if template.Resources[0].Properties.StorageProfile.DataDisks != nil { - data_disks := make([]AdditionalDiskArtifact, len(template.Resources[0].Properties.StorageProfile.DataDisks)) - for i, additionaldisk := range template.Resources[0].Properties.StorageProfile.DataDisks { - additionalVhdUri, err := url.Parse(additionaldisk.Image.Uri) - if err != nil { - return nil, err - } - data_disks[i].AdditionalDiskUri = additionalVhdUri.String() - data_disks[i].AdditionalDiskUriReadOnlySas = getSasUrl(getStorageUrlPath(additionalVhdUri)) - } - additional_disks = &data_disks - } - - return &Artifact{ - OSType: osType, - OSDiskUri: vhdUri.String(), - OSDiskUriReadOnlySas: getSasUrl(getStorageUrlPath(vhdUri)), - TemplateUri: templateUri.String(), - TemplateUriReadOnlySas: getSasUrl(getStorageUrlPath(templateUri)), - - AdditionalDisks: additional_disks, - - StorageAccountLocation: template.Resources[0].Location, - - StateData: generatedData, - }, nil -} - -func getStorageUrlPath(u *url.URL) string { - parts := strings.Split(u.Path, "/") - return strings.Join(parts[3:], "/") -} - -func storageUriToTemplateUri(su *url.URL) (*url.URL, error) { - // packer-osDisk.4085bb15-3644-4641-b9cd-f575918640b4.vhd -> 4085bb15-3644-4641-b9cd-f575918640b4 - filename := path.Base(su.Path) - parts := strings.Split(filename, ".") - - if len(parts) < 3 { - return nil, fmt.Errorf("malformed URL") - } - - // packer-osDisk.4085bb15-3644-4641-b9cd-f575918640b4.vhd -> packer - prefixParts := strings.Split(parts[0], "-") - prefix := strings.Join(prefixParts[:len(prefixParts)-1], "-") - - templateFilename := fmt.Sprintf("%s-vmTemplate.%s.json", prefix, parts[1]) - - // https://storage.blob.core.windows.net/system/Microsoft.Compute/Images/images/packer-osDisk.4085bb15-3644-4641-b9cd-f575918640b4.vhd" - // -> - // https://storage.blob.core.windows.net/system/Microsoft.Compute/Images/images/packer-vmTemplate.4085bb15-3644-4641-b9cd-f575918640b4.json" - return url.Parse(strings.Replace(su.String(), filename, templateFilename, 1)) -} - -func (a *Artifact) isManagedImage() bool { - return a.ManagedImageResourceGroupName != "" -} - -func (*Artifact) BuilderId() string { - return BuilderId -} - -func (*Artifact) Files() []string { - return []string{} -} - -func (a *Artifact) Id() string { - if a.OSDiskUri != "" { - return a.OSDiskUri - } - return a.ManagedImageId -} - -func (a *Artifact) State(name string) interface{} { - if _, ok := a.StateData[name]; ok { - return a.StateData[name] - } - - switch name { - case "atlas.artifact.metadata": - return a.stateAtlasMetadata() - default: - return nil - } -} - -func (a *Artifact) String() string { - var buf bytes.Buffer - - buf.WriteString(fmt.Sprintf("%s:\n\n", a.BuilderId())) - buf.WriteString(fmt.Sprintf("OSType: %s\n", a.OSType)) - if a.isManagedImage() { - buf.WriteString(fmt.Sprintf("ManagedImageResourceGroupName: %s\n", a.ManagedImageResourceGroupName)) - buf.WriteString(fmt.Sprintf("ManagedImageName: %s\n", a.ManagedImageName)) - buf.WriteString(fmt.Sprintf("ManagedImageId: %s\n", a.ManagedImageId)) - buf.WriteString(fmt.Sprintf("ManagedImageLocation: %s\n", a.ManagedImageLocation)) - if a.ManagedImageOSDiskSnapshotName != "" { - buf.WriteString(fmt.Sprintf("ManagedImageOSDiskSnapshotName: %s\n", a.ManagedImageOSDiskSnapshotName)) - } - if a.ManagedImageDataDiskSnapshotPrefix != "" { - buf.WriteString(fmt.Sprintf("ManagedImageDataDiskSnapshotPrefix: %s\n", a.ManagedImageDataDiskSnapshotPrefix)) - } - if a.ManagedImageSharedImageGalleryId != "" { - buf.WriteString(fmt.Sprintf("ManagedImageSharedImageGalleryId: %s\n", a.ManagedImageSharedImageGalleryId)) - } - if a.OSDiskUri != "" { - buf.WriteString(fmt.Sprintf("OSDiskUri: %s\n", a.OSDiskUri)) - } - if a.OSDiskUriReadOnlySas != "" { - buf.WriteString(fmt.Sprintf("OSDiskUriReadOnlySas: %s\n", a.OSDiskUriReadOnlySas)) - } - } 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)) - if a.AdditionalDisks != nil { - for i, additionaldisk := range *a.AdditionalDisks { - buf.WriteString(fmt.Sprintf("AdditionalDiskUri (datadisk-%d): %s\n", i+1, additionaldisk.AdditionalDiskUri)) - buf.WriteString(fmt.Sprintf("AdditionalDiskUriReadOnlySas (datadisk-%d): %s\n", i+1, additionaldisk.AdditionalDiskUriReadOnlySas)) - } - } - } - - return buf.String() -} - -func (*Artifact) Destroy() error { - return nil -} - -func (a *Artifact) stateAtlasMetadata() interface{} { - metadata := make(map[string]string) - metadata["StorageAccountLocation"] = a.StorageAccountLocation - metadata["OSDiskUri"] = a.OSDiskUri - metadata["OSDiskUriReadOnlySas"] = a.OSDiskUriReadOnlySas - metadata["TemplateUri"] = a.TemplateUri - metadata["TemplateUriReadOnlySas"] = a.TemplateUriReadOnlySas - - return metadata -} diff --git a/builder/azure/arm/artifact_test.go b/builder/azure/arm/artifact_test.go deleted file mode 100644 index 81acdb101..000000000 --- a/builder/azure/arm/artifact_test.go +++ /dev/null @@ -1,521 +0,0 @@ -package arm - -import ( - "fmt" - "strings" - "testing" -) - -func getFakeSasUrl(name string) string { - return fmt.Sprintf("SAS-%s", name) -} - -func generatedData() map[string]interface{} { - return make(map[string]interface{}) -} - -func TestArtifactIdVHD(t *testing.T) { - template := CaptureTemplate{ - Resources: []CaptureResources{ - { - Properties: CaptureProperties{ - StorageProfile: CaptureStorageProfile{ - OSDisk: CaptureDisk{ - Image: CaptureUri{ - Uri: "https://storage.blob.core.windows.net/system/Microsoft.Compute/Images/images/packer-osDisk.4085bb15-3644-4641-b9cd-f575918640b4.vhd", - }, - }, - }, - }, - Location: "southcentralus", - }, - }, - } - - artifact, err := NewArtifact(&template, getFakeSasUrl, "Linux", generatedData()) - if err != nil { - t.Fatalf("err=%s", err) - } - - expected := "https://storage.blob.core.windows.net/system/Microsoft.Compute/Images/images/packer-osDisk.4085bb15-3644-4641-b9cd-f575918640b4.vhd" - - result := artifact.Id() - if result != expected { - t.Fatalf("bad: %s", result) - } -} - -func TestArtifactIDManagedImage(t *testing.T) { - template := CaptureTemplate{ - Resources: []CaptureResources{ - { - Properties: CaptureProperties{ - StorageProfile: CaptureStorageProfile{ - OSDisk: CaptureDisk{ - Image: CaptureUri{ - Uri: "https://storage.blob.core.windows.net/system/Microsoft.Compute/Images/images/packer-osDisk.4085bb15-3644-4641-b9cd-f575918640b4.vhd", - }, - }, - }, - }, - Location: "southcentralus", - }, - }, - } - - artifact, err := NewManagedImageArtifact("Linux", "fakeResourceGroup", "fakeName", "fakeLocation", "fakeID", "fakeOsDiskSnapshotName", "fakeDataDiskSnapshotPrefix", generatedData(), false, &template, getFakeSasUrl) - if err != nil { - t.Fatalf("err=%s", err) - } - - expected := `Azure.ResourceManagement.VMImage: - -OSType: Linux -ManagedImageResourceGroupName: fakeResourceGroup -ManagedImageName: fakeName -ManagedImageId: fakeID -ManagedImageLocation: fakeLocation -ManagedImageOSDiskSnapshotName: fakeOsDiskSnapshotName -ManagedImageDataDiskSnapshotPrefix: fakeDataDiskSnapshotPrefix -` - - result := artifact.String() - if result != expected { - t.Fatalf("bad: %s", result) - } -} - -func TestArtifactIDManagedImageWithoutOSDiskSnapshotName(t *testing.T) { - template := CaptureTemplate{ - Resources: []CaptureResources{ - { - Properties: CaptureProperties{ - StorageProfile: CaptureStorageProfile{ - OSDisk: CaptureDisk{ - Image: CaptureUri{ - Uri: "https://storage.blob.core.windows.net/system/Microsoft.Compute/Images/images/packer-osDisk.4085bb15-3644-4641-b9cd-f575918640b4.vhd", - }, - }, - }, - }, - Location: "southcentralus", - }, - }, - } - - artifact, err := NewManagedImageArtifact("Linux", "fakeResourceGroup", "fakeName", "fakeLocation", "fakeID", "", "fakeDataDiskSnapshotPrefix", generatedData(), false, &template, getFakeSasUrl) - if err != nil { - t.Fatalf("err=%s", err) - } - - expected := `Azure.ResourceManagement.VMImage: - -OSType: Linux -ManagedImageResourceGroupName: fakeResourceGroup -ManagedImageName: fakeName -ManagedImageId: fakeID -ManagedImageLocation: fakeLocation -ManagedImageDataDiskSnapshotPrefix: fakeDataDiskSnapshotPrefix -` - - result := artifact.String() - if result != expected { - t.Fatalf("bad: %s", result) - } -} - -func TestArtifactIDManagedImageWithoutDataDiskSnapshotPrefix(t *testing.T) { - template := CaptureTemplate{ - Resources: []CaptureResources{ - { - Properties: CaptureProperties{ - StorageProfile: CaptureStorageProfile{ - OSDisk: CaptureDisk{ - Image: CaptureUri{ - Uri: "https://storage.blob.core.windows.net/system/Microsoft.Compute/Images/images/packer-osDisk.4085bb15-3644-4641-b9cd-f575918640b4.vhd", - }, - }, - }, - }, - Location: "southcentralus", - }, - }, - } - - artifact, err := NewManagedImageArtifact("Linux", "fakeResourceGroup", "fakeName", "fakeLocation", "fakeID", "fakeOsDiskSnapshotName", "", generatedData(), false, &template, getFakeSasUrl) - if err != nil { - t.Fatalf("err=%s", err) - } - - expected := `Azure.ResourceManagement.VMImage: - -OSType: Linux -ManagedImageResourceGroupName: fakeResourceGroup -ManagedImageName: fakeName -ManagedImageId: fakeID -ManagedImageLocation: fakeLocation -ManagedImageOSDiskSnapshotName: fakeOsDiskSnapshotName -` - - result := artifact.String() - if result != expected { - t.Fatalf("bad: %s", result) - } -} - -func TestArtifactIDManagedImageWithKeepingTheOSDisk(t *testing.T) { - template := CaptureTemplate{ - Resources: []CaptureResources{ - { - Properties: CaptureProperties{ - StorageProfile: CaptureStorageProfile{ - OSDisk: CaptureDisk{ - Image: CaptureUri{ - Uri: "https://storage.blob.core.windows.net/system/Microsoft.Compute/Images/images/packer-osDisk.4085bb15-3644-4641-b9cd-f575918640b4.vhd", - }, - }, - }, - }, - Location: "southcentralus", - }, - }, - } - - artifact, err := NewManagedImageArtifact("Linux", "fakeResourceGroup", "fakeName", "fakeLocation", "fakeID", "fakeOsDiskSnapshotName", "", generatedData(), true, &template, getFakeSasUrl) - if err != nil { - t.Fatalf("err=%s", err) - } - - expected := `Azure.ResourceManagement.VMImage: - -OSType: Linux -ManagedImageResourceGroupName: fakeResourceGroup -ManagedImageName: fakeName -ManagedImageId: fakeID -ManagedImageLocation: fakeLocation -ManagedImageOSDiskSnapshotName: fakeOsDiskSnapshotName -OSDiskUri: https://storage.blob.core.windows.net/system/Microsoft.Compute/Images/images/packer-osDisk.4085bb15-3644-4641-b9cd-f575918640b4.vhd -OSDiskUriReadOnlySas: SAS-Images/images/packer-osDisk.4085bb15-3644-4641-b9cd-f575918640b4.vhd -` - - result := artifact.String() - if result != expected { - t.Fatalf("bad: %s", result) - } -} - -func TestArtifactIDManagedImageWithSharedImageGalleryId(t *testing.T) { - artifact, err := NewManagedImageArtifactWithSIGAsDestination("Linux", "fakeResourceGroup", "fakeName", "fakeLocation", "fakeID", "fakeOsDiskSnapshotName", "fakeDataDiskSnapshotPrefix", "fakeSharedImageGallery", generatedData()) - if err != nil { - t.Fatalf("err=%s", err) - } - - expected := `Azure.ResourceManagement.VMImage: - -OSType: Linux -ManagedImageResourceGroupName: fakeResourceGroup -ManagedImageName: fakeName -ManagedImageId: fakeID -ManagedImageLocation: fakeLocation -ManagedImageOSDiskSnapshotName: fakeOsDiskSnapshotName -ManagedImageDataDiskSnapshotPrefix: fakeDataDiskSnapshotPrefix -ManagedImageSharedImageGalleryId: fakeSharedImageGallery -` - - result := artifact.String() - if result != expected { - t.Fatalf("bad: %s", result) - } -} - -func TestArtifactString(t *testing.T) { - template := CaptureTemplate{ - Resources: []CaptureResources{ - { - Properties: CaptureProperties{ - StorageProfile: CaptureStorageProfile{ - OSDisk: CaptureDisk{ - Image: CaptureUri{ - Uri: "https://storage.blob.core.windows.net/system/Microsoft.Compute/Images/images/packer-osDisk.4085bb15-3644-4641-b9cd-f575918640b4.vhd", - }, - }, - }, - }, - Location: "southcentralus", - }, - }, - } - - artifact, err := NewArtifact(&template, getFakeSasUrl, "Linux", generatedData()) - if err != nil { - t.Fatalf("err=%s", err) - } - - testSubject := artifact.String() - if !strings.Contains(testSubject, "OSDiskUri: https://storage.blob.core.windows.net/system/Microsoft.Compute/Images/images/packer-osDisk.4085bb15-3644-4641-b9cd-f575918640b4.vhd") { - t.Errorf("Expected String() output to contain OSDiskUri") - } - if !strings.Contains(testSubject, "OSDiskUriReadOnlySas: SAS-Images/images/packer-osDisk.4085bb15-3644-4641-b9cd-f575918640b4.vhd") { - t.Errorf("Expected String() output to contain OSDiskUriReadOnlySas") - } - if !strings.Contains(testSubject, "TemplateUri: https://storage.blob.core.windows.net/system/Microsoft.Compute/Images/images/packer-vmTemplate.4085bb15-3644-4641-b9cd-f575918640b4.json") { - t.Errorf("Expected String() output to contain TemplateUri") - } - if !strings.Contains(testSubject, "TemplateUriReadOnlySas: SAS-Images/images/packer-vmTemplate.4085bb15-3644-4641-b9cd-f575918640b4.json") { - t.Errorf("Expected String() output to contain TemplateUriReadOnlySas") - } - if !strings.Contains(testSubject, "StorageAccountLocation: southcentralus") { - t.Errorf("Expected String() output to contain StorageAccountLocation") - } - if !strings.Contains(testSubject, "OSType: Linux") { - t.Errorf("Expected String() output to contain OSType") - } -} - -func TestAdditionalDiskArtifactString(t *testing.T) { - template := CaptureTemplate{ - Resources: []CaptureResources{ - { - Properties: CaptureProperties{ - StorageProfile: CaptureStorageProfile{ - OSDisk: CaptureDisk{ - Image: CaptureUri{ - Uri: "https://storage.blob.core.windows.net/system/Microsoft.Compute/Images/images/packer-osDisk.4085bb15-3644-4641-b9cd-f575918640b4.vhd", - }, - }, - DataDisks: []CaptureDisk{ - { - Image: CaptureUri{ - Uri: "https://storage.blob.core.windows.net/system/Microsoft.Compute/Images/images/packer-datadisk-1.4085bb15-3644-4641-b9cd-f575918640b4.vhd", - }, - }, - }, - }, - }, - Location: "southcentralus", - }, - }, - } - - artifact, err := NewArtifact(&template, getFakeSasUrl, "Linux", generatedData()) - if err != nil { - t.Fatalf("err=%s", err) - } - - testSubject := artifact.String() - if !strings.Contains(testSubject, "OSDiskUri: https://storage.blob.core.windows.net/system/Microsoft.Compute/Images/images/packer-osDisk.4085bb15-3644-4641-b9cd-f575918640b4.vhd") { - t.Errorf("Expected String() output to contain OSDiskUri") - } - if !strings.Contains(testSubject, "OSDiskUriReadOnlySas: SAS-Images/images/packer-osDisk.4085bb15-3644-4641-b9cd-f575918640b4.vhd") { - t.Errorf("Expected String() output to contain OSDiskUriReadOnlySas") - } - if !strings.Contains(testSubject, "TemplateUri: https://storage.blob.core.windows.net/system/Microsoft.Compute/Images/images/packer-vmTemplate.4085bb15-3644-4641-b9cd-f575918640b4.json") { - t.Errorf("Expected String() output to contain TemplateUri") - } - if !strings.Contains(testSubject, "TemplateUriReadOnlySas: SAS-Images/images/packer-vmTemplate.4085bb15-3644-4641-b9cd-f575918640b4.json") { - t.Errorf("Expected String() output to contain TemplateUriReadOnlySas") - } - if !strings.Contains(testSubject, "StorageAccountLocation: southcentralus") { - t.Errorf("Expected String() output to contain StorageAccountLocation") - } - if !strings.Contains(testSubject, "OSType: Linux") { - t.Errorf("Expected String() output to contain OSType") - } - if !strings.Contains(testSubject, "AdditionalDiskUri (datadisk-1): https://storage.blob.core.windows.net/system/Microsoft.Compute/Images/images/packer-datadisk-1.4085bb15-3644-4641-b9cd-f575918640b4.vhd") { - t.Errorf("Expected String() output to contain AdditionalDiskUri") - } - if !strings.Contains(testSubject, "AdditionalDiskUriReadOnlySas (datadisk-1): SAS-Images/images/packer-datadisk-1.4085bb15-3644-4641-b9cd-f575918640b4.vhd") { - t.Errorf("Expected String() output to contain AdditionalDiskUriReadOnlySas") - } -} - -func TestArtifactProperties(t *testing.T) { - template := CaptureTemplate{ - Resources: []CaptureResources{ - { - Properties: CaptureProperties{ - StorageProfile: CaptureStorageProfile{ - OSDisk: CaptureDisk{ - Image: CaptureUri{ - Uri: "https://storage.blob.core.windows.net/system/Microsoft.Compute/Images/images/packer-osDisk.4085bb15-3644-4641-b9cd-f575918640b4.vhd", - }, - }, - }, - }, - Location: "southcentralus", - }, - }, - } - - testSubject, err := NewArtifact(&template, getFakeSasUrl, "Linux", generatedData()) - if err != nil { - t.Fatalf("err=%s", err) - } - - if testSubject.OSDiskUri != "https://storage.blob.core.windows.net/system/Microsoft.Compute/Images/images/packer-osDisk.4085bb15-3644-4641-b9cd-f575918640b4.vhd" { - t.Errorf("Expected template to be 'https://storage.blob.core.windows.net/system/Microsoft.Compute/Images/images/packer-osDisk.4085bb15-3644-4641-b9cd-f575918640b4.vhd', but got %s", testSubject.OSDiskUri) - } - if testSubject.OSDiskUriReadOnlySas != "SAS-Images/images/packer-osDisk.4085bb15-3644-4641-b9cd-f575918640b4.vhd" { - t.Errorf("Expected template to be 'SAS-Images/images/packer-osDisk.4085bb15-3644-4641-b9cd-f575918640b4.vhd', but got %s", testSubject.OSDiskUriReadOnlySas) - } - if testSubject.TemplateUri != "https://storage.blob.core.windows.net/system/Microsoft.Compute/Images/images/packer-vmTemplate.4085bb15-3644-4641-b9cd-f575918640b4.json" { - t.Errorf("Expected template to be 'https://storage.blob.core.windows.net/system/Microsoft.Compute/Images/images/packer-vmTemplate.4085bb15-3644-4641-b9cd-f575918640b4.json', but got %s", testSubject.TemplateUri) - } - if testSubject.TemplateUriReadOnlySas != "SAS-Images/images/packer-vmTemplate.4085bb15-3644-4641-b9cd-f575918640b4.json" { - t.Errorf("Expected template to be 'SAS-Images/images/packer-vmTemplate.4085bb15-3644-4641-b9cd-f575918640b4.json', but got %s", testSubject.TemplateUriReadOnlySas) - } - if testSubject.StorageAccountLocation != "southcentralus" { - t.Errorf("Expected StorageAccountLocation to be 'southcentral', but got %s", testSubject.StorageAccountLocation) - } - if testSubject.OSType != "Linux" { - t.Errorf("Expected OSType to be 'Linux', but got %s", testSubject.OSType) - } -} - -func TestAdditionalDiskArtifactProperties(t *testing.T) { - template := CaptureTemplate{ - Resources: []CaptureResources{ - { - Properties: CaptureProperties{ - StorageProfile: CaptureStorageProfile{ - OSDisk: CaptureDisk{ - Image: CaptureUri{ - Uri: "https://storage.blob.core.windows.net/system/Microsoft.Compute/Images/images/packer-osDisk.4085bb15-3644-4641-b9cd-f575918640b4.vhd", - }, - }, - DataDisks: []CaptureDisk{ - { - Image: CaptureUri{ - Uri: "https://storage.blob.core.windows.net/system/Microsoft.Compute/Images/images/packer-datadisk-1.4085bb15-3644-4641-b9cd-f575918640b4.vhd", - }, - }, - }, - }, - }, - Location: "southcentralus", - }, - }, - } - - testSubject, err := NewArtifact(&template, getFakeSasUrl, "Linux", generatedData()) - if err != nil { - t.Fatalf("err=%s", err) - } - - if testSubject.OSDiskUri != "https://storage.blob.core.windows.net/system/Microsoft.Compute/Images/images/packer-osDisk.4085bb15-3644-4641-b9cd-f575918640b4.vhd" { - t.Errorf("Expected template to be 'https://storage.blob.core.windows.net/system/Microsoft.Compute/Images/images/packer-osDisk.4085bb15-3644-4641-b9cd-f575918640b4.vhd', but got %s", testSubject.OSDiskUri) - } - if testSubject.OSDiskUriReadOnlySas != "SAS-Images/images/packer-osDisk.4085bb15-3644-4641-b9cd-f575918640b4.vhd" { - t.Errorf("Expected template to be 'SAS-Images/images/packer-osDisk.4085bb15-3644-4641-b9cd-f575918640b4.vhd', but got %s", testSubject.OSDiskUriReadOnlySas) - } - if testSubject.TemplateUri != "https://storage.blob.core.windows.net/system/Microsoft.Compute/Images/images/packer-vmTemplate.4085bb15-3644-4641-b9cd-f575918640b4.json" { - t.Errorf("Expected template to be 'https://storage.blob.core.windows.net/system/Microsoft.Compute/Images/images/packer-vmTemplate.4085bb15-3644-4641-b9cd-f575918640b4.json', but got %s", testSubject.TemplateUri) - } - if testSubject.TemplateUriReadOnlySas != "SAS-Images/images/packer-vmTemplate.4085bb15-3644-4641-b9cd-f575918640b4.json" { - t.Errorf("Expected template to be 'SAS-Images/images/packer-vmTemplate.4085bb15-3644-4641-b9cd-f575918640b4.json', but got %s", testSubject.TemplateUriReadOnlySas) - } - if testSubject.StorageAccountLocation != "southcentralus" { - t.Errorf("Expected StorageAccountLocation to be 'southcentral', but got %s", testSubject.StorageAccountLocation) - } - if testSubject.OSType != "Linux" { - t.Errorf("Expected OSType to be 'Linux', but got %s", testSubject.OSType) - } - if testSubject.AdditionalDisks == nil { - t.Errorf("Expected AdditionalDisks to be not nil") - } - if len(*testSubject.AdditionalDisks) != 1 { - t.Errorf("Expected AdditionalDisks to have one additional disk, but got %d", len(*testSubject.AdditionalDisks)) - } - if (*testSubject.AdditionalDisks)[0].AdditionalDiskUri != "https://storage.blob.core.windows.net/system/Microsoft.Compute/Images/images/packer-datadisk-1.4085bb15-3644-4641-b9cd-f575918640b4.vhd" { - t.Errorf("Expected additional disk uri to be 'https://storage.blob.core.windows.net/system/Microsoft.Compute/Images/images/packer-datadisk-1.4085bb15-3644-4641-b9cd-f575918640b4.vhd', but got %s", (*testSubject.AdditionalDisks)[0].AdditionalDiskUri) - } - if (*testSubject.AdditionalDisks)[0].AdditionalDiskUriReadOnlySas != "SAS-Images/images/packer-datadisk-1.4085bb15-3644-4641-b9cd-f575918640b4.vhd" { - t.Errorf("Expected additional disk sas to be 'SAS-Images/images/packer-datadisk-1.4085bb15-3644-4641-b9cd-f575918640b4.vhd', but got %s", (*testSubject.AdditionalDisks)[0].AdditionalDiskUriReadOnlySas) - } -} - -func TestArtifactOverHyphenatedCaptureUri(t *testing.T) { - template := CaptureTemplate{ - Resources: []CaptureResources{ - { - Properties: CaptureProperties{ - StorageProfile: CaptureStorageProfile{ - OSDisk: CaptureDisk{ - Image: CaptureUri{ - Uri: "https://storage.blob.core.windows.net/system/Microsoft.Compute/Images/images/pac-ker-osDisk.4085bb15-3644-4641-b9cd-f575918640b4.vhd", - }, - }, - }, - }, - Location: "southcentralus", - }, - }, - } - - testSubject, err := NewArtifact(&template, getFakeSasUrl, "Linux", generatedData()) - if err != nil { - t.Fatalf("err=%s", err) - } - - if testSubject.TemplateUri != "https://storage.blob.core.windows.net/system/Microsoft.Compute/Images/images/pac-ker-vmTemplate.4085bb15-3644-4641-b9cd-f575918640b4.json" { - t.Errorf("Expected template to be 'https://storage.blob.core.windows.net/system/Microsoft.Compute/Images/images/pac-ker-vmTemplate.4085bb15-3644-4641-b9cd-f575918640b4.json', but got %s", testSubject.TemplateUri) - } -} - -func TestArtifactRejectMalformedTemplates(t *testing.T) { - template := CaptureTemplate{} - - _, err := NewArtifact(&template, getFakeSasUrl, "Linux", generatedData()) - if err == nil { - t.Fatalf("Expected artifact creation to fail, but it succeeded.") - } -} - -func TestArtifactRejectMalformedStorageUri(t *testing.T) { - template := CaptureTemplate{ - Resources: []CaptureResources{ - { - Properties: CaptureProperties{ - StorageProfile: CaptureStorageProfile{ - OSDisk: CaptureDisk{ - Image: CaptureUri{ - Uri: "bark", - }, - }, - }, - }, - }, - }, - } - - _, err := NewArtifact(&template, getFakeSasUrl, "Linux", generatedData()) - if err == nil { - t.Fatalf("Expected artifact creation to fail, but it succeeded.") - } -} - -func TestArtifactState_StateData(t *testing.T) { - expectedData := "this is the data" - artifact := &Artifact{ - StateData: map[string]interface{}{"state_data": expectedData}, - } - - // Valid state - result := artifact.State("state_data") - if result != expectedData { - t.Fatalf("Bad: State data was %s instead of %s", result, expectedData) - } - - // Invalid state - result = artifact.State("invalid_key") - if result != nil { - t.Fatalf("Bad: State should be nil for invalid state data name") - } - - // Nil StateData should not fail and should return nil - artifact = &Artifact{} - result = artifact.State("key") - if result != nil { - t.Fatalf("Bad: State should be nil for nil StateData") - } -} diff --git a/builder/azure/arm/azure_client.go b/builder/azure/arm/azure_client.go deleted file mode 100644 index 26dadc336..000000000 --- a/builder/azure/arm/azure_client.go +++ /dev/null @@ -1,311 +0,0 @@ -package arm - -import ( - "context" - "encoding/json" - "fmt" - "math" - "net/http" - "net/url" - "os" - "strconv" - "time" - - "github.com/Azure/azure-sdk-for-go/services/compute/mgmt/2018-04-01/compute" - newCompute "github.com/Azure/azure-sdk-for-go/services/compute/mgmt/2019-03-01/compute" - "github.com/Azure/azure-sdk-for-go/services/keyvault/mgmt/2018-02-14/keyvault" - "github.com/Azure/azure-sdk-for-go/services/network/mgmt/2018-01-01/network" - "github.com/Azure/azure-sdk-for-go/services/resources/mgmt/2018-02-01/resources" - armStorage "github.com/Azure/azure-sdk-for-go/services/storage/mgmt/2017-10-01/storage" - "github.com/Azure/azure-sdk-for-go/storage" - "github.com/Azure/go-autorest/autorest" - "github.com/Azure/go-autorest/autorest/adal" - "github.com/Azure/go-autorest/autorest/azure" - "github.com/hashicorp/packer-plugin-sdk/useragent" - "github.com/hashicorp/packer/builder/azure/common" - "github.com/hashicorp/packer/builder/azure/version" -) - -const ( - EnvPackerLogAzureMaxLen = "PACKER_LOG_AZURE_MAXLEN" -) - -type AzureClient struct { - storage.BlobStorageClient - resources.DeploymentsClient - resources.DeploymentOperationsClient - resources.GroupsClient - network.PublicIPAddressesClient - network.InterfacesClient - network.SubnetsClient - network.VirtualNetworksClient - network.SecurityGroupsClient - compute.ImagesClient - compute.VirtualMachinesClient - common.VaultClient - armStorage.AccountsClient - compute.DisksClient - compute.SnapshotsClient - newCompute.GalleryImageVersionsClient - newCompute.GalleryImagesClient - - InspectorMaxLength int - Template *CaptureTemplate - LastError azureErrorResponse - VaultClientDelete keyvault.VaultsClient -} - -func getCaptureResponse(body string) *CaptureTemplate { - var operation CaptureOperation - err := json.Unmarshal([]byte(body), &operation) - if err != nil { - return nil - } - - if operation.Properties != nil && operation.Properties.Output != nil { - return operation.Properties.Output - } - - return nil -} - -// HACK(chrboum): This method is a hack. It was written to work around this issue -// (https://github.com/Azure/azure-sdk-for-go/issues/307) and to an extent this -// issue (https://github.com/Azure/azure-rest-api-specs/issues/188). -// -// Capturing a VM is a long running operation that requires polling. There are -// couple different forms of polling, and the end result of a poll operation is -// discarded by the SDK. It is expected that any discarded data can be re-fetched, -// so discarding it has minimal impact. Unfortunately, there is no way to re-fetch -// the template returned by a capture call that I am aware of. -// -// If the second issue were fixed the VM ID would be included when GET'ing a VM. The -// VM ID could be used to locate the captured VHD, and captured template. -// Unfortunately, the VM ID is not included so this method cannot be used either. -// -// This code captures the template and saves it to the client (the AzureClient type). -// It expects that the capture API is called only once, or rather you only care that the -// last call's value is important because subsequent requests are not persisted. There -// is no care given to multiple threads writing this value because for our use case -// it does not matter. -func templateCapture(client *AzureClient) autorest.RespondDecorator { - return func(r autorest.Responder) autorest.Responder { - return autorest.ResponderFunc(func(resp *http.Response) error { - body, bodyString := handleBody(resp.Body, math.MaxInt64) - resp.Body = body - - captureTemplate := getCaptureResponse(bodyString) - if captureTemplate != nil { - client.Template = captureTemplate - } - - return r.Respond(resp) - }) - } -} - -func errorCapture(client *AzureClient) autorest.RespondDecorator { - return func(r autorest.Responder) autorest.Responder { - return autorest.ResponderFunc(func(resp *http.Response) error { - body, bodyString := handleBody(resp.Body, math.MaxInt64) - resp.Body = body - - errorResponse := newAzureErrorResponse(bodyString) - if errorResponse != nil { - client.LastError = *errorResponse - } - - return r.Respond(resp) - }) - } -} - -// WAITING(chrboum): I have logged https://github.com/Azure/azure-sdk-for-go/issues/311 to get this -// method included in the SDK. It has been accepted, and I'll cut over to the official way -// once it ships. -func byConcatDecorators(decorators ...autorest.RespondDecorator) autorest.RespondDecorator { - return func(r autorest.Responder) autorest.Responder { - return autorest.DecorateResponder(r, decorators...) - } -} - -func NewAzureClient(subscriptionID, sigSubscriptionID, resourceGroupName, storageAccountName string, - cloud *azure.Environment, sharedGalleryTimeout time.Duration, pollingDuration time.Duration, - servicePrincipalToken, servicePrincipalTokenVault *adal.ServicePrincipalToken) (*AzureClient, error) { - - var azureClient = &AzureClient{} - - maxlen := getInspectorMaxLength() - - azureClient.DeploymentsClient = resources.NewDeploymentsClientWithBaseURI(cloud.ResourceManagerEndpoint, subscriptionID) - azureClient.DeploymentsClient.Authorizer = autorest.NewBearerAuthorizer(servicePrincipalToken) - azureClient.DeploymentsClient.RequestInspector = withInspection(maxlen) - azureClient.DeploymentsClient.ResponseInspector = byConcatDecorators(byInspecting(maxlen), errorCapture(azureClient)) - azureClient.DeploymentsClient.UserAgent = fmt.Sprintf("%s %s", useragent.String(version.AzurePluginVersion.FormattedVersion()), azureClient.DeploymentsClient.UserAgent) - azureClient.DeploymentsClient.Client.PollingDuration = pollingDuration - - azureClient.DeploymentOperationsClient = resources.NewDeploymentOperationsClientWithBaseURI(cloud.ResourceManagerEndpoint, subscriptionID) - azureClient.DeploymentOperationsClient.Authorizer = autorest.NewBearerAuthorizer(servicePrincipalToken) - azureClient.DeploymentOperationsClient.RequestInspector = withInspection(maxlen) - azureClient.DeploymentOperationsClient.ResponseInspector = byConcatDecorators(byInspecting(maxlen), errorCapture(azureClient)) - azureClient.DeploymentOperationsClient.UserAgent = fmt.Sprintf("%s %s", useragent.String(version.AzurePluginVersion.FormattedVersion()), azureClient.DeploymentOperationsClient.UserAgent) - azureClient.DeploymentOperationsClient.Client.PollingDuration = pollingDuration - - azureClient.DisksClient = compute.NewDisksClientWithBaseURI(cloud.ResourceManagerEndpoint, subscriptionID) - azureClient.DisksClient.Authorizer = autorest.NewBearerAuthorizer(servicePrincipalToken) - azureClient.DisksClient.RequestInspector = withInspection(maxlen) - azureClient.DisksClient.ResponseInspector = byConcatDecorators(byInspecting(maxlen), errorCapture(azureClient)) - azureClient.DisksClient.UserAgent = fmt.Sprintf("%s %s", useragent.String(version.AzurePluginVersion.FormattedVersion()), azureClient.DisksClient.UserAgent) - azureClient.DisksClient.Client.PollingDuration = pollingDuration - - azureClient.GroupsClient = resources.NewGroupsClientWithBaseURI(cloud.ResourceManagerEndpoint, subscriptionID) - azureClient.GroupsClient.Authorizer = autorest.NewBearerAuthorizer(servicePrincipalToken) - azureClient.GroupsClient.RequestInspector = withInspection(maxlen) - azureClient.GroupsClient.ResponseInspector = byConcatDecorators(byInspecting(maxlen), errorCapture(azureClient)) - azureClient.GroupsClient.UserAgent = fmt.Sprintf("%s %s", useragent.String(version.AzurePluginVersion.FormattedVersion()), azureClient.GroupsClient.UserAgent) - azureClient.GroupsClient.Client.PollingDuration = pollingDuration - - azureClient.ImagesClient = compute.NewImagesClientWithBaseURI(cloud.ResourceManagerEndpoint, subscriptionID) - azureClient.ImagesClient.Authorizer = autorest.NewBearerAuthorizer(servicePrincipalToken) - azureClient.ImagesClient.RequestInspector = withInspection(maxlen) - azureClient.ImagesClient.ResponseInspector = byConcatDecorators(byInspecting(maxlen), errorCapture(azureClient)) - azureClient.ImagesClient.UserAgent = fmt.Sprintf("%s %s", useragent.String(version.AzurePluginVersion.FormattedVersion()), azureClient.ImagesClient.UserAgent) - azureClient.ImagesClient.Client.PollingDuration = pollingDuration - - azureClient.InterfacesClient = network.NewInterfacesClientWithBaseURI(cloud.ResourceManagerEndpoint, subscriptionID) - azureClient.InterfacesClient.Authorizer = autorest.NewBearerAuthorizer(servicePrincipalToken) - azureClient.InterfacesClient.RequestInspector = withInspection(maxlen) - azureClient.InterfacesClient.ResponseInspector = byConcatDecorators(byInspecting(maxlen), errorCapture(azureClient)) - azureClient.InterfacesClient.UserAgent = fmt.Sprintf("%s %s", useragent.String(version.AzurePluginVersion.FormattedVersion()), azureClient.InterfacesClient.UserAgent) - azureClient.InterfacesClient.Client.PollingDuration = pollingDuration - - azureClient.SubnetsClient = network.NewSubnetsClientWithBaseURI(cloud.ResourceManagerEndpoint, subscriptionID) - azureClient.SubnetsClient.Authorizer = autorest.NewBearerAuthorizer(servicePrincipalToken) - azureClient.SubnetsClient.RequestInspector = withInspection(maxlen) - azureClient.SubnetsClient.ResponseInspector = byConcatDecorators(byInspecting(maxlen), errorCapture(azureClient)) - azureClient.SubnetsClient.UserAgent = fmt.Sprintf("%s %s", useragent.String(version.AzurePluginVersion.FormattedVersion()), azureClient.SubnetsClient.UserAgent) - azureClient.SubnetsClient.Client.PollingDuration = pollingDuration - - azureClient.VirtualNetworksClient = network.NewVirtualNetworksClientWithBaseURI(cloud.ResourceManagerEndpoint, subscriptionID) - azureClient.VirtualNetworksClient.Authorizer = autorest.NewBearerAuthorizer(servicePrincipalToken) - azureClient.VirtualNetworksClient.RequestInspector = withInspection(maxlen) - azureClient.VirtualNetworksClient.ResponseInspector = byConcatDecorators(byInspecting(maxlen), errorCapture(azureClient)) - azureClient.VirtualNetworksClient.UserAgent = fmt.Sprintf("%s %s", useragent.String(version.AzurePluginVersion.FormattedVersion()), azureClient.VirtualNetworksClient.UserAgent) - azureClient.VirtualNetworksClient.Client.PollingDuration = pollingDuration - - azureClient.SecurityGroupsClient = network.NewSecurityGroupsClientWithBaseURI(cloud.ResourceManagerEndpoint, subscriptionID) - azureClient.SecurityGroupsClient.Authorizer = autorest.NewBearerAuthorizer(servicePrincipalToken) - azureClient.SecurityGroupsClient.RequestInspector = withInspection(maxlen) - azureClient.SecurityGroupsClient.ResponseInspector = byConcatDecorators(byInspecting(maxlen), errorCapture(azureClient)) - azureClient.SecurityGroupsClient.UserAgent = fmt.Sprintf("%s %s", useragent.String(version.AzurePluginVersion.FormattedVersion()), azureClient.SecurityGroupsClient.UserAgent) - - azureClient.PublicIPAddressesClient = network.NewPublicIPAddressesClientWithBaseURI(cloud.ResourceManagerEndpoint, subscriptionID) - azureClient.PublicIPAddressesClient.Authorizer = autorest.NewBearerAuthorizer(servicePrincipalToken) - azureClient.PublicIPAddressesClient.RequestInspector = withInspection(maxlen) - azureClient.PublicIPAddressesClient.ResponseInspector = byConcatDecorators(byInspecting(maxlen), errorCapture(azureClient)) - azureClient.PublicIPAddressesClient.UserAgent = fmt.Sprintf("%s %s", useragent.String(version.AzurePluginVersion.FormattedVersion()), azureClient.PublicIPAddressesClient.UserAgent) - azureClient.PublicIPAddressesClient.Client.PollingDuration = pollingDuration - - azureClient.VirtualMachinesClient = compute.NewVirtualMachinesClientWithBaseURI(cloud.ResourceManagerEndpoint, subscriptionID) - azureClient.VirtualMachinesClient.Authorizer = autorest.NewBearerAuthorizer(servicePrincipalToken) - azureClient.VirtualMachinesClient.RequestInspector = withInspection(maxlen) - azureClient.VirtualMachinesClient.ResponseInspector = byConcatDecorators(byInspecting(maxlen), templateCapture(azureClient), errorCapture(azureClient)) - azureClient.VirtualMachinesClient.UserAgent = fmt.Sprintf("%s %s", useragent.String(version.AzurePluginVersion.FormattedVersion()), azureClient.VirtualMachinesClient.UserAgent) - azureClient.VirtualMachinesClient.Client.PollingDuration = pollingDuration - - azureClient.SnapshotsClient = compute.NewSnapshotsClientWithBaseURI(cloud.ResourceManagerEndpoint, subscriptionID) - azureClient.SnapshotsClient.Authorizer = autorest.NewBearerAuthorizer(servicePrincipalToken) - azureClient.SnapshotsClient.RequestInspector = withInspection(maxlen) - azureClient.SnapshotsClient.ResponseInspector = byConcatDecorators(byInspecting(maxlen), errorCapture(azureClient)) - azureClient.SnapshotsClient.UserAgent = fmt.Sprintf("%s %s", useragent.String(version.AzurePluginVersion.FormattedVersion()), azureClient.SnapshotsClient.UserAgent) - azureClient.SnapshotsClient.Client.PollingDuration = pollingDuration - - azureClient.AccountsClient = armStorage.NewAccountsClientWithBaseURI(cloud.ResourceManagerEndpoint, subscriptionID) - azureClient.AccountsClient.Authorizer = autorest.NewBearerAuthorizer(servicePrincipalToken) - azureClient.AccountsClient.RequestInspector = withInspection(maxlen) - azureClient.AccountsClient.ResponseInspector = byConcatDecorators(byInspecting(maxlen), errorCapture(azureClient)) - azureClient.AccountsClient.UserAgent = fmt.Sprintf("%s %s", useragent.String(version.AzurePluginVersion.FormattedVersion()), azureClient.AccountsClient.UserAgent) - azureClient.AccountsClient.Client.PollingDuration = pollingDuration - - azureClient.GalleryImageVersionsClient = newCompute.NewGalleryImageVersionsClientWithBaseURI(cloud.ResourceManagerEndpoint, subscriptionID) - azureClient.GalleryImageVersionsClient.Authorizer = autorest.NewBearerAuthorizer(servicePrincipalToken) - azureClient.GalleryImageVersionsClient.RequestInspector = withInspection(maxlen) - azureClient.GalleryImageVersionsClient.ResponseInspector = byConcatDecorators(byInspecting(maxlen), errorCapture(azureClient)) - azureClient.GalleryImageVersionsClient.UserAgent = fmt.Sprintf("%s %s", useragent.String(version.AzurePluginVersion.FormattedVersion()), azureClient.GalleryImageVersionsClient.UserAgent) - azureClient.GalleryImageVersionsClient.Client.PollingDuration = sharedGalleryTimeout - if sigSubscriptionID != "" { - azureClient.GalleryImageVersionsClient.SubscriptionID = sigSubscriptionID - } - - azureClient.GalleryImagesClient = newCompute.NewGalleryImagesClientWithBaseURI(cloud.ResourceManagerEndpoint, subscriptionID) - azureClient.GalleryImagesClient.Authorizer = autorest.NewBearerAuthorizer(servicePrincipalToken) - azureClient.GalleryImagesClient.RequestInspector = withInspection(maxlen) - azureClient.GalleryImagesClient.ResponseInspector = byConcatDecorators(byInspecting(maxlen), errorCapture(azureClient)) - azureClient.GalleryImagesClient.UserAgent = fmt.Sprintf("%s %s", useragent.String(version.AzurePluginVersion.FormattedVersion()), azureClient.GalleryImagesClient.UserAgent) - azureClient.GalleryImagesClient.Client.PollingDuration = pollingDuration - if sigSubscriptionID != "" { - azureClient.GalleryImagesClient.SubscriptionID = sigSubscriptionID - } - - keyVaultURL, err := url.Parse(cloud.KeyVaultEndpoint) - if err != nil { - return nil, err - } - - azureClient.VaultClient = common.NewVaultClient(*keyVaultURL) - azureClient.VaultClient.Authorizer = autorest.NewBearerAuthorizer(servicePrincipalTokenVault) - azureClient.VaultClient.RequestInspector = withInspection(maxlen) - azureClient.VaultClient.ResponseInspector = byConcatDecorators(byInspecting(maxlen), errorCapture(azureClient)) - azureClient.VaultClient.UserAgent = fmt.Sprintf("%s %s", useragent.String(version.AzurePluginVersion.FormattedVersion()), azureClient.VaultClient.UserAgent) - azureClient.VaultClient.Client.PollingDuration = pollingDuration - - // This client is different than the above because it manages the vault - // itself rather than the contents of the vault. - azureClient.VaultClientDelete = keyvault.NewVaultsClient(subscriptionID) - azureClient.VaultClientDelete.Authorizer = autorest.NewBearerAuthorizer(servicePrincipalToken) - azureClient.VaultClientDelete.RequestInspector = withInspection(maxlen) - azureClient.VaultClientDelete.ResponseInspector = byConcatDecorators(byInspecting(maxlen), errorCapture(azureClient)) - azureClient.VaultClientDelete.UserAgent = fmt.Sprintf("%s %s", useragent.String(version.AzurePluginVersion.FormattedVersion()), azureClient.VaultClientDelete.UserAgent) - azureClient.VaultClientDelete.Client.PollingDuration = pollingDuration - - // If this is a managed disk build, this should be ignored. - if resourceGroupName != "" && storageAccountName != "" { - accountKeys, err := azureClient.AccountsClient.ListKeys(context.TODO(), 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() - } - - return azureClient, nil -} - -func getInspectorMaxLength() int64 { - value, ok := os.LookupEnv(EnvPackerLogAzureMaxLen) - if !ok { - return math.MaxInt64 - } - - i, err := strconv.ParseInt(value, 10, 64) - if err != nil { - return 0 - } - - if i < 0 { - return 0 - } - - return i -} diff --git a/builder/azure/arm/azure_error_response.go b/builder/azure/arm/azure_error_response.go deleted file mode 100644 index e8e50c9eb..000000000 --- a/builder/azure/arm/azure_error_response.go +++ /dev/null @@ -1,67 +0,0 @@ -package arm - -import ( - "bytes" - "encoding/json" - "fmt" -) - -type azureErrorDetails struct { - Code string `json:"code"` - Message string `json:"message"` - Details []azureErrorDetails `json:"details"` -} - -type azureErrorResponse struct { - ErrorDetails azureErrorDetails `json:"error"` -} - -func newAzureErrorResponse(s string) *azureErrorResponse { - var errorResponse azureErrorResponse - err := json.Unmarshal([]byte(s), &errorResponse) - if err == nil { - return &errorResponse - } - - return nil -} - -func (e *azureErrorDetails) isEmpty() bool { - return e.Code == "" -} - -func (e *azureErrorResponse) isEmpty() bool { - return e.ErrorDetails.isEmpty() -} - -func (e *azureErrorResponse) Error() string { - var buf bytes.Buffer - //buf.WriteString("-=-=- ERROR -=-=-") - formatAzureErrorResponse(e.ErrorDetails, &buf, "") - //buf.WriteString("-=-=- ERROR -=-=-") - return buf.String() -} - -// format a Azure Error Response by recursing through the JSON structure. -// -// Errors may contain nested errors, which are JSON documents that have been -// serialized and escaped. Keep following this nesting all the way down... -func formatAzureErrorResponse(error azureErrorDetails, buf *bytes.Buffer, indent string) { - if error.isEmpty() { - return - } - - buf.WriteString(fmt.Sprintf("ERROR: %s-> %s : %s\n", indent, error.Code, error.Message)) - for _, x := range error.Details { - newIndent := fmt.Sprintf("%s ", indent) - - var aer azureErrorResponse - err := json.Unmarshal([]byte(x.Message), &aer) - if err == nil { - buf.WriteString(fmt.Sprintf("ERROR: %s-> %s\n", newIndent, x.Code)) - formatAzureErrorResponse(aer.ErrorDetails, buf, newIndent) - } else { - buf.WriteString(fmt.Sprintf("ERROR: %s-> %s : %s\n", newIndent, x.Code, x.Message)) - } - } -} diff --git a/builder/azure/arm/azure_error_response_test.TestAzureErrorNestedShouldFormat.approved.txt b/builder/azure/arm/azure_error_response_test.TestAzureErrorNestedShouldFormat.approved.txt deleted file mode 100644 index 39d4deeec..000000000 --- a/builder/azure/arm/azure_error_response_test.TestAzureErrorNestedShouldFormat.approved.txt +++ /dev/null @@ -1,4 +0,0 @@ -ERROR: -> DeploymentFailed : At least one resource deployment operation failed. Please list deployment operations for details. Please see https://aka.ms/arm-debug for usage details. -ERROR: -> BadRequest -ERROR: -> InvalidRequestFormat : Cannot parse the request. -ERROR: -> InvalidJson : Error converting value "playground" to type 'Microsoft.WindowsAzure.Networking.Nrp.Frontend.Contract.Csm.Public.IpAllocationMethod'. Path 'properties.publicIPAllocationMethod', line 1, position 130. diff --git a/builder/azure/arm/azure_error_response_test.TestAzureErrorSimpleShouldFormat.approved.txt b/builder/azure/arm/azure_error_response_test.TestAzureErrorSimpleShouldFormat.approved.txt deleted file mode 100644 index 4b4834c62..000000000 --- a/builder/azure/arm/azure_error_response_test.TestAzureErrorSimpleShouldFormat.approved.txt +++ /dev/null @@ -1 +0,0 @@ -ERROR: -> ResourceNotFound : The Resource 'Microsoft.Compute/images/PackerUbuntuImage' under resource group 'packer-test00' was not found. diff --git a/builder/azure/arm/azure_error_response_test.go b/builder/azure/arm/azure_error_response_test.go deleted file mode 100644 index 91f03ed8d..000000000 --- a/builder/azure/arm/azure_error_response_test.go +++ /dev/null @@ -1,77 +0,0 @@ -package arm - -import ( - "strings" - "testing" - - approvaltests "github.com/approvals/go-approval-tests" - "github.com/hashicorp/packer-plugin-sdk/json" -) - -const AzureErrorSimple = `{"error":{"code":"ResourceNotFound","message":"The Resource 'Microsoft.Compute/images/PackerUbuntuImage' under resource group 'packer-test00' was not found."}}` -const AzureErrorNested = `{"status":"Failed","error":{"code":"DeploymentFailed","message":"At least one resource deployment operation failed. Please list deployment operations for details. Please see https://aka.ms/arm-debug for usage details.","details":[{"code":"BadRequest","message":"{\r\n \"error\": {\r\n \"code\": \"InvalidRequestFormat\",\r\n \"message\": \"Cannot parse the request.\",\r\n \"details\": [\r\n {\r\n \"code\": \"InvalidJson\",\r\n \"message\": \"Error converting value \\\"playground\\\" to type 'Microsoft.WindowsAzure.Networking.Nrp.Frontend.Contract.Csm.Public.IpAllocationMethod'. Path 'properties.publicIPAllocationMethod', line 1, position 130.\"\r\n }\r\n ]\r\n }\r\n}"}]}}` - -func TestAzureErrorSimpleShouldUnmarshal(t *testing.T) { - var azureErrorResponse azureErrorResponse - err := json.Unmarshal([]byte(AzureErrorSimple), &azureErrorResponse) - if err != nil { - t.Fatal(err) - } - - if azureErrorResponse.ErrorDetails.Code != "ResourceNotFound" { - t.Errorf("Error.Code") - } - if azureErrorResponse.ErrorDetails.Message != "The Resource 'Microsoft.Compute/images/PackerUbuntuImage' under resource group 'packer-test00' was not found." { - t.Errorf("Error.Message") - } -} - -func TestAzureErrorNestedShouldUnmarshal(t *testing.T) { - var azureError azureErrorResponse - err := json.Unmarshal([]byte(AzureErrorNested), &azureError) - if err != nil { - t.Fatal(err) - } - - if azureError.ErrorDetails.Code != "DeploymentFailed" { - t.Errorf("Error.Code") - } - if !strings.HasPrefix(azureError.ErrorDetails.Message, "At least one resource deployment operation failed") { - t.Errorf("Error.Message") - } -} - -func TestAzureErrorEmptyShouldFormat(t *testing.T) { - var aer azureErrorResponse - s := aer.Error() - - if s != "" { - t.Fatalf("Expected \"\", but got %s", aer.Error()) - } -} - -func TestAzureErrorSimpleShouldFormat(t *testing.T) { - var azureErrorResponse azureErrorResponse - err := json.Unmarshal([]byte(AzureErrorSimple), &azureErrorResponse) - if err != nil { - t.Fatal(err) - } - - err = approvaltests.VerifyString(t, azureErrorResponse.Error()) - if err != nil { - t.Fatal(err) - } -} - -func TestAzureErrorNestedShouldFormat(t *testing.T) { - var azureErrorResponse azureErrorResponse - err := json.Unmarshal([]byte(AzureErrorNested), &azureErrorResponse) - if err != nil { - t.Fatal(err) - } - - err = approvaltests.VerifyString(t, azureErrorResponse.Error()) - if err != nil { - t.Fatal(err) - } -} diff --git a/builder/azure/arm/builder.go b/builder/azure/arm/builder.go deleted file mode 100644 index a18434914..000000000 --- a/builder/azure/arm/builder.go +++ /dev/null @@ -1,496 +0,0 @@ -package arm - -import ( - "context" - "errors" - "fmt" - "log" - "os" - "runtime" - "strings" - "time" - - armstorage "github.com/Azure/azure-sdk-for-go/services/storage/mgmt/2017-10-01/storage" - "github.com/Azure/azure-sdk-for-go/storage" - "github.com/Azure/go-autorest/autorest/adal" - "github.com/dgrijalva/jwt-go" - "github.com/hashicorp/hcl/v2/hcldec" - "github.com/hashicorp/packer-plugin-sdk/communicator" - "github.com/hashicorp/packer-plugin-sdk/multistep" - "github.com/hashicorp/packer-plugin-sdk/multistep/commonsteps" - packersdk "github.com/hashicorp/packer-plugin-sdk/packer" - packerAzureCommon "github.com/hashicorp/packer/builder/azure/common" - "github.com/hashicorp/packer/builder/azure/common/constants" - "github.com/hashicorp/packer/builder/azure/common/lin" -) - -type Builder struct { - config Config - stateBag multistep.StateBag - runner multistep.Runner -} - -const ( - DefaultSasBlobContainer = "system/Microsoft.Compute" - DefaultSecretName = "packerKeyVaultSecret" -) - -func (b *Builder) ConfigSpec() hcldec.ObjectSpec { return b.config.FlatMapstructure().HCL2Spec() } - -func (b *Builder) Prepare(raws ...interface{}) ([]string, []string, error) { - warnings, errs := b.config.Prepare(raws...) - if errs != nil { - return nil, warnings, errs - } - - b.stateBag = new(multistep.BasicStateBag) - b.configureStateBag(b.stateBag) - b.setTemplateParameters(b.stateBag) - b.setImageParameters(b.stateBag) - - return nil, warnings, errs -} - -func (b *Builder) Run(ctx context.Context, ui packersdk.Ui, hook packersdk.Hook) (packersdk.Artifact, error) { - - ui.Say("Running builder ...") - - ctx, cancel := context.WithCancel(ctx) - defer cancel() - - // FillParameters function captures authType and sets defaults. - err := b.config.ClientConfig.FillParameters() - if err != nil { - return nil, err - } - - //When running Packer on an Azure instance using Managed Identity, FillParameters will update SubscriptionID from the instance - // so lets make sure to update our state bag with the valid subscriptionID. - if b.config.isManagedImage() && b.config.SharedGalleryDestination.SigDestinationGalleryName != "" { - b.stateBag.Put(constants.ArmManagedImageSubscription, b.config.ClientConfig.SubscriptionID) - } - - log.Print(":: Configuration") - packerAzureCommon.DumpConfig(&b.config, func(s string) { log.Print(s) }) - - b.stateBag.Put("hook", hook) - b.stateBag.Put(constants.Ui, ui) - - spnCloud, spnKeyVault, err := b.getServicePrincipalTokens(ui.Say) - if err != nil { - return nil, err - } - - ui.Message("Creating Azure Resource Manager (ARM) client ...") - azureClient, err := NewAzureClient( - b.config.ClientConfig.SubscriptionID, - b.config.SharedGalleryDestination.SigDestinationSubscription, - b.config.ResourceGroupName, - b.config.StorageAccount, - b.config.ClientConfig.CloudEnvironment(), - b.config.SharedGalleryTimeout, - b.config.PollingDurationTimeout, - spnCloud, - spnKeyVault) - - if err != nil { - return nil, err - } - - resolver := newResourceResolver(azureClient) - if err := resolver.Resolve(&b.config); err != nil { - return nil, err - } - if b.config.ClientConfig.ObjectID == "" { - b.config.ClientConfig.ObjectID = getObjectIdFromToken(ui, spnCloud) - } else { - ui.Message("You have provided Object_ID which is no longer needed, azure packer builder determines this dynamically from the authentication token") - } - - if b.config.ClientConfig.ObjectID == "" && b.config.OSType != constants.Target_Linux { - return nil, fmt.Errorf("could not determine the ObjectID for the user, which is required for Windows builds") - } - - if b.config.isManagedImage() { - _, err := azureClient.GroupsClient.Get(ctx, b.config.ManagedImageResourceGroupName) - if err != nil { - return nil, fmt.Errorf("Cannot locate the managed image resource group %s.", b.config.ManagedImageResourceGroupName) - } - - // If a managed image already exists it cannot be overwritten. - _, err = azureClient.ImagesClient.Get(ctx, b.config.ManagedImageResourceGroupName, b.config.ManagedImageName, "") - if err == nil { - if b.config.PackerForce { - ui.Say(fmt.Sprintf("the managed image named %s already exists, but deleting it due to -force flag", b.config.ManagedImageName)) - f, err := azureClient.ImagesClient.Delete(ctx, b.config.ManagedImageResourceGroupName, b.config.ManagedImageName) - if err == nil { - err = f.WaitForCompletionRef(ctx, azureClient.ImagesClient.Client) - } - if err != nil { - return nil, fmt.Errorf("failed to delete the managed image named %s : %s", b.config.ManagedImageName, azureClient.LastError.Error()) - } - } else { - return nil, fmt.Errorf("the managed image named %s already exists in the resource group %s, use the -force option to automatically delete it.", b.config.ManagedImageName, b.config.ManagedImageResourceGroupName) - } - } - } else { - // User is not using Managed Images to build, warning message here that this path is being deprecated - ui.Error("Warning: You are using Azure Packer Builder to create VHDs which is being deprecated, consider using Managed Images. Learn more https://www.packer.io/docs/builders/azure/arm#azure-arm-builder-specific-options") - } - - if b.config.BuildResourceGroupName != "" { - group, err := azureClient.GroupsClient.Get(ctx, b.config.BuildResourceGroupName) - if err != nil { - return nil, fmt.Errorf("Cannot locate the existing build resource resource group %s.", b.config.BuildResourceGroupName) - } - - b.config.Location = *group.Location - } - - b.config.validateLocationZoneResiliency(ui.Say) - - if b.config.StorageAccount != "" { - account, err := b.getBlobAccount(ctx, azureClient, b.config.ResourceGroupName, b.config.StorageAccount) - if err != nil { - return nil, err - } - b.config.storageAccountBlobEndpoint = *account.AccountProperties.PrimaryEndpoints.Blob - - 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 - if b.isPublicPrivateNetworkCommunication() && b.isPrivateNetworkCommunication() { - endpointConnectType = PublicEndpointInPrivateNetwork - } else if b.isPrivateNetworkCommunication() { - endpointConnectType = PrivateEndpoint - } - - b.setRuntimeParameters(b.stateBag) - b.setTemplateParameters(b.stateBag) - b.setImageParameters(b.stateBag) - - deploymentName := b.stateBag.Get(constants.ArmDeploymentName).(string) - - // For Managed Images, validate that Shared Gallery Image exists before publishing to SIG - if b.config.isManagedImage() && b.config.SharedGalleryDestination.SigDestinationGalleryName != "" { - _, err = azureClient.GalleryImagesClient.Get(ctx, b.config.SharedGalleryDestination.SigDestinationResourceGroup, b.config.SharedGalleryDestination.SigDestinationGalleryName, b.config.SharedGalleryDestination.SigDestinationImageName) - if err != nil { - return nil, fmt.Errorf("the Shared Gallery Image to which to publish the managed image version to does not exist in the resource group %s", b.config.SharedGalleryDestination.SigDestinationResourceGroup) - } - // SIG requires that replication regions include the region in which the Managed Image resides - managedImageLocation := normalizeAzureRegion(b.stateBag.Get(constants.ArmLocation).(string)) - foundMandatoryReplicationRegion := false - var normalizedReplicationRegions []string - for _, region := range b.config.SharedGalleryDestination.SigDestinationReplicationRegions { - // change region to lower-case and strip spaces - normalizedRegion := normalizeAzureRegion(region) - normalizedReplicationRegions = append(normalizedReplicationRegions, normalizedRegion) - if strings.EqualFold(normalizedRegion, managedImageLocation) { - foundMandatoryReplicationRegion = true - continue - } - } - if foundMandatoryReplicationRegion == false { - b.config.SharedGalleryDestination.SigDestinationReplicationRegions = append(normalizedReplicationRegions, managedImageLocation) - } - b.stateBag.Put(constants.ArmManagedImageSharedGalleryReplicationRegions, b.config.SharedGalleryDestination.SigDestinationReplicationRegions) - } - - var steps []multistep.Step - if b.config.OSType == constants.Target_Linux { - steps = []multistep.Step{ - NewStepCreateResourceGroup(azureClient, ui), - NewStepValidateTemplate(azureClient, ui, &b.config, GetVirtualMachineDeployment), - NewStepDeployTemplate(azureClient, ui, &b.config, deploymentName, GetVirtualMachineDeployment), - NewStepGetIPAddress(azureClient, ui, endpointConnectType), - &communicator.StepConnectSSH{ - Config: &b.config.Comm, - Host: lin.SSHHost, - SSHConfig: b.config.Comm.SSHConfigFunc(), - }, - &commonsteps.StepProvision{}, - &commonsteps.StepCleanupTempKeys{ - Comm: &b.config.Comm, - }, - NewStepGetOSDisk(azureClient, ui), - NewStepGetAdditionalDisks(azureClient, ui), - NewStepPowerOffCompute(azureClient, ui), - NewStepSnapshotOSDisk(azureClient, ui, &b.config), - NewStepSnapshotDataDisks(azureClient, ui, &b.config), - NewStepCaptureImage(azureClient, ui), - NewStepPublishToSharedImageGallery(azureClient, ui, &b.config), - } - } else if b.config.OSType == constants.Target_Windows { - steps = []multistep.Step{ - NewStepCreateResourceGroup(azureClient, ui), - } - if b.config.BuildKeyVaultName == "" { - keyVaultDeploymentName := b.stateBag.Get(constants.ArmKeyVaultDeploymentName).(string) - steps = append(steps, - NewStepValidateTemplate(azureClient, ui, &b.config, GetKeyVaultDeployment), - NewStepDeployTemplate(azureClient, ui, &b.config, keyVaultDeploymentName, GetKeyVaultDeployment), - ) - } else { - steps = append(steps, NewStepCertificateInKeyVault(&azureClient.VaultClient, ui, &b.config)) - } - steps = append(steps, - NewStepGetCertificate(azureClient, ui), - NewStepSetCertificate(&b.config, ui), - NewStepValidateTemplate(azureClient, ui, &b.config, GetVirtualMachineDeployment), - NewStepDeployTemplate(azureClient, ui, &b.config, deploymentName, GetVirtualMachineDeployment), - NewStepGetIPAddress(azureClient, ui, endpointConnectType), - &communicator.StepConnectWinRM{ - Config: &b.config.Comm, - Host: func(stateBag multistep.StateBag) (string, error) { - return stateBag.Get(constants.SSHHost).(string), nil - }, - WinRMConfig: func(multistep.StateBag) (*communicator.WinRMConfig, error) { - return &communicator.WinRMConfig{ - Username: b.config.UserName, - Password: b.config.Password, - }, nil - }, - }, - &commonsteps.StepProvision{}, - NewStepGetOSDisk(azureClient, ui), - NewStepGetAdditionalDisks(azureClient, ui), - NewStepPowerOffCompute(azureClient, ui), - NewStepSnapshotOSDisk(azureClient, ui, &b.config), - NewStepSnapshotDataDisks(azureClient, ui, &b.config), - NewStepCaptureImage(azureClient, ui), - NewStepPublishToSharedImageGallery(azureClient, ui, &b.config), - ) - } else { - return nil, fmt.Errorf("Builder does not support the os_type '%s'", b.config.OSType) - } - - if b.config.PackerDebug { - ui.Message(fmt.Sprintf("temp admin user: '%s'", b.config.UserName)) - ui.Message(fmt.Sprintf("temp admin password: '%s'", b.config.Password)) - - if len(b.config.Comm.SSHPrivateKey) != 0 { - debugKeyPath := fmt.Sprintf("%s-%s.pem", b.config.PackerBuildName, b.config.tmpComputeName) - ui.Message(fmt.Sprintf("temp ssh key: %s", debugKeyPath)) - - b.writeSSHPrivateKey(ui, debugKeyPath) - } - } - - b.runner = commonsteps.NewRunner(steps, b.config.PackerConfig, ui) - b.runner.Run(ctx, b.stateBag) - - // Report any errors. - if rawErr, ok := b.stateBag.GetOk(constants.Error); ok { - return nil, rawErr.(error) - } - - // If we were interrupted or cancelled, then just exit. - if _, ok := b.stateBag.GetOk(multistep.StateCancelled); ok { - return nil, errors.New("Build was cancelled.") - } - - if _, ok := b.stateBag.GetOk(multistep.StateHalted); ok { - return nil, errors.New("Build was halted.") - } - - getSasUrlFunc := func(name string) string { - blob := azureClient.BlobStorageClient.GetContainerReference(DefaultSasBlobContainer).GetBlobReference(name) - options := storage.BlobSASOptions{} - options.BlobServiceSASPermissions.Read = true - options.Expiry = time.Now().AddDate(0, 1, 0).UTC() // one month - sasUrl, _ := blob.GetSASURI(options) - return sasUrl - } - - generatedData := map[string]interface{}{"generated_data": b.stateBag.Get("generated_data")} - if b.config.isManagedImage() { - managedImageID := fmt.Sprintf("/subscriptions/%s/resourceGroups/%s/providers/Microsoft.Compute/images/%s", - b.config.ClientConfig.SubscriptionID, b.config.ManagedImageResourceGroupName, b.config.ManagedImageName) - if b.config.SharedGalleryDestination.SigDestinationGalleryName != "" { - return NewManagedImageArtifactWithSIGAsDestination(b.config.OSType, - b.config.ManagedImageResourceGroupName, - b.config.ManagedImageName, - b.config.Location, - managedImageID, - b.config.ManagedImageOSDiskSnapshotName, - b.config.ManagedImageDataDiskSnapshotPrefix, - b.stateBag.Get(constants.ArmManagedImageSharedGalleryId).(string), - generatedData) - } else if template, ok := b.stateBag.GetOk(constants.ArmCaptureTemplate); ok { - return NewManagedImageArtifact(b.config.OSType, - b.config.ManagedImageResourceGroupName, - b.config.ManagedImageName, - b.config.Location, - managedImageID, - b.config.ManagedImageOSDiskSnapshotName, - b.config.ManagedImageDataDiskSnapshotPrefix, - generatedData, - b.stateBag.Get(constants.ArmKeepOSDisk).(bool), - template.(*CaptureTemplate), - getSasUrlFunc) - } - return NewManagedImageArtifact(b.config.OSType, - b.config.ManagedImageResourceGroupName, - b.config.ManagedImageName, - b.config.Location, - managedImageID, - b.config.ManagedImageOSDiskSnapshotName, - b.config.ManagedImageDataDiskSnapshotPrefix, - generatedData, - b.stateBag.Get(constants.ArmKeepOSDisk).(bool), - nil, - getSasUrlFunc) - } else if template, ok := b.stateBag.GetOk(constants.ArmCaptureTemplate); ok { - return NewArtifact( - template.(*CaptureTemplate), - getSasUrlFunc, - b.config.OSType, - generatedData) - } - - return &Artifact{ - StateData: generatedData, - }, nil -} - -func (b *Builder) writeSSHPrivateKey(ui packersdk.Ui, debugKeyPath string) { - f, err := os.Create(debugKeyPath) - if err != nil { - ui.Say(fmt.Sprintf("Error saving debug key: %s", err)) - } - defer f.Close() - - // Write the key out - if _, err := f.Write(b.config.Comm.SSHPrivateKey); err != nil { - ui.Say(fmt.Sprintf("Error saving debug key: %s", err)) - return - } - - // Chmod it so that it is SSH ready - if runtime.GOOS != "windows" { - if err := f.Chmod(0600); err != nil { - ui.Say(fmt.Sprintf("Error setting permissions of debug key: %s", err)) - } - } -} - -func (b *Builder) isPublicPrivateNetworkCommunication() bool { - return DefaultPrivateVirtualNetworkWithPublicIp != b.config.PrivateVirtualNetworkWithPublicIp -} - -func (b *Builder) isPrivateNetworkCommunication() bool { - return b.config.VirtualNetworkName != "" -} - -func equalLocation(location1, location2 string) bool { - return strings.EqualFold(canonicalizeLocation(location1), canonicalizeLocation(location2)) -} - -func canonicalizeLocation(location string) string { - return strings.Replace(location, " ", "", -1) -} - -func (b *Builder) getBlobAccount(ctx context.Context, client *AzureClient, resourceGroupName string, storageAccountName string) (*armstorage.Account, error) { - account, err := client.AccountsClient.GetProperties(ctx, resourceGroupName, storageAccountName) - if err != nil { - return nil, err - } - - return &account, err -} - -func (b *Builder) configureStateBag(stateBag multistep.StateBag) { - stateBag.Put(constants.AuthorizedKey, b.config.sshAuthorizedKey) - - stateBag.Put(constants.ArmTags, packerAzureCommon.MapToAzureTags(b.config.AzureTags)) - stateBag.Put(constants.ArmComputeName, b.config.tmpComputeName) - stateBag.Put(constants.ArmDeploymentName, b.config.tmpDeploymentName) - - if b.config.OSType == constants.Target_Windows && b.config.BuildKeyVaultName == "" { - stateBag.Put(constants.ArmKeyVaultDeploymentName, fmt.Sprintf("kv%s", b.config.tmpDeploymentName)) - } - - stateBag.Put(constants.ArmKeyVaultName, b.config.tmpKeyVaultName) - stateBag.Put(constants.ArmIsExistingKeyVault, false) - if b.config.BuildKeyVaultName != "" { - stateBag.Put(constants.ArmKeyVaultName, b.config.BuildKeyVaultName) - b.config.tmpKeyVaultName = b.config.BuildKeyVaultName - stateBag.Put(constants.ArmIsExistingKeyVault, true) - } - - stateBag.Put(constants.ArmNicName, b.config.tmpNicName) - stateBag.Put(constants.ArmPublicIPAddressName, b.config.tmpPublicIPAddressName) - stateBag.Put(constants.ArmResourceGroupName, b.config.BuildResourceGroupName) - stateBag.Put(constants.ArmIsExistingResourceGroup, true) - - if b.config.tmpResourceGroupName != "" { - stateBag.Put(constants.ArmResourceGroupName, b.config.tmpResourceGroupName) - stateBag.Put(constants.ArmIsExistingResourceGroup, false) - - if b.config.BuildResourceGroupName != "" { - stateBag.Put(constants.ArmDoubleResourceGroupNameSet, true) - } - } - - stateBag.Put(constants.ArmStorageAccountName, b.config.StorageAccount) - stateBag.Put(constants.ArmIsManagedImage, b.config.isManagedImage()) - stateBag.Put(constants.ArmManagedImageResourceGroupName, b.config.ManagedImageResourceGroupName) - stateBag.Put(constants.ArmManagedImageName, b.config.ManagedImageName) - stateBag.Put(constants.ArmManagedImageOSDiskSnapshotName, b.config.ManagedImageOSDiskSnapshotName) - stateBag.Put(constants.ArmManagedImageDataDiskSnapshotPrefix, b.config.ManagedImageDataDiskSnapshotPrefix) - stateBag.Put(constants.ArmAsyncResourceGroupDelete, b.config.AsyncResourceGroupDelete) - stateBag.Put(constants.ArmKeepOSDisk, b.config.KeepOSDisk) - - if b.config.isManagedImage() && b.config.SharedGalleryDestination.SigDestinationGalleryName != "" { - stateBag.Put(constants.ArmManagedImageSigPublishResourceGroup, b.config.SharedGalleryDestination.SigDestinationResourceGroup) - stateBag.Put(constants.ArmManagedImageSharedGalleryName, b.config.SharedGalleryDestination.SigDestinationGalleryName) - stateBag.Put(constants.ArmManagedImageSharedGalleryImageName, b.config.SharedGalleryDestination.SigDestinationImageName) - stateBag.Put(constants.ArmManagedImageSharedGalleryImageVersion, b.config.SharedGalleryDestination.SigDestinationImageVersion) - stateBag.Put(constants.ArmManagedImageSharedGalleryImageVersionStorageAccountType, b.config.SharedGalleryDestination.SigDestinationStorageAccountType) - stateBag.Put(constants.ArmManagedImageSubscription, b.config.ClientConfig.SubscriptionID) - stateBag.Put(constants.ArmManagedImageSharedGalleryImageVersionEndOfLifeDate, b.config.SharedGalleryImageVersionEndOfLifeDate) - stateBag.Put(constants.ArmManagedImageSharedGalleryImageVersionReplicaCount, b.config.SharedGalleryImageVersionReplicaCount) - stateBag.Put(constants.ArmManagedImageSharedGalleryImageVersionExcludeFromLatest, b.config.SharedGalleryImageVersionExcludeFromLatest) - } -} - -// Parameters that are only known at runtime after querying Azure. -func (b *Builder) setRuntimeParameters(stateBag multistep.StateBag) { - stateBag.Put(constants.ArmLocation, b.config.Location) -} - -func (b *Builder) setTemplateParameters(stateBag multistep.StateBag) { - stateBag.Put(constants.ArmVirtualMachineCaptureParameters, b.config.toVirtualMachineCaptureParameters()) -} - -func (b *Builder) setImageParameters(stateBag multistep.StateBag) { - stateBag.Put(constants.ArmImageParameters, b.config.toImageParameters()) -} - -func (b *Builder) getServicePrincipalTokens(say func(string)) (*adal.ServicePrincipalToken, *adal.ServicePrincipalToken, error) { - return b.config.ClientConfig.GetServicePrincipalTokens(say) -} - -func getObjectIdFromToken(ui packersdk.Ui, token *adal.ServicePrincipalToken) string { - claims := jwt.MapClaims{} - var p jwt.Parser - - var err error - - _, _, err = p.ParseUnverified(token.OAuthToken(), claims) - - if err != nil { - ui.Error(fmt.Sprintf("Failed to parse the token,Error: %s", err.Error())) - return "" - } - - oid, _ := claims["oid"].(string) - return oid -} - -func normalizeAzureRegion(name string) string { - return strings.ToLower(strings.Replace(name, " ", "", -1)) -} diff --git a/builder/azure/arm/builder_acc_test.go b/builder/azure/arm/builder_acc_test.go deleted file mode 100644 index d9a48117a..000000000 --- a/builder/azure/arm/builder_acc_test.go +++ /dev/null @@ -1,513 +0,0 @@ -package arm - -// these tests require the following variables to be set, -// although some test will only use a subset: -// -// * ARM_CLIENT_ID -// * ARM_CLIENT_SECRET -// * ARM_SUBSCRIPTION_ID -// * ARM_STORAGE_ACCOUNT -// -// The subscription in question should have a resource group -// called "packer-acceptance-test" in "South Central US" region. The -// storage account referred to in the above variable should -// be inside this resource group and in "South Central US" as well. -// -// In addition, the PACKER_ACC variable should also be set to -// a non-empty value to enable Packer acceptance tests and the -// options "-v -timeout 90m" should be provided to the test -// command, e.g.: -// go test -v -timeout 90m -run TestBuilderAcc_.* - -import ( - "bytes" - "context" - "errors" - "fmt" - "os" - "strings" - "testing" - - "github.com/Azure/go-autorest/autorest" - "github.com/Azure/go-autorest/autorest/azure/auth" - packersdk "github.com/hashicorp/packer-plugin-sdk/packer" - builderT "github.com/hashicorp/packer/acctest" -) - -const DeviceLoginAcceptanceTest = "DEVICELOGIN_TEST" - -func TestBuilderAcc_ManagedDisk_Windows(t *testing.T) { - builderT.Test(t, builderT.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Builder: &Builder{}, - Template: testBuilderAccManagedDiskWindows, - }) -} - -func TestBuilderAcc_ManagedDisk_Windows_Build_Resource_Group(t *testing.T) { - builderT.Test(t, builderT.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Builder: &Builder{}, - Template: testBuilderAccManagedDiskWindowsBuildResourceGroup, - }) -} - -func TestBuilderAcc_ManagedDisk_Windows_Build_Resource_Group_Additional_Disk(t *testing.T) { - builderT.Test(t, builderT.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Builder: &Builder{}, - Template: testBuilderAccManagedDiskWindowsBuildResourceGroupAdditionalDisk, - }) -} - -func TestBuilderAcc_ManagedDisk_Windows_DeviceLogin(t *testing.T) { - if os.Getenv(DeviceLoginAcceptanceTest) == "" { - t.Skip(fmt.Sprintf( - "Device Login Acceptance tests skipped unless env '%s' set, as its requires manual step during execution", - DeviceLoginAcceptanceTest)) - return - } - builderT.Test(t, builderT.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Builder: &Builder{}, - Template: testBuilderAccManagedDiskWindowsDeviceLogin, - }) -} - -func TestBuilderAcc_ManagedDisk_Linux(t *testing.T) { - builderT.Test(t, builderT.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Builder: &Builder{}, - Template: testBuilderAccManagedDiskLinux, - }) -} - -func TestBuilderAcc_ManagedDisk_Linux_DeviceLogin(t *testing.T) { - if os.Getenv(DeviceLoginAcceptanceTest) == "" { - t.Skip(fmt.Sprintf( - "Device Login Acceptance tests skipped unless env '%s' set, as its requires manual step during execution", - DeviceLoginAcceptanceTest)) - return - } - builderT.Test(t, builderT.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Builder: &Builder{}, - Template: testBuilderAccManagedDiskLinuxDeviceLogin, - }) -} - -func TestBuilderAcc_ManagedDisk_Linux_AzureCLI(t *testing.T) { - if os.Getenv("AZURE_CLI_AUTH") == "" { - t.Skip("Azure CLI Acceptance tests skipped unless env 'AZURE_CLI_AUTH' is set, and an active `az login` session has been established") - return - } - - var b Builder - builderT.Test(t, builderT.TestCase{ - PreCheck: func() { testAuthPreCheck(t) }, - Builder: &b, - Template: testBuilderAccManagedDiskLinuxAzureCLI, - Check: func([]packersdk.Artifact) error { - checkTemporaryGroupDeleted(t, &b) - return nil - }, - }) -} - -func TestBuilderAcc_Blob_Windows(t *testing.T) { - builderT.Test(t, builderT.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Builder: &Builder{}, - Template: testBuilderAccBlobWindows, - }) -} - -func TestBuilderAcc_Blob_Linux(t *testing.T) { - var b Builder - builderT.Test(t, builderT.TestCase{ - PreCheck: func() { testAuthPreCheck(t) }, - Builder: &b, - Template: testBuilderAccBlobLinux, - Check: func([]packersdk.Artifact) error { - checkUnmanagedVHDDeleted(t, &b) - return nil - }, - }) -} - -func testAccPreCheck(*testing.T) {} - -func testAuthPreCheck(t *testing.T) { - _, err := auth.NewAuthorizerFromEnvironment() - if err != nil { - t.Fatalf("failed to auth to azure: %s", err) - } -} - -func checkTemporaryGroupDeleted(t *testing.T, b *Builder) { - ui := testUi() - - spnCloud, spnKeyVault, err := b.getServicePrincipalTokens(ui.Say) - if err != nil { - t.Fatalf("failed getting azure tokens: %s", err) - } - - ui.Message("Creating test Azure Resource Manager (ARM) client ...") - azureClient, err := NewAzureClient( - b.config.ClientConfig.SubscriptionID, - b.config.SharedGalleryDestination.SigDestinationSubscription, - b.config.ResourceGroupName, - b.config.StorageAccount, - b.config.ClientConfig.CloudEnvironment(), - b.config.SharedGalleryTimeout, - b.config.PollingDurationTimeout, - spnCloud, - spnKeyVault) - - if err != nil { - t.Fatalf("failed to create azure client: %s", err) - } - - // Validate resource group has been deleted - _, err = azureClient.GroupsClient.Get(context.Background(), b.config.tmpResourceGroupName) - if err == nil || !resourceNotFound(err) { - t.Fatalf("failed validating resource group deletion: %s", err) - } -} - -func checkUnmanagedVHDDeleted(t *testing.T, b *Builder) { - ui := testUi() - - spnCloud, spnKeyVault, err := b.getServicePrincipalTokens(ui.Say) - if err != nil { - t.Fatalf("failed getting azure tokens: %s", err) - } - - azureClient, err := NewAzureClient( - b.config.ClientConfig.SubscriptionID, - b.config.SharedGalleryDestination.SigDestinationSubscription, - b.config.ResourceGroupName, - b.config.StorageAccount, - b.config.ClientConfig.CloudEnvironment(), - b.config.SharedGalleryTimeout, - b.config.PollingDurationTimeout, - spnCloud, - spnKeyVault) - - if err != nil { - t.Fatalf("failed to create azure client: %s", err) - } - - // validate temporary os blob was deleted - blob := azureClient.BlobStorageClient.GetContainerReference("images").GetBlobReference(b.config.tmpOSDiskName) - _, err = blob.BreakLease(nil) - if err != nil && !strings.Contains(err.Error(), "BlobNotFound") { - t.Fatalf("failed validating deletion of unmanaged vhd: %s", err) - } - - // Validate resource group has been deleted - _, err = azureClient.GroupsClient.Get(context.Background(), b.config.tmpResourceGroupName) - if err == nil || !resourceNotFound(err) { - t.Fatalf("failed validating resource group deletion: %s", err) - } -} - -func resourceNotFound(err error) bool { - derr := autorest.DetailedError{} - return errors.As(err, &derr) && derr.StatusCode == 404 -} - -func testUi() *packersdk.BasicUi { - return &packersdk.BasicUi{ - Reader: new(bytes.Buffer), - Writer: new(bytes.Buffer), - ErrorWriter: new(bytes.Buffer), - } -} - -const testBuilderAccManagedDiskWindows = ` -{ - "variables": { - "client_id": "{{env ` + "`ARM_CLIENT_ID`" + `}}", - "client_secret": "{{env ` + "`ARM_CLIENT_SECRET`" + `}}", - "subscription_id": "{{env ` + "`ARM_SUBSCRIPTION_ID`" + `}}" - }, - "builders": [{ - "type": "test", - - "client_id": "{{user ` + "`client_id`" + `}}", - "client_secret": "{{user ` + "`client_secret`" + `}}", - "subscription_id": "{{user ` + "`subscription_id`" + `}}", - - "managed_image_resource_group_name": "packer-acceptance-test", - "managed_image_name": "testBuilderAccManagedDiskWindows-{{timestamp}}", - - "os_type": "Windows", - "image_publisher": "MicrosoftWindowsServer", - "image_offer": "WindowsServer", - "image_sku": "2012-R2-Datacenter", - - "communicator": "winrm", - "winrm_use_ssl": "true", - "winrm_insecure": "true", - "winrm_timeout": "3m", - "winrm_username": "packer", - "async_resourcegroup_delete": "true", - - "location": "South Central US", - "vm_size": "Standard_DS2_v2" - }] -} -` - -const testBuilderAccManagedDiskWindowsBuildResourceGroup = ` -{ - "variables": { - "client_id": "{{env ` + "`ARM_CLIENT_ID`" + `}}", - "client_secret": "{{env ` + "`ARM_CLIENT_SECRET`" + `}}", - "subscription_id": "{{env ` + "`ARM_SUBSCRIPTION_ID`" + `}}" - }, - "builders": [{ - "type": "test", - - "client_id": "{{user ` + "`client_id`" + `}}", - "client_secret": "{{user ` + "`client_secret`" + `}}", - "subscription_id": "{{user ` + "`subscription_id`" + `}}", - - "build_resource_group_name" : "packer-acceptance-test", - "managed_image_resource_group_name": "packer-acceptance-test", - "managed_image_name": "testBuilderAccManagedDiskWindowsBuildResourceGroup-{{timestamp}}", - - "os_type": "Windows", - "image_publisher": "MicrosoftWindowsServer", - "image_offer": "WindowsServer", - "image_sku": "2012-R2-Datacenter", - - "communicator": "winrm", - "winrm_use_ssl": "true", - "winrm_insecure": "true", - "winrm_timeout": "3m", - "winrm_username": "packer", - "async_resourcegroup_delete": "true", - - "vm_size": "Standard_DS2_v2" - }] -} -` - -const testBuilderAccManagedDiskWindowsBuildResourceGroupAdditionalDisk = ` -{ - "variables": { - "client_id": "{{env ` + "`ARM_CLIENT_ID`" + `}}", - "client_secret": "{{env ` + "`ARM_CLIENT_SECRET`" + `}}", - "subscription_id": "{{env ` + "`ARM_SUBSCRIPTION_ID`" + `}}" - }, - "builders": [{ - "type": "test", - - "client_id": "{{user ` + "`client_id`" + `}}", - "client_secret": "{{user ` + "`client_secret`" + `}}", - "subscription_id": "{{user ` + "`subscription_id`" + `}}", - - "build_resource_group_name" : "packer-acceptance-test", - "managed_image_resource_group_name": "packer-acceptance-test", - "managed_image_name": "testBuilderAccManagedDiskWindowsBuildResourceGroupAdditionDisk-{{timestamp}}", - - "os_type": "Windows", - "image_publisher": "MicrosoftWindowsServer", - "image_offer": "WindowsServer", - "image_sku": "2012-R2-Datacenter", - - "communicator": "winrm", - "winrm_use_ssl": "true", - "winrm_insecure": "true", - "winrm_timeout": "3m", - "winrm_username": "packer", - "async_resourcegroup_delete": "true", - - "vm_size": "Standard_DS2_v2", - "disk_additional_size": [10,15] - }] -} -` - -const testBuilderAccManagedDiskWindowsDeviceLogin = ` -{ - "variables": { - "subscription_id": "{{env ` + "`ARM_SUBSCRIPTION_ID`" + `}}" - }, - "builders": [{ - "type": "test", - - "subscription_id": "{{user ` + "`subscription_id`" + `}}", - - "managed_image_resource_group_name": "packer-acceptance-test", - "managed_image_name": "testBuilderAccManagedDiskWindowsDeviceLogin-{{timestamp}}", - - "os_type": "Windows", - "image_publisher": "MicrosoftWindowsServer", - "image_offer": "WindowsServer", - "image_sku": "2012-R2-Datacenter", - - "communicator": "winrm", - "winrm_use_ssl": "true", - "winrm_insecure": "true", - "winrm_timeout": "3m", - "winrm_username": "packer", - - "location": "South Central US", - "vm_size": "Standard_DS2_v2" - }] -} -` - -const testBuilderAccManagedDiskLinux = ` -{ - "variables": { - "client_id": "{{env ` + "`ARM_CLIENT_ID`" + `}}", - "client_secret": "{{env ` + "`ARM_CLIENT_SECRET`" + `}}", - "subscription_id": "{{env ` + "`ARM_SUBSCRIPTION_ID`" + `}}" - }, - "builders": [{ - "type": "test", - - "client_id": "{{user ` + "`client_id`" + `}}", - "client_secret": "{{user ` + "`client_secret`" + `}}", - "subscription_id": "{{user ` + "`subscription_id`" + `}}", - - "managed_image_resource_group_name": "packer-acceptance-test", - "managed_image_name": "testBuilderAccManagedDiskLinux-{{timestamp}}", - - "os_type": "Linux", - "image_publisher": "Canonical", - "image_offer": "UbuntuServer", - "image_sku": "16.04-LTS", - - "location": "South Central US", - "vm_size": "Standard_DS2_v2", - "azure_tags": { - "env": "testing", - "builder": "packer" - } - }] -} -` - -const testBuilderAccManagedDiskLinuxDeviceLogin = ` -{ - "variables": { - "subscription_id": "{{env ` + "`ARM_SUBSCRIPTION_ID`" + `}}" - }, - "builders": [{ - "type": "test", - - "subscription_id": "{{user ` + "`subscription_id`" + `}}", - - "managed_image_resource_group_name": "packer-acceptance-test", - "managed_image_name": "testBuilderAccManagedDiskLinuxDeviceLogin-{{timestamp}}", - - "os_type": "Linux", - "image_publisher": "Canonical", - "image_offer": "UbuntuServer", - "image_sku": "16.04-LTS", - "async_resourcegroup_delete": "true", - - "location": "South Central US", - "vm_size": "Standard_DS2_v2" - }] -} -` - -const testBuilderAccBlobWindows = ` -{ - "variables": { - "client_id": "{{env ` + "`ARM_CLIENT_ID`" + `}}", - "client_secret": "{{env ` + "`ARM_CLIENT_SECRET`" + `}}", - "subscription_id": "{{env ` + "`ARM_SUBSCRIPTION_ID`" + `}}", - "storage_account": "{{env ` + "`ARM_STORAGE_ACCOUNT`" + `}}" - }, - "builders": [{ - "type": "test", - - "client_id": "{{user ` + "`client_id`" + `}}", - "client_secret": "{{user ` + "`client_secret`" + `}}", - "subscription_id": "{{user ` + "`subscription_id`" + `}}", - - "storage_account": "{{user ` + "`storage_account`" + `}}", - "resource_group_name": "packer-acceptance-test", - "capture_container_name": "test", - "capture_name_prefix": "testBuilderAccBlobWin", - - "os_type": "Windows", - "image_publisher": "MicrosoftWindowsServer", - "image_offer": "WindowsServer", - "image_sku": "2012-R2-Datacenter", - - "communicator": "winrm", - "winrm_use_ssl": "true", - "winrm_insecure": "true", - "winrm_timeout": "3m", - "winrm_username": "packer", - - "location": "South Central US", - "vm_size": "Standard_DS2_v2" - }] -} -` - -const testBuilderAccBlobLinux = ` -{ - "variables": { - "client_id": "{{env ` + "`ARM_CLIENT_ID`" + `}}", - "client_secret": "{{env ` + "`ARM_CLIENT_SECRET`" + `}}", - "subscription_id": "{{env ` + "`ARM_SUBSCRIPTION_ID`" + `}}", - "storage_account": "{{env ` + "`ARM_STORAGE_ACCOUNT`" + `}}" - }, - "builders": [{ - "type": "test", - - "client_id": "{{user ` + "`client_id`" + `}}", - "client_secret": "{{user ` + "`client_secret`" + `}}", - "subscription_id": "{{user ` + "`subscription_id`" + `}}", - - "storage_account": "{{user ` + "`storage_account`" + `}}", - "resource_group_name": "packer-acceptance-test", - "capture_container_name": "test", - "capture_name_prefix": "testBuilderAccBlobLinux", - - "os_type": "Linux", - "image_publisher": "Canonical", - "image_offer": "UbuntuServer", - "image_sku": "16.04-LTS", - - "location": "South Central US", - "vm_size": "Standard_DS2_v2" - }] -} -` - -const testBuilderAccManagedDiskLinuxAzureCLI = ` -{ - "builders": [{ - "type": "test", - - "use_azure_cli_auth": true, - - "managed_image_resource_group_name": "packer-acceptance-test", - "managed_image_name": "testBuilderAccManagedDiskLinuxAzureCLI-{{timestamp}}", - "temp_resource_group_name": "packer-acceptance-test-managed-cli", - - "os_type": "Linux", - "image_publisher": "Canonical", - "image_offer": "UbuntuServer", - "image_sku": "16.04-LTS", - - "location": "South Central US", - "vm_size": "Standard_DS2_v2", - "azure_tags": { - "env": "testing", - "builder": "packer" - } - }] -} -` diff --git a/builder/azure/arm/builder_test.go b/builder/azure/arm/builder_test.go deleted file mode 100644 index 3f4bb77c0..000000000 --- a/builder/azure/arm/builder_test.go +++ /dev/null @@ -1,67 +0,0 @@ -package arm - -import ( - "testing" - - "github.com/hashicorp/packer/builder/azure/common/constants" -) - -func TestStateBagShouldBePopulatedExpectedValues(t *testing.T) { - var testSubject Builder - _, _, err := testSubject.Prepare(getArmBuilderConfiguration(), getPackerConfiguration()) - if err != nil { - t.Fatalf("failed to prepare: %s", err) - } - - var expectedStateBagKeys = []string{ - constants.AuthorizedKey, - - constants.ArmTags, - constants.ArmComputeName, - constants.ArmDeploymentName, - constants.ArmNicName, - constants.ArmResourceGroupName, - constants.ArmStorageAccountName, - constants.ArmVirtualMachineCaptureParameters, - constants.ArmPublicIPAddressName, - constants.ArmAsyncResourceGroupDelete, - } - - for _, v := range expectedStateBagKeys { - if _, ok := testSubject.stateBag.GetOk(v); ok == false { - t.Errorf("Expected the builder's state bag to contain '%s', but it did not.", v) - } - } -} - -func TestStateBagShouldPoluateExpectedTags(t *testing.T) { - var testSubject Builder - - expectedTags := map[string]string{ - "env": "test", - "builder": "packer", - } - armConfig := getArmBuilderConfiguration() - armConfig["azure_tags"] = expectedTags - - _, _, err := testSubject.Prepare(armConfig, getPackerConfiguration()) - if err != nil { - t.Fatalf("failed to prepare: %s", err) - } - - tags, ok := testSubject.stateBag.Get(constants.ArmTags).(map[string]*string) - if !ok { - t.Errorf("Expected the builder's state bag to contain tags of type %T, but didn't.", testSubject.config.AzureTags) - } - - if len(tags) != len(expectedTags) { - t.Errorf("expect tags from state to be the same length as tags from config") - } - - for k, v := range tags { - if expectedTags[k] != *v { - t.Errorf("expect tag value of %s to be %s, but got %s", k, expectedTags[k], *v) - } - } - -} diff --git a/builder/azure/arm/capture_template.go b/builder/azure/arm/capture_template.go deleted file mode 100644 index 2ba2c48b8..000000000 --- a/builder/azure/arm/capture_template.go +++ /dev/null @@ -1,84 +0,0 @@ -package arm - -type CaptureTemplateParameter struct { - Type string `json:"type"` - DefaultValue string `json:"defaultValue,omitempty"` -} - -type CaptureHardwareProfile struct { - VMSize string `json:"vmSize"` -} - -type CaptureUri struct { - Uri string `json:"uri"` -} - -type CaptureDisk struct { - OSType string `json:"osType"` - Name string `json:"name"` - Image CaptureUri `json:"image"` - Vhd CaptureUri `json:"vhd"` - CreateOption string `json:"createOption"` - Caching string `json:"caching"` -} - -type CaptureStorageProfile struct { - OSDisk CaptureDisk `json:"osDisk"` - DataDisks []CaptureDisk `json:"dataDisks"` -} - -type CaptureOSProfile struct { - ComputerName string `json:"computerName"` - AdminUsername string `json:"adminUsername"` - AdminPassword string `json:"adminPassword"` -} - -type CaptureNetworkInterface struct { - Id string `json:"id"` -} - -type CaptureNetworkProfile struct { - NetworkInterfaces []CaptureNetworkInterface `json:"networkInterfaces"` -} - -type CaptureBootDiagnostics struct { - Enabled bool `json:"enabled"` -} - -type CaptureDiagnosticProfile struct { - BootDiagnostics CaptureBootDiagnostics `json:"bootDiagnostics"` -} - -type CaptureProperties struct { - HardwareProfile CaptureHardwareProfile `json:"hardwareProfile"` - StorageProfile CaptureStorageProfile `json:"storageProfile"` - OSProfile CaptureOSProfile `json:"osProfile"` - NetworkProfile CaptureNetworkProfile `json:"networkProfile"` - DiagnosticsProfile CaptureDiagnosticProfile `json:"diagnosticsProfile"` - ProvisioningState int `json:"provisioningState"` -} - -type CaptureResources struct { - ApiVersion string `json:"apiVersion"` - Name string `json:"name"` - Type string `json:"type"` - Location string `json:"location"` - Properties CaptureProperties `json:"properties"` -} - -type CaptureTemplate struct { - Schema string `json:"$schema"` - ContentVersion string `json:"contentVersion"` - Parameters map[string]CaptureTemplateParameter `json:"parameters"` - Resources []CaptureResources `json:"resources"` -} - -type CaptureOperationProperties struct { - Output *CaptureTemplate `json:"output"` -} - -type CaptureOperation struct { - OperationId string `json:"operationId"` - Status string `json:"status"` - Properties *CaptureOperationProperties `json:"properties"` -} diff --git a/builder/azure/arm/capture_template_test.go b/builder/azure/arm/capture_template_test.go deleted file mode 100644 index 10be51ee8..000000000 --- a/builder/azure/arm/capture_template_test.go +++ /dev/null @@ -1,272 +0,0 @@ -package arm - -import ( - "encoding/json" - "testing" -) - -var captureTemplate01 = `{ - "operationId": "ac1c7c38-a591-41b3-89bd-ea39fceace1b", - "status": "Succeeded", - "startTime": "2016-04-04T21:07:25.2900874+00:00", - "endTime": "2016-04-04T21:07:26.4776321+00:00", - "properties": { - "output": { - "$schema": "http://schema.management.azure.com/schemas/2014-04-01-preview/VM_IP.json", - "contentVersion": "1.0.0.0", - "parameters": { - "vmName": { - "type": "string" - }, - "vmSize": { - "type": "string", - "defaultValue": "Standard_A2" - }, - "adminUserName": { - "type": "string" - }, - "adminPassword": { - "type": "securestring" - }, - "networkInterfaceId": { - "type": "string" - } - }, - "resources": [ - { - "apiVersion": "2015-06-15", - "properties": { - "hardwareProfile": { - "vmSize": "[parameters('vmSize')]" - }, - "storageProfile": { - "osDisk": { - "osType": "Linux", - "name": "packer-osDisk.32118633-6dc9-449f-83b6-a7d2983bec14.vhd", - "createOption": "FromImage", - "image": { - "uri": "http://storage.blob.core.windows.net/system/Microsoft.Compute/Images/images/packer-osDisk.32118633-6dc9-449f-83b6-a7d2983bec14.vhd" - }, - "vhd": { - "uri": "http://storage.blob.core.windows.net/vmcontainerce1a1b75-f480-47cb-8e6e-55142e4a5f68/osDisk.ce1a1b75-f480-47cb-8e6e-55142e4a5f68.vhd" - }, - "caching": "ReadWrite" - }, - "dataDisks": [ - { - "lun": 0, - "name": "packer-datadisk-0.32118633-6dc9-449f-83b6-a7d2983bec14.vhd", - "createOption": "Empty", - "image": { - "uri": "http://storage.blob.core.windows.net/system/Microsoft.Compute/Images/images/packer-datadisk-0.32118633-6dc9-449f-83b6-a7d2983bec14.vhd" - }, - "vhd": { - "uri": "http://storage.blob.core.windows.net/vmcontainerce1a1b75-f480-47cb-8e6e-55142e4a5f68/datadisk-0.ce1a1b75-f480-47cb-8e6e-55142e4a5f68.vhd" - }, - "caching": "ReadWrite" - }, - { - "lun": 1, - "name": "packer-datadisk-1.32118633-6dc9-449f-83b6-a7d2983bec14.vhd", - "createOption": "Empty", - "image": { - "uri": "http://storage.blob.core.windows.net/system/Microsoft.Compute/Images/images/packer-datadisk-1.32118633-6dc9-449f-83b6-a7d2983bec14.vhd" - }, - "vhd": { - "uri": "http://storage.blob.core.windows.net/vmcontainerce1a1b75-f480-47cb-8e6e-55142e4a5f68/datadisk-1.ce1a1b75-f480-47cb-8e6e-55142e4a5f68.vhd" - }, - "caching": "ReadWrite" - } - ] - }, - "osProfile": { - "computerName": "[parameters('vmName')]", - "adminUsername": "[parameters('adminUsername')]", - "adminPassword": "[parameters('adminPassword')]" - }, - "networkProfile": { - "networkInterfaces": [ - { - "id": "[parameters('networkInterfaceId')]" - } - ] - }, - "diagnosticsProfile": { - "bootDiagnostics": { - "enabled": false - } - }, - "provisioningState": 0 - }, - "name": "[parameters('vmName')]", - "type": "Microsoft.Compute/virtualMachines", - "location": "southcentralus" - } - ] - } - } -}` - -var captureTemplate02 = `{ - "operationId": "ac1c7c38-a591-41b3-89bd-ea39fceace1b", - "status": "Succeeded", - "startTime": "2016-04-04T21:07:25.2900874+00:00", - "endTime": "2016-04-04T21:07:26.4776321+00:00" -}` - -func TestCaptureParseJson(t *testing.T) { - var operation CaptureOperation - err := json.Unmarshal([]byte(captureTemplate01), &operation) - if err != nil { - t.Fatalf("failed to the sample capture operation: %s", err) - } - - testSubject := operation.Properties.Output - if testSubject.Schema != "http://schema.management.azure.com/schemas/2014-04-01-preview/VM_IP.json" { - t.Errorf("Schema's value was unexpected: %s", testSubject.Schema) - } - if testSubject.ContentVersion != "1.0.0.0" { - t.Errorf("ContentVersion's value was unexpected: %s", testSubject.ContentVersion) - } - - // == Parameters ==================================== - if len(testSubject.Parameters) != 5 { - t.Fatalf("expected parameters to have 5 keys, but got %d", len(testSubject.Parameters)) - } - if _, ok := testSubject.Parameters["vmName"]; !ok { - t.Errorf("Parameters['vmName'] was an expected parameters, but it did not exist") - } - if testSubject.Parameters["vmName"].Type != "string" { - t.Errorf("Parameters['vmName'].Type == 'string', but got '%s'", testSubject.Parameters["vmName"].Type) - } - if _, ok := testSubject.Parameters["vmSize"]; !ok { - t.Errorf("Parameters['vmSize'] was an expected parameters, but it did not exist") - } - if testSubject.Parameters["vmSize"].Type != "string" { - t.Errorf("Parameters['vmSize'].Type == 'string', but got '%s'", testSubject.Parameters["vmSize"]) - } - if testSubject.Parameters["vmSize"].DefaultValue != "Standard_A2" { - t.Errorf("Parameters['vmSize'].DefaultValue == 'string', but got '%s'", testSubject.Parameters["vmSize"].DefaultValue) - } - - // == Resources ===================================== - if len(testSubject.Resources) != 1 { - t.Fatalf("expected resources to have length 1, but got %d", len(testSubject.Resources)) - } - if testSubject.Resources[0].Name != "[parameters('vmName')]" { - t.Errorf("Resources[0].Name's value was unexpected: %s", testSubject.Resources[0].Name) - } - if testSubject.Resources[0].Type != "Microsoft.Compute/virtualMachines" { - t.Errorf("Resources[0].Type's value was unexpected: %s", testSubject.Resources[0].Type) - } - if testSubject.Resources[0].Location != "southcentralus" { - t.Errorf("Resources[0].Location's value was unexpected: %s", testSubject.Resources[0].Location) - } - - // == Resources/Properties ===================================== - if testSubject.Resources[0].Properties.ProvisioningState != 0 { - t.Errorf("Resources[0].Properties.ProvisioningState's value was unexpected: %d", testSubject.Resources[0].Properties.ProvisioningState) - } - - // == Resources/Properties/HardwareProfile ====================== - hardwareProfile := testSubject.Resources[0].Properties.HardwareProfile - if hardwareProfile.VMSize != "[parameters('vmSize')]" { - t.Errorf("Resources[0].Properties.HardwareProfile.VMSize's value was unexpected: %s", hardwareProfile.VMSize) - } - - // == Resources/Properties/StorageProfile/OSDisk ================ - osDisk := testSubject.Resources[0].Properties.StorageProfile.OSDisk - if osDisk.OSType != "Linux" { - t.Errorf("Resources[0].Properties.StorageProfile.OSDisk.OSDisk's value was unexpected: %s", osDisk.OSType) - } - if osDisk.Name != "packer-osDisk.32118633-6dc9-449f-83b6-a7d2983bec14.vhd" { - t.Errorf("Resources[0].Properties.StorageProfile.OSDisk.Name's value was unexpected: %s", osDisk.Name) - } - if osDisk.CreateOption != "FromImage" { - t.Errorf("Resources[0].Properties.StorageProfile.OSDisk.CreateOption's value was unexpected: %s", osDisk.CreateOption) - } - if osDisk.Image.Uri != "http://storage.blob.core.windows.net/system/Microsoft.Compute/Images/images/packer-osDisk.32118633-6dc9-449f-83b6-a7d2983bec14.vhd" { - t.Errorf("Resources[0].Properties.StorageProfile.OSDisk.Image.Uri's value was unexpected: %s", osDisk.Image.Uri) - } - if osDisk.Vhd.Uri != "http://storage.blob.core.windows.net/vmcontainerce1a1b75-f480-47cb-8e6e-55142e4a5f68/osDisk.ce1a1b75-f480-47cb-8e6e-55142e4a5f68.vhd" { - t.Errorf("Resources[0].Properties.StorageProfile.OSDisk.Vhd.Uri's value was unexpected: %s", osDisk.Vhd.Uri) - } - if osDisk.Caching != "ReadWrite" { - t.Errorf("Resources[0].Properties.StorageProfile.OSDisk.Caching's value was unexpected: %s", osDisk.Caching) - } - - // == Resources/Properties/StorageProfile/DataDisks ================ - dataDisks := testSubject.Resources[0].Properties.StorageProfile.DataDisks - if len(dataDisks) != 2 { - t.Errorf("Resources[0].Properties.StorageProfile.DataDisks, 2 disks expected but was: %d", len(dataDisks)) - } - if dataDisks[0].Name != "packer-datadisk-0.32118633-6dc9-449f-83b6-a7d2983bec14.vhd" { - t.Errorf("Resources[0].Properties.StorageProfile.dataDisks[0].Name's value was unexpected: %s", dataDisks[0].Name) - } - if dataDisks[0].CreateOption != "Empty" { - t.Errorf("Resources[0].Properties.StorageProfile.dataDisks[0].CreateOption's value was unexpected: %s", dataDisks[0].CreateOption) - } - if dataDisks[0].Image.Uri != "http://storage.blob.core.windows.net/system/Microsoft.Compute/Images/images/packer-datadisk-0.32118633-6dc9-449f-83b6-a7d2983bec14.vhd" { - t.Errorf("Resources[0].Properties.StorageProfile.dataDisks[0].Image.Uri's value was unexpected: %s", dataDisks[0].Image.Uri) - } - if dataDisks[0].Vhd.Uri != "http://storage.blob.core.windows.net/vmcontainerce1a1b75-f480-47cb-8e6e-55142e4a5f68/datadisk-0.ce1a1b75-f480-47cb-8e6e-55142e4a5f68.vhd" { - t.Errorf("Resources[0].Properties.StorageProfile.dataDisks[0].Vhd.Uri's value was unexpected: %s", dataDisks[0].Vhd.Uri) - } - if dataDisks[0].Caching != "ReadWrite" { - t.Errorf("Resources[0].Properties.StorageProfile.dataDisks[0].Caching's value was unexpected: %s", dataDisks[0].Caching) - } - if dataDisks[1].Name != "packer-datadisk-1.32118633-6dc9-449f-83b6-a7d2983bec14.vhd" { - t.Errorf("Resources[0].Properties.StorageProfile.dataDisks[1].Name's value was unexpected: %s", dataDisks[1].Name) - } - if dataDisks[1].CreateOption != "Empty" { - t.Errorf("Resources[0].Properties.StorageProfile.dataDisks[1].CreateOption's value was unexpected: %s", dataDisks[1].CreateOption) - } - if dataDisks[1].Image.Uri != "http://storage.blob.core.windows.net/system/Microsoft.Compute/Images/images/packer-datadisk-1.32118633-6dc9-449f-83b6-a7d2983bec14.vhd" { - t.Errorf("Resources[0].Properties.StorageProfile.dataDisks[1].Image.Uri's value was unexpected: %s", dataDisks[1].Image.Uri) - } - if dataDisks[1].Vhd.Uri != "http://storage.blob.core.windows.net/vmcontainerce1a1b75-f480-47cb-8e6e-55142e4a5f68/datadisk-1.ce1a1b75-f480-47cb-8e6e-55142e4a5f68.vhd" { - t.Errorf("Resources[0].Properties.StorageProfile.dataDisks[1].Vhd.Uri's value was unexpected: %s", dataDisks[1].Vhd.Uri) - } - if dataDisks[1].Caching != "ReadWrite" { - t.Errorf("Resources[0].Properties.StorageProfile.dataDisks[1].Caching's value was unexpected: %s", dataDisks[1].Caching) - } - - // == Resources/Properties/OSProfile ============================ - osProfile := testSubject.Resources[0].Properties.OSProfile - if osProfile.AdminPassword != "[parameters('adminPassword')]" { - t.Errorf("Resources[0].Properties.OSProfile.AdminPassword's value was unexpected: %s", osProfile.AdminPassword) - } - if osProfile.AdminUsername != "[parameters('adminUsername')]" { - t.Errorf("Resources[0].Properties.OSProfile.AdminUsername's value was unexpected: %s", osProfile.AdminUsername) - } - if osProfile.ComputerName != "[parameters('vmName')]" { - t.Errorf("Resources[0].Properties.OSProfile.ComputerName's value was unexpected: %s", osProfile.ComputerName) - } - - // == Resources/Properties/NetworkProfile ======================= - networkProfile := testSubject.Resources[0].Properties.NetworkProfile - if len(networkProfile.NetworkInterfaces) != 1 { - t.Errorf("Count of Resources[0].Properties.NetworkProfile.NetworkInterfaces was expected to be 1, but go %d", len(networkProfile.NetworkInterfaces)) - } - if networkProfile.NetworkInterfaces[0].Id != "[parameters('networkInterfaceId')]" { - t.Errorf("Resources[0].Properties.NetworkProfile.NetworkInterfaces[0].Id's value was unexpected: %s", networkProfile.NetworkInterfaces[0].Id) - } - - // == Resources/Properties/DiagnosticsProfile =================== - diagnosticsProfile := testSubject.Resources[0].Properties.DiagnosticsProfile - if diagnosticsProfile.BootDiagnostics.Enabled != false { - t.Errorf("Resources[0].Properties.DiagnosticsProfile.BootDiagnostics.Enabled's value was unexpected: %t", diagnosticsProfile.BootDiagnostics.Enabled) - } -} - -func TestCaptureEmptyOperationJson(t *testing.T) { - var operation CaptureOperation - err := json.Unmarshal([]byte(captureTemplate02), &operation) - if err != nil { - t.Fatalf("failed to the sample capture operation: %s", err) - } - - if operation.Properties != nil { - t.Errorf("JSON contained no properties, but value was not nil: %+v", operation.Properties) - } -} diff --git a/builder/azure/arm/config.go b/builder/azure/arm/config.go deleted file mode 100644 index 6f35a2035..000000000 --- a/builder/azure/arm/config.go +++ /dev/null @@ -1,1252 +0,0 @@ -//go:generate packer-sdc struct-markdown -//go:generate packer-sdc mapstructure-to-hcl2 -type Config,SharedImageGallery,SharedImageGalleryDestination,PlanInformation - -package arm - -import ( - "crypto/rand" - "crypto/rsa" - "crypto/x509" - "crypto/x509/pkix" - "encoding/base64" - "encoding/json" - "fmt" - "io/ioutil" - "math/big" - "net" - "regexp" - "strings" - "time" - - "github.com/hashicorp/packer-plugin-sdk/random" - - "github.com/Azure/azure-sdk-for-go/services/compute/mgmt/2018-04-01/compute" - "github.com/Azure/go-autorest/autorest/to" - "github.com/masterzen/winrm" - - "github.com/hashicorp/packer-plugin-sdk/common" - "github.com/hashicorp/packer-plugin-sdk/communicator" - packersdk "github.com/hashicorp/packer-plugin-sdk/packer" - "github.com/hashicorp/packer-plugin-sdk/template/config" - "github.com/hashicorp/packer-plugin-sdk/template/interpolate" - azcommon "github.com/hashicorp/packer/builder/azure/common" - "github.com/hashicorp/packer/builder/azure/common/client" - "github.com/hashicorp/packer/builder/azure/common/constants" - "github.com/hashicorp/packer/builder/azure/pkcs12" - - "golang.org/x/crypto/ssh" -) - -const ( - DefaultImageVersion = "latest" - DefaultUserName = "packer" - DefaultPrivateVirtualNetworkWithPublicIp = false - DefaultVMSize = "Standard_A1" - DefaultKeyVaultSKU = "standard" -) - -const ( - // https://docs.microsoft.com/en-us/azure/architecture/best-practices/naming-conventions#naming-rules-and-restrictions - // Regular expressions in Go are not expressive enough, such that the regular expression returned by Azure - // can be used (no backtracking). - // - // -> ^[^_\W][\w-._]{0,79}(?.UUID.vhd` and stored in the specified capture - // container along side the OS disk. The additional disks are included in - // the deployment template `PREFIX-vmTemplate.UUID`. - // - // For Managed build the final artifacts are included in the managed image. - // The additional disk will have the same storage account type as the OS - // disk, as specified with the `managed_image_storage_account_type` - // setting. - AdditionalDiskSize []int32 `mapstructure:"disk_additional_size" required:"false"` - // Specify the disk caching type. Valid values - // are None, ReadOnly, and ReadWrite. The default value is ReadWrite. - DiskCachingType string `mapstructure:"disk_caching_type" required:"false"` - diskCachingType compute.CachingTypes - // Specify the list of IP addresses and CIDR blocks that should be - // allowed access to the VM. If provided, an Azure Network Security - // Group will be created with corresponding rules and be bound to - // the subnet of the VM. - // Providing `allowed_inbound_ip_addresses` in combination with - // `virtual_network_name` is not allowed. - AllowedInboundIpAddresses []string `mapstructure:"allowed_inbound_ip_addresses"` - - // Specify storage to store Boot Diagnostics -- Enabling this option - // will create 2 Files in the specified storage account. (serial console log & screehshot file) - // once the build is completed, it has to be removed manually. - // see [here](https://docs.microsoft.com/en-us/azure/virtual-machines/troubleshooting/boot-diagnostics) for more info - BootDiagSTGAccount string `mapstructure:"boot_diag_storage_account" required:"false"` - - // specify custom azure resource names during build limited to max 10 characters - // this will set the prefix for the resources. The actuall resource names will be - // `custom_resource_build_prefix` + resourcetype + 5 character random alphanumeric string - CustomResourcePrefix string `mapstructure:"custom_resource_build_prefix" required:"false"` - - // Runtime Values - UserName string `mapstructure-to-hcl2:",skip"` - Password string `mapstructure-to-hcl2:",skip"` - tmpAdminPassword string - tmpCertificatePassword string - tmpResourceGroupName string - tmpComputeName string - tmpNicName string - tmpPublicIPAddressName string - tmpDeploymentName string - tmpKeyVaultName string - tmpOSDiskName string - tmpDataDiskName string - tmpSubnetName string - tmpVirtualNetworkName string - tmpNsgName string - tmpWinRMCertificateUrl string - - // Authentication with the VM via SSH - sshAuthorizedKey string - - // Authentication with the VM via WinRM - winrmCertificate string - - Comm communicator.Config `mapstructure:",squash"` - ctx interpolate.Context - // If you want packer to delete the - // temporary resource group asynchronously set this value. It's a boolean - // value and defaults to false. Important Setting this true means that - // your builds are faster, however any failed deletes are not reported. - AsyncResourceGroupDelete bool `mapstructure:"async_resourcegroup_delete" required:"false"` -} - -type keyVaultCertificate struct { - Data string `json:"data"` - DataType string `json:"dataType"` - Password string `json:"password,omitempty"` -} - -func (c *Config) toVMID() string { - var resourceGroupName string - if c.tmpResourceGroupName != "" { - resourceGroupName = c.tmpResourceGroupName - } else { - resourceGroupName = c.BuildResourceGroupName - } - return fmt.Sprintf("/subscriptions/%s/resourceGroups/%s/providers/Microsoft.Compute/virtualMachines/%s", c.ClientConfig.SubscriptionID, resourceGroupName, c.tmpComputeName) -} - -func (c *Config) isManagedImage() bool { - return c.ManagedImageName != "" -} - -func (c *Config) toVirtualMachineCaptureParameters() *compute.VirtualMachineCaptureParameters { - return &compute.VirtualMachineCaptureParameters{ - DestinationContainerName: &c.CaptureContainerName, - VhdPrefix: &c.CaptureNamePrefix, - OverwriteVhds: to.BoolPtr(false), - } -} - -func (c *Config) toImageParameters() *compute.Image { - return &compute.Image{ - ImageProperties: &compute.ImageProperties{ - SourceVirtualMachine: &compute.SubResource{ - ID: to.StringPtr(c.toVMID()), - }, - StorageProfile: &compute.ImageStorageProfile{ - ZoneResilient: to.BoolPtr(c.ManagedImageZoneResilient), - }, - }, - Location: to.StringPtr(c.Location), - Tags: azcommon.MapToAzureTags(c.AzureTags), - } -} - -func (c *Config) createCertificate() (string, error) { - privateKey, err := rsa.GenerateKey(rand.Reader, 2048) - if err != nil { - err = fmt.Errorf("Failed to Generate Private Key: %s", err) - return "", err - } - - host := fmt.Sprintf("%s.cloudapp.net", c.tmpComputeName) - notBefore := time.Now() - notAfter := notBefore.Add(24 * time.Hour) - - serialNumber, err := rand.Int(rand.Reader, new(big.Int).Lsh(big.NewInt(1), 128)) - if err != nil { - err = fmt.Errorf("Failed to Generate Serial Number: %v", err) - return "", err - } - - template := x509.Certificate{ - SerialNumber: serialNumber, - Issuer: pkix.Name{ - CommonName: host, - }, - Subject: pkix.Name{ - CommonName: host, - }, - NotBefore: notBefore, - NotAfter: notAfter, - - KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature, - ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth}, - BasicConstraintsValid: true, - } - - derBytes, err := x509.CreateCertificate(rand.Reader, &template, &template, &privateKey.PublicKey, privateKey) - if err != nil { - err = fmt.Errorf("Failed to Create Certificate: %s", err) - return "", err - } - - pfxBytes, err := pkcs12.Encode(derBytes, privateKey, c.tmpCertificatePassword) - if err != nil { - err = fmt.Errorf("Failed to encode certificate as PFX: %s", err) - return "", err - } - - keyVaultDescription := keyVaultCertificate{ - Data: base64.StdEncoding.EncodeToString(pfxBytes), - DataType: "pfx", - Password: c.tmpCertificatePassword, - } - - bytes, err := json.Marshal(keyVaultDescription) - if err != nil { - err = fmt.Errorf("Failed to marshal key vault description: %s", err) - return "", err - } - - return base64.StdEncoding.EncodeToString(bytes), nil -} - -func (c *Config) Prepare(raws ...interface{}) ([]string, error) { - c.ctx.Funcs = azcommon.TemplateFuncs - err := config.Decode(c, &config.DecodeOpts{ - PluginType: BuilderId, - Interpolate: true, - InterpolateContext: &c.ctx, - }, raws...) - - if err != nil { - return nil, err - } - - provideDefaultValues(c) - setRuntimeValues(c) - err = setUserNamePassword(c) - if err != nil { - return nil, err - } - - // copy singular blocks - c.AzureTag.CopyOn(&c.AzureTags) - - err = c.ClientConfig.SetDefaultValues() - if err != nil { - return nil, err - } - - err = setCustomData(c) - if err != nil { - return nil, err - } - - // NOTE: if the user did not specify a communicator, then default to both - // SSH and WinRM. This is for backwards compatibility because the code did - // not specifically force the user to set a communicator. - if c.Comm.Type == "" || strings.EqualFold(c.Comm.Type, "ssh") { - err = setSshValues(c) - if err != nil { - return nil, err - } - } - - if c.Comm.Type == "" || strings.EqualFold(c.Comm.Type, "winrm") { - err = setWinRMCertificate(c) - if err != nil { - return nil, err - } - } - - var errs *packersdk.MultiError - errs = packersdk.MultiErrorAppend(errs, c.Comm.Prepare(&c.ctx)...) - - assertRequiredParametersSet(c, errs) - assertTagProperties(c, errs) - if errs != nil && len(errs.Errors) > 0 { - return nil, errs - } - - return nil, nil -} - -func setSshValues(c *Config) error { - if c.Comm.SSHTimeout == 0 { - c.Comm.SSHTimeout = 20 * time.Minute - } - - if c.Comm.SSHPrivateKeyFile != "" { - privateKeyBytes, err := c.Comm.ReadSSHPrivateKeyFile() - if err != nil { - return err - } - signer, err := ssh.ParsePrivateKey(privateKeyBytes) - if err != nil { - return err - } - - publicKey := signer.PublicKey() - c.sshAuthorizedKey = fmt.Sprintf("%s %s packer Azure Deployment%s", - publicKey.Type(), - base64.StdEncoding.EncodeToString(publicKey.Marshal()), - time.Now().Format(time.RFC3339)) - c.Comm.SSHPrivateKey = privateKeyBytes - - } else { - sshKeyPair, err := NewOpenSshKeyPair() - if err != nil { - return err - } - - c.sshAuthorizedKey = sshKeyPair.AuthorizedKey() - c.Comm.SSHPrivateKey = sshKeyPair.PrivateKey() - } - - return nil -} - -func setWinRMCertificate(c *Config) error { - c.Comm.WinRMTransportDecorator = - func() winrm.Transporter { - return &winrm.ClientNTLM{} - } - - cert, err := c.createCertificate() - c.winrmCertificate = cert - - return err -} - -func setRuntimeValues(c *Config) { - var tempName = NewTempName(c.CustomResourcePrefix) - - c.tmpAdminPassword = tempName.AdminPassword - // store so that we can access this later during provisioning - packersdk.LogSecretFilter.Set(c.tmpAdminPassword) - - c.tmpCertificatePassword = tempName.CertificatePassword - if c.TempComputeName == "" { - c.tmpComputeName = tempName.ComputeName - } else { - c.tmpComputeName = c.TempComputeName - } - c.tmpDeploymentName = tempName.DeploymentName - // Only set tmpResourceGroupName if no name has been specified - if c.TempResourceGroupName == "" && c.BuildResourceGroupName == "" { - c.tmpResourceGroupName = tempName.ResourceGroupName - } else if c.TempResourceGroupName != "" && c.BuildResourceGroupName == "" { - c.tmpResourceGroupName = c.TempResourceGroupName - } - if c.TempNicName == "" { - c.tmpNicName = tempName.NicName - } else { - c.tmpNicName = c.TempNicName - } - c.tmpNicName = tempName.NicName - c.tmpPublicIPAddressName = tempName.PublicIPAddressName - if c.TempOSDiskName == "" { - c.tmpOSDiskName = tempName.OSDiskName - } else { - c.tmpOSDiskName = c.TempOSDiskName - } - c.tmpDataDiskName = tempName.DataDiskName - c.tmpSubnetName = tempName.SubnetName - c.tmpVirtualNetworkName = tempName.VirtualNetworkName - c.tmpNsgName = tempName.NsgName - c.tmpKeyVaultName = tempName.KeyVaultName -} - -func setUserNamePassword(c *Config) error { - // Set default credentials generated by the builder - c.UserName = DefaultUserName - c.Password = c.tmpAdminPassword - - // Set communicator specific credentials and update defaults if different. - // Communicator specific credentials need to be updated as the standard Packer - // SSHConfigFunc and WinRMConfigFunc use communicator specific credentials, unless overwritten. - - // SSH comm - if c.Comm.SSHUsername == "" { - c.Comm.SSHUsername = c.UserName - } - c.UserName = c.Comm.SSHUsername - - // if user has an explicit wish to use an SSH password, we'll set it - if c.Comm.SSHPassword != "" { - c.Password = c.Comm.SSHPassword - } - - if c.Comm.Type == "ssh" { - return nil - } - - // WinRM comm - if c.Comm.WinRMUser == "" { - c.Comm.WinRMUser = c.UserName - } - c.UserName = c.Comm.WinRMUser - - if c.Comm.WinRMPassword == "" { - // Configure password settings using Azure generated credentials - c.Comm.WinRMPassword = c.Password - } - - if !isValidPassword(c.Comm.WinRMPassword) { - return fmt.Errorf("The supplied \"winrm_password\" must be between 8-123 characters long and must satisfy at least 3 from the following: \n1) Contains an uppercase character \n2) Contains a lowercase character\n3) Contains a numeric digit\n4) Contains a special character\n5) Control characters are not allowed") - } - c.Password = c.Comm.WinRMPassword - - return nil -} - -func setCustomData(c *Config) error { - if c.CustomDataFile == "" { - return nil - } - - b, err := ioutil.ReadFile(c.CustomDataFile) - if err != nil { - return err - } - - c.customData = base64.StdEncoding.EncodeToString(b) - return nil -} - -func provideDefaultValues(c *Config) { - if c.VMSize == "" { - c.VMSize = DefaultVMSize - } - - if c.ManagedImageStorageAccountType == "" { - c.managedImageStorageAccountType = compute.StorageAccountTypesStandardLRS - } - - if c.DiskCachingType == "" { - c.diskCachingType = compute.CachingTypesReadWrite - } - - if c.ImagePublisher != "" && c.ImageVersion == "" { - c.ImageVersion = DefaultImageVersion - } - - if c.BuildKeyVaultSKU == "" { - c.BuildKeyVaultSKU = DefaultKeyVaultSKU - } - - c.ClientConfig.SetDefaultValues() -} - -func assertTagProperties(c *Config, errs *packersdk.MultiError) { - if len(c.AzureTags) > 15 { - errs = packersdk.MultiErrorAppend(errs, fmt.Errorf("a max of 15 tags are supported, but %d were provided", len(c.AzureTags))) - } - - for k, v := range c.AzureTags { - if len(k) > 512 { - errs = packersdk.MultiErrorAppend(errs, fmt.Errorf("the tag name %q exceeds (%d) the 512 character limit", k, len(k))) - } - if len(v) > 256 { - errs = packersdk.MultiErrorAppend(errs, fmt.Errorf("the tag name %q exceeds (%d) the 256 character limit", v, len(v))) - } - } -} - -//nolint:ineffassign //this triggers a false positive because errs is passed by reference -func assertRequiredParametersSet(c *Config, errs *packersdk.MultiError) { - c.ClientConfig.Validate(errs) - - ///////////////////////////////////////////// - // Identity - if len(c.UserAssignedManagedIdentities) != 0 { - for _, rid := range c.UserAssignedManagedIdentities { - r, err := client.ParseResourceID(rid) - if err != nil { - err := fmt.Errorf("Error parsing resource ID from `user_assigned_managed_identities`; please make sure"+ - " that this value follows the full resource id format: "+ - "/subscriptions//resourcegroups//providers/Microsoft.ManagedIdentity/userAssignedIdentities/.\n"+ - " Original error: %s", err) - errs = packersdk.MultiErrorAppend(errs, err) - } else { - if !strings.EqualFold(r.Provider, "Microsoft.ManagedIdentity") { - errs = packersdk.MultiErrorAppend(errs, fmt.Errorf("A valid user assigned managed identity resource id must have a correct resource provider")) - } - if !strings.EqualFold(r.ResourceType.String(), "userAssignedIdentities") { - errs = packersdk.MultiErrorAppend(errs, fmt.Errorf("A valid user assigned managed identity resource id must have a correct resource type")) - } - } - } - } - - ///////////////////////////////////////////// - // Capture - if c.CaptureContainerName == "" && c.ManagedImageName == "" { - errs = packersdk.MultiErrorAppend(errs, fmt.Errorf("A capture_container_name or managed_image_name must be specified")) - } - - if c.CaptureNamePrefix == "" && c.ManagedImageResourceGroupName == "" { - errs = packersdk.MultiErrorAppend(errs, fmt.Errorf("A capture_name_prefix or managed_image_resource_group_name must be specified")) - } - - if (c.CaptureNamePrefix != "" || c.CaptureContainerName != "") && (c.ManagedImageResourceGroupName != "" || c.ManagedImageName != "") { - errs = packersdk.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 c.CaptureContainerName != "" { - if !reCaptureContainerName.MatchString(c.CaptureContainerName) { - errs = packersdk.MultiErrorAppend(errs, fmt.Errorf("A capture_container_name must satisfy the regular expression %q.", reCaptureContainerName.String())) - } - - if strings.HasSuffix(c.CaptureContainerName, "-") { - errs = packersdk.MultiErrorAppend(errs, fmt.Errorf("A capture_container_name must not end with a hyphen, e.g. '-'.")) - } - - if strings.Contains(c.CaptureContainerName, "--") { - errs = packersdk.MultiErrorAppend(errs, fmt.Errorf("A capture_container_name must not contain consecutive hyphens, e.g. '--'.")) - } - - if c.CaptureNamePrefix == "" { - errs = packersdk.MultiErrorAppend(errs, fmt.Errorf("A capture_name_prefix must be specified")) - } - - if !reCaptureNamePrefix.MatchString(c.CaptureNamePrefix) { - errs = packersdk.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 = packersdk.MultiErrorAppend(errs, fmt.Errorf("A capture_name_prefix must not end with a hyphen or period.")) - } - } - - if c.TempResourceGroupName != "" && c.BuildResourceGroupName != "" { - errs = packersdk.MultiErrorAppend(errs, fmt.Errorf("The settings temp_resource_group_name and build_resource_group_name cannot both be defined. Please define one or neither.")) - } - - ///////////////////////////////////////////// - // Compute - toInt := func(b bool) int { - if b { - return 1 - } else { - return 0 - } - } - - isImageUrl := c.ImageUrl != "" - isCustomManagedImage := c.CustomManagedImageName != "" || c.CustomManagedImageResourceGroupName != "" - isSharedGallery := c.SharedGallery.GalleryName != "" - isPlatformImage := c.ImagePublisher != "" || c.ImageOffer != "" || c.ImageSku != "" - - countSourceInputs := toInt(isImageUrl) + toInt(isCustomManagedImage) + toInt(isPlatformImage) + toInt(isSharedGallery) - - if countSourceInputs > 1 { - errs = packersdk.MultiErrorAppend(errs, fmt.Errorf("Specify either a VHD (image_url), Image Reference (image_publisher, image_offer, image_sku), a Managed Disk (custom_managed_disk_image_name, custom_managed_disk_resource_group_name), or a Shared Gallery Image (shared_image_gallery)")) - } - - if isImageUrl && c.ManagedImageResourceGroupName != "" { - errs = packersdk.MultiErrorAppend(errs, fmt.Errorf("A managed image must be created from a managed image, it cannot be created from a VHD.")) - } - - if c.SharedGallery.GalleryName != "" { - if c.SharedGallery.Subscription == "" { - errs = packersdk.MultiErrorAppend(errs, fmt.Errorf("A shared_image_gallery.subscription must be specified")) - } - if c.SharedGallery.ResourceGroup == "" { - errs = packersdk.MultiErrorAppend(errs, fmt.Errorf("A shared_image_gallery.resource_group must be specified")) - } - if c.SharedGallery.ImageName == "" { - errs = packersdk.MultiErrorAppend(errs, fmt.Errorf("A shared_image_gallery.image_name must be specified")) - } - if c.CaptureContainerName != "" { - errs = packersdk.MultiErrorAppend(errs, fmt.Errorf("VHD Target [capture_container_name] is not supported when using Shared Image Gallery as source. Use managed_image_resource_group_name instead.")) - } - if c.CaptureNamePrefix != "" { - errs = packersdk.MultiErrorAppend(errs, fmt.Errorf("VHD Target [capture_name_prefix] is not supported when using Shared Image Gallery as source. Use managed_image_name instead.")) - } - } else if c.ImageUrl == "" && c.CustomManagedImageName == "" { - if c.ImagePublisher == "" { - errs = packersdk.MultiErrorAppend(errs, fmt.Errorf("An image_publisher must be specified")) - } - if c.ImageOffer == "" { - errs = packersdk.MultiErrorAppend(errs, fmt.Errorf("An image_offer must be specified")) - } - if c.ImageSku == "" { - errs = packersdk.MultiErrorAppend(errs, fmt.Errorf("An image_sku must be specified")) - } - } else if c.ImageUrl == "" && c.ImagePublisher == "" { - if c.CustomManagedImageResourceGroupName == "" { - errs = packersdk.MultiErrorAppend(errs, fmt.Errorf("A custom_managed_image_resource_group_name must be specified")) - } - if c.CustomManagedImageName == "" { - errs = packersdk.MultiErrorAppend(errs, fmt.Errorf("A custom_managed_image_name must be specified")) - } - if c.ManagedImageResourceGroupName == "" { - errs = packersdk.MultiErrorAppend(errs, fmt.Errorf("A managed_image_resource_group_name must be specified")) - } - if c.ManagedImageName == "" { - errs = packersdk.MultiErrorAppend(errs, fmt.Errorf("A managed_image_name must be specified")) - } - } else { - if c.ImagePublisher != "" || c.ImageOffer != "" || c.ImageSku != "" || c.ImageVersion != "" { - errs = packersdk.MultiErrorAppend(errs, fmt.Errorf("An image_url must not be specified if image_publisher, image_offer, image_sku, or image_version is specified")) - } - } - - ///////////////////////////////////////////// - // Deployment - xor := func(a, b bool) bool { - return (a || b) && !(a && b) - } - - if !xor((c.StorageAccount != "" || c.ResourceGroupName != ""), (c.ManagedImageName != "" || c.ManagedImageResourceGroupName != "")) { - errs = packersdk.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 !xor(c.Location != "", c.BuildResourceGroupName != "") { - errs = packersdk.MultiErrorAppend(errs, fmt.Errorf("Specify either a location to create the resource group in or an existing build_resource_group_name, but not both.")) - } - - if c.ManagedImageName == "" && c.ManagedImageResourceGroupName == "" { - if c.StorageAccount == "" { - errs = packersdk.MultiErrorAppend(errs, fmt.Errorf("A storage_account must be specified")) - } - if c.ResourceGroupName == "" { - errs = packersdk.MultiErrorAppend(errs, fmt.Errorf("A resource_group_name must be specified")) - } - } - - if c.TempResourceGroupName != "" { - if ok, err := assertResourceGroupName(c.TempResourceGroupName, "temp_resource_group_name"); !ok { - errs = packersdk.MultiErrorAppend(errs, err) - } - } - - if c.BuildResourceGroupName != "" { - if ok, err := assertResourceGroupName(c.BuildResourceGroupName, "build_resource_group_name"); !ok { - errs = packersdk.MultiErrorAppend(errs, err) - } - } - - if c.ManagedImageResourceGroupName != "" { - if ok, err := assertResourceGroupName(c.ManagedImageResourceGroupName, "managed_image_resource_group_name"); !ok { - errs = packersdk.MultiErrorAppend(errs, err) - } - } - - if c.ManagedImageName != "" { - if ok, err := assertManagedImageName(c.ManagedImageName, "managed_image_name"); !ok { - errs = packersdk.MultiErrorAppend(errs, err) - } - } - - if c.ManagedImageName != "" && c.ManagedImageResourceGroupName != "" && c.SharedGalleryDestination.SigDestinationGalleryName != "" { - if c.SharedGalleryDestination.SigDestinationResourceGroup == "" { - errs = packersdk.MultiErrorAppend(errs, fmt.Errorf("A resource_group must be specified for shared_image_gallery_destination")) - } - if c.SharedGalleryDestination.SigDestinationImageName == "" { - errs = packersdk.MultiErrorAppend(errs, fmt.Errorf("An image_name must be specified for shared_image_gallery_destination")) - } - if c.SharedGalleryDestination.SigDestinationImageVersion == "" { - errs = packersdk.MultiErrorAppend(errs, fmt.Errorf("An image_version must be specified for shared_image_gallery_destination")) - } - if len(c.SharedGalleryDestination.SigDestinationReplicationRegions) == 0 { - errs = packersdk.MultiErrorAppend(errs, fmt.Errorf("A list of replication_regions must be specified for shared_image_gallery_destination")) - } - if c.SharedGalleryDestination.SigDestinationSubscription == "" { - c.SharedGalleryDestination.SigDestinationSubscription = c.ClientConfig.SubscriptionID - } - } - if c.SharedGalleryTimeout == 0 { - // default to a one-hour timeout. In the sdk, the default is 15 m. - c.SharedGalleryTimeout = 60 * time.Minute - } - - if c.ManagedImageOSDiskSnapshotName != "" { - if ok, err := assertManagedImageOSDiskSnapshotName(c.ManagedImageOSDiskSnapshotName, "managed_image_os_disk_snapshot_name"); !ok { - errs = packersdk.MultiErrorAppend(errs, err) - } - } - - if c.ManagedImageDataDiskSnapshotPrefix != "" { - if ok, err := assertManagedImageDataDiskSnapshotName(c.ManagedImageDataDiskSnapshotPrefix, "managed_image_data_disk_snapshot_prefix"); !ok { - errs = packersdk.MultiErrorAppend(errs, err) - } - } - - if c.CustomResourcePrefix != "" { - if ok, err := assertResourceNamePrefix(c.CustomResourcePrefix, "custom_resource_build_prefix"); !ok { - errs = packersdk.MultiErrorAppend(errs, err) - } - } - - if c.VirtualNetworkName == "" && c.VirtualNetworkResourceGroupName != "" { - errs = packersdk.MultiErrorAppend(errs, fmt.Errorf("If virtual_network_resource_group_name is specified, so must virtual_network_name")) - } - if c.VirtualNetworkName == "" && c.VirtualNetworkSubnetName != "" { - errs = packersdk.MultiErrorAppend(errs, fmt.Errorf("If virtual_network_subnet_name is specified, so must virtual_network_name")) - } - - if c.AllowedInboundIpAddresses != nil && len(c.AllowedInboundIpAddresses) >= 1 { - if c.VirtualNetworkName != "" { - errs = packersdk.MultiErrorAppend(errs, fmt.Errorf("If virtual_network_name is specified, allowed_inbound_ip_addresses cannot be specified")) - } else { - if ok, err := assertAllowedInboundIpAddresses(c.AllowedInboundIpAddresses, "allowed_inbound_ip_addresses"); !ok { - errs = packersdk.MultiErrorAppend(errs, err) - } - } - } - - ///////////////////////////////////////////// - // Plan Info - if c.PlanInfo.PlanName != "" || c.PlanInfo.PlanProduct != "" || c.PlanInfo.PlanPublisher != "" || c.PlanInfo.PlanPromotionCode != "" { - if c.PlanInfo.PlanName == "" || c.PlanInfo.PlanProduct == "" || c.PlanInfo.PlanPublisher == "" { - errs = packersdk.MultiErrorAppend(errs, fmt.Errorf("if either plan_name, plan_product, plan_publisher, or plan_promotion_code are defined then plan_name, plan_product, and plan_publisher must be defined")) - } else { - if c.AzureTags == nil { - c.AzureTags = make(map[string]string) - } - - c.AzureTags["PlanInfo"] = c.PlanInfo.PlanName - c.AzureTags["PlanProduct"] = c.PlanInfo.PlanProduct - c.AzureTags["PlanPublisher"] = c.PlanInfo.PlanPublisher - c.AzureTags["PlanPromotionCode"] = c.PlanInfo.PlanPromotionCode - } - } - - ///////////////////////////////////////////// - // Polling Duration Timeout - if c.PollingDurationTimeout == 0 { - // In the sdk, the default is 15 m. - c.PollingDurationTimeout = 15 * time.Minute - } - - ///////////////////////////////////////////// - // OS - if strings.EqualFold(c.OSType, constants.Target_Linux) { - c.OSType = constants.Target_Linux - } else if strings.EqualFold(c.OSType, constants.Target_Windows) { - c.OSType = constants.Target_Windows - } else if c.OSType == "" { - errs = packersdk.MultiErrorAppend(errs, fmt.Errorf("An os_type must be specified")) - } else { - errs = packersdk.MultiErrorAppend(errs, fmt.Errorf("The os_type %q is invalid", c.OSType)) - } - - ///////////////////////////////////////////// - // Storage - switch c.ManagedImageStorageAccountType { - case "", string(compute.StorageAccountTypesStandardLRS): - c.managedImageStorageAccountType = compute.StorageAccountTypesStandardLRS - case string(compute.StorageAccountTypesPremiumLRS): - c.managedImageStorageAccountType = compute.StorageAccountTypesPremiumLRS - default: - errs = packersdk.MultiErrorAppend(errs, fmt.Errorf("The managed_image_storage_account_type %q is invalid", c.ManagedImageStorageAccountType)) - } - - if ok, err := assertSigAllowedStorageAccountType(c.SharedGalleryDestination.SigDestinationStorageAccountType); !ok { - errs = packersdk.MultiErrorAppend(errs, err) - } - - switch c.DiskCachingType { - case string(compute.CachingTypesNone): - c.diskCachingType = compute.CachingTypesNone - case string(compute.CachingTypesReadOnly): - c.diskCachingType = compute.CachingTypesReadOnly - case "", string(compute.CachingTypesReadWrite): - c.diskCachingType = compute.CachingTypesReadWrite - default: - errs = packersdk.MultiErrorAppend(errs, fmt.Errorf("The disk_caching_type %q is invalid", c.DiskCachingType)) - } -} - -func assertManagedImageName(name, setting string) (bool, error) { - if !isValidAzureName(reManagedDiskName, name) { - return false, fmt.Errorf("The setting %s must match the regular expression %q, and not end with a '-' or '.'.", setting, validManagedDiskName) - } - return true, nil -} - -func assertManagedImageOSDiskSnapshotName(name, setting string) (bool, error) { - if !isValidAzureName(reSnapshotName, name) { - return false, fmt.Errorf("The setting %s must only contain characters from a-z, A-Z, 0-9 and _ and the maximum length is 80 characters", setting) - } - return true, nil -} - -func assertManagedImageDataDiskSnapshotName(name, setting string) (bool, error) { - if !isValidAzureName(reSnapshotPrefix, name) { - return false, fmt.Errorf("The setting %s must only contain characters from a-z, A-Z, 0-9 and _ and the maximum length (excluding the prefix) is 60 characters", setting) - } - return true, nil -} - -func assertResourceNamePrefix(name, setting string) (bool, error) { - if !isValidAzureName(reResourceNamePrefix, name) { - return false, fmt.Errorf("The setting %s must only contain characters from a-z, A-Z, 0-9 and _ and the maximum length is 10 characters", setting) - } - return true, nil -} - -func assertAllowedInboundIpAddresses(ipAddresses []string, setting string) (bool, error) { - for _, ipAddress := range ipAddresses { - if net.ParseIP(ipAddress) == nil { - if _, _, err := net.ParseCIDR(ipAddress); err != nil { - return false, fmt.Errorf("The setting %s must only contain valid IP addresses or CIDR blocks", setting) - } - } - } - return true, nil -} - -func assertSigAllowedStorageAccountType(s string) (bool, error) { - _, err := getSigDestinationStorageAccountType(s) - if err != nil { - return false, err - } - return true, nil -} - -func assertResourceGroupName(rgn, setting string) (bool, error) { - if !isValidAzureName(reResourceGroupName, rgn) { - return false, fmt.Errorf("The setting %s must match the regular expression %q, and not end with a '-' or '.'.", setting, validResourceGroupNameRe) - } - return true, nil -} - -func isValidAzureName(re *regexp.Regexp, rgn string) bool { - return re.Match([]byte(rgn)) && - !strings.HasSuffix(rgn, ".") && - !strings.HasSuffix(rgn, "-") -} - -// The supplied password must be between 8-123 characters long and must satisfy at least 3 of password complexity requirements from the following: -// 1) Contains an uppercase character -// 2) Contains a lowercase character -// 3) Contains a numeric digit -// 4) Contains a special character -// 5) Control characters are not allowed (a very specific case - not included in this validation) -func isValidPassword(password string) bool { - if !(len(password) >= 8 && len(password) <= 123) { - return false - } - - requirements := 0 - if strings.ContainsAny(password, random.PossibleNumbers) { - requirements++ - } - if strings.ContainsAny(password, random.PossibleLowerCase) { - requirements++ - } - if strings.ContainsAny(password, random.PossibleUpperCase) { - requirements++ - } - if strings.ContainsAny(password, random.PossibleSpecialCharacter) { - requirements++ - } - - return requirements >= 3 -} - -func (c *Config) validateLocationZoneResiliency(say func(s string)) { - // Docs on regions that support Availibility Zones: - // https://docs.microsoft.com/en-us/azure/availability-zones/az-overview#regions-that-support-availability-zones - // Query technical names for locations: - // az account list-locations --query '[].name' -o tsv - - var zones = make(map[string]struct{}) - zones["westeurope"] = struct{}{} - zones["centralus"] = struct{}{} - zones["eastus2"] = struct{}{} - zones["francecentral"] = struct{}{} - zones["northeurope"] = struct{}{} - zones["southeastasia"] = struct{}{} - zones["westus2"] = struct{}{} - - if _, ok := zones[c.Location]; !ok { - say(fmt.Sprintf("WARNING: Zone resiliency may not be supported in %s, checkout the docs at https://docs.microsoft.com/en-us/azure/availability-zones/", c.Location)) - } -} diff --git a/builder/azure/arm/config.hcl2spec.go b/builder/azure/arm/config.hcl2spec.go deleted file mode 100644 index e520d2b9f..000000000 --- a/builder/azure/arm/config.hcl2spec.go +++ /dev/null @@ -1,361 +0,0 @@ -// Code generated by "packer-sdc mapstructure-to-hcl2"; DO NOT EDIT. - -package arm - -import ( - "github.com/hashicorp/hcl/v2/hcldec" - "github.com/hashicorp/packer-plugin-sdk/template/config" - "github.com/zclconf/go-cty/cty" -) - -// FlatConfig is an auto-generated flat version of Config. -// Where the contents of a field with a `mapstructure:,squash` tag are bubbled up. -type FlatConfig struct { - PackerBuildName *string `mapstructure:"packer_build_name" cty:"packer_build_name" hcl:"packer_build_name"` - PackerBuilderType *string `mapstructure:"packer_builder_type" cty:"packer_builder_type" hcl:"packer_builder_type"` - PackerCoreVersion *string `mapstructure:"packer_core_version" cty:"packer_core_version" hcl:"packer_core_version"` - PackerDebug *bool `mapstructure:"packer_debug" cty:"packer_debug" hcl:"packer_debug"` - PackerForce *bool `mapstructure:"packer_force" cty:"packer_force" hcl:"packer_force"` - PackerOnError *string `mapstructure:"packer_on_error" cty:"packer_on_error" hcl:"packer_on_error"` - PackerUserVars map[string]string `mapstructure:"packer_user_variables" cty:"packer_user_variables" hcl:"packer_user_variables"` - PackerSensitiveVars []string `mapstructure:"packer_sensitive_variables" cty:"packer_sensitive_variables" hcl:"packer_sensitive_variables"` - CloudEnvironmentName *string `mapstructure:"cloud_environment_name" required:"false" cty:"cloud_environment_name" hcl:"cloud_environment_name"` - ClientID *string `mapstructure:"client_id" cty:"client_id" hcl:"client_id"` - ClientSecret *string `mapstructure:"client_secret" cty:"client_secret" hcl:"client_secret"` - ClientCertPath *string `mapstructure:"client_cert_path" cty:"client_cert_path" hcl:"client_cert_path"` - ClientCertExpireTimeout *string `mapstructure:"client_cert_token_timeout" required:"false" cty:"client_cert_token_timeout" hcl:"client_cert_token_timeout"` - ClientJWT *string `mapstructure:"client_jwt" cty:"client_jwt" hcl:"client_jwt"` - ObjectID *string `mapstructure:"object_id" cty:"object_id" hcl:"object_id"` - TenantID *string `mapstructure:"tenant_id" required:"false" cty:"tenant_id" hcl:"tenant_id"` - SubscriptionID *string `mapstructure:"subscription_id" cty:"subscription_id" hcl:"subscription_id"` - UseAzureCLIAuth *bool `mapstructure:"use_azure_cli_auth" required:"false" cty:"use_azure_cli_auth" hcl:"use_azure_cli_auth"` - UserAssignedManagedIdentities []string `mapstructure:"user_assigned_managed_identities" required:"false" cty:"user_assigned_managed_identities" hcl:"user_assigned_managed_identities"` - CaptureNamePrefix *string `mapstructure:"capture_name_prefix" cty:"capture_name_prefix" hcl:"capture_name_prefix"` - CaptureContainerName *string `mapstructure:"capture_container_name" cty:"capture_container_name" hcl:"capture_container_name"` - SharedGallery *FlatSharedImageGallery `mapstructure:"shared_image_gallery" required:"false" cty:"shared_image_gallery" hcl:"shared_image_gallery"` - SharedGalleryDestination *FlatSharedImageGalleryDestination `mapstructure:"shared_image_gallery_destination" cty:"shared_image_gallery_destination" hcl:"shared_image_gallery_destination"` - SharedGalleryTimeout *string `mapstructure:"shared_image_gallery_timeout" cty:"shared_image_gallery_timeout" hcl:"shared_image_gallery_timeout"` - SharedGalleryImageVersionEndOfLifeDate *string `mapstructure:"shared_gallery_image_version_end_of_life_date" required:"false" cty:"shared_gallery_image_version_end_of_life_date" hcl:"shared_gallery_image_version_end_of_life_date"` - SharedGalleryImageVersionReplicaCount *int32 `mapstructure:"shared_image_gallery_replica_count" required:"false" cty:"shared_image_gallery_replica_count" hcl:"shared_image_gallery_replica_count"` - SharedGalleryImageVersionExcludeFromLatest *bool `mapstructure:"shared_gallery_image_version_exclude_from_latest" required:"false" cty:"shared_gallery_image_version_exclude_from_latest" hcl:"shared_gallery_image_version_exclude_from_latest"` - ImagePublisher *string `mapstructure:"image_publisher" required:"true" cty:"image_publisher" hcl:"image_publisher"` - ImageOffer *string `mapstructure:"image_offer" required:"true" cty:"image_offer" hcl:"image_offer"` - ImageSku *string `mapstructure:"image_sku" required:"true" cty:"image_sku" hcl:"image_sku"` - ImageVersion *string `mapstructure:"image_version" required:"false" cty:"image_version" hcl:"image_version"` - ImageUrl *string `mapstructure:"image_url" required:"true" cty:"image_url" hcl:"image_url"` - CustomManagedImageName *string `mapstructure:"custom_managed_image_name" required:"true" cty:"custom_managed_image_name" hcl:"custom_managed_image_name"` - CustomManagedImageResourceGroupName *string `mapstructure:"custom_managed_image_resource_group_name" required:"true" cty:"custom_managed_image_resource_group_name" hcl:"custom_managed_image_resource_group_name"` - Location *string `mapstructure:"location" cty:"location" hcl:"location"` - VMSize *string `mapstructure:"vm_size" required:"false" cty:"vm_size" hcl:"vm_size"` - ManagedImageResourceGroupName *string `mapstructure:"managed_image_resource_group_name" cty:"managed_image_resource_group_name" hcl:"managed_image_resource_group_name"` - ManagedImageName *string `mapstructure:"managed_image_name" cty:"managed_image_name" hcl:"managed_image_name"` - ManagedImageStorageAccountType *string `mapstructure:"managed_image_storage_account_type" required:"false" cty:"managed_image_storage_account_type" hcl:"managed_image_storage_account_type"` - ManagedImageOSDiskSnapshotName *string `mapstructure:"managed_image_os_disk_snapshot_name" required:"false" cty:"managed_image_os_disk_snapshot_name" hcl:"managed_image_os_disk_snapshot_name"` - ManagedImageDataDiskSnapshotPrefix *string `mapstructure:"managed_image_data_disk_snapshot_prefix" required:"false" cty:"managed_image_data_disk_snapshot_prefix" hcl:"managed_image_data_disk_snapshot_prefix"` - KeepOSDisk *bool `mapstructure:"keep_os_disk" required:"false" cty:"keep_os_disk" hcl:"keep_os_disk"` - ManagedImageZoneResilient *bool `mapstructure:"managed_image_zone_resilient" required:"false" cty:"managed_image_zone_resilient" hcl:"managed_image_zone_resilient"` - AzureTags map[string]string `mapstructure:"azure_tags" required:"false" cty:"azure_tags" hcl:"azure_tags"` - AzureTag []config.FlatNameValue `mapstructure:"azure_tag" required:"false" cty:"azure_tag" hcl:"azure_tag"` - ResourceGroupName *string `mapstructure:"resource_group_name" cty:"resource_group_name" hcl:"resource_group_name"` - StorageAccount *string `mapstructure:"storage_account" cty:"storage_account" hcl:"storage_account"` - TempComputeName *string `mapstructure:"temp_compute_name" required:"false" cty:"temp_compute_name" hcl:"temp_compute_name"` - TempNicName *string `mapstructure:"temp_nic_name" required:"false" cty:"temp_nic_name" hcl:"temp_nic_name"` - TempResourceGroupName *string `mapstructure:"temp_resource_group_name" cty:"temp_resource_group_name" hcl:"temp_resource_group_name"` - BuildResourceGroupName *string `mapstructure:"build_resource_group_name" cty:"build_resource_group_name" hcl:"build_resource_group_name"` - BuildKeyVaultName *string `mapstructure:"build_key_vault_name" cty:"build_key_vault_name" hcl:"build_key_vault_name"` - BuildKeyVaultSKU *string `mapstructure:"build_key_vault_sku" cty:"build_key_vault_sku" hcl:"build_key_vault_sku"` - PrivateVirtualNetworkWithPublicIp *bool `mapstructure:"private_virtual_network_with_public_ip" required:"false" cty:"private_virtual_network_with_public_ip" hcl:"private_virtual_network_with_public_ip"` - VirtualNetworkName *string `mapstructure:"virtual_network_name" required:"false" cty:"virtual_network_name" hcl:"virtual_network_name"` - VirtualNetworkSubnetName *string `mapstructure:"virtual_network_subnet_name" required:"false" cty:"virtual_network_subnet_name" hcl:"virtual_network_subnet_name"` - VirtualNetworkResourceGroupName *string `mapstructure:"virtual_network_resource_group_name" required:"false" cty:"virtual_network_resource_group_name" hcl:"virtual_network_resource_group_name"` - CustomDataFile *string `mapstructure:"custom_data_file" required:"false" cty:"custom_data_file" hcl:"custom_data_file"` - PlanInfo *FlatPlanInformation `mapstructure:"plan_info" required:"false" cty:"plan_info" hcl:"plan_info"` - PollingDurationTimeout *string `mapstructure:"polling_duration_timeout" required:"false" cty:"polling_duration_timeout" hcl:"polling_duration_timeout"` - OSType *string `mapstructure:"os_type" required:"false" cty:"os_type" hcl:"os_type"` - TempOSDiskName *string `mapstructure:"temp_os_disk_name" required:"false" cty:"temp_os_disk_name" hcl:"temp_os_disk_name"` - OSDiskSizeGB *int32 `mapstructure:"os_disk_size_gb" required:"false" cty:"os_disk_size_gb" hcl:"os_disk_size_gb"` - AdditionalDiskSize []int32 `mapstructure:"disk_additional_size" required:"false" cty:"disk_additional_size" hcl:"disk_additional_size"` - DiskCachingType *string `mapstructure:"disk_caching_type" required:"false" cty:"disk_caching_type" hcl:"disk_caching_type"` - AllowedInboundIpAddresses []string `mapstructure:"allowed_inbound_ip_addresses" cty:"allowed_inbound_ip_addresses" hcl:"allowed_inbound_ip_addresses"` - BootDiagSTGAccount *string `mapstructure:"boot_diag_storage_account" required:"false" cty:"boot_diag_storage_account" hcl:"boot_diag_storage_account"` - CustomResourcePrefix *string `mapstructure:"custom_resource_build_prefix" required:"false" cty:"custom_resource_build_prefix" hcl:"custom_resource_build_prefix"` - Type *string `mapstructure:"communicator" cty:"communicator" hcl:"communicator"` - PauseBeforeConnect *string `mapstructure:"pause_before_connecting" cty:"pause_before_connecting" hcl:"pause_before_connecting"` - SSHHost *string `mapstructure:"ssh_host" cty:"ssh_host" hcl:"ssh_host"` - SSHPort *int `mapstructure:"ssh_port" cty:"ssh_port" hcl:"ssh_port"` - SSHUsername *string `mapstructure:"ssh_username" cty:"ssh_username" hcl:"ssh_username"` - SSHPassword *string `mapstructure:"ssh_password" cty:"ssh_password" hcl:"ssh_password"` - SSHKeyPairName *string `mapstructure:"ssh_keypair_name" undocumented:"true" cty:"ssh_keypair_name" hcl:"ssh_keypair_name"` - SSHTemporaryKeyPairName *string `mapstructure:"temporary_key_pair_name" undocumented:"true" cty:"temporary_key_pair_name" hcl:"temporary_key_pair_name"` - SSHTemporaryKeyPairType *string `mapstructure:"temporary_key_pair_type" cty:"temporary_key_pair_type" hcl:"temporary_key_pair_type"` - SSHTemporaryKeyPairBits *int `mapstructure:"temporary_key_pair_bits" cty:"temporary_key_pair_bits" hcl:"temporary_key_pair_bits"` - SSHCiphers []string `mapstructure:"ssh_ciphers" cty:"ssh_ciphers" hcl:"ssh_ciphers"` - SSHClearAuthorizedKeys *bool `mapstructure:"ssh_clear_authorized_keys" cty:"ssh_clear_authorized_keys" hcl:"ssh_clear_authorized_keys"` - SSHKEXAlgos []string `mapstructure:"ssh_key_exchange_algorithms" cty:"ssh_key_exchange_algorithms" hcl:"ssh_key_exchange_algorithms"` - SSHPrivateKeyFile *string `mapstructure:"ssh_private_key_file" undocumented:"true" cty:"ssh_private_key_file" hcl:"ssh_private_key_file"` - SSHCertificateFile *string `mapstructure:"ssh_certificate_file" cty:"ssh_certificate_file" hcl:"ssh_certificate_file"` - SSHPty *bool `mapstructure:"ssh_pty" cty:"ssh_pty" hcl:"ssh_pty"` - SSHTimeout *string `mapstructure:"ssh_timeout" cty:"ssh_timeout" hcl:"ssh_timeout"` - SSHWaitTimeout *string `mapstructure:"ssh_wait_timeout" undocumented:"true" cty:"ssh_wait_timeout" hcl:"ssh_wait_timeout"` - SSHAgentAuth *bool `mapstructure:"ssh_agent_auth" undocumented:"true" cty:"ssh_agent_auth" hcl:"ssh_agent_auth"` - SSHDisableAgentForwarding *bool `mapstructure:"ssh_disable_agent_forwarding" cty:"ssh_disable_agent_forwarding" hcl:"ssh_disable_agent_forwarding"` - SSHHandshakeAttempts *int `mapstructure:"ssh_handshake_attempts" cty:"ssh_handshake_attempts" hcl:"ssh_handshake_attempts"` - SSHBastionHost *string `mapstructure:"ssh_bastion_host" cty:"ssh_bastion_host" hcl:"ssh_bastion_host"` - SSHBastionPort *int `mapstructure:"ssh_bastion_port" cty:"ssh_bastion_port" hcl:"ssh_bastion_port"` - SSHBastionAgentAuth *bool `mapstructure:"ssh_bastion_agent_auth" cty:"ssh_bastion_agent_auth" hcl:"ssh_bastion_agent_auth"` - SSHBastionUsername *string `mapstructure:"ssh_bastion_username" cty:"ssh_bastion_username" hcl:"ssh_bastion_username"` - SSHBastionPassword *string `mapstructure:"ssh_bastion_password" cty:"ssh_bastion_password" hcl:"ssh_bastion_password"` - SSHBastionInteractive *bool `mapstructure:"ssh_bastion_interactive" cty:"ssh_bastion_interactive" hcl:"ssh_bastion_interactive"` - SSHBastionPrivateKeyFile *string `mapstructure:"ssh_bastion_private_key_file" cty:"ssh_bastion_private_key_file" hcl:"ssh_bastion_private_key_file"` - SSHBastionCertificateFile *string `mapstructure:"ssh_bastion_certificate_file" cty:"ssh_bastion_certificate_file" hcl:"ssh_bastion_certificate_file"` - SSHFileTransferMethod *string `mapstructure:"ssh_file_transfer_method" cty:"ssh_file_transfer_method" hcl:"ssh_file_transfer_method"` - SSHProxyHost *string `mapstructure:"ssh_proxy_host" cty:"ssh_proxy_host" hcl:"ssh_proxy_host"` - SSHProxyPort *int `mapstructure:"ssh_proxy_port" cty:"ssh_proxy_port" hcl:"ssh_proxy_port"` - SSHProxyUsername *string `mapstructure:"ssh_proxy_username" cty:"ssh_proxy_username" hcl:"ssh_proxy_username"` - SSHProxyPassword *string `mapstructure:"ssh_proxy_password" cty:"ssh_proxy_password" hcl:"ssh_proxy_password"` - SSHKeepAliveInterval *string `mapstructure:"ssh_keep_alive_interval" cty:"ssh_keep_alive_interval" hcl:"ssh_keep_alive_interval"` - SSHReadWriteTimeout *string `mapstructure:"ssh_read_write_timeout" cty:"ssh_read_write_timeout" hcl:"ssh_read_write_timeout"` - SSHRemoteTunnels []string `mapstructure:"ssh_remote_tunnels" cty:"ssh_remote_tunnels" hcl:"ssh_remote_tunnels"` - SSHLocalTunnels []string `mapstructure:"ssh_local_tunnels" cty:"ssh_local_tunnels" hcl:"ssh_local_tunnels"` - SSHPublicKey []byte `mapstructure:"ssh_public_key" undocumented:"true" cty:"ssh_public_key" hcl:"ssh_public_key"` - SSHPrivateKey []byte `mapstructure:"ssh_private_key" undocumented:"true" cty:"ssh_private_key" hcl:"ssh_private_key"` - WinRMUser *string `mapstructure:"winrm_username" cty:"winrm_username" hcl:"winrm_username"` - WinRMPassword *string `mapstructure:"winrm_password" cty:"winrm_password" hcl:"winrm_password"` - WinRMHost *string `mapstructure:"winrm_host" cty:"winrm_host" hcl:"winrm_host"` - WinRMNoProxy *bool `mapstructure:"winrm_no_proxy" cty:"winrm_no_proxy" hcl:"winrm_no_proxy"` - WinRMPort *int `mapstructure:"winrm_port" cty:"winrm_port" hcl:"winrm_port"` - WinRMTimeout *string `mapstructure:"winrm_timeout" cty:"winrm_timeout" hcl:"winrm_timeout"` - WinRMUseSSL *bool `mapstructure:"winrm_use_ssl" cty:"winrm_use_ssl" hcl:"winrm_use_ssl"` - WinRMInsecure *bool `mapstructure:"winrm_insecure" cty:"winrm_insecure" hcl:"winrm_insecure"` - WinRMUseNTLM *bool `mapstructure:"winrm_use_ntlm" cty:"winrm_use_ntlm" hcl:"winrm_use_ntlm"` - AsyncResourceGroupDelete *bool `mapstructure:"async_resourcegroup_delete" required:"false" cty:"async_resourcegroup_delete" hcl:"async_resourcegroup_delete"` -} - -// FlatMapstructure returns a new FlatConfig. -// FlatConfig is an auto-generated flat version of Config. -// Where the contents a fields with a `mapstructure:,squash` tag are bubbled up. -func (*Config) FlatMapstructure() interface{ HCL2Spec() map[string]hcldec.Spec } { - return new(FlatConfig) -} - -// HCL2Spec returns the hcl spec of a Config. -// This spec is used by HCL to read the fields of Config. -// The decoded values from this spec will then be applied to a FlatConfig. -func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec { - s := map[string]hcldec.Spec{ - "packer_build_name": &hcldec.AttrSpec{Name: "packer_build_name", Type: cty.String, Required: false}, - "packer_builder_type": &hcldec.AttrSpec{Name: "packer_builder_type", Type: cty.String, Required: false}, - "packer_core_version": &hcldec.AttrSpec{Name: "packer_core_version", Type: cty.String, Required: false}, - "packer_debug": &hcldec.AttrSpec{Name: "packer_debug", Type: cty.Bool, Required: false}, - "packer_force": &hcldec.AttrSpec{Name: "packer_force", Type: cty.Bool, Required: false}, - "packer_on_error": &hcldec.AttrSpec{Name: "packer_on_error", Type: cty.String, Required: false}, - "packer_user_variables": &hcldec.AttrSpec{Name: "packer_user_variables", Type: cty.Map(cty.String), Required: false}, - "packer_sensitive_variables": &hcldec.AttrSpec{Name: "packer_sensitive_variables", Type: cty.List(cty.String), Required: false}, - "cloud_environment_name": &hcldec.AttrSpec{Name: "cloud_environment_name", Type: cty.String, Required: false}, - "client_id": &hcldec.AttrSpec{Name: "client_id", Type: cty.String, Required: false}, - "client_secret": &hcldec.AttrSpec{Name: "client_secret", Type: cty.String, Required: false}, - "client_cert_path": &hcldec.AttrSpec{Name: "client_cert_path", Type: cty.String, Required: false}, - "client_cert_token_timeout": &hcldec.AttrSpec{Name: "client_cert_token_timeout", Type: cty.String, Required: false}, - "client_jwt": &hcldec.AttrSpec{Name: "client_jwt", Type: cty.String, Required: false}, - "object_id": &hcldec.AttrSpec{Name: "object_id", Type: cty.String, Required: false}, - "tenant_id": &hcldec.AttrSpec{Name: "tenant_id", Type: cty.String, Required: false}, - "subscription_id": &hcldec.AttrSpec{Name: "subscription_id", Type: cty.String, Required: false}, - "use_azure_cli_auth": &hcldec.AttrSpec{Name: "use_azure_cli_auth", Type: cty.Bool, Required: false}, - "user_assigned_managed_identities": &hcldec.AttrSpec{Name: "user_assigned_managed_identities", Type: cty.List(cty.String), Required: false}, - "capture_name_prefix": &hcldec.AttrSpec{Name: "capture_name_prefix", Type: cty.String, Required: false}, - "capture_container_name": &hcldec.AttrSpec{Name: "capture_container_name", Type: cty.String, Required: false}, - "shared_image_gallery": &hcldec.BlockSpec{TypeName: "shared_image_gallery", Nested: hcldec.ObjectSpec((*FlatSharedImageGallery)(nil).HCL2Spec())}, - "shared_image_gallery_destination": &hcldec.BlockSpec{TypeName: "shared_image_gallery_destination", Nested: hcldec.ObjectSpec((*FlatSharedImageGalleryDestination)(nil).HCL2Spec())}, - "shared_image_gallery_timeout": &hcldec.AttrSpec{Name: "shared_image_gallery_timeout", Type: cty.String, Required: false}, - "shared_gallery_image_version_end_of_life_date": &hcldec.AttrSpec{Name: "shared_gallery_image_version_end_of_life_date", Type: cty.String, Required: false}, - "shared_image_gallery_replica_count": &hcldec.AttrSpec{Name: "shared_image_gallery_replica_count", Type: cty.Number, Required: false}, - "shared_gallery_image_version_exclude_from_latest": &hcldec.AttrSpec{Name: "shared_gallery_image_version_exclude_from_latest", Type: cty.Bool, Required: false}, - "image_publisher": &hcldec.AttrSpec{Name: "image_publisher", Type: cty.String, Required: false}, - "image_offer": &hcldec.AttrSpec{Name: "image_offer", Type: cty.String, Required: false}, - "image_sku": &hcldec.AttrSpec{Name: "image_sku", Type: cty.String, Required: false}, - "image_version": &hcldec.AttrSpec{Name: "image_version", Type: cty.String, Required: false}, - "image_url": &hcldec.AttrSpec{Name: "image_url", Type: cty.String, Required: false}, - "custom_managed_image_name": &hcldec.AttrSpec{Name: "custom_managed_image_name", Type: cty.String, Required: false}, - "custom_managed_image_resource_group_name": &hcldec.AttrSpec{Name: "custom_managed_image_resource_group_name", Type: cty.String, Required: false}, - "location": &hcldec.AttrSpec{Name: "location", Type: cty.String, Required: false}, - "vm_size": &hcldec.AttrSpec{Name: "vm_size", Type: cty.String, Required: false}, - "managed_image_resource_group_name": &hcldec.AttrSpec{Name: "managed_image_resource_group_name", Type: cty.String, Required: false}, - "managed_image_name": &hcldec.AttrSpec{Name: "managed_image_name", Type: cty.String, Required: false}, - "managed_image_storage_account_type": &hcldec.AttrSpec{Name: "managed_image_storage_account_type", Type: cty.String, Required: false}, - "managed_image_os_disk_snapshot_name": &hcldec.AttrSpec{Name: "managed_image_os_disk_snapshot_name", Type: cty.String, Required: false}, - "managed_image_data_disk_snapshot_prefix": &hcldec.AttrSpec{Name: "managed_image_data_disk_snapshot_prefix", Type: cty.String, Required: false}, - "keep_os_disk": &hcldec.AttrSpec{Name: "keep_os_disk", Type: cty.Bool, Required: false}, - "managed_image_zone_resilient": &hcldec.AttrSpec{Name: "managed_image_zone_resilient", Type: cty.Bool, Required: false}, - "azure_tags": &hcldec.AttrSpec{Name: "azure_tags", Type: cty.Map(cty.String), Required: false}, - "azure_tag": &hcldec.BlockListSpec{TypeName: "azure_tag", Nested: hcldec.ObjectSpec((*config.FlatNameValue)(nil).HCL2Spec())}, - "resource_group_name": &hcldec.AttrSpec{Name: "resource_group_name", Type: cty.String, Required: false}, - "storage_account": &hcldec.AttrSpec{Name: "storage_account", Type: cty.String, Required: false}, - "temp_compute_name": &hcldec.AttrSpec{Name: "temp_compute_name", Type: cty.String, Required: false}, - "temp_nic_name": &hcldec.AttrSpec{Name: "temp_nic_name", Type: cty.String, Required: false}, - "temp_resource_group_name": &hcldec.AttrSpec{Name: "temp_resource_group_name", Type: cty.String, Required: false}, - "build_resource_group_name": &hcldec.AttrSpec{Name: "build_resource_group_name", Type: cty.String, Required: false}, - "build_key_vault_name": &hcldec.AttrSpec{Name: "build_key_vault_name", Type: cty.String, Required: false}, - "build_key_vault_sku": &hcldec.AttrSpec{Name: "build_key_vault_sku", Type: cty.String, Required: false}, - "private_virtual_network_with_public_ip": &hcldec.AttrSpec{Name: "private_virtual_network_with_public_ip", Type: cty.Bool, Required: false}, - "virtual_network_name": &hcldec.AttrSpec{Name: "virtual_network_name", Type: cty.String, Required: false}, - "virtual_network_subnet_name": &hcldec.AttrSpec{Name: "virtual_network_subnet_name", Type: cty.String, Required: false}, - "virtual_network_resource_group_name": &hcldec.AttrSpec{Name: "virtual_network_resource_group_name", Type: cty.String, Required: false}, - "custom_data_file": &hcldec.AttrSpec{Name: "custom_data_file", Type: cty.String, Required: false}, - "plan_info": &hcldec.BlockSpec{TypeName: "plan_info", Nested: hcldec.ObjectSpec((*FlatPlanInformation)(nil).HCL2Spec())}, - "polling_duration_timeout": &hcldec.AttrSpec{Name: "polling_duration_timeout", Type: cty.String, Required: false}, - "os_type": &hcldec.AttrSpec{Name: "os_type", Type: cty.String, Required: false}, - "temp_os_disk_name": &hcldec.AttrSpec{Name: "temp_os_disk_name", Type: cty.String, Required: false}, - "os_disk_size_gb": &hcldec.AttrSpec{Name: "os_disk_size_gb", Type: cty.Number, Required: false}, - "disk_additional_size": &hcldec.AttrSpec{Name: "disk_additional_size", Type: cty.List(cty.Number), Required: false}, - "disk_caching_type": &hcldec.AttrSpec{Name: "disk_caching_type", Type: cty.String, Required: false}, - "allowed_inbound_ip_addresses": &hcldec.AttrSpec{Name: "allowed_inbound_ip_addresses", Type: cty.List(cty.String), Required: false}, - "boot_diag_storage_account": &hcldec.AttrSpec{Name: "boot_diag_storage_account", Type: cty.String, Required: false}, - "custom_resource_build_prefix": &hcldec.AttrSpec{Name: "custom_resource_build_prefix", Type: cty.String, Required: false}, - "communicator": &hcldec.AttrSpec{Name: "communicator", Type: cty.String, Required: false}, - "pause_before_connecting": &hcldec.AttrSpec{Name: "pause_before_connecting", Type: cty.String, Required: false}, - "ssh_host": &hcldec.AttrSpec{Name: "ssh_host", Type: cty.String, Required: false}, - "ssh_port": &hcldec.AttrSpec{Name: "ssh_port", Type: cty.Number, Required: false}, - "ssh_username": &hcldec.AttrSpec{Name: "ssh_username", Type: cty.String, Required: false}, - "ssh_password": &hcldec.AttrSpec{Name: "ssh_password", Type: cty.String, Required: false}, - "ssh_keypair_name": &hcldec.AttrSpec{Name: "ssh_keypair_name", Type: cty.String, Required: false}, - "temporary_key_pair_name": &hcldec.AttrSpec{Name: "temporary_key_pair_name", Type: cty.String, Required: false}, - "temporary_key_pair_type": &hcldec.AttrSpec{Name: "temporary_key_pair_type", Type: cty.String, Required: false}, - "temporary_key_pair_bits": &hcldec.AttrSpec{Name: "temporary_key_pair_bits", Type: cty.Number, Required: false}, - "ssh_ciphers": &hcldec.AttrSpec{Name: "ssh_ciphers", Type: cty.List(cty.String), Required: false}, - "ssh_clear_authorized_keys": &hcldec.AttrSpec{Name: "ssh_clear_authorized_keys", Type: cty.Bool, Required: false}, - "ssh_key_exchange_algorithms": &hcldec.AttrSpec{Name: "ssh_key_exchange_algorithms", Type: cty.List(cty.String), Required: false}, - "ssh_private_key_file": &hcldec.AttrSpec{Name: "ssh_private_key_file", Type: cty.String, Required: false}, - "ssh_certificate_file": &hcldec.AttrSpec{Name: "ssh_certificate_file", Type: cty.String, Required: false}, - "ssh_pty": &hcldec.AttrSpec{Name: "ssh_pty", Type: cty.Bool, Required: false}, - "ssh_timeout": &hcldec.AttrSpec{Name: "ssh_timeout", Type: cty.String, Required: false}, - "ssh_wait_timeout": &hcldec.AttrSpec{Name: "ssh_wait_timeout", Type: cty.String, Required: false}, - "ssh_agent_auth": &hcldec.AttrSpec{Name: "ssh_agent_auth", Type: cty.Bool, Required: false}, - "ssh_disable_agent_forwarding": &hcldec.AttrSpec{Name: "ssh_disable_agent_forwarding", Type: cty.Bool, Required: false}, - "ssh_handshake_attempts": &hcldec.AttrSpec{Name: "ssh_handshake_attempts", Type: cty.Number, Required: false}, - "ssh_bastion_host": &hcldec.AttrSpec{Name: "ssh_bastion_host", Type: cty.String, Required: false}, - "ssh_bastion_port": &hcldec.AttrSpec{Name: "ssh_bastion_port", Type: cty.Number, Required: false}, - "ssh_bastion_agent_auth": &hcldec.AttrSpec{Name: "ssh_bastion_agent_auth", Type: cty.Bool, Required: false}, - "ssh_bastion_username": &hcldec.AttrSpec{Name: "ssh_bastion_username", Type: cty.String, Required: false}, - "ssh_bastion_password": &hcldec.AttrSpec{Name: "ssh_bastion_password", Type: cty.String, Required: false}, - "ssh_bastion_interactive": &hcldec.AttrSpec{Name: "ssh_bastion_interactive", Type: cty.Bool, Required: false}, - "ssh_bastion_private_key_file": &hcldec.AttrSpec{Name: "ssh_bastion_private_key_file", Type: cty.String, Required: false}, - "ssh_bastion_certificate_file": &hcldec.AttrSpec{Name: "ssh_bastion_certificate_file", Type: cty.String, Required: false}, - "ssh_file_transfer_method": &hcldec.AttrSpec{Name: "ssh_file_transfer_method", Type: cty.String, Required: false}, - "ssh_proxy_host": &hcldec.AttrSpec{Name: "ssh_proxy_host", Type: cty.String, Required: false}, - "ssh_proxy_port": &hcldec.AttrSpec{Name: "ssh_proxy_port", Type: cty.Number, Required: false}, - "ssh_proxy_username": &hcldec.AttrSpec{Name: "ssh_proxy_username", Type: cty.String, Required: false}, - "ssh_proxy_password": &hcldec.AttrSpec{Name: "ssh_proxy_password", Type: cty.String, Required: false}, - "ssh_keep_alive_interval": &hcldec.AttrSpec{Name: "ssh_keep_alive_interval", Type: cty.String, Required: false}, - "ssh_read_write_timeout": &hcldec.AttrSpec{Name: "ssh_read_write_timeout", Type: cty.String, Required: false}, - "ssh_remote_tunnels": &hcldec.AttrSpec{Name: "ssh_remote_tunnels", Type: cty.List(cty.String), Required: false}, - "ssh_local_tunnels": &hcldec.AttrSpec{Name: "ssh_local_tunnels", Type: cty.List(cty.String), Required: false}, - "ssh_public_key": &hcldec.AttrSpec{Name: "ssh_public_key", Type: cty.List(cty.Number), Required: false}, - "ssh_private_key": &hcldec.AttrSpec{Name: "ssh_private_key", Type: cty.List(cty.Number), Required: false}, - "winrm_username": &hcldec.AttrSpec{Name: "winrm_username", Type: cty.String, Required: false}, - "winrm_password": &hcldec.AttrSpec{Name: "winrm_password", Type: cty.String, Required: false}, - "winrm_host": &hcldec.AttrSpec{Name: "winrm_host", Type: cty.String, Required: false}, - "winrm_no_proxy": &hcldec.AttrSpec{Name: "winrm_no_proxy", Type: cty.Bool, Required: false}, - "winrm_port": &hcldec.AttrSpec{Name: "winrm_port", Type: cty.Number, Required: false}, - "winrm_timeout": &hcldec.AttrSpec{Name: "winrm_timeout", Type: cty.String, Required: false}, - "winrm_use_ssl": &hcldec.AttrSpec{Name: "winrm_use_ssl", Type: cty.Bool, Required: false}, - "winrm_insecure": &hcldec.AttrSpec{Name: "winrm_insecure", Type: cty.Bool, Required: false}, - "winrm_use_ntlm": &hcldec.AttrSpec{Name: "winrm_use_ntlm", Type: cty.Bool, Required: false}, - "async_resourcegroup_delete": &hcldec.AttrSpec{Name: "async_resourcegroup_delete", Type: cty.Bool, Required: false}, - } - return s -} - -// FlatPlanInformation is an auto-generated flat version of PlanInformation. -// Where the contents of a field with a `mapstructure:,squash` tag are bubbled up. -type FlatPlanInformation struct { - PlanName *string `mapstructure:"plan_name" cty:"plan_name" hcl:"plan_name"` - PlanProduct *string `mapstructure:"plan_product" cty:"plan_product" hcl:"plan_product"` - PlanPublisher *string `mapstructure:"plan_publisher" cty:"plan_publisher" hcl:"plan_publisher"` - PlanPromotionCode *string `mapstructure:"plan_promotion_code" cty:"plan_promotion_code" hcl:"plan_promotion_code"` -} - -// FlatMapstructure returns a new FlatPlanInformation. -// FlatPlanInformation is an auto-generated flat version of PlanInformation. -// Where the contents a fields with a `mapstructure:,squash` tag are bubbled up. -func (*PlanInformation) FlatMapstructure() interface{ HCL2Spec() map[string]hcldec.Spec } { - return new(FlatPlanInformation) -} - -// HCL2Spec returns the hcl spec of a PlanInformation. -// This spec is used by HCL to read the fields of PlanInformation. -// The decoded values from this spec will then be applied to a FlatPlanInformation. -func (*FlatPlanInformation) HCL2Spec() map[string]hcldec.Spec { - s := map[string]hcldec.Spec{ - "plan_name": &hcldec.AttrSpec{Name: "plan_name", Type: cty.String, Required: false}, - "plan_product": &hcldec.AttrSpec{Name: "plan_product", Type: cty.String, Required: false}, - "plan_publisher": &hcldec.AttrSpec{Name: "plan_publisher", Type: cty.String, Required: false}, - "plan_promotion_code": &hcldec.AttrSpec{Name: "plan_promotion_code", Type: cty.String, Required: false}, - } - return s -} - -// FlatSharedImageGallery is an auto-generated flat version of SharedImageGallery. -// Where the contents of a field with a `mapstructure:,squash` tag are bubbled up. -type FlatSharedImageGallery struct { - Subscription *string `mapstructure:"subscription" cty:"subscription" hcl:"subscription"` - ResourceGroup *string `mapstructure:"resource_group" cty:"resource_group" hcl:"resource_group"` - GalleryName *string `mapstructure:"gallery_name" cty:"gallery_name" hcl:"gallery_name"` - ImageName *string `mapstructure:"image_name" cty:"image_name" hcl:"image_name"` - ImageVersion *string `mapstructure:"image_version" required:"false" cty:"image_version" hcl:"image_version"` -} - -// FlatMapstructure returns a new FlatSharedImageGallery. -// FlatSharedImageGallery is an auto-generated flat version of SharedImageGallery. -// Where the contents a fields with a `mapstructure:,squash` tag are bubbled up. -func (*SharedImageGallery) FlatMapstructure() interface{ HCL2Spec() map[string]hcldec.Spec } { - return new(FlatSharedImageGallery) -} - -// HCL2Spec returns the hcl spec of a SharedImageGallery. -// This spec is used by HCL to read the fields of SharedImageGallery. -// The decoded values from this spec will then be applied to a FlatSharedImageGallery. -func (*FlatSharedImageGallery) HCL2Spec() map[string]hcldec.Spec { - s := map[string]hcldec.Spec{ - "subscription": &hcldec.AttrSpec{Name: "subscription", Type: cty.String, Required: false}, - "resource_group": &hcldec.AttrSpec{Name: "resource_group", Type: cty.String, Required: false}, - "gallery_name": &hcldec.AttrSpec{Name: "gallery_name", Type: cty.String, Required: false}, - "image_name": &hcldec.AttrSpec{Name: "image_name", Type: cty.String, Required: false}, - "image_version": &hcldec.AttrSpec{Name: "image_version", Type: cty.String, Required: false}, - } - return s -} - -// FlatSharedImageGalleryDestination is an auto-generated flat version of SharedImageGalleryDestination. -// Where the contents of a field with a `mapstructure:,squash` tag are bubbled up. -type FlatSharedImageGalleryDestination struct { - SigDestinationSubscription *string `mapstructure:"subscription" cty:"subscription" hcl:"subscription"` - SigDestinationResourceGroup *string `mapstructure:"resource_group" cty:"resource_group" hcl:"resource_group"` - SigDestinationGalleryName *string `mapstructure:"gallery_name" cty:"gallery_name" hcl:"gallery_name"` - SigDestinationImageName *string `mapstructure:"image_name" cty:"image_name" hcl:"image_name"` - SigDestinationImageVersion *string `mapstructure:"image_version" cty:"image_version" hcl:"image_version"` - SigDestinationReplicationRegions []string `mapstructure:"replication_regions" cty:"replication_regions" hcl:"replication_regions"` - SigDestinationStorageAccountType *string `mapstructure:"storage_account_type" cty:"storage_account_type" hcl:"storage_account_type"` -} - -// FlatMapstructure returns a new FlatSharedImageGalleryDestination. -// FlatSharedImageGalleryDestination is an auto-generated flat version of SharedImageGalleryDestination. -// Where the contents a fields with a `mapstructure:,squash` tag are bubbled up. -func (*SharedImageGalleryDestination) FlatMapstructure() interface{ HCL2Spec() map[string]hcldec.Spec } { - return new(FlatSharedImageGalleryDestination) -} - -// HCL2Spec returns the hcl spec of a SharedImageGalleryDestination. -// This spec is used by HCL to read the fields of SharedImageGalleryDestination. -// The decoded values from this spec will then be applied to a FlatSharedImageGalleryDestination. -func (*FlatSharedImageGalleryDestination) HCL2Spec() map[string]hcldec.Spec { - s := map[string]hcldec.Spec{ - "subscription": &hcldec.AttrSpec{Name: "subscription", Type: cty.String, Required: false}, - "resource_group": &hcldec.AttrSpec{Name: "resource_group", Type: cty.String, Required: false}, - "gallery_name": &hcldec.AttrSpec{Name: "gallery_name", Type: cty.String, Required: false}, - "image_name": &hcldec.AttrSpec{Name: "image_name", Type: cty.String, Required: false}, - "image_version": &hcldec.AttrSpec{Name: "image_version", Type: cty.String, Required: false}, - "replication_regions": &hcldec.AttrSpec{Name: "replication_regions", Type: cty.List(cty.String), Required: false}, - "storage_account_type": &hcldec.AttrSpec{Name: "storage_account_type", Type: cty.String, Required: false}, - } - return s -} diff --git a/builder/azure/arm/config_test.go b/builder/azure/arm/config_test.go deleted file mode 100644 index 83b51f937..000000000 --- a/builder/azure/arm/config_test.go +++ /dev/null @@ -1,2188 +0,0 @@ -package arm - -import ( - "fmt" - "testing" - "time" - - "github.com/Azure/azure-sdk-for-go/services/compute/mgmt/2018-04-01/compute" - "github.com/google/go-cmp/cmp" - sdkconfig "github.com/hashicorp/packer-plugin-sdk/template/config" - "github.com/hashicorp/packer/builder/azure/common/constants" -) - -// List of configuration parameters that are required by the ARM builder. -var requiredConfigValues = []string{ - "capture_name_prefix", - "capture_container_name", - "client_id", - "client_secret", - "image_offer", - "image_publisher", - "image_sku", - "location", - "os_type", - "storage_account", - "resource_group_name", - "subscription_id", -} - -func TestConfigShouldProvideReasonableDefaultValues(t *testing.T) { - var c Config - _, err := c.Prepare(getArmBuilderConfiguration(), getPackerConfiguration()) - - if err != nil { - t.Error("Expected configuration creation to succeed, but it failed!\n") - t.Fatalf(" errors: %s\n", err) - } - - if c.UserName == "" { - t.Error("Expected 'UserName' to be populated, but it was empty!") - } - - if c.VMSize == "" { - t.Error("Expected 'VMSize' to be populated, but it was empty!") - } - - if c.ClientConfig.ObjectID != "" { - t.Errorf("Expected 'ObjectID' to be nil, but it was '%s'!", c.ClientConfig.ObjectID) - } - - if c.managedImageStorageAccountType == "" { - t.Errorf("Expected 'managedImageStorageAccountType' to be populated, but it was empty!") - } - - if c.diskCachingType == "" { - t.Errorf("Expected 'diskCachingType' to be populated, but it was empty!") - } -} - -func TestConfigUserNameOverride(t *testing.T) { - builderValues := getArmBuilderConfiguration() - builderValues["ssh_username"] = "override_username" - builderValues["communicator"] = "ssh" - - var c Config - _, err := c.Prepare(builderValues, getPackerConfiguration()) - - if err != nil { - t.Fatalf("newConfig failed: %s", err) - } - - // SSH comm - if c.Password != c.tmpAdminPassword { - t.Errorf("Expected 'Password' to be set to generated password, but found %q!", c.Password) - } - if c.Comm.SSHPassword != "" { - t.Errorf("Expected 'c.Comm.SSHPassword' to be empty, but found %q!", c.Comm.SSHPassword) - } - if c.UserName != "override_username" { - t.Errorf("Expected 'UserName' to be set to 'override_username', but found %q!", c.UserName) - } - if c.Comm.SSHUsername != "override_username" { - t.Errorf("Expected 'c.Comm.SSHUsername' to be set to 'override_username', but found %q!", c.Comm.SSHUsername) - } - - // Winrm comm - c = Config{} - builderValues = getArmBuilderConfiguration() - builderValues["communicator"] = "winrm" - builderValues["winrm_username"] = "override_winrm_username" - _, err = c.Prepare(builderValues, getPackerConfiguration()) - if err != nil { - t.Fatalf("newConfig failed: %s", err) - } - if c.Password != c.tmpAdminPassword { - t.Errorf("Expected 'Password' to be set to generated password, but found %q!", c.Password) - } - if c.Comm.WinRMPassword != c.tmpAdminPassword { - t.Errorf("Expected 'c.Comm.WinRMPassword' to be set to generated password, but found %q!", c.Comm.WinRMPassword) - } - if c.UserName != "override_winrm_username" { - t.Errorf("Expected 'UserName' to be set to 'override_winrm_username', but found %q!", c.UserName) - } - if c.Comm.WinRMUser != "override_winrm_username" { - t.Errorf("Expected 'c.Comm.WinRMUser' to be set to 'override_winrm_username', but found %q!", c.Comm.WinRMUser) - } -} -func TestConfigShouldBeAbleToOverrideDefaultedValues(t *testing.T) { - builderValues := getArmBuilderConfiguration() - builderValues["ssh_password"] = "override_password" - builderValues["ssh_username"] = "override_username" - builderValues["vm_size"] = "override_vm_size" - builderValues["communicator"] = "ssh" - builderValues["managed_image_storage_account_type"] = "Premium_LRS" - builderValues["disk_caching_type"] = "None" - - var c Config - _, err := c.Prepare(builderValues, getPackerConfiguration()) - - if err != nil { - t.Fatalf("newConfig failed: %s", err) - } - - if c.VMSize != "override_vm_size" { - t.Errorf("Expected 'vm_size' to be set to 'override_vm_size', but found %q!", c.VMSize) - } - - if c.managedImageStorageAccountType != compute.StorageAccountTypesPremiumLRS { - t.Errorf("Expected 'managed_image_storage_account_type' to be set to 'Premium_LRS', but found %q!", c.managedImageStorageAccountType) - } - - if c.diskCachingType != compute.CachingTypesNone { - t.Errorf("Expected 'disk_caching_type' to be set to 'None', but found %q!", c.diskCachingType) - } - - // SSH comm - if c.Password != "override_password" { - t.Errorf("Expected 'Password' to be set to 'override_password', but found %q!", c.Password) - } - if c.Comm.SSHPassword != "override_password" { - t.Errorf("Expected 'c.Comm.SSHPassword' to be set to 'override_password', but found %q!", c.Comm.SSHPassword) - } - if c.UserName != "override_username" { - t.Errorf("Expected 'UserName' to be set to 'override_username', but found %q!", c.UserName) - } - if c.Comm.SSHUsername != "override_username" { - t.Errorf("Expected 'c.Comm.SSHUsername' to be set to 'override_username', but found %q!", c.Comm.SSHUsername) - } - - // Winrm comm - c = Config{} - builderValues = getArmBuilderConfiguration() - builderValues["communicator"] = "winrm" - builderValues["winrm_password"] = "Override_winrm_password1" - builderValues["winrm_username"] = "override_winrm_username" - _, err = c.Prepare(builderValues, getPackerConfiguration()) - if err != nil { - t.Fatalf("newConfig failed: %s", err) - } - if c.Password != "Override_winrm_password1" { - t.Errorf("Expected 'Password' to be set to 'Override_winrm_password1', but found %q!", c.Password) - } - if c.Comm.WinRMPassword != "Override_winrm_password1" { - t.Errorf("Expected 'c.Comm.WinRMPassword' to be set to 'Override_winrm_password1', but found %q!", c.Comm.WinRMPassword) - } - if c.UserName != "override_winrm_username" { - t.Errorf("Expected 'UserName' to be set to 'override_winrm_username', but found %q!", c.UserName) - } - if c.Comm.WinRMUser != "override_winrm_username" { - t.Errorf("Expected 'c.Comm.WinRMUser' to be set to 'override_winrm_username', but found %q!", c.Comm.WinRMUser) - } -} - -func TestConfigShouldDefaultVMSizeToStandardA1(t *testing.T) { - var c Config - c.Prepare(getArmBuilderConfiguration(), getPackerConfiguration()) - - if c.VMSize != "Standard_A1" { - t.Errorf("Expected 'VMSize' to default to 'Standard_A1', but got '%s'.", c.VMSize) - } -} - -func TestConfigShouldDefaultImageVersionToLatest(t *testing.T) { - var c Config - c.Prepare(getArmBuilderConfiguration(), getPackerConfiguration()) - - if c.ImageVersion != "latest" { - t.Errorf("Expected 'ImageVersion' to default to 'latest', but got '%s'.", c.ImageVersion) - } -} - -func TestConfigShouldNotDefaultImageVersionIfCustomImage(t *testing.T) { - config := map[string]string{ - "capture_name_prefix": "ignore", - "capture_container_name": "ignore", - "location": "ignore", - "image_url": "ignore", - "storage_account": "ignore", - "resource_group_name": "ignore", - "subscription_id": "ignore", - "os_type": constants.Target_Linux, - "communicator": "none", - } - - var c Config - c.Prepare(config, getPackerConfiguration()) - if c.ImageVersion != "" { - t.Errorf("Expected 'ImageVersion' to empty, but got '%s'.", c.ImageVersion) - } -} - -func TestConfigShouldNormalizeOSTypeCase(t *testing.T) { - config := map[string]string{ - "capture_name_prefix": "ignore", - "capture_container_name": "ignore", - "location": "ignore", - "image_url": "ignore", - "storage_account": "ignore", - "resource_group_name": "ignore", - "subscription_id": "ignore", - "communicator": "none", - } - - os_types := map[string][]string{ - constants.Target_Linux: {"linux", "LiNuX"}, - constants.Target_Windows: {"windows", "WiNdOWs"}, - } - - for k, v := range os_types { - for _, os_type := range v { - config["os_type"] = os_type - var c Config - _, err := c.Prepare(config, getPackerConfiguration()) - if err != nil { - t.Fatalf("Expected config to accept the value %q, but it did not", os_type) - } - - if c.OSType != k { - t.Fatalf("Expected config to normalize the value %q to %q, but it did not", os_type, constants.Target_Linux) - } - } - } - - bad_os_types := []string{"", "does-not-exist"} - for _, os_type := range bad_os_types { - config["os_type"] = os_type - var c Config - _, err := c.Prepare(config, getPackerConfiguration()) - if err == nil { - t.Fatalf("Expected config to not accept the value %q, but it did", os_type) - } - } -} - -func TestConfigShouldRejectCustomImageAndMarketPlace(t *testing.T) { - config := map[string]string{ - "capture_name_prefix": "ignore", - "capture_container_name": "ignore", - "location": "ignore", - "image_url": "ignore", - "resource_group_name": "ignore", - "storage_account": "ignore", - "subscription_id": "ignore", - "os_type": constants.Target_Linux, - "communicator": "none", - } - packerConfiguration := getPackerConfiguration() - marketPlace := []string{"image_publisher", "image_offer", "image_sku"} - - for _, x := range marketPlace { - config[x] = "ignore" - var c Config - _, err := c.Prepare(config, packerConfiguration) - if err == nil { - t.Errorf("Expected Config to reject image_url and %s, but it did not", x) - } - } -} - -func TestConfigVirtualNetworkNameIsOptional(t *testing.T) { - config := map[string]string{ - "capture_name_prefix": "ignore", - "capture_container_name": "ignore", - "location": "ignore", - "image_url": "ignore", - "storage_account": "ignore", - "resource_group_name": "ignore", - "subscription_id": "ignore", - "os_type": constants.Target_Linux, - "communicator": "none", - "virtual_network_name": "MyVirtualNetwork", - } - - var c Config - c.Prepare(config, getPackerConfiguration()) - if c.VirtualNetworkName != "MyVirtualNetwork" { - t.Errorf("Expected Config to set virtual_network_name to MyVirtualNetwork, but got %q", c.VirtualNetworkName) - } - if c.VirtualNetworkResourceGroupName != "" { - t.Errorf("Expected Config to leave virtual_network_resource_group_name to '', but got %q", c.VirtualNetworkResourceGroupName) - } - if c.VirtualNetworkSubnetName != "" { - t.Errorf("Expected Config to leave virtual_network_subnet_name to '', but got %q", c.VirtualNetworkSubnetName) - } -} - -// The user can pass the value virtual_network_resource_group_name to avoid the lookup of -// a virtual network's resource group, or to help with disambiguation. The value should -// only be set if virtual_network_name was set. -func TestConfigVirtualNetworkResourceGroupNameMustBeSetWithVirtualNetworkName(t *testing.T) { - config := map[string]string{ - "capture_name_prefix": "ignore", - "capture_container_name": "ignore", - "location": "ignore", - "image_url": "ignore", - "storage_account": "ignore", - "resource_group_name": "ignore", - "subscription_id": "ignore", - "os_type": constants.Target_Linux, - "communicator": "none", - "virtual_network_resource_group_name": "MyVirtualNetworkRG", - } - - var c Config - _, err := c.Prepare(config, getPackerConfiguration()) - if err == nil { - t.Error("Expected Config to reject virtual_network_resource_group_name, if virtual_network_name is not set.") - } -} - -// The user can pass the value virtual_network_subnet_name to avoid the lookup of -// a virtual network subnet's name, or to help with disambiguation. The value should -// only be set if virtual_network_name was set. -func TestConfigVirtualNetworkSubnetNameMustBeSetWithVirtualNetworkName(t *testing.T) { - config := map[string]string{ - "capture_name_prefix": "ignore", - "capture_container_name": "ignore", - "location": "ignore", - "image_url": "ignore", - "storage_account": "ignore", - "resource_group_name": "ignore", - "subscription_id": "ignore", - "os_type": constants.Target_Linux, - "communicator": "none", - "virtual_network_subnet_name": "MyVirtualNetworkRG", - } - - var c Config - _, err := c.Prepare(config, getPackerConfiguration()) - if err == nil { - t.Error("Expected Config to reject virtual_network_subnet_name, if virtual_network_name is not set.") - } -} - -func TestConfigAllowedInboundIpAddressesIsOptional(t *testing.T) { - config := map[string]string{ - "capture_name_prefix": "ignore", - "capture_container_name": "ignore", - "location": "ignore", - "image_url": "ignore", - "storage_account": "ignore", - "resource_group_name": "ignore", - "subscription_id": "ignore", - "os_type": constants.Target_Linux, - "communicator": "none", - "virtual_network_name": "MyVirtualNetwork", - } - - var c Config - _, err := c.Prepare(config, getPackerConfiguration()) - if err != nil { - t.Fatal(err) - } - if c.AllowedInboundIpAddresses != nil { - t.Errorf("Expected Config to set allowed_inbound_ip_addresses to nil, but got %v", c.AllowedInboundIpAddresses) - } -} - -func TestConfigShouldAcceptCorrectInboundIpAddresses(t *testing.T) { - ipValue0 := "127.0.0.1" - ipValue1 := "127.0.0.2" - cidrValue2 := "192.168.100.0/24" - cidrValue3 := "10.10.1.16/32" - config := map[string]interface{}{ - "capture_name_prefix": "ignore", - "capture_container_name": "ignore", - "location": "ignore", - "image_url": "ignore", - "storage_account": "ignore", - "resource_group_name": "ignore", - "subscription_id": "ignore", - "os_type": constants.Target_Linux, - "communicator": "none", - } - - config["allowed_inbound_ip_addresses"] = ipValue0 - var c Config - _, err := c.Prepare(config, getPackerConfiguration()) - if err != nil { - t.Fatal(err) - } - if c.AllowedInboundIpAddresses == nil || len(c.AllowedInboundIpAddresses) != 1 || - c.AllowedInboundIpAddresses[0] != ipValue0 { - t.Errorf("Expected 'allowed_inbound_ip_addresses' to have one element (%s), but got '%v'.", ipValue0, c.AllowedInboundIpAddresses) - } - - config["allowed_inbound_ip_addresses"] = cidrValue2 - _, err = c.Prepare(config, getPackerConfiguration()) - if err != nil { - t.Fatal(err) - } - if c.AllowedInboundIpAddresses == nil || len(c.AllowedInboundIpAddresses) != 1 || - c.AllowedInboundIpAddresses[0] != cidrValue2 { - t.Errorf("Expected 'allowed_inbound_ip_addresses' to have one element (%s), but got '%v'.", cidrValue2, c.AllowedInboundIpAddresses) - } - - config["allowed_inbound_ip_addresses"] = []string{ipValue0, cidrValue2, ipValue1, cidrValue3} - _, err = c.Prepare(config, getPackerConfiguration()) - if err != nil { - t.Fatal(err) - } - if c.AllowedInboundIpAddresses == nil || len(c.AllowedInboundIpAddresses) != 4 || - c.AllowedInboundIpAddresses[0] != ipValue0 || c.AllowedInboundIpAddresses[1] != cidrValue2 || - c.AllowedInboundIpAddresses[2] != ipValue1 || c.AllowedInboundIpAddresses[3] != cidrValue3 { - t.Errorf("Expected 'allowed_inbound_ip_addresses' to have four elements (%s %s %s %s), but got '%v'.", ipValue0, cidrValue2, ipValue1, - cidrValue3, c.AllowedInboundIpAddresses) - } -} - -func TestConfigShouldRejectIncorrectInboundIpAddresses(t *testing.T) { - config := map[string]interface{}{ - "capture_name_prefix": "ignore", - "capture_container_name": "ignore", - "location": "ignore", - "image_url": "ignore", - "storage_account": "ignore", - "resource_group_name": "ignore", - "subscription_id": "ignore", - "os_type": constants.Target_Linux, - "communicator": "none", - } - - config["allowed_inbound_ip_addresses"] = []string{"127.0.0.1", "127.0.0.two"} - var c Config - _, err := c.Prepare(config, getPackerConfiguration()) - if err == nil { - t.Errorf("Expected configuration creation to fail, but it succeeded with the malformed allowed_inbound_ip_addresses set to %v", c.AllowedInboundIpAddresses) - } - - config["allowed_inbound_ip_addresses"] = []string{"192.168.100.1000/24", "10.10.1.16/32"} - _, err = c.Prepare(config, getPackerConfiguration()) - if err == nil { - // 192.168.100.1000/24 is invalid - t.Errorf("Expected configuration creation to fail, but it succeeded with the malformed allowed_inbound_ip_addresses set to %v", c.AllowedInboundIpAddresses) - } -} - -func TestConfigShouldRejectInboundIpAddressesWithVirtualNetwork(t *testing.T) { - config := map[string]interface{}{ - "capture_name_prefix": "ignore", - "capture_container_name": "ignore", - "location": "ignore", - "image_url": "ignore", - "storage_account": "ignore", - "resource_group_name": "ignore", - "subscription_id": "ignore", - "os_type": constants.Target_Linux, - "communicator": "none", - "allowed_inbound_ip_addresses": "127.0.0.1", - } - - var c Config - _, err := c.Prepare(config, getPackerConfiguration()) - if err != nil { - t.Fatal(err) - } - - config["virtual_network_name"] = "some_vnet_name" - _, err = c.Prepare(config, getPackerConfiguration()) - if err == nil { - t.Errorf("Expected configuration creation to fail, but it succeeded with allowed_inbound_ip_addresses and virtual_network_name both specified") - } -} - -func TestConfigShouldDefaultToPublicCloud(t *testing.T) { - var c Config - c.Prepare(getArmBuilderConfiguration(), getPackerConfiguration()) - - if c.ClientConfig.CloudEnvironmentName != "Public" { - t.Errorf("Expected 'CloudEnvironmentName' to default to 'Public', but got '%s'.", c.ClientConfig.CloudEnvironmentName) - } - - if c.ClientConfig.CloudEnvironment() == nil || c.ClientConfig.CloudEnvironment().Name != "AzurePublicCloud" { - t.Errorf("Expected 'cloudEnvironment' to be set to 'AzurePublicCloud', but got '%s'.", c.ClientConfig.CloudEnvironment()) - } -} - -func TestConfigInstantiatesCorrectAzureEnvironment(t *testing.T) { - config := map[string]string{ - "capture_name_prefix": "ignore", - "capture_container_name": "ignore", - "image_offer": "ignore", - "image_publisher": "ignore", - "image_sku": "ignore", - "location": "ignore", - "storage_account": "ignore", - "resource_group_name": "ignore", - "subscription_id": "ignore", - "os_type": constants.Target_Linux, - "communicator": "none", - } - - // user input is fun :) - var table = []struct { - name string - environmentName string - }{ - {"China", "AzureChinaCloud"}, - {"ChinaCloud", "AzureChinaCloud"}, - {"AzureChinaCloud", "AzureChinaCloud"}, - {"aZuReChInAcLoUd", "AzureChinaCloud"}, - - {"USGovernment", "AzureUSGovernmentCloud"}, - {"USGovernmentCloud", "AzureUSGovernmentCloud"}, - {"AzureUSGovernmentCloud", "AzureUSGovernmentCloud"}, - {"aZuReUsGoVeRnMeNtClOuD", "AzureUSGovernmentCloud"}, - - {"Public", "AzurePublicCloud"}, - {"PublicCloud", "AzurePublicCloud"}, - {"AzurePublicCloud", "AzurePublicCloud"}, - {"aZuRePuBlIcClOuD", "AzurePublicCloud"}, - } - - packerConfiguration := getPackerConfiguration() - - for _, x := range table { - config["cloud_environment_name"] = x.name - var c Config - _, err := c.Prepare(config, packerConfiguration) - if err != nil { - t.Fatal(err) - } - - if c.ClientConfig.CloudEnvironment() == nil || c.ClientConfig.CloudEnvironment().Name != x.environmentName { - t.Errorf("Expected 'cloudEnvironment' to be set to '%s', but got '%s'.", x.environmentName, c.ClientConfig.CloudEnvironment()) - } - } -} - -func TestUserShouldProvideRequiredValues(t *testing.T) { - builderValues := getArmBuilderConfiguration() - - // Ensure we can successfully create a config. - var c Config - _, err := c.Prepare(builderValues, getPackerConfiguration()) - if err != nil { - t.Error("Expected configuration creation to succeed, but it failed!\n") - t.Fatalf(" -> %+v\n", builderValues) - } - - // Take away a required element, and ensure construction fails. - for _, v := range requiredConfigValues { - originalValue := builderValues[v] - delete(builderValues, v) - - var c Config - _, err := c.Prepare(builderValues, getPackerConfiguration()) - if err == nil { - t.Error("Expected configuration creation to fail, but it succeeded!\n") - t.Fatalf(" -> %+v\n", builderValues) - } - - builderValues[v] = originalValue - } -} - -func TestSystemShouldDefineRuntimeValues(t *testing.T) { - var c Config - c.Prepare(getArmBuilderConfiguration(), getPackerConfiguration()) - - if c.Password == "" { - t.Errorf("Expected Password to not be empty, but it was '%s'!", c.Password) - } - - if c.tmpComputeName == "" { - t.Errorf("Expected tmpComputeName to not be empty, but it was '%s'!", c.tmpComputeName) - } - - if c.tmpDeploymentName == "" { - t.Errorf("Expected tmpDeploymentName to not be empty, but it was '%s'!", c.tmpDeploymentName) - } - - if c.tmpResourceGroupName == "" { - t.Errorf("Expected tmpResourceGroupName to not be empty, but it was '%s'!", c.tmpResourceGroupName) - } - - if c.tmpOSDiskName == "" { - t.Errorf("Expected tmpOSDiskName to not be empty, but it was '%s'!", c.tmpOSDiskName) - } - - if c.tmpDataDiskName == "" { - t.Errorf("Expected tmpDataDiskName to not be empty, but it was '%s'!", c.tmpDataDiskName) - } - - if c.tmpNsgName == "" { - t.Errorf("Expected tmpNsgName to not be empty, but it was '%s'!", c.tmpNsgName) - } -} - -func TestConfigShouldTransformToVirtualMachineCaptureParameters(t *testing.T) { - var c Config - c.Prepare(getArmBuilderConfiguration(), getPackerConfiguration()) - parameters := c.toVirtualMachineCaptureParameters() - - if *parameters.DestinationContainerName != c.CaptureContainerName { - t.Errorf("Expected DestinationContainerName to be equal to config's CaptureContainerName, but they were '%s' and '%s' respectively.", *parameters.DestinationContainerName, c.CaptureContainerName) - } - - if *parameters.VhdPrefix != c.CaptureNamePrefix { - t.Errorf("Expected DestinationContainerName to be equal to config's CaptureContainerName, but they were '%s' and '%s' respectively.", *parameters.VhdPrefix, c.CaptureNamePrefix) - } - - if *parameters.OverwriteVhds != false { - t.Error("Expected OverwriteVhds to be false, but it was not.") - } -} - -func TestConfigShouldSupportPackersConfigElements(t *testing.T) { - var c Config - _, err := c.Prepare( - getArmBuilderConfiguration(), - getPackerConfiguration(), - getPackerCommunicatorConfiguration()) - - if err != nil { - t.Fatal(err) - } - - if c.Comm.SSHTimeout != 1*time.Hour { - t.Errorf("Expected Comm.SSHTimeout to be a duration of an hour, but got '%s' instead.", c.Comm.SSHTimeout) - } - - if c.Comm.WinRMTimeout != 2*time.Hour { - t.Errorf("Expected Comm.WinRMTimeout to be a durationof two hours, but got '%s' instead.", c.Comm.WinRMTimeout) - } -} - -func TestWinRMConfigShouldSetRoundTripDecorator(t *testing.T) { - config := getArmBuilderConfiguration() - config["communicator"] = "winrm" - config["winrm_username"] = "username" - config["winrm_password"] = "Password123" - - var c Config - _, err := c.Prepare(config, getPackerConfiguration()) - if err != nil { - t.Fatal(err) - } - - if c.Comm.WinRMTransportDecorator == nil { - t.Error("Expected WinRMTransportDecorator to be set, but it was nil") - } -} - -func TestUserDeviceLoginIsEnabledForLinux(t *testing.T) { - config := map[string]string{ - "capture_name_prefix": "ignore", - "capture_container_name": "ignore", - "image_offer": "ignore", - "image_publisher": "ignore", - "image_sku": "ignore", - "location": "ignore", - "storage_account": "ignore", - "resource_group_name": "ignore", - "subscription_id": "ignore", - "os_type": constants.Target_Linux, - "communicator": "none", - } - - var c Config - _, err := c.Prepare(config, getPackerConfiguration()) - if err != nil { - t.Fatalf("failed to use device login for Linux: %s", err) - } -} - -func TestConfigShouldRejectMalformedCaptureNamePrefix(t *testing.T) { - config := map[string]string{ - "capture_container_name": "ignore", - "image_offer": "ignore", - "image_publisher": "ignore", - "image_sku": "ignore", - "location": "ignore", - "storage_account": "ignore", - "resource_group_name": "ignore", - "subscription_id": "ignore", - "communicator": "none", - // Does not matter for this test case, just pick one. - "os_type": constants.Target_Linux, - } - - wellFormedCaptureNamePrefix := []string{ - "packer", - "AbcdefghijklmnopqrstuvwX", - "hyphen-hyphen", - "0leading-number", - "v1.core.local", - } - - for _, x := range wellFormedCaptureNamePrefix { - config["capture_name_prefix"] = x - var c Config - _, err := c.Prepare(config, getPackerConfiguration()) - - if err != nil { - t.Errorf("Expected test to pass, but it failed with the well-formed capture_name_prefix set to %q.", x) - } - } - - malformedCaptureNamePrefix := []string{ - "-leading-hyphen", - "trailing-hyphen-", - "trailing-period.", - "_leading-underscore", - "punc-!@#$%^&*()_+-=-punc", - "There-are-too-many-characters-in-the-name-and-the-limit-is-twenty-four", - } - - for _, x := range malformedCaptureNamePrefix { - config["capture_name_prefix"] = x - var c Config - _, err := c.Prepare(config, getPackerConfiguration()) - - if err == nil { - t.Errorf("Expected test to fail, but it succeeded with the malformed capture_name_prefix set to %q.", x) - } - } -} - -func TestConfigShouldRejectMalformedCaptureContainerName(t *testing.T) { - config := map[string]string{ - "capture_name_prefix": "ignore", - "image_offer": "ignore", - "image_publisher": "ignore", - "image_sku": "ignore", - "location": "ignore", - "storage_account": "ignore", - "resource_group_name": "ignore", - "subscription_id": "ignore", - "communicator": "none", - // Does not matter for this test case, just pick one. - "os_type": constants.Target_Linux, - } - - wellFormedCaptureContainerName := []string{ - "0leading", - "aleading", - "hype-hyphen", - "abcdefghijklmnopqrstuvwxyz0123456789-abcdefghijklmnopqrstuvwxyz", // 63 characters - } - - for _, x := range wellFormedCaptureContainerName { - config["capture_container_name"] = x - var c Config - _, err := c.Prepare(config, getPackerConfiguration()) - - if err != nil { - t.Errorf("Expected test to pass, but it failed with the well-formed capture_container_name set to %q.", x) - } - } - - malformedCaptureContainerName := []string{ - "No-Capitals", - "double--hyphens", - "-leading-hyphen", - "trailing-hyphen-", - "punc-!@#$%^&*()_+-=-punc", - "there-are-over-63-characters-in-this-string-and-that-is-a-bad-container-name", - } - - for _, x := range malformedCaptureContainerName { - config["capture_container_name"] = x - var c Config - _, err := c.Prepare(config, getPackerConfiguration()) - - if err == nil { - t.Errorf("Expected test to fail, but it succeeded with the malformed capture_container_name set to %q.", x) - } - } -} - -func TestConfigShouldRejectMalformedManagedImageOSDiskSnapshotName(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", - "managed_image_os_disk_snapshot_name": "ignore", - // Does not matter for this test case, just pick one. - "os_type": constants.Target_Linux, - } - - wellFormedManagedImageOSDiskSnapshotName := []string{ - "AbcdefghijklmnopqrstuvwX", - "underscore_underscore", - "0leading_number", - "really_loooooooooooooooooooooooooooooooooooooooooooooooooong", - } - - for _, x := range wellFormedManagedImageOSDiskSnapshotName { - config["managed_image_os_disk_snapshot_name"] = x - var c Config - _, err := c.Prepare(config, getPackerConfiguration()) - - if err != nil { - t.Errorf("Expected test to pass, but it failed with the well-formed managed_image_os_disk_snapshot_name set to %q.", x) - } - } - - malformedManagedImageOSDiskSnapshotName := []string{ - "-leading-hyphen", - "trailing-hyphen-", - "trailing-period.", - "punc-!@#$%^&*()_+-=-punc", - "really_looooooooooooooooooooooooooooooooooooooooooooooooooooooong_exceeding_80_char_limit", - } - - for _, x := range malformedManagedImageOSDiskSnapshotName { - config["managed_image_os_disk_snapshot_name"] = x - var c Config - _, err := c.Prepare(config, getPackerConfiguration()) - - if err == nil { - t.Errorf("Expected test to fail, but it succeeded with the malformed managed_image_os_disk_snapshot_name set to %q.", x) - } - } -} - -func TestConfigShouldRejectMalformedManagedImageDataDiskSnapshotPrefix(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", - "managed_image_data_disk_snapshot_prefix": "ignore", - // Does not matter for this test case, just pick one. - "os_type": constants.Target_Linux, - } - - wellFormedManagedImageDataDiskSnapshotPrefix := []string{ - "min_ten_chars", - "AbcdefghijklmnopqrstuvwX", - "underscore_underscore", - "0leading_number", - "less_than_sixty_characters", - } - - for _, x := range wellFormedManagedImageDataDiskSnapshotPrefix { - config["managed_image_data_disk_snapshot_prefix"] = x - var c Config - _, err := c.Prepare(config, getPackerConfiguration()) - - if err != nil { - t.Errorf("Expected test to pass, but it failed with the well-formed managed_image_data_disk_snapshot_prefix set to %q.", x) - } - } - - malformedManagedImageDataDiskSnapshotPrefix := []string{ - "-leading-hyphen", - "trailing-hyphen-", - "trailing-period.", - "punc-!@#$%^&*()_+-=-punc", - "really_looooooooooooooooooooooooooooooooooooooooooooooooooooooong_exceeding_60_char_limit", - } - - for _, x := range malformedManagedImageDataDiskSnapshotPrefix { - config["managed_image_data_disk_snapshot_prefix"] = x - var c Config - _, err := c.Prepare(config, getPackerConfiguration()) - - if err == nil { - t.Errorf("Expected test to fail, but it succeeded with the malformed managed_image_data_disk_snapshot_prefix set to %q.", x) - } - } -} - -func TestConfigShouldAcceptTags(t *testing.T) { - config := map[string]interface{}{ - "capture_name_prefix": "ignore", - "capture_container_name": "ignore", - "image_offer": "ignore", - "image_publisher": "ignore", - "image_sku": "ignore", - "location": "ignore", - "storage_account": "ignore", - "resource_group_name": "ignore", - "subscription_id": "ignore", - "communicator": "none", - // Does not matter for this test case, just pick one. - "os_type": constants.Target_Linux, - "azure_tags": map[string]string{ - "tag01": "value01", - "tag02": "value02", - }, - } - - c := Config{ - AzureTag: sdkconfig.NameValues{ - {Name: "tag03", Value: "value03"}, - }, - } - _, err := c.Prepare(config, getPackerConfiguration()) - if err != nil { - t.Fatal(err) - } - - if diff := cmp.Diff(c.AzureTags, map[string]string{ - "tag01": "value01", - "tag02": "value02", - "tag03": "value03", - }); diff != "" { - t.Fatalf("unexpected azure tags: %s", diff) - } -} - -func TestConfigShouldAcceptTag(t *testing.T) { - config := map[string]interface{}{ - "capture_name_prefix": "ignore", - "capture_container_name": "ignore", - "image_offer": "ignore", - "image_publisher": "ignore", - "image_sku": "ignore", - "location": "ignore", - "storage_account": "ignore", - "resource_group_name": "ignore", - "subscription_id": "ignore", - "communicator": "none", - // Does not matter for this test case, just pick one. - "os_type": constants.Target_Linux, - } - - c := Config{ - AzureTag: sdkconfig.NameValues{ - {Name: "tag03", Value: "value03"}, - }, - } - _, err := c.Prepare(config, getPackerConfiguration()) - if err != nil { - t.Fatal(err) - } - - if diff := cmp.Diff(c.AzureTags, map[string]string{ - "tag03": "value03", - }); diff != "" { - t.Fatalf("unexpected azure tags: %s", diff) - } -} - -func TestConfigShouldRejectTagsInExcessOf15AcceptTags(t *testing.T) { - tooManyTags := map[string]string{} - for i := 0; i < 16; i++ { - tooManyTags[fmt.Sprintf("tag%.2d", i)] = "ignored" - } - - config := map[string]interface{}{ - "capture_name_prefix": "ignore", - "capture_container_name": "ignore", - "image_offer": "ignore", - "image_publisher": "ignore", - "image_sku": "ignore", - "location": "ignore", - "storage_account": "ignore", - "resource_group_name": "ignore", - "subscription_id": "ignore", - "communicator": "none", - // Does not matter for this test case, just pick one. - "os_type": constants.Target_Linux, - "azure_tags": tooManyTags, - } - - var c Config - _, err := c.Prepare(config, getPackerConfiguration()) - - if err == nil { - t.Fatal("expected config to reject based on an excessive amount of tags (> 15)") - } -} - -func TestConfigShouldRejectExcessiveTagNameLength(t *testing.T) { - nameTooLong := make([]byte, 513) - for i := range nameTooLong { - nameTooLong[i] = 'a' - } - - tags := map[string]string{} - tags[string(nameTooLong)] = "ignored" - - config := map[string]interface{}{ - "capture_name_prefix": "ignore", - "capture_container_name": "ignore", - "image_offer": "ignore", - "image_publisher": "ignore", - "image_sku": "ignore", - "location": "ignore", - "storage_account": "ignore", - "resource_group_name": "ignore", - "subscription_id": "ignore", - "communicator": "none", - // Does not matter for this test case, just pick one. - "os_type": constants.Target_Linux, - "azure_tags": tags, - } - - var c Config - _, err := c.Prepare(config, getPackerConfiguration()) - if err == nil { - t.Fatal("expected config to reject tag name based on length (> 512)") - } -} - -func TestConfigShouldRejectExcessiveTagValueLength(t *testing.T) { - valueTooLong := make([]byte, 257) - for i := range valueTooLong { - valueTooLong[i] = 'a' - } - - tags := map[string]string{} - tags["tag01"] = string(valueTooLong) - - config := map[string]interface{}{ - "capture_name_prefix": "ignore", - "capture_container_name": "ignore", - "image_offer": "ignore", - "image_publisher": "ignore", - "image_sku": "ignore", - "location": "ignore", - "storage_account": "ignore", - "resource_group_name": "ignore", - "subscription_id": "ignore", - "communicator": "none", - // Does not matter for this test case, just pick one. - "os_type": constants.Target_Linux, - "azure_tags": tags, - } - - var c Config - _, err := c.Prepare(config, getPackerConfiguration()) - if err == nil { - t.Fatal("expected config to reject tag value based on length (> 256)") - } -} - -func TestConfigZoneResilientShouldDefaultToFalse(t *testing.T) { - config := map[string]interface{}{ - "managed_image_name": "ignore", - "managed_image_resource_group_name": "ignore", - "build_resource_group_name": "ignore", - "image_publisher": "igore", - "image_offer": "ignore", - "image_sku": "ignore", - "os_type": "linux", - } - - var c Config - _, err := c.Prepare(config, getPackerConfiguration()) - if err != nil { - t.Fatal(err) - } - - p := c.toImageParameters() - if *p.ImageProperties.StorageProfile.ZoneResilient { - t.Fatal("expected zone resilient default to be false") - } -} - -func TestConfigZoneResilientSetFromConfig(t *testing.T) { - config := map[string]interface{}{ - "managed_image_name": "ignore", - "managed_image_resource_group_name": "ignore", - "build_resource_group_name": "ignore", - "image_publisher": "igore", - "image_offer": "ignore", - "image_sku": "ignore", - "os_type": "linux", - "managed_image_zone_resilient": true, - } - - var c Config - _, err := c.Prepare(config, getPackerConfiguration()) - if err != nil { - t.Fatal(err) - } - - p := c.toImageParameters() - if *p.ImageProperties.StorageProfile.ZoneResilient == false { - t.Fatal("expected managed image zone resilient to be true from config") - } -} - -func TestConfigShouldRejectMissingCustomDataFile(t *testing.T) { - config := map[string]interface{}{ - "capture_name_prefix": "ignore", - "capture_container_name": "ignore", - "image_offer": "ignore", - "image_publisher": "ignore", - "image_sku": "ignore", - "location": "ignore", - "storage_account": "ignore", - "resource_group_name": "ignore", - "subscription_id": "ignore", - "communicator": "none", - // Does not matter for this test case, just pick one. - "os_type": constants.Target_Linux, - "custom_data_file": "/this/file/does/not/exist", - } - - var c Config - _, err := c.Prepare(config, getPackerConfiguration()) - if err == nil { - t.Fatal("expected config to reject missing custom data file") - } -} - -func TestConfigShouldRejectManagedImageOSDiskSnapshotNameWithoutManagedImageName(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_os_disk_snapshot_name": "ignore", - // Does not matter for this test case, just pick one. - "os_type": constants.Target_Linux, - } - - var c Config - _, err := c.Prepare(config, getPackerConfiguration()) - if err == nil { - t.Fatal("expected config to reject Managed Image build with OS disk snapshot name but without managed image name") - } -} - -func TestConfigShouldRejectManagedImageOSDiskSnapshotNameWithoutManagedImageResourceGroupName(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_name": "ignore", - "managed_image_os_disk_snapshot_name": "ignore", - // Does not matter for this test case, just pick one. - "os_type": constants.Target_Linux, - } - - var c Config - _, err := c.Prepare(config, getPackerConfiguration()) - if err == nil { - t.Fatal("expected config to reject Managed Image build with OS disk snapshot name but without managed image resource group name") - } -} - -func TestConfigShouldRejectImageDataDiskSnapshotPrefixWithoutManagedImageName(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_data_disk_snapshot_prefix": "ignore", - // Does not matter for this test case, just pick one. - "os_type": constants.Target_Linux, - } - - var c Config - _, err := c.Prepare(config, getPackerConfiguration()) - if err == nil { - t.Fatal("expected config to reject Managed Image build with data disk snapshot prefix but without managed image name") - } -} - -func TestConfigShouldRejectImageDataDiskSnapshotPrefixWithoutManagedImageResourceGroupName(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_name": "ignore", - "managed_image_data_disk_snapshot_prefix": "ignore", - // Does not matter for this test case, just pick one. - "os_type": constants.Target_Linux, - } - - var c Config - _, err := c.Prepare(config, getPackerConfiguration()) - if err == nil { - t.Fatal("expected config to reject Managed Image build with data disk snapshot prefix but without managed image resource group name") - } -} - -func TestConfigShouldAcceptManagedImageOSDiskSnapshotNameAndManagedImageDataDiskSnapshotPrefix(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", - "managed_image_os_disk_snapshot_name": "ignore_ignore", - "managed_image_data_disk_snapshot_prefix": "ignore_ignore", - // Does not matter for this test case, just pick one. - "os_type": constants.Target_Linux, - } - - var c Config - _, err := c.Prepare(config, getPackerConfiguration()) - if err != nil { - t.Fatal("expected config to accept platform managed image build") - } -} - -func TestConfigShouldRejectManagedImageOSDiskSnapshotNameAndManagedImageDataDiskSnapshotPrefixWithCaptureContainerName(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", - "managed_image_os_disk_snapshot_name": "ignore_ignore", - "managed_image_data_disk_snapshot_prefix": "ignore_ignore", - // Does not matter for this test case, just pick one. - "os_type": constants.Target_Linux, - } - - var c Config - _, err := c.Prepare(config, getPackerConfiguration()) - if err == nil { - t.Fatal("expected config to reject Managed Image build with data disk snapshot prefix and OS disk snapshot name with capture container name") - } -} - -func TestConfigShouldRejectManagedImageOSDiskSnapshotNameAndManagedImageDataDiskSnapshotPrefixWithCaptureNamePrefix(t *testing.T) { - config := map[string]interface{}{ - "image_offer": "ignore", - "image_publisher": "ignore", - "image_sku": "ignore", - "location": "ignore", - "subscription_id": "ignore", - "communicator": "none", - "capture_name_prefix": "ignore", - "managed_image_os_disk_snapshot_name": "ignore_ignore", - "managed_image_data_disk_snapshot_prefix": "ignore_ignore", - // Does not matter for this test case, just pick one. - "os_type": constants.Target_Linux, - } - - var c Config - _, err := c.Prepare(config, getPackerConfiguration()) - if err == nil { - t.Fatal("expected config to reject Managed Image build with data disk snapshot prefix and OS disk snapshot name with capture name prefix") - } -} - -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, - } - - var c Config - _, err := c.Prepare(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, - } - - var c Config - _, err := c.Prepare(config, getPackerConfiguration()) - if err == nil { - t.Fatal("expected config to reject VHD and Managed Image build") - } -} - -// If the user specified a build of a VHD, but started with a managed image it should be rejected. -func TestConfigShouldRejectManagedImageSourceAndVhdOutput(t *testing.T) { - config := map[string]interface{}{ - "image_url": "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, - } - - var c Config - _, err := c.Prepare(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, - } - - var c Config - _, err := c.Prepare(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, - } - - var c Config - _, err := c.Prepare(config, getPackerConfiguration()) - if err == nil { - t.Fatal("expected config to reject custom and platform input for a managed image build") - } -} - -func TestConfigShouldRejectMalformedManageImageStorageAccountTypes(t *testing.T) { - config := map[string]interface{}{ - "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", - "managed_image_storage_account_type": "--invalid--", - - // Does not matter for this test case, just pick one. - "os_type": constants.Target_Linux, - } - - var c Config - _, err := c.Prepare(config, getPackerConfiguration()) - if err == nil { - t.Fatal("expected config to reject custom and platform input for a managed image build") - } -} - -func TestConfigShouldRejectMalformedDiskCachingType(t *testing.T) { - config := map[string]interface{}{ - "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", - "disk_caching_type": "--invalid--", - - // Does not matter for this test case, just pick one. - "os_type": constants.Target_Linux, - } - - var c Config - _, err := c.Prepare(config, getPackerConfiguration()) - if err == nil { - t.Fatal("expected config to reject custom and platform input for a managed image build") - } -} - -func TestConfigShouldAcceptManagedImageStorageAccountTypes(t *testing.T) { - config := map[string]interface{}{ - "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, - } - - storage_account_types := []string{"Premium_LRS", "Standard_LRS"} - - for _, x := range storage_account_types { - config["managed_image_storage_account_type"] = x - var c Config - _, err := c.Prepare(config, getPackerConfiguration()) - if err != nil { - t.Fatalf("expected config to accept a managed_image_storage_account_type of %q", x) - } - } -} - -func TestConfigShouldAcceptDiskCachingTypes(t *testing.T) { - config := map[string]interface{}{ - "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, - } - - storage_account_types := []string{"None", "ReadOnly", "ReadWrite"} - - for _, x := range storage_account_types { - config["disk_caching_type"] = x - var c Config - _, err := c.Prepare(config, getPackerConfiguration()) - if err != nil { - t.Fatalf("expected config to accept a disk_caching_type of %q", x) - } - } -} - -func TestConfigShouldRejectTempAndBuildResourceGroupName(t *testing.T) { - config := map[string]interface{}{ - "capture_name_prefix": "ignore", - "capture_container_name": "ignore", - "image_offer": "ignore", - "image_publisher": "ignore", - "image_sku": "ignore", - "location": "ignore", - "storage_account": "ignore", - "resource_group_name": "ignore", - "subscription_id": "ignore", - "communicator": "none", - - // custom may define one or the other, but not both - "temp_resource_group_name": "rgn00", - "build_resource_group_name": "rgn00", - } - - var c Config - _, err := c.Prepare(config, getPackerConfiguration()) - if err == nil { - t.Fatal("expected config to reject the use of both temp_resource_group_name and build_resource_group_name") - } -} - -func TestConfigShouldRejectInvalidResourceGroupNames(t *testing.T) { - config := map[string]interface{}{ - "capture_name_prefix": "ignore", - "capture_container_name": "ignore", - "image_offer": "ignore", - "image_publisher": "ignore", - "image_sku": "ignore", - "location": "ignore", - "storage_account": "ignore", - "resource_group_name": "ignore", - "subscription_id": "ignore", - "communicator": "none", - "os_type": "linux", - } - - tests := []struct { - name string - ok bool - }{ - // The Good - {"packer-Resource-Group-jt2j3fc", true}, - {"My", true}, - {"My-(with-parens)-Resource-Group", true}, - - // The Bad - {"My Resource Group", false}, - {"My-Resource-Group-", false}, - {"My.Resource.Group.", false}, - - // The Ugly - {"My!@#!@#%$%yM", false}, - {" ", false}, - {"My10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", false}, - } - - settings := []string{"temp_resource_group_name", "build_resource_group_name"} - - for _, x := range settings { - for _, y := range tests { - config[x] = y.name - - var c Config - _, err := c.Prepare(config, getPackerConfiguration()) - if !y.ok && err == nil { - t.Errorf("expected config to reject %q for setting %q", y.name, x) - } else if y.ok && err != nil { - t.Errorf("expected config to accept %q for setting %q", y.name, x) - } - } - - delete(config, "location") // not valid for build_resource_group_name - delete(config, x) - } -} - -func TestConfigShouldRejectManagedDiskNames(t *testing.T) { - config := map[string]interface{}{ - "image_offer": "ignore", - "image_publisher": "ignore", - "image_sku": "ignore", - "location": "ignore", - "subscription_id": "ignore", - "communicator": "none", - "os_type": "linux", - "managed_image_name": "ignore", - "managed_image_resource_group_name": "ignore", - } - - testsResourceGroupNames := []struct { - name string - ok bool - }{ - // The Good - {"packer-Resource-Group-jt2j3fc", true}, - {"My", true}, - {"My-(with-parens)-Resource-Group", true}, - - // The Bad - {"My Resource Group", false}, - {"My-Resource-Group-", false}, - {"My.Resource.Group.", false}, - - // The Ugly - {"My!@#!@#%$%yM", false}, - {" ", false}, - {"My10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", false}, - } - - settingUnderTest := "managed_image_resource_group_name" - for _, y := range testsResourceGroupNames { - config[settingUnderTest] = y.name - - var c Config - _, err := c.Prepare(config, getPackerConfiguration()) - if !y.ok && err == nil { - t.Errorf("expected config to reject %q for setting %q", y.name, settingUnderTest) - } else if y.ok && err != nil { - t.Errorf("expected config to accept %q for setting %q", y.name, settingUnderTest) - } - } - - config["managed_image_resource_group_name"] = "ignored" - - testNames := []struct { - name string - ok bool - }{ - // The Good - {"ManagedDiskName", true}, - {"Managed-Disk-Name", true}, - {"My33", true}, - - // The Bad - {"Managed Disk Name", false}, - {"Managed-Disk-Name-", false}, - {"Managed.Disk.Name.", false}, - - // The Ugly - {"My!@#!@#%$%yM", false}, - {" ", false}, - {"My10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", false}, - } - - settingUnderTest = "managed_image_name" - for _, y := range testNames { - config[settingUnderTest] = y.name - - var c Config - _, err := c.Prepare(config, getPackerConfiguration()) - if !y.ok && err == nil { - t.Logf("expected config to reject %q for setting %q", y.name, settingUnderTest) - } else if y.ok && err != nil { - t.Logf("expected config to accept %q for setting %q", y.name, settingUnderTest) - } - } -} - -func TestConfigAdditionalDiskDefaultIsNil(t *testing.T) { - var c Config - c.Prepare(getArmBuilderConfiguration(), getPackerConfiguration()) - if c.AdditionalDiskSize != nil { - t.Errorf("Expected Config to not have a set of additional disks, but got a non nil value") - } -} - -func TestConfigAdditionalDiskOverrideDefault(t *testing.T) { - config := map[string]string{ - "capture_name_prefix": "ignore", - "capture_container_name": "ignore", - "location": "ignore", - "image_url": "ignore", - "storage_account": "ignore", - "resource_group_name": "ignore", - "subscription_id": "ignore", - "os_type": constants.Target_Linux, - "communicator": "none", - } - - diskconfig := map[string][]int32{ - "disk_additional_size": {32, 64}, - } - - var c Config - c.Prepare(config, diskconfig, getPackerConfiguration()) - if c.AdditionalDiskSize == nil { - t.Errorf("Expected Config to have a set of additional disks, but got nil") - } - if len(c.AdditionalDiskSize) != 2 { - t.Errorf("Expected Config to have a 2 additional disks, but got %d additional disks", len(c.AdditionalDiskSize)) - } - if c.AdditionalDiskSize[0] != 32 { - t.Errorf("Expected Config to have the first additional disks of size 32Gb, but got %dGb", c.AdditionalDiskSize[0]) - } - if c.AdditionalDiskSize[1] != 64 { - t.Errorf("Expected Config to have the second additional disks of size 64Gb, but got %dGb", c.AdditionalDiskSize[1]) - } -} - -// Test that configuration handles plan info -// -// The use of plan info requires that the following three properties are set. -// -// 1. plan_name -// 2. plan_product -// 3. plan_publisher -func TestPlanInfoConfiguration(t *testing.T) { - config := map[string]interface{}{ - "capture_name_prefix": "ignore", - "capture_container_name": "ignore", - "image_offer": "ignore", - "image_publisher": "ignore", - "image_sku": "ignore", - "location": "ignore", - "storage_account": "ignore", - "resource_group_name": "ignore", - "subscription_id": "ignore", - "os_type": "linux", - "communicator": "none", - } - - planInfo := map[string]string{ - "plan_name": "--plan-name--", - } - config["plan_info"] = planInfo - - var c Config - _, err := c.Prepare(config, getPackerConfiguration()) - if err == nil { - t.Fatal("expected config to reject the use of plan_name without plan_product and plan_publisher") - } - - planInfo["plan_product"] = "--plan-product--" - _, err = c.Prepare(config, getPackerConfiguration()) - if err == nil { - t.Fatal("expected config to reject the use of plan_name and plan_product without plan_publisher") - } - - planInfo["plan_publisher"] = "--plan-publisher--" - _, err = c.Prepare(config, getPackerConfiguration()) - if err != nil { - t.Fatalf("expected config to accept a complete plan configuration: %s", err) - } - - if c.PlanInfo.PlanName != "--plan-name--" { - t.Fatalf("Expected PlanName to be '--plan-name--', but got %q", c.PlanInfo.PlanName) - } - if c.PlanInfo.PlanProduct != "--plan-product--" { - t.Fatalf("Expected PlanProduct to be '--plan-product--', but got %q", c.PlanInfo.PlanProduct) - } - if c.PlanInfo.PlanPublisher != "--plan-publisher--" { - t.Fatalf("Expected PlanPublisher to be '--plan-publisher--, but got %q", c.PlanInfo.PlanPublisher) - } -} - -func TestPlanInfoPromotionCode(t *testing.T) { - config := map[string]interface{}{ - "capture_name_prefix": "ignore", - "capture_container_name": "ignore", - "image_offer": "ignore", - "image_publisher": "ignore", - "image_sku": "ignore", - "location": "ignore", - "storage_account": "ignore", - "resource_group_name": "ignore", - "subscription_id": "ignore", - "os_type": "linux", - "communicator": "none", - "plan_info": map[string]string{ - "plan_name": "--plan-name--", - "plan_product": "--plan-product--", - "plan_publisher": "--plan-publisher--", - "plan_promotion_code": "--plan-promotion-code--", - }, - } - - var c Config - _, err := c.Prepare(config, getPackerConfiguration()) - if err != nil { - t.Fatalf("expected config to accept plan_info configuration, but got %s", err) - } - - if c.PlanInfo.PlanName != "--plan-name--" { - t.Fatalf("Expected PlanName to be '--plan-name--', but got %q", c.PlanInfo.PlanName) - } - if c.PlanInfo.PlanProduct != "--plan-product--" { - t.Fatalf("Expected PlanProduct to be '--plan-product--', but got %q", c.PlanInfo.PlanProduct) - } - if c.PlanInfo.PlanPublisher != "--plan-publisher--" { - t.Fatalf("Expected PlanPublisher to be '--plan-publisher--, but got %q", c.PlanInfo.PlanPublisher) - } - if c.PlanInfo.PlanPromotionCode != "--plan-promotion-code--" { - t.Fatalf("Expected PlanPublisher to be '--plan-promotion-code----, but got %q", c.PlanInfo.PlanPromotionCode) - } -} - -// plan_info defines 3 or 4 tags based on plan data. -// The user can define up to 15 tags. If the combination of these two -// exceeds the max tag amount, the builder should reject the configuration. -func TestPlanInfoTooManyTagsErrors(t *testing.T) { - exactMaxNumberOfTags := map[string]string{} - for i := 0; i < 15; i++ { - exactMaxNumberOfTags[fmt.Sprintf("tag%.2d", i)] = "ignored" - } - - config := map[string]interface{}{ - "capture_name_prefix": "ignore", - "capture_container_name": "ignore", - "image_offer": "ignore", - "image_publisher": "ignore", - "image_sku": "ignore", - "location": "ignore", - "storage_account": "ignore", - "resource_group_name": "ignore", - "subscription_id": "ignore", - "os_type": "linux", - "communicator": "none", - "azure_tags": exactMaxNumberOfTags, - "plan_info": map[string]string{ - "plan_name": "--plan-name--", - "plan_product": "--plan-product--", - "plan_publisher": "--plan-publisher--", - "plan_promotion_code": "--plan-promotion-code--", - }, - } - - var c Config - _, err := c.Prepare(config, getPackerConfiguration()) - if err == nil { - t.Fatal("expected config to reject configuration due to excess tags") - } -} - -// The Azure builder creates temporary resources, but the user has some control over -// these values. This test asserts those values are controllable by the user. -func TestConfigShouldAllowTempNameOverrides(t *testing.T) { - config := map[string]interface{}{ - "image_offer": "ignore", - "image_publisher": "ignore", - "image_sku": "ignore", - "location": "ignore", - "subscription_id": "ignore", - "communicator": "none", - "os_type": "linux", - "managed_image_name": "ignore", - "managed_image_resource_group_name": "ignore", - "temp_resource_group_name": "myTempResourceGroupName", - "temp_compute_name": "myTempComputeName", - } - - var c Config - _, err := c.Prepare(config, getPackerConfiguration()) - if err != nil { - t.Errorf("newConfig failed with %q", err) - } - - if c.TempResourceGroupName != "myTempResourceGroupName" { - t.Errorf("expected TempResourceGroupName to be %q, but got %q", "myTempResourceGroupName", c.TempResourceGroupName) - } - if c.tmpResourceGroupName != "myTempResourceGroupName" { - t.Errorf("expected tmpResourceGroupName to be %q, but got %q", "myTempResourceGroupName", c.tmpResourceGroupName) - } - - if c.TempComputeName != "myTempComputeName" { - t.Errorf("expected TempComputeName to be %q, but got %q", "myTempComputeName", c.TempComputeName) - } - if c.tmpComputeName != "myTempComputeName" { - t.Errorf("expected tmpComputeName to be %q, but got %q", "myTempComputeName", c.tmpResourceGroupName) - } -} - -func TestConfigShouldAllowAsyncResourceGroupOverride(t *testing.T) { - config := map[string]interface{}{ - "image_offer": "ignore", - "image_publisher": "ignore", - "image_sku": "ignore", - "location": "ignore", - "subscription_id": "ignore", - "communicator": "none", - "os_type": "linux", - "managed_image_name": "ignore", - "managed_image_resource_group_name": "ignore", - "async_resourcegroup_delete": "true", - } - - var c Config - _, err := c.Prepare(config, getPackerConfiguration()) - if err != nil { - t.Errorf("newConfig failed with %q", err) - } - - if c.AsyncResourceGroupDelete != true { - t.Errorf("expected async_resourcegroup_delete to be %q, but got %t", "async_resourcegroup_delete", c.AsyncResourceGroupDelete) - } -} -func TestConfigShouldAllowAsyncResourceGroupOverrideNoValue(t *testing.T) { - config := map[string]interface{}{ - "image_offer": "ignore", - "image_publisher": "ignore", - "image_sku": "ignore", - "location": "ignore", - "subscription_id": "ignore", - "communicator": "none", - "os_type": "linux", - "managed_image_name": "ignore", - "managed_image_resource_group_name": "ignore", - } - - var c Config - _, err := c.Prepare(config, getPackerConfiguration()) - if err != nil { - t.Errorf("newConfig failed with %q", err) - } - - if c.AsyncResourceGroupDelete != false { - t.Errorf("expected async_resourcegroup_delete to be %q, but got %t", "async_resourcegroup_delete", c.AsyncResourceGroupDelete) - } -} -func TestConfigShouldAllowAsyncResourceGroupOverrideBadValue(t *testing.T) { - config := map[string]interface{}{ - "image_offer": "ignore", - "image_publisher": "ignore", - "image_sku": "ignore", - "location": "ignore", - "subscription_id": "ignore", - "communicator": "none", - "os_type": "linux", - "managed_image_name": "ignore", - "managed_image_resource_group_name": "ignore", - "async_resourcegroup_delete": "asdasda", - } - - var c Config - _, err := c.Prepare(config, getPackerConfiguration()) - if err != nil { - t.Log("newConfig failed which is expected ", err) - } - -} -func TestConfigShouldAllowSharedImageGalleryOptions(t *testing.T) { - config := map[string]interface{}{ - "location": "ignore", - "subscription_id": "ignore", - "os_type": "linux", - "shared_image_gallery": map[string]string{ - "subscription": "ignore", - "resource_group": "ignore", - "gallery_name": "ignore", - "image_name": "ignore", - "image_version": "ignore", - }, - } - - var c Config - _, err := c.Prepare(config, getPackerConfiguration()) - if err == nil { - t.Log("expected config to accept Shared Image Gallery options", err) - } - -} - -func TestConfigShouldRejectSharedImageGalleryInvalidStorageAccountType(t *testing.T) { - config := map[string]interface{}{ - "location": "ignore", - "subscription_id": "ignore", - "os_type": "linux", - "shared_image_gallery": map[string]string{ - "subscription": "ignore", - "resource_group": "ignore", - "gallery_name": "ignore", - "image_name": "ignore", - "image_version": "ignore", - "storage_account_type": "--invalid--", - }, - } - - var c Config - _, err := c.Prepare(config, getPackerConfiguration()) - if err != nil { - t.Log("config Shared Image Gallery with unsupported storage account type failed which is expected", err) - } - -} - -func TestConfigShouldRejectSharedImageGalleryWithVhdTarget(t *testing.T) { - config := map[string]interface{}{ - "location": "ignore", - "subscription_id": "ignore", - "os_type": "linux", - "shared_image_gallery": map[string]string{ - "subscription": "ignore", - "resource_group": "ignore", - "gallery_name": "ignore", - "image_name": "ignore", - "image_version": "ignore", - }, - "resource_group_name": "ignore", - "storage_account": "ignore", - "capture_container_name": "ignore", - "capture_name_prefix": "ignore", - } - - var c Config - _, err := c.Prepare(config, getPackerConfiguration()) - if err != nil { - t.Log("expected an error if Shared Image Gallery source is used with VHD target", err) - } -} - -func Test_GivenZoneNotSupportingResiliency_ConfigValidate_ShouldWarn(t *testing.T) { - builderValues := getArmBuilderConfiguration() - builderValues["managed_image_zone_resilient"] = "true" - builderValues["location"] = "ukwest" - - var c Config - _, err := c.Prepare(builderValues, getPackerConfiguration()) - if err != nil { - t.Errorf("newConfig failed with %q", err) - } - - var m = "" - c.validateLocationZoneResiliency(func(s string) { m = s }) - - if m != "WARNING: Zone resiliency may not be supported in ukwest, checkout the docs at https://docs.microsoft.com/en-us/azure/availability-zones/" { - t.Errorf("warning message not as expected: %s", m) - } -} - -func Test_GivenZoneSupportingResiliency_ConfigValidate_ShouldNotWarn(t *testing.T) { - builderValues := getArmBuilderConfiguration() - builderValues["managed_image_zone_resilient"] = "true" - builderValues["location"] = "westeurope" - - var c Config - _, err := c.Prepare(builderValues, getPackerConfiguration()) - if err != nil { - t.Errorf("newConfig failed with %q", err) - } - - var m = "" - c.validateLocationZoneResiliency(func(s string) { m = s }) - - if m != "" { - t.Errorf("warning message not as expected: %s", m) - } -} - -func TestConfig_PrepareProvidedWinRMPassword(t *testing.T) { - config := getArmBuilderConfiguration() - config["communicator"] = "winrm" - - var c Config - tc := []struct { - name string - password string - shouldFail bool - }{ - { - name: "password should be longer than 8 characters", - password: "packer", - shouldFail: true, - }, - { - name: "password should be shorter than 123 characters", - password: "1Aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", - shouldFail: true, - }, - { - name: "password should have valid size but only lower and upper case letters", - password: "AAAbbbCCC", - shouldFail: true, - }, - { - name: "password should have valid size but only digits and upper case letters", - password: "AAA12345", - shouldFail: true, - }, - { - name: "password should have valid size, digits, upper and lower case letters", - password: "AAA12345bbb", - shouldFail: false, - }, - { - name: "password should have valid size, digits, special characters and lower case letters", - password: "//12345bbb", - shouldFail: false, - }, - } - - for _, tt := range tc { - t.Run(tt.name, func(t *testing.T) { - config["winrm_password"] = tt.password - _, err := c.Prepare(config) - fail := err != nil - if tt.shouldFail != fail { - t.Fatalf("bad: %s. Expected fail is: %t but it was %t", tt.name, tt.shouldFail, fail) - } - }) - } -} - -func getArmBuilderConfiguration() map[string]interface{} { - m := make(map[string]interface{}) - for _, v := range requiredConfigValues { - m[v] = "ignored00" - } - - m["communicator"] = "none" - m["os_type"] = constants.Target_Linux - return m -} - -func getArmBuilderConfigurationWithWindows() map[string]string { - m := make(map[string]string) - for _, v := range requiredConfigValues { - m[v] = "ignored00" - } - - m["object_id"] = "ignored00" - m["tenant_id"] = "ignored00" - m["winrm_username"] = "ignored00" - m["communicator"] = "winrm" - m["os_type"] = constants.Target_Windows - return m -} - -func getPackerConfiguration() interface{} { - config := map[string]interface{}{ - "packer_build_name": "azure-arm-vm", - "packer_builder_type": "azure-arm-vm", - "packer_debug": "false", - "packer_force": "false", - "packer_template_path": "/home/jenkins/azure-arm-vm/template.json", - } - - return config -} - -func getPackerCommunicatorConfiguration() map[string]string { - config := map[string]string{ - "ssh_timeout": "1h", - "winrm_timeout": "2h", - } - - return config -} - -func getPackerSSHPasswordCommunicatorConfiguration() map[string]string { - config := map[string]string{ - "ssh_password": "superS3cret", - } - - return config -} - -func TestConfigShouldRejectMalformedUserAssignedManagedIdentities(t *testing.T) { - config := map[string]interface{}{ - "capture_name_prefix": "ignore", - "capture_container_name": "ignore", - "image_offer": "ignore", - "image_publisher": "ignore", - "image_sku": "ignore", - "location": "ignore", - "storage_account": "ignore", - "resource_group_name": "ignore", - "subscription_id": "ignore", - "communicator": "none", - // Does not matter for this test case, just pick one. - "os_type": constants.Target_Linux, - } - - config["user_assigned_managed_identities"] = []string{"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/rg1/providers/Microsoft.ManagedIdentity/userAssignedIdentities/id"} - var c Config - if _, err := c.Prepare(config, getPackerConfiguration()); err != nil { - t.Error("Expected test to pass, but it failed with the well-formed user_assigned_managed_identities.") - } - - malformedUserAssignedManagedIdentityResourceIds := []string{ - "not_a_resource_id", - "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/rg1/providers/Microsoft.ManagedIdentity/userAssignedIdentities/", - "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/rg1/providers/Microsoft.Compute/images/im", - "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/rg1/providers/Microsoft.ManagedIdentity/userAssignedIdentitie/id", - } - - for _, x := range malformedUserAssignedManagedIdentityResourceIds { - config["user_assigned_managed_identities"] = x - var c Config - if _, err := c.Prepare(config, getPackerConfiguration()); err == nil { - t.Errorf("Expected test to fail, but it succeeded with the malformed user_assigned_managed_identities set to %q.", x) - } - } -} diff --git a/builder/azure/arm/inspector.go b/builder/azure/arm/inspector.go deleted file mode 100644 index e760323d5..000000000 --- a/builder/azure/arm/inspector.go +++ /dev/null @@ -1,71 +0,0 @@ -package arm - -import ( - "bytes" - "io/ioutil" - "log" - "net/http" - - "io" - - "github.com/Azure/go-autorest/autorest" - "github.com/Azure/go-autorest/autorest/azure" - "github.com/hashicorp/packer/builder/azure/common/logutil" -) - -func chop(data []byte, maxlen int64) string { - s := string(data) - if int64(len(s)) > maxlen { - s = s[:maxlen] + "..." - } - return s -} - -func handleBody(body io.ReadCloser, maxlen int64) (io.ReadCloser, string) { - if body == nil { - return nil, "" - } - - defer body.Close() - - b, err := ioutil.ReadAll(body) - if err != nil { - return nil, "" - } - - return ioutil.NopCloser(bytes.NewReader(b)), chop(b, maxlen) -} - -func withInspection(maxlen int64) autorest.PrepareDecorator { - return func(p autorest.Preparer) autorest.Preparer { - return autorest.PreparerFunc(func(r *http.Request) (*http.Request, error) { - body, bodyString := handleBody(r.Body, maxlen) - r.Body = body - - log.Print("Azure request", logutil.Fields{ - "method": r.Method, - "request": r.URL.String(), - "body": bodyString, - }) - return p.Prepare(r) - }) - } -} - -func byInspecting(maxlen int64) autorest.RespondDecorator { - return func(r autorest.Responder) autorest.Responder { - return autorest.ResponderFunc(func(resp *http.Response) error { - body, bodyString := handleBody(resp.Body, maxlen) - resp.Body = body - - log.Print("Azure response", logutil.Fields{ - "status": resp.Status, - "method": resp.Request.Method, - "request": resp.Request.URL.String(), - "x-ms-request-id": azure.ExtractRequestID(resp), - "body": bodyString, - }) - return r.Respond(resp) - }) - } -} diff --git a/builder/azure/arm/openssh_key_pair.go b/builder/azure/arm/openssh_key_pair.go deleted file mode 100644 index 5ab97c00e..000000000 --- a/builder/azure/arm/openssh_key_pair.go +++ /dev/null @@ -1,59 +0,0 @@ -package arm - -import ( - "crypto/rand" - "crypto/rsa" - "crypto/x509" - "encoding/base64" - "encoding/pem" - "fmt" - "time" - - "golang.org/x/crypto/ssh" -) - -const ( - KeySize = 2048 -) - -type OpenSshKeyPair struct { - privateKey *rsa.PrivateKey - publicKey ssh.PublicKey -} - -func NewOpenSshKeyPair() (*OpenSshKeyPair, error) { - return NewOpenSshKeyPairWithSize(KeySize) -} - -func NewOpenSshKeyPairWithSize(keySize int) (*OpenSshKeyPair, error) { - privateKey, err := rsa.GenerateKey(rand.Reader, keySize) - if err != nil { - return nil, err - } - - publicKey, err := ssh.NewPublicKey(&privateKey.PublicKey) - if err != nil { - return nil, err - } - - return &OpenSshKeyPair{ - privateKey: privateKey, - publicKey: publicKey, - }, nil -} - -func (s *OpenSshKeyPair) AuthorizedKey() string { - return fmt.Sprintf("%s %s packer Azure Deployment%s", - s.publicKey.Type(), - base64.StdEncoding.EncodeToString(s.publicKey.Marshal()), - time.Now().Format(time.RFC3339)) -} - -func (s *OpenSshKeyPair) PrivateKey() []byte { - privateKey := pem.EncodeToMemory(&pem.Block{ - Type: "RSA PRIVATE KEY", - Bytes: x509.MarshalPKCS1PrivateKey(s.privateKey), - }) - - return privateKey -} diff --git a/builder/azure/arm/openssh_key_pair_test.go b/builder/azure/arm/openssh_key_pair_test.go deleted file mode 100644 index 8dc9cebf2..000000000 --- a/builder/azure/arm/openssh_key_pair_test.go +++ /dev/null @@ -1,37 +0,0 @@ -package arm - -import ( - "testing" - - "golang.org/x/crypto/ssh" -) - -func TestFart(t *testing.T) { - -} - -func TestAuthorizedKeyShouldParse(t *testing.T) { - testSubject, err := NewOpenSshKeyPairWithSize(512) - if err != nil { - t.Fatalf("Failed to create a new OpenSSH key pair, err=%s.", err) - } - - authorizedKey := testSubject.AuthorizedKey() - - _, _, _, _, err = ssh.ParseAuthorizedKey([]byte(authorizedKey)) - if err != nil { - t.Fatalf("Failed to parse the authorized key, err=%s", err) - } -} - -func TestPrivateKeyShouldParse(t *testing.T) { - testSubject, err := NewOpenSshKeyPairWithSize(512) - if err != nil { - t.Fatalf("Failed to create a new OpenSSH key pair, err=%s.", err) - } - - _, err = ssh.ParsePrivateKey([]byte(testSubject.PrivateKey())) - if err != nil { - t.Fatalf("Failed to parse the private key, err=%s\n", err) - } -} diff --git a/builder/azure/arm/resource_resolver.go b/builder/azure/arm/resource_resolver.go deleted file mode 100644 index 8b89d78af..000000000 --- a/builder/azure/arm/resource_resolver.go +++ /dev/null @@ -1,141 +0,0 @@ -package arm - -// Code to resolve resources that are required by the API. These resources -// can most likely be resolved without asking the user, thereby reducing the -// amount of configuration they need to provide. -// -// Resource resolver differs from config retriever because resource resolver -// requires a client to communicate with the Azure API. A config retriever is -// used to determine values without use of a client. - -import ( - "context" - "fmt" - "strings" - - "github.com/Azure/azure-sdk-for-go/services/compute/mgmt/2018-04-01/compute" -) - -type resourceResolver struct { - client *AzureClient - findVirtualNetworkResourceGroup func(*AzureClient, string) (string, error) - findVirtualNetworkSubnet func(*AzureClient, string, string) (string, error) -} - -func newResourceResolver(client *AzureClient) *resourceResolver { - return &resourceResolver{ - client: client, - findVirtualNetworkResourceGroup: findVirtualNetworkResourceGroup, - findVirtualNetworkSubnet: findVirtualNetworkSubnet, - } -} - -func (s *resourceResolver) Resolve(c *Config) error { - if s.shouldResolveResourceGroup(c) { - resourceGroupName, err := s.findVirtualNetworkResourceGroup(s.client, c.VirtualNetworkName) - if err != nil { - return err - } - - subnetName, err := s.findVirtualNetworkSubnet(s.client, resourceGroupName, c.VirtualNetworkName) - if err != nil { - return err - } - - c.VirtualNetworkResourceGroupName = resourceGroupName - c.VirtualNetworkSubnetName = subnetName - } - - if s.shouldResolveManagedImageName(c) { - image, err := findManagedImageByName(s.client, c.CustomManagedImageName, c.CustomManagedImageResourceGroupName) - if err != nil { - return err - } - - c.customManagedImageID = *image.ID - } - - return nil -} - -func (s *resourceResolver) shouldResolveResourceGroup(c *Config) bool { - return c.VirtualNetworkName != "" && c.VirtualNetworkResourceGroupName == "" -} - -func (s *resourceResolver) shouldResolveManagedImageName(c *Config) bool { - return c.CustomManagedImageName != "" -} - -func getResourceGroupNameFromId(id string) string { - // "/subscriptions/3f499422-dd76-4114-8859-86d526c9deb6/resourceGroups/packer-Resource-Group-yylnwsl30j/providers/... - xs := strings.Split(id, "/") - return xs[4] -} - -func findManagedImageByName(client *AzureClient, name, resourceGroupName string) (*compute.Image, error) { - images, err := client.ImagesClient.ListByResourceGroupComplete(context.TODO(), resourceGroupName) - if err != nil { - return nil, err - } - - for images.NotDone() { - image := images.Value() - if strings.EqualFold(name, *image.Name) { - return &image, nil - } - if err = images.Next(); err != nil { - return nil, err - } - } - - return nil, fmt.Errorf("Cannot find an image named '%s' in the resource group '%s'", name, resourceGroupName) -} - -func findVirtualNetworkResourceGroup(client *AzureClient, name string) (string, error) { - virtualNetworks, err := client.VirtualNetworksClient.ListAllComplete(context.TODO()) - if err != nil { - return "", err - } - - resourceGroupNames := make([]string, 0) - for virtualNetworks.NotDone() { - virtualNetwork := virtualNetworks.Value() - if strings.EqualFold(name, *virtualNetwork.Name) { - rgn := getResourceGroupNameFromId(*virtualNetwork.ID) - resourceGroupNames = append(resourceGroupNames, rgn) - } - if err = virtualNetworks.Next(); err != nil { - return "", err - } - } - - if len(resourceGroupNames) == 0 { - return "", fmt.Errorf("Cannot find a resource group with a virtual network called %q", name) - } - - if len(resourceGroupNames) > 1 { - return "", fmt.Errorf("Found multiple resource groups with a virtual network called %q, please use virtual_network_subnet_name and virtual_network_resource_group_name to disambiguate", name) - } - - return resourceGroupNames[0], nil -} - -func findVirtualNetworkSubnet(client *AzureClient, resourceGroupName string, name string) (string, error) { - subnets, err := client.SubnetsClient.List(context.TODO(), resourceGroupName, name) - if err != nil { - return "", err - } - - subnetList := subnets.Values() // only first page of subnets, but only interested in ==0 or >1 - - if len(subnetList) == 0 { - return "", fmt.Errorf("Cannot find a subnet in the resource group %q associated with the virtual network called %q", resourceGroupName, name) - } - - if len(subnetList) > 1 { - return "", fmt.Errorf("Found multiple subnets in the resource group %q associated with the virtual network called %q, please use virtual_network_subnet_name and virtual_network_resource_group_name to disambiguate", resourceGroupName, name) - } - - subnet := subnetList[0] - return *subnet.Name, nil -} diff --git a/builder/azure/arm/resource_resolver_test.go b/builder/azure/arm/resource_resolver_test.go deleted file mode 100644 index 68b227ee0..000000000 --- a/builder/azure/arm/resource_resolver_test.go +++ /dev/null @@ -1,79 +0,0 @@ -package arm - -import ( - "testing" -) - -func TestResourceResolverIgnoresEmptyVirtualNetworkName(t *testing.T) { - var c Config - c.Prepare(getArmBuilderConfiguration(), getPackerConfiguration()) - if c.VirtualNetworkName != "" { - t.Fatalf("Expected VirtualNetworkName to be empty by default") - } - - sut := newTestResourceResolver() - sut.findVirtualNetworkResourceGroup = nil // assert that this is not even called - sut.Resolve(&c) - - if c.VirtualNetworkName != "" { - t.Fatalf("Expected VirtualNetworkName to be empty") - } - if c.VirtualNetworkResourceGroupName != "" { - t.Fatalf("Expected VirtualNetworkResourceGroupName to be empty") - } -} - -// If the user fully specified the virtual network name and resource group then -// there is no need to do a lookup. -func TestResourceResolverIgnoresSetVirtualNetwork(t *testing.T) { - var c Config - c.Prepare(getArmBuilderConfiguration(), getPackerConfiguration()) - c.VirtualNetworkName = "--virtual-network-name--" - c.VirtualNetworkResourceGroupName = "--virtual-network-resource-group-name--" - c.VirtualNetworkSubnetName = "--virtual-network-subnet-name--" - - sut := newTestResourceResolver() - sut.findVirtualNetworkResourceGroup = nil // assert that this is not even called - sut.findVirtualNetworkSubnet = nil // assert that this is not even called - sut.Resolve(&c) - - if c.VirtualNetworkName != "--virtual-network-name--" { - t.Fatalf("Expected VirtualNetworkName to be --virtual-network-name--") - } - if c.VirtualNetworkResourceGroupName != "--virtual-network-resource-group-name--" { - t.Fatalf("Expected VirtualNetworkResourceGroupName to be --virtual-network-resource-group-name--") - } - if c.VirtualNetworkSubnetName != "--virtual-network-subnet-name--" { - t.Fatalf("Expected VirtualNetworkSubnetName to be --virtual-network-subnet-name--") - } -} - -// If the user set virtual network name then the code should resolve virtual network -// resource group name. -func TestResourceResolverSetVirtualNetworkResourceGroupName(t *testing.T) { - var c Config - c.Prepare(getArmBuilderConfiguration(), getPackerConfiguration()) - c.VirtualNetworkName = "--virtual-network-name--" - - sut := newTestResourceResolver() - sut.Resolve(&c) - - if c.VirtualNetworkResourceGroupName != "findVirtualNetworkResourceGroup is mocked" { - t.Fatalf("Expected VirtualNetworkResourceGroupName to be 'findVirtualNetworkResourceGroup is mocked'") - } - if c.VirtualNetworkSubnetName != "findVirtualNetworkSubnet is mocked" { - t.Fatalf("Expected findVirtualNetworkSubnet to be 'findVirtualNetworkSubnet is mocked'") - } -} - -func newTestResourceResolver() resourceResolver { - return resourceResolver{ - client: nil, - findVirtualNetworkResourceGroup: func(*AzureClient, string) (string, error) { - return "findVirtualNetworkResourceGroup is mocked", nil - }, - findVirtualNetworkSubnet: func(*AzureClient, string, string) (string, error) { - return "findVirtualNetworkSubnet is mocked", nil - }, - } -} diff --git a/builder/azure/arm/step.go b/builder/azure/arm/step.go deleted file mode 100644 index def6ebd72..000000000 --- a/builder/azure/arm/step.go +++ /dev/null @@ -1,20 +0,0 @@ -package arm - -import ( - "github.com/hashicorp/packer-plugin-sdk/multistep" - "github.com/hashicorp/packer/builder/azure/common/constants" -) - -func processStepResult( - err error, sayError func(error), state multistep.StateBag) multistep.StepAction { - - if err != nil { - state.Put(constants.Error, err) - sayError(err) - - return multistep.ActionHalt - } - - return multistep.ActionContinue - -} diff --git a/builder/azure/arm/step_capture_image.go b/builder/azure/arm/step_capture_image.go deleted file mode 100644 index fa65f8415..000000000 --- a/builder/azure/arm/step_capture_image.go +++ /dev/null @@ -1,120 +0,0 @@ -package arm - -import ( - "context" - "fmt" - - "github.com/Azure/azure-sdk-for-go/services/compute/mgmt/2018-04-01/compute" - "github.com/hashicorp/packer-plugin-sdk/multistep" - packersdk "github.com/hashicorp/packer-plugin-sdk/packer" - "github.com/hashicorp/packer/builder/azure/common/constants" -) - -type StepCaptureImage struct { - client *AzureClient - generalizeVM func(resourceGroupName, computeName string) error - captureVhd func(ctx context.Context, resourceGroupName string, computeName string, parameters *compute.VirtualMachineCaptureParameters) error - captureManagedImage func(ctx context.Context, resourceGroupName string, computeName string, parameters *compute.Image) error - get func(client *AzureClient) *CaptureTemplate - say func(message string) - error func(e error) -} - -func NewStepCaptureImage(client *AzureClient, ui packersdk.Ui) *StepCaptureImage { - var step = &StepCaptureImage{ - client: client, - get: func(client *AzureClient) *CaptureTemplate { - return client.Template - }, - say: func(message string) { - ui.Say(message) - }, - error: func(e error) { - ui.Error(e.Error()) - }, - } - - step.generalizeVM = step.generalize - step.captureVhd = step.captureImage - step.captureManagedImage = step.captureImageFromVM - - return step -} - -func (s *StepCaptureImage) generalize(resourceGroupName string, computeName string) error { - _, err := s.client.Generalize(context.TODO(), resourceGroupName, computeName) - if err != nil { - s.say(s.client.LastError.Error()) - } - return err -} - -func (s *StepCaptureImage) captureImageFromVM(ctx context.Context, resourceGroupName string, imageName string, image *compute.Image) error { - f, err := s.client.ImagesClient.CreateOrUpdate(ctx, resourceGroupName, imageName, *image) - if err != nil { - s.say(s.client.LastError.Error()) - } - return f.WaitForCompletionRef(ctx, s.client.ImagesClient.Client) -} - -func (s *StepCaptureImage) captureImage(ctx context.Context, resourceGroupName string, computeName string, parameters *compute.VirtualMachineCaptureParameters) error { - f, err := s.client.VirtualMachinesClient.Capture(ctx, resourceGroupName, computeName, *parameters) - if err != nil { - s.say(s.client.LastError.Error()) - } - return f.WaitForCompletionRef(ctx, s.client.VirtualMachinesClient.Client) -} - -func (s *StepCaptureImage) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction { - s.say("Capturing image ...") - - var computeName = state.Get(constants.ArmComputeName).(string) - var location = state.Get(constants.ArmLocation).(string) - var resourceGroupName = state.Get(constants.ArmResourceGroupName).(string) - var vmCaptureParameters = state.Get(constants.ArmVirtualMachineCaptureParameters).(*compute.VirtualMachineCaptureParameters) - var imageParameters = state.Get(constants.ArmImageParameters).(*compute.Image) - - var isManagedImage = state.Get(constants.ArmIsManagedImage).(bool) - var targetManagedImageResourceGroupName = state.Get(constants.ArmManagedImageResourceGroupName).(string) - var targetManagedImageName = state.Get(constants.ArmManagedImageName).(string) - var targetManagedImageLocation = state.Get(constants.ArmLocation).(string) - - s.say(fmt.Sprintf(" -> Compute ResourceGroupName : '%s'", resourceGroupName)) - s.say(fmt.Sprintf(" -> Compute Name : '%s'", computeName)) - s.say(fmt.Sprintf(" -> Compute Location : '%s'", location)) - - err := s.generalizeVM(resourceGroupName, computeName) - - if err == nil { - if isManagedImage { - s.say(fmt.Sprintf(" -> Image ResourceGroupName : '%s'", targetManagedImageResourceGroupName)) - s.say(fmt.Sprintf(" -> Image Name : '%s'", targetManagedImageName)) - s.say(fmt.Sprintf(" -> Image Location : '%s'", targetManagedImageLocation)) - err = s.captureManagedImage(ctx, targetManagedImageResourceGroupName, targetManagedImageName, imageParameters) - } else { - err = s.captureVhd(ctx, resourceGroupName, computeName, vmCaptureParameters) - } - } - if err != nil { - state.Put(constants.Error, err) - s.error(err) - - return multistep.ActionHalt - } - - // HACK(chrboum): I do not like this. The capture method should be returning this value - // instead having to pass in another lambda. - // - // Having to resort to capturing the template via an inspector is hack, and once I can - // resolve that I can cleanup this code too. See the comments in azure_client.go for more - // details. - // [paulmey]: autorest.Future now has access to the last http.Response, but I'm not sure if - // the body is still accessible. - template := s.get(s.client) - state.Put(constants.ArmCaptureTemplate, template) - - return multistep.ActionContinue -} - -func (*StepCaptureImage) Cleanup(multistep.StateBag) { -} diff --git a/builder/azure/arm/step_capture_image_test.go b/builder/azure/arm/step_capture_image_test.go deleted file mode 100644 index 3ca6d7756..000000000 --- a/builder/azure/arm/step_capture_image_test.go +++ /dev/null @@ -1,137 +0,0 @@ -package arm - -import ( - "context" - "fmt" - "testing" - - "github.com/Azure/azure-sdk-for-go/services/compute/mgmt/2018-04-01/compute" - "github.com/hashicorp/packer-plugin-sdk/multistep" - "github.com/hashicorp/packer/builder/azure/common/constants" -) - -func TestStepCaptureImageShouldFailIfCaptureFails(t *testing.T) { - var testSubject = &StepCaptureImage{ - captureVhd: func(context.Context, string, string, *compute.VirtualMachineCaptureParameters) error { - return fmt.Errorf("!! Unit Test FAIL !!") - }, - generalizeVM: func(string, string) error { - return nil - }, - get: func(client *AzureClient) *CaptureTemplate { - return nil - }, - say: func(message string) {}, - error: func(e error) {}, - } - - stateBag := createTestStateBagStepCaptureImage() - - var result = testSubject.Run(context.Background(), stateBag) - if result != multistep.ActionHalt { - t.Fatalf("Expected the step to return 'ActionHalt', but got '%d'.", result) - } - - if _, ok := stateBag.GetOk(constants.Error); ok == false { - t.Fatalf("Expected the step to set stateBag['%s'], but it was not.", constants.Error) - } -} - -func TestStepCaptureImageShouldPassIfCapturePasses(t *testing.T) { - var testSubject = &StepCaptureImage{ - captureVhd: func(context.Context, string, string, *compute.VirtualMachineCaptureParameters) error { return nil }, - generalizeVM: func(string, string) error { - return nil - }, - get: func(client *AzureClient) *CaptureTemplate { - return nil - }, - say: func(message string) {}, - error: func(e error) {}, - } - - stateBag := createTestStateBagStepCaptureImage() - - var result = testSubject.Run(context.Background(), stateBag) - if result != multistep.ActionContinue { - t.Fatalf("Expected the step to return 'ActionContinue', but got '%d'.", result) - } - - if _, ok := stateBag.GetOk(constants.Error); ok == true { - t.Fatalf("Expected the step to not set stateBag['%s'], but it was.", constants.Error) - } -} - -func TestStepCaptureImageShouldTakeStepArgumentsFromStateBag(t *testing.T) { - cancelCh := make(chan<- struct{}) - defer close(cancelCh) - - var actualResourceGroupName string - var actualComputeName string - var actualVirtualMachineCaptureParameters *compute.VirtualMachineCaptureParameters - actualCaptureTemplate := &CaptureTemplate{ - Schema: "!! Unit Test !!", - } - - var testSubject = &StepCaptureImage{ - captureVhd: func(ctx context.Context, resourceGroupName string, computeName string, parameters *compute.VirtualMachineCaptureParameters) error { - actualResourceGroupName = resourceGroupName - actualComputeName = computeName - actualVirtualMachineCaptureParameters = parameters - - return nil - }, - generalizeVM: func(string, string) error { - return nil - }, - get: func(client *AzureClient) *CaptureTemplate { - return actualCaptureTemplate - }, - say: func(message string) {}, - error: func(e error) {}, - } - - stateBag := createTestStateBagStepCaptureImage() - var result = testSubject.Run(context.Background(), stateBag) - - if result != multistep.ActionContinue { - t.Fatalf("Expected the step to return 'ActionContinue', but got '%d'.", result) - } - - var expectedComputeName = stateBag.Get(constants.ArmComputeName).(string) - var expectedResourceGroupName = stateBag.Get(constants.ArmResourceGroupName).(string) - var expectedVirtualMachineCaptureParameters = stateBag.Get(constants.ArmVirtualMachineCaptureParameters).(*compute.VirtualMachineCaptureParameters) - var expectedCaptureTemplate = stateBag.Get(constants.ArmCaptureTemplate).(*CaptureTemplate) - - if actualComputeName != expectedComputeName { - t.Fatal("Expected StepCaptureImage to source 'constants.ArmComputeName' from the state bag, but it did not.") - } - - if actualResourceGroupName != expectedResourceGroupName { - t.Fatal("Expected StepCaptureImage to source 'constants.ArmResourceGroupName' from the state bag, but it did not.") - } - - if actualVirtualMachineCaptureParameters != expectedVirtualMachineCaptureParameters { - t.Fatal("Expected StepCaptureImage to source 'constants.ArmVirtualMachineCaptureParameters' from the state bag, but it did not.") - } - - if actualCaptureTemplate != expectedCaptureTemplate { - t.Fatal("Expected StepCaptureImage to source 'constants.ArmCaptureTemplate' from the state bag, but it did not.") - } -} - -func createTestStateBagStepCaptureImage() multistep.StateBag { - stateBag := new(multistep.BasicStateBag) - - stateBag.Put(constants.ArmLocation, "localhost") - stateBag.Put(constants.ArmComputeName, "Unit Test: ComputeName") - stateBag.Put(constants.ArmResourceGroupName, "Unit Test: ResourceGroupName") - stateBag.Put(constants.ArmVirtualMachineCaptureParameters, &compute.VirtualMachineCaptureParameters{}) - - stateBag.Put(constants.ArmIsManagedImage, false) - stateBag.Put(constants.ArmManagedImageResourceGroupName, "") - stateBag.Put(constants.ArmManagedImageName, "") - stateBag.Put(constants.ArmImageParameters, &compute.Image{}) - - return stateBag -} diff --git a/builder/azure/arm/step_certificate_in_keyvault.go b/builder/azure/arm/step_certificate_in_keyvault.go deleted file mode 100644 index 523d88609..000000000 --- a/builder/azure/arm/step_certificate_in_keyvault.go +++ /dev/null @@ -1,45 +0,0 @@ -package arm - -import ( - "context" - "fmt" - - "github.com/hashicorp/packer-plugin-sdk/multistep" - packersdk "github.com/hashicorp/packer-plugin-sdk/packer" - "github.com/hashicorp/packer/builder/azure/common" - "github.com/hashicorp/packer/builder/azure/common/constants" -) - -type StepCertificateInKeyVault struct { - config *Config - client common.AZVaultClientIface - say func(message string) - error func(e error) -} - -func NewStepCertificateInKeyVault(cli common.AZVaultClientIface, ui packersdk.Ui, config *Config) *StepCertificateInKeyVault { - var step = &StepCertificateInKeyVault{ - client: cli, - config: config, - say: func(message string) { ui.Say(message) }, - error: func(e error) { ui.Error(e.Error()) }, - } - - return step -} - -func (s *StepCertificateInKeyVault) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction { - s.say("Setting the certificate in the KeyVault...") - var keyVaultName = state.Get(constants.ArmKeyVaultName).(string) - - err := s.client.SetSecret(keyVaultName, DefaultSecretName, s.config.winrmCertificate) - if err != nil { - s.error(fmt.Errorf("Error setting winrm cert in custom keyvault: %s", err)) - return multistep.ActionHalt - } - - return multistep.ActionContinue -} - -func (*StepCertificateInKeyVault) Cleanup(multistep.StateBag) { -} diff --git a/builder/azure/arm/step_certificate_in_keyvault_test.go b/builder/azure/arm/step_certificate_in_keyvault_test.go deleted file mode 100644 index a892943f3..000000000 --- a/builder/azure/arm/step_certificate_in_keyvault_test.go +++ /dev/null @@ -1,66 +0,0 @@ -package arm - -import ( - "bytes" - "context" - "testing" - - "github.com/hashicorp/packer-plugin-sdk/multistep" - packersdk "github.com/hashicorp/packer-plugin-sdk/packer" - azcommon "github.com/hashicorp/packer/builder/azure/common" - "github.com/hashicorp/packer/builder/azure/common/constants" -) - -func TestNewStepCertificateInKeyVault(t *testing.T) { - cli := azcommon.MockAZVaultClient{} - ui := &packersdk.BasicUi{ - Reader: new(bytes.Buffer), - Writer: new(bytes.Buffer), - } - state := new(multistep.BasicStateBag) - state.Put(constants.ArmKeyVaultName, "testKeyVaultName") - - config := &Config{ - winrmCertificate: "testCertificateString", - } - - certKVStep := NewStepCertificateInKeyVault(&cli, ui, config) - stepAction := certKVStep.Run(context.TODO(), state) - - if stepAction == multistep.ActionHalt { - t.Fatalf("step should have succeeded.") - } - if !cli.SetSecretCalled { - t.Fatalf("Step should have called SetSecret on Azure client.") - } - if cli.SetSecretCert != "testCertificateString" { - t.Fatalf("Step should have read cert from winRMCertificate field on config.") - } - if cli.SetSecretVaultName != "testKeyVaultName" { - t.Fatalf("step should have read keyvault name from state.") - } -} - -func TestNewStepCertificateInKeyVault_error(t *testing.T) { - // Tell mock to return an error - cli := azcommon.MockAZVaultClient{} - cli.IsError = true - - ui := &packersdk.BasicUi{ - Reader: new(bytes.Buffer), - Writer: new(bytes.Buffer), - } - state := new(multistep.BasicStateBag) - state.Put(constants.ArmKeyVaultName, "testKeyVaultName") - - config := &Config{ - winrmCertificate: "testCertificateString", - } - - certKVStep := NewStepCertificateInKeyVault(&cli, ui, config) - stepAction := certKVStep.Run(context.TODO(), state) - - if stepAction != multistep.ActionHalt { - t.Fatalf("step should have failed.") - } -} diff --git a/builder/azure/arm/step_create_resource_group.go b/builder/azure/arm/step_create_resource_group.go deleted file mode 100644 index e8d8c4a75..000000000 --- a/builder/azure/arm/step_create_resource_group.go +++ /dev/null @@ -1,146 +0,0 @@ -package arm - -import ( - "context" - "errors" - "fmt" - - "github.com/Azure/azure-sdk-for-go/services/resources/mgmt/2018-02-01/resources" - "github.com/hashicorp/packer-plugin-sdk/multistep" - packersdk "github.com/hashicorp/packer-plugin-sdk/packer" - "github.com/hashicorp/packer/builder/azure/common/constants" -) - -type StepCreateResourceGroup struct { - client *AzureClient - create func(ctx context.Context, resourceGroupName string, location string, tags map[string]*string) error - say func(message string) - error func(e error) - exists func(ctx context.Context, resourceGroupName string) (bool, error) -} - -func NewStepCreateResourceGroup(client *AzureClient, ui packersdk.Ui) *StepCreateResourceGroup { - var step = &StepCreateResourceGroup{ - client: client, - say: func(message string) { ui.Say(message) }, - error: func(e error) { ui.Error(e.Error()) }, - } - - step.create = step.createResourceGroup - step.exists = step.doesResourceGroupExist - return step -} - -func (s *StepCreateResourceGroup) createResourceGroup(ctx context.Context, resourceGroupName string, location string, tags map[string]*string) error { - _, err := s.client.GroupsClient.CreateOrUpdate(ctx, resourceGroupName, resources.Group{ - Location: &location, - Tags: tags, - }) - - if err != nil { - s.say(s.client.LastError.Error()) - } - return err -} - -func (s *StepCreateResourceGroup) doesResourceGroupExist(ctx context.Context, resourceGroupName string) (bool, error) { - exists, err := s.client.GroupsClient.CheckExistence(ctx, resourceGroupName) - if err != nil { - s.say(s.client.LastError.Error()) - } - - return exists.Response.StatusCode != 404, err -} - -func (s *StepCreateResourceGroup) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction { - var doubleResource, ok = state.GetOk(constants.ArmDoubleResourceGroupNameSet) - if ok && doubleResource.(bool) { - err := errors.New("You have filled in both temp_resource_group_name and build_resource_group_name. Please choose one.") - return processStepResult(err, s.error, state) - } - - var resourceGroupName = state.Get(constants.ArmResourceGroupName).(string) - var location = state.Get(constants.ArmLocation).(string) - tags, ok := state.Get(constants.ArmTags).(map[string]*string) - if !ok { - err := fmt.Errorf("failed to extract tags from state bag") - state.Put(constants.Error, err) - s.error(err) - return multistep.ActionHalt - } - - exists, err := s.exists(ctx, resourceGroupName) - if err != nil { - return processStepResult(err, s.error, state) - } - configThinksExists := state.Get(constants.ArmIsExistingResourceGroup).(bool) - if exists != configThinksExists { - if configThinksExists { - err = errors.New("The resource group you want to use does not exist yet. Please use temp_resource_group_name to create a temporary resource group.") - } else { - err = errors.New("A resource group with that name already exists. Please use build_resource_group_name to use an existing resource group.") - } - return processStepResult(err, s.error, state) - } - - // If the resource group exists, we may not have permissions to update it so we don't. - if !exists { - s.say("Creating resource group ...") - - s.say(fmt.Sprintf(" -> ResourceGroupName : '%s'", resourceGroupName)) - s.say(fmt.Sprintf(" -> Location : '%s'", location)) - s.say(fmt.Sprintf(" -> Tags :")) - for k, v := range tags { - s.say(fmt.Sprintf(" ->> %s : %s", k, *v)) - } - err = s.create(ctx, resourceGroupName, location, tags) - if err == nil { - state.Put(constants.ArmIsResourceGroupCreated, true) - } - } else { - s.say("Using existing resource group ...") - s.say(fmt.Sprintf(" -> ResourceGroupName : '%s'", resourceGroupName)) - s.say(fmt.Sprintf(" -> Location : '%s'", location)) - state.Put(constants.ArmIsResourceGroupCreated, true) - } - - return processStepResult(err, s.error, state) -} - -func (s *StepCreateResourceGroup) Cleanup(state multistep.StateBag) { - isCreated, ok := state.GetOk(constants.ArmIsResourceGroupCreated) - if !ok || !isCreated.(bool) { - return - } - - ui := state.Get("ui").(packersdk.Ui) - if state.Get(constants.ArmIsExistingResourceGroup).(bool) { - ui.Say("\nThe resource group was not created by Packer, not deleting ...") - return - } - - ctx := context.TODO() - resourceGroupName := state.Get(constants.ArmResourceGroupName).(string) - if exists, err := s.exists(ctx, resourceGroupName); !exists || err != nil { - return - } - - ui.Say("\nCleanup requested, deleting resource group ...") - f, err := s.client.GroupsClient.Delete(ctx, resourceGroupName) - if err == nil { - if state.Get(constants.ArmAsyncResourceGroupDelete).(bool) { - s.say(fmt.Sprintf("\n Not waiting for Resource Group delete as requested by user. Resource Group Name is %s", resourceGroupName)) - } else { - err = f.WaitForCompletionRef(ctx, s.client.GroupsClient.Client) - } - } - if err != nil { - ui.Error(fmt.Sprintf("Error deleting resource group. Please delete it manually.\n\n"+ - "Name: %s\n"+ - "Error: %s", resourceGroupName, err)) - return - } - if !state.Get(constants.ArmAsyncResourceGroupDelete).(bool) { - ui.Say("Resource group has been deleted.") - } -} diff --git a/builder/azure/arm/step_create_resource_group_test.go b/builder/azure/arm/step_create_resource_group_test.go deleted file mode 100644 index d07d39830..000000000 --- a/builder/azure/arm/step_create_resource_group_test.go +++ /dev/null @@ -1,251 +0,0 @@ -package arm - -import ( - "context" - "errors" - "fmt" - "testing" - - "github.com/hashicorp/packer-plugin-sdk/multistep" - "github.com/hashicorp/packer/builder/azure/common/constants" -) - -func TestStepCreateResourceGroupShouldFailIfBothGroupNames(t *testing.T) { - stateBag := new(multistep.BasicStateBag) - - stateBag.Put(constants.ArmDoubleResourceGroupNameSet, true) - - value := "Unit Test: Tags" - tags := map[string]*string{ - "tag01": &value, - } - - stateBag.Put(constants.ArmTags, tags) - var testSubject = &StepCreateResourceGroup{ - create: func(context.Context, string, string, map[string]*string) error { return nil }, - say: func(message string) {}, - error: func(e error) {}, - exists: func(context.Context, string) (bool, error) { return false, nil }, - } - var result = testSubject.Run(context.Background(), stateBag) - if result != multistep.ActionHalt { - t.Fatalf("Expected the step to return 'ActionHalt', but got '%d'.", result) - } - - if _, ok := stateBag.GetOk(constants.Error); ok == false { - t.Fatalf("Expected the step to set stateBag['%s'], but it was not.", constants.Error) - } -} - -func TestStepCreateResourceGroupShouldFailIfCreateFails(t *testing.T) { - var testSubject = &StepCreateResourceGroup{ - create: func(context.Context, string, string, map[string]*string) error { - return fmt.Errorf("!! Unit Test FAIL !!") - }, - say: func(message string) {}, - error: func(e error) {}, - exists: func(context.Context, string) (bool, error) { return false, nil }, - } - - stateBag := createTestStateBagStepCreateResourceGroup() - - var result = testSubject.Run(context.Background(), stateBag) - if result != multistep.ActionHalt { - t.Fatalf("Expected the step to return 'ActionHalt', but got '%d'.", result) - } - - if _, ok := stateBag.GetOk(constants.Error); ok == false { - t.Fatalf("Expected the step to set stateBag['%s'], but it was not.", constants.Error) - } -} - -func TestStepCreateResourceGroupShouldFailIfExistsFails(t *testing.T) { - var testSubject = &StepCreateResourceGroup{ - create: func(context.Context, string, string, map[string]*string) error { return nil }, - say: func(message string) {}, - error: func(e error) {}, - exists: func(context.Context, string) (bool, error) { return false, errors.New("FAIL") }, - } - - stateBag := createTestStateBagStepCreateResourceGroup() - - var result = testSubject.Run(context.Background(), stateBag) - if result != multistep.ActionHalt { - t.Fatalf("Expected the step to return 'ActionHalt', but got '%d'.", result) - } - - if _, ok := stateBag.GetOk(constants.Error); ok == false { - t.Fatalf("Expected the step to set stateBag['%s'], but it was not.", constants.Error) - } -} - -func TestStepCreateResourceGroupShouldPassIfCreatePasses(t *testing.T) { - var testSubject = &StepCreateResourceGroup{ - create: func(context.Context, string, string, map[string]*string) error { return nil }, - say: func(message string) {}, - error: func(e error) {}, - exists: func(context.Context, string) (bool, error) { return false, nil }, - } - - stateBag := createTestStateBagStepCreateResourceGroup() - - var result = testSubject.Run(context.Background(), stateBag) - if result != multistep.ActionContinue { - t.Fatalf("Expected the step to return 'ActionContinue', but got '%d'.", result) - } - - if _, ok := stateBag.GetOk(constants.Error); ok == true { - t.Fatalf("Expected the step to not set stateBag['%s'], but it was.", constants.Error) - } -} - -func TestStepCreateResourceGroupShouldTakeStepArgumentsFromStateBag(t *testing.T) { - var actualResourceGroupName string - var actualLocation string - var actualTags map[string]*string - - var testSubject = &StepCreateResourceGroup{ - create: func(ctx context.Context, resourceGroupName string, location string, tags map[string]*string) error { - actualResourceGroupName = resourceGroupName - actualLocation = location - actualTags = tags - return nil - }, - say: func(message string) {}, - error: func(e error) {}, - exists: func(context.Context, string) (bool, error) { return false, nil }, - } - - stateBag := createTestStateBagStepCreateResourceGroup() - var result = testSubject.Run(context.Background(), stateBag) - - if result != multistep.ActionContinue { - t.Fatalf("Expected the step to return 'ActionContinue', but got '%d'.", result) - } - - var expectedResourceGroupName = stateBag.Get(constants.ArmResourceGroupName).(string) - var expectedLocation = stateBag.Get(constants.ArmLocation).(string) - var expectedTags = stateBag.Get(constants.ArmTags).(map[string]*string) - - if actualResourceGroupName != expectedResourceGroupName { - t.Fatal("Expected the step to source 'constants.ArmResourceGroupName' from the state bag, but it did not.") - } - - if actualLocation != expectedLocation { - t.Fatal("Expected the step to source 'constants.ArmResourceGroupName' from the state bag, but it did not.") - } - - if len(expectedTags) != len(actualTags) && expectedTags["tag01"] != actualTags["tag01"] { - t.Fatal("Expected the step to source 'constants.ArmTags' from the state bag, but it did not.") - } - - _, ok := stateBag.GetOk(constants.ArmIsResourceGroupCreated) - if !ok { - t.Fatal("Expected the step to add item to stateBag['constants.ArmIsResourceGroupCreated'], but it did not.") - } -} - -func TestStepCreateResourceGroupMarkShouldFailIfTryingExistingButDoesntExist(t *testing.T) { - var testSubject = &StepCreateResourceGroup{ - create: func(context.Context, string, string, map[string]*string) error { - return fmt.Errorf("!! Unit Test FAIL !!") - }, - say: func(message string) {}, - error: func(e error) {}, - exists: func(context.Context, string) (bool, error) { return false, nil }, - } - - stateBag := createTestExistingStateBagStepCreateResourceGroup() - - var result = testSubject.Run(context.Background(), stateBag) - if result != multistep.ActionHalt { - t.Fatalf("Expected the step to return 'ActionHalt', but got '%d'.", result) - } - - if _, ok := stateBag.GetOk(constants.Error); ok == false { - t.Fatalf("Expected the step to set stateBag['%s'], but it was not.", constants.Error) - } -} - -func TestStepCreateResourceGroupMarkShouldFailIfTryingTempButExist(t *testing.T) { - var testSubject = &StepCreateResourceGroup{ - create: func(context.Context, string, string, map[string]*string) error { - return fmt.Errorf("!! Unit Test FAIL !!") - }, - say: func(message string) {}, - error: func(e error) {}, - exists: func(context.Context, string) (bool, error) { return true, nil }, - } - - stateBag := createTestStateBagStepCreateResourceGroup() - - var result = testSubject.Run(context.Background(), stateBag) - if result != multistep.ActionHalt { - t.Fatalf("Expected the step to return 'ActionHalt', but got '%d'.", result) - } - - if _, ok := stateBag.GetOk(constants.Error); ok == false { - t.Fatalf("Expected the step to set stateBag['%s'], but it was not.", constants.Error) - } -} - -func createTestStateBagStepCreateResourceGroup() multistep.StateBag { - stateBag := new(multistep.BasicStateBag) - - stateBag.Put(constants.ArmLocation, "Unit Test: Location") - stateBag.Put(constants.ArmResourceGroupName, "Unit Test: ResourceGroupName") - stateBag.Put(constants.ArmIsExistingResourceGroup, false) - - value := "Unit Test: Tags" - tags := map[string]*string{ - "tag01": &value, - } - - stateBag.Put(constants.ArmTags, tags) - return stateBag -} - -func createTestExistingStateBagStepCreateResourceGroup() multistep.StateBag { - stateBag := new(multistep.BasicStateBag) - - stateBag.Put(constants.ArmLocation, "Unit Test: Location") - stateBag.Put(constants.ArmResourceGroupName, "Unit Test: ResourceGroupName") - stateBag.Put(constants.ArmIsExistingResourceGroup, true) - - value := "Unit Test: Tags" - tags := map[string]*string{ - "tag01": &value, - } - - stateBag.Put(constants.ArmTags, tags) - return stateBag -} - -func TestStepCreateResourceGroupShouldFailIfTagsFailCast(t *testing.T) { - stateBag := new(multistep.BasicStateBag) - - stateBag.Put(constants.ArmLocation, "Unit Test: Location") - stateBag.Put(constants.ArmResourceGroupName, "Unit Test: ResourceGroupName") - stateBag.Put(constants.ArmIsExistingResourceGroup, true) - - value := "Unit Test: Tags" - tags := map[string]string{ - "tag01": value, - } - - stateBag.Put(constants.ArmTags, tags) - var testSubject = &StepCreateResourceGroup{ - create: func(context.Context, string, string, map[string]*string) error { return nil }, - say: func(message string) {}, - error: func(e error) {}, - exists: func(context.Context, string) (bool, error) { return false, nil }, - } - var result = testSubject.Run(context.Background(), stateBag) - if result != multistep.ActionHalt { - t.Fatalf("Expected the step to return 'ActionHalt', but got '%d'.", result) - } - - if _, ok := stateBag.GetOk(constants.Error); ok == false { - t.Fatalf("Expected the step to set stateBag['%s'], but it was not.", constants.Error) - } -} diff --git a/builder/azure/arm/step_delete_additional_disks.go b/builder/azure/arm/step_delete_additional_disks.go deleted file mode 100644 index f87992323..000000000 --- a/builder/azure/arm/step_delete_additional_disks.go +++ /dev/null @@ -1,118 +0,0 @@ -package arm - -import ( - "context" - "errors" - "fmt" - "net/url" - "strings" - - "github.com/hashicorp/packer/builder/azure/common/constants" - - "github.com/hashicorp/packer-plugin-sdk/multistep" - packersdk "github.com/hashicorp/packer-plugin-sdk/packer" -) - -type StepDeleteAdditionalDisk struct { - client *AzureClient - delete func(string, string) error - deleteManaged func(context.Context, string, string) error - say func(message string) - error func(e error) -} - -func NewStepDeleteAdditionalDisks(client *AzureClient, ui packersdk.Ui) *StepDeleteAdditionalDisk { - var step = &StepDeleteAdditionalDisk{ - client: client, - say: func(message string) { ui.Say(message) }, - error: func(e error) { ui.Error(e.Error()) }, - } - - step.delete = step.deleteBlob - step.deleteManaged = step.deleteManagedDisk - return step -} - -func (s *StepDeleteAdditionalDisk) deleteBlob(storageContainerName string, blobName string) error { - blob := s.client.BlobStorageClient.GetContainerReference(storageContainerName).GetBlobReference(blobName) - _, err := blob.BreakLease(nil) - if err != nil && !strings.Contains(err.Error(), "LeaseNotPresentWithLeaseOperation") { - s.say(s.client.LastError.Error()) - return err - } - - err = blob.Delete(nil) - if err != nil { - s.say(s.client.LastError.Error()) - } - return err -} - -func (s *StepDeleteAdditionalDisk) deleteManagedDisk(ctx context.Context, resourceGroupName string, diskName string) error { - xs := strings.Split(diskName, "/") - diskName = xs[len(xs)-1] - f, err := s.client.DisksClient.Delete(ctx, resourceGroupName, diskName) - if err == nil { - err = f.WaitForCompletionRef(ctx, s.client.DisksClient.Client) - } - return err -} - -func (s *StepDeleteAdditionalDisk) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction { - s.say("Deleting the temporary Additional disk ...") - - var dataDisks []string - - if disks := state.Get(constants.ArmAdditionalDiskVhds); disks != nil { - dataDisks = disks.([]string) - } - var isManagedDisk = state.Get(constants.ArmIsManagedImage).(bool) - var isExistingResourceGroup = state.Get(constants.ArmIsExistingResourceGroup).(bool) - var resourceGroupName = state.Get(constants.ArmResourceGroupName).(string) - - if dataDisks == nil { - s.say(fmt.Sprintf(" -> No Additional Disks specified")) - return multistep.ActionContinue - } - - if isManagedDisk && !isExistingResourceGroup { - s.say(fmt.Sprintf(" -> Additional Disk : skipping, managed disk was used...")) - return multistep.ActionContinue - } - - for i, additionaldisk := range dataDisks { - s.say(fmt.Sprintf(" -> Additional Disk %d: '%s'", i+1, additionaldisk)) - var err error - if isManagedDisk { - err = s.deleteManaged(ctx, resourceGroupName, additionaldisk) - if err != nil { - s.say("Failed to delete the managed Additional Disk!") - return processStepResult(err, s.error, state) - } - continue - } - - u, err := url.Parse(additionaldisk) - if err != nil { - s.say("Failed to parse the Additional Disk's VHD URI!") - return processStepResult(err, s.error, state) - } - - xs := strings.Split(u.Path, "/") - if len(xs) < 3 { - err = errors.New("Failed to parse Additional Disk's VHD URI!") - } else { - var storageAccountName = xs[1] - var blobName = strings.Join(xs[2:], "/") - - err = s.delete(storageAccountName, blobName) - } - if err != nil { - return processStepResult(err, s.error, state) - } - } - return multistep.ActionContinue -} - -func (*StepDeleteAdditionalDisk) Cleanup(multistep.StateBag) { -} diff --git a/builder/azure/arm/step_delete_additional_disks_test.go b/builder/azure/arm/step_delete_additional_disks_test.go deleted file mode 100644 index 1a2729012..000000000 --- a/builder/azure/arm/step_delete_additional_disks_test.go +++ /dev/null @@ -1,227 +0,0 @@ -package arm - -import ( - "context" - "errors" - "fmt" - "testing" - - "github.com/hashicorp/packer-plugin-sdk/multistep" - "github.com/hashicorp/packer/builder/azure/common/constants" -) - -func TestStepDeleteAdditionalDiskShouldFailIfGetFails(t *testing.T) { - var testSubject = &StepDeleteAdditionalDisk{ - delete: func(string, string) error { return fmt.Errorf("!! Unit Test FAIL !!") }, - deleteManaged: func(context.Context, string, string) error { return nil }, - say: func(message string) {}, - error: func(e error) {}, - } - - stateBag := DeleteTestStateBagStepDeleteAdditionalDisk([]string{"http://storage.blob.core.windows.net/images/pkrvm_os.vhd"}) - - var result = testSubject.Run(context.Background(), stateBag) - if result != multistep.ActionHalt { - t.Fatalf("Expected the step to return 'ActionHalt', but got '%d'.", result) - } - - if _, ok := stateBag.GetOk(constants.Error); ok == false { - t.Fatalf("Expected the step to set stateBag['%s'], but it was not.", constants.Error) - } -} - -func TestStepDeleteAdditionalDiskShouldPassIfGetPasses(t *testing.T) { - var testSubject = &StepDeleteAdditionalDisk{ - delete: func(string, string) error { return nil }, - say: func(message string) {}, - error: func(e error) {}, - } - - stateBag := DeleteTestStateBagStepDeleteAdditionalDisk([]string{"http://storage.blob.core.windows.net/images/pkrvm_os.vhd"}) - - var result = testSubject.Run(context.Background(), stateBag) - if result != multistep.ActionContinue { - t.Fatalf("Expected the step to return 'ActionContinue', but got '%d'.", result) - } - - if _, ok := stateBag.GetOk(constants.Error); ok == true { - t.Fatalf("Expected the step to not set stateBag['%s'], but it was.", constants.Error) - } -} - -func TestStepDeleteAdditionalDiskShouldTakeStepArgumentsFromStateBag(t *testing.T) { - var actualStorageContainerName string - var actualBlobName string - - var testSubject = &StepDeleteAdditionalDisk{ - delete: func(storageContainerName string, blobName string) error { - actualStorageContainerName = storageContainerName - actualBlobName = blobName - return nil - }, - say: func(message string) {}, - error: func(e error) {}, - } - - stateBag := DeleteTestStateBagStepDeleteAdditionalDisk([]string{"http://storage.blob.core.windows.net/images/pkrvm_os.vhd"}) - var result = testSubject.Run(context.Background(), stateBag) - - if result != multistep.ActionContinue { - t.Fatalf("Expected the step to return 'ActionContinue', but got '%d'.", result) - } - - if actualStorageContainerName != "images" { - t.Fatalf("Expected the storage container name to be 'images', but found '%s'.", actualStorageContainerName) - } - - if actualBlobName != "pkrvm_os.vhd" { - t.Fatalf("Expected the blob name to be 'pkrvm_os.vhd', but found '%s'.", actualBlobName) - } -} - -func TestStepDeleteAdditionalDiskShouldHandleComplexStorageContainerNames(t *testing.T) { - var actualStorageContainerName string - var actualBlobName string - - var testSubject = &StepDeleteAdditionalDisk{ - delete: func(storageContainerName string, blobName string) error { - actualStorageContainerName = storageContainerName - actualBlobName = blobName - return nil - }, - say: func(message string) {}, - error: func(e error) {}, - } - - stateBag := DeleteTestStateBagStepDeleteAdditionalDisk([]string{"http://storage.blob.core.windows.net/abc/def/pkrvm_os.vhd"}) - testSubject.Run(context.Background(), stateBag) - - if actualStorageContainerName != "abc" { - t.Fatalf("Expected the storage container name to be 'abc/def', but found '%s'.", actualStorageContainerName) - } - - if actualBlobName != "def/pkrvm_os.vhd" { - t.Fatalf("Expected the blob name to be 'pkrvm_os.vhd', but found '%s'.", actualBlobName) - } -} - -func TestStepDeleteAdditionalDiskShouldFailIfVHDNameCannotBeURLParsed(t *testing.T) { - var testSubject = &StepDeleteAdditionalDisk{ - delete: func(string, string) error { return nil }, - say: func(message string) {}, - error: func(e error) {}, - deleteManaged: func(context.Context, string, string) error { return nil }, - } - - // Invalid URL per https://golang.org/src/net/url/url_test.go - stateBag := DeleteTestStateBagStepDeleteAdditionalDisk([]string{"http://[fe80::1%en0]/"}) - - var result = testSubject.Run(context.Background(), stateBag) - if result != multistep.ActionHalt { - t.Fatalf("Expected the step to return 'ActionHalt', but got '%v'.", result) - } - - if _, ok := stateBag.GetOk(constants.Error); ok == false { - t.Fatalf("Expected the step to not stateBag['%s'], but it was.", constants.Error) - } -} -func TestStepDeleteAdditionalDiskShouldFailIfVHDNameIsTooShort(t *testing.T) { - var testSubject = &StepDeleteAdditionalDisk{ - delete: func(string, string) error { return nil }, - say: func(message string) {}, - error: func(e error) {}, - deleteManaged: func(context.Context, string, string) error { return nil }, - } - - stateBag := DeleteTestStateBagStepDeleteAdditionalDisk([]string{"storage.blob.core.windows.net/abc"}) - - var result = testSubject.Run(context.Background(), stateBag) - if result != multistep.ActionHalt { - t.Fatalf("Expected the step to return 'ActionHalt', but got '%d'.", result) - } - - if _, ok := stateBag.GetOk(constants.Error); ok == false { - t.Fatalf("Expected the step to not stateBag['%s'], but it was.", constants.Error) - } -} - -func TestStepDeleteAdditionalDiskShouldPassIfManagedDiskInTempResourceGroup(t *testing.T) { - var testSubject = &StepDeleteAdditionalDisk{ - delete: func(string, string) error { return nil }, - say: func(message string) {}, - error: func(e error) {}, - } - - stateBag := new(multistep.BasicStateBag) - stateBag.Put(constants.ArmAdditionalDiskVhds, []string{"subscriptions/123-456-789/resourceGroups/existingresourcegroup/providers/Microsoft.Compute/disks/osdisk"}) - stateBag.Put(constants.ArmIsManagedImage, true) - stateBag.Put(constants.ArmIsExistingResourceGroup, false) - stateBag.Put(constants.ArmResourceGroupName, "testgroup") - - var result = testSubject.Run(context.Background(), stateBag) - if result != multistep.ActionContinue { - t.Fatalf("Expected the step to return 'ActionContinue', but got '%d'.", result) - } - - if _, ok := stateBag.GetOk(constants.Error); ok == true { - t.Fatalf("Expected the step to not set stateBag['%s'], but it was.", constants.Error) - } -} - -func TestStepDeleteAdditionalDiskShouldFailIfManagedDiskInExistingResourceGroupFailsToDelete(t *testing.T) { - var testSubject = &StepDeleteAdditionalDisk{ - delete: func(string, string) error { return nil }, - say: func(message string) {}, - error: func(e error) {}, - deleteManaged: func(context.Context, string, string) error { return errors.New("UNIT TEST FAIL!") }, - } - - stateBag := new(multistep.BasicStateBag) - stateBag.Put(constants.ArmAdditionalDiskVhds, []string{"subscriptions/123-456-789/resourceGroups/existingresourcegroup/providers/Microsoft.Compute/disks/osdisk"}) - stateBag.Put(constants.ArmIsManagedImage, true) - stateBag.Put(constants.ArmIsExistingResourceGroup, true) - stateBag.Put(constants.ArmResourceGroupName, "testgroup") - - var result = testSubject.Run(context.Background(), stateBag) - if result != multistep.ActionHalt { - t.Fatalf("Expected the step to return 'ActionHalt', but got '%d'.", result) - } - - if _, ok := stateBag.GetOk(constants.Error); ok == false { - t.Fatalf("Expected the step to not stateBag['%s'], but it was.", constants.Error) - } -} - -func TestStepDeleteAdditionalDiskShouldFailIfManagedDiskInExistingResourceGroupIsDeleted(t *testing.T) { - var testSubject = &StepDeleteAdditionalDisk{ - delete: func(string, string) error { return nil }, - say: func(message string) {}, - error: func(e error) {}, - deleteManaged: func(context.Context, string, string) error { return nil }, - } - - stateBag := new(multistep.BasicStateBag) - stateBag.Put(constants.ArmAdditionalDiskVhds, []string{"subscriptions/123-456-789/resourceGroups/existingresourcegroup/providers/Microsoft.Compute/disks/osdisk"}) - stateBag.Put(constants.ArmIsManagedImage, true) - stateBag.Put(constants.ArmIsExistingResourceGroup, true) - stateBag.Put(constants.ArmResourceGroupName, "testgroup") - - var result = testSubject.Run(context.Background(), stateBag) - if result != multistep.ActionContinue { - t.Fatalf("Expected the step to return 'ActionContinue', but got '%d'.", result) - } - - if _, ok := stateBag.GetOk(constants.Error); ok == true { - t.Fatalf("Expected the step to not set stateBag['%s'], but it was.", constants.Error) - } -} - -func DeleteTestStateBagStepDeleteAdditionalDisk(osDiskVhds []string) multistep.StateBag { - stateBag := new(multistep.BasicStateBag) - stateBag.Put(constants.ArmAdditionalDiskVhds, osDiskVhds) - stateBag.Put(constants.ArmIsManagedImage, false) - stateBag.Put(constants.ArmIsExistingResourceGroup, false) - stateBag.Put(constants.ArmResourceGroupName, "testgroup") - - return stateBag -} diff --git a/builder/azure/arm/step_deploy_template.go b/builder/azure/arm/step_deploy_template.go deleted file mode 100644 index 9c40c732f..000000000 --- a/builder/azure/arm/step_deploy_template.go +++ /dev/null @@ -1,306 +0,0 @@ -package arm - -import ( - "context" - "errors" - "fmt" - "net/url" - "strings" - "sync" - "time" - - "github.com/hashicorp/packer-plugin-sdk/multistep" - packersdk "github.com/hashicorp/packer-plugin-sdk/packer" - "github.com/hashicorp/packer-plugin-sdk/retry" - "github.com/hashicorp/packer/builder/azure/common/constants" -) - -type StepDeployTemplate struct { - client *AzureClient - deploy func(ctx context.Context, resourceGroupName string, deploymentName string) error - delete func(ctx context.Context, deploymentName, resourceGroupName string) error - disk func(ctx context.Context, resourceGroupName string, computeName string) (string, string, error) - deleteDisk func(ctx context.Context, imageType string, imageName string, resourceGroupName string) error - deleteDeployment func(ctx context.Context, state multistep.StateBag) error - say func(message string) - error func(e error) - config *Config - factory templateFactoryFunc - name string -} - -func NewStepDeployTemplate(client *AzureClient, ui packersdk.Ui, config *Config, deploymentName string, factory templateFactoryFunc) *StepDeployTemplate { - var step = &StepDeployTemplate{ - client: client, - say: func(message string) { ui.Say(message) }, - error: func(e error) { ui.Error(e.Error()) }, - config: config, - factory: factory, - name: deploymentName, - } - - step.deploy = step.deployTemplate - step.delete = step.deleteDeploymentResources - step.disk = step.getImageDetails - step.deleteDisk = step.deleteImage - step.deleteDeployment = step.deleteDeploymentObject - return step -} - -func (s *StepDeployTemplate) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction { - s.say("Deploying deployment template ...") - - var resourceGroupName = state.Get(constants.ArmResourceGroupName).(string) - s.say(fmt.Sprintf(" -> ResourceGroupName : '%s'", resourceGroupName)) - s.say(fmt.Sprintf(" -> DeploymentName : '%s'", s.name)) - - return processStepResult( - s.deploy(ctx, resourceGroupName, s.name), - s.error, state) -} - -func (s *StepDeployTemplate) Cleanup(state multistep.StateBag) { - defer func() { - err := s.deleteDeployment(context.Background(), state) - if err != nil { - s.say(err.Error()) - } - }() - - ui := state.Get("ui").(packersdk.Ui) - ui.Say("\nDeleting individual resources ...") - - deploymentName := s.name - resourceGroupName := state.Get(constants.ArmResourceGroupName).(string) - // Get image disk details before deleting the image; otherwise we won't be able to - // delete the disk as the image request will return a 404 - computeName := state.Get(constants.ArmComputeName).(string) - imageType, imageName, err := s.disk(context.TODO(), resourceGroupName, computeName) - - if err != nil && !strings.Contains(err.Error(), "ResourceNotFound") { - ui.Error(fmt.Sprintf("Could not retrieve OS Image details: %s", err)) - } - err = s.delete(context.TODO(), deploymentName, resourceGroupName) - if err != nil { - s.reportIfError(err, resourceGroupName) - } - - // The disk was not found on the VM, this is an error. - if imageType == "" && imageName == "" { - ui.Error(fmt.Sprintf("Failed to find temporary OS disk on VM. Please delete manually.\n\n"+ - "VM Name: %s\n"+ - "Error: %s", computeName, err)) - return - } - if !state.Get(constants.ArmKeepOSDisk).(bool) { - ui.Say(fmt.Sprintf(" Deleting -> %s : '%s'", imageType, imageName)) - err = s.deleteDisk(context.TODO(), imageType, imageName, resourceGroupName) - if err != nil { - ui.Error(fmt.Sprintf("Error deleting resource. Please delete manually.\n\n"+ - "Name: %s\n"+ - "Error: %s", imageName, err)) - } - } -} - -func (s *StepDeployTemplate) deployTemplate(ctx context.Context, resourceGroupName string, deploymentName string) error { - deployment, err := s.factory(s.config) - if err != nil { - return err - } - - f, err := s.client.DeploymentsClient.CreateOrUpdate(ctx, resourceGroupName, deploymentName, *deployment) - if err != nil { - s.say(s.client.LastError.Error()) - return err - } - - err = f.WaitForCompletionRef(ctx, s.client.DeploymentsClient.Client) - if err == nil { - s.say(s.client.LastError.Error()) - } - - return err -} - -func (s *StepDeployTemplate) deleteDeploymentObject(ctx context.Context, state multistep.StateBag) error { - deploymentName := s.name - resourceGroupName := state.Get(constants.ArmResourceGroupName).(string) - ui := state.Get("ui").(packersdk.Ui) - - ui.Say(fmt.Sprintf("Removing the created Deployment object: '%s'", deploymentName)) - f, err := s.client.DeploymentsClient.Delete(ctx, resourceGroupName, deploymentName) - if err != nil { - return err - } - - return f.WaitForCompletionRef(ctx, s.client.DeploymentsClient.Client) -} - -func (s *StepDeployTemplate) getImageDetails(ctx context.Context, resourceGroupName string, computeName string) (string, string, error) { - //We can't depend on constants.ArmOSDiskVhd being set - var imageName, imageType string - vm, err := s.client.VirtualMachinesClient.Get(ctx, resourceGroupName, computeName, "") - if err != nil { - return imageName, imageType, err - } - - if vm.StorageProfile.OsDisk.Vhd != nil { - imageType = "image" - imageName = *vm.StorageProfile.OsDisk.Vhd.URI - return imageType, imageName, nil - } - - imageType = "Microsoft.Compute/disks" - imageName = *vm.StorageProfile.OsDisk.ManagedDisk.ID - - return imageType, imageName, nil -} - -//TODO(paulmey): move to helpers file -func deleteResource(ctx context.Context, client *AzureClient, resourceType string, resourceName string, resourceGroupName string) error { - switch resourceType { - case "Microsoft.Compute/virtualMachines": - f, err := client.VirtualMachinesClient.Delete(ctx, resourceGroupName, resourceName) - if err == nil { - err = f.WaitForCompletionRef(ctx, client.VirtualMachinesClient.Client) - } - return err - case "Microsoft.KeyVault/vaults": - _, err := client.VaultClientDelete.Delete(ctx, resourceGroupName, resourceName) - return err - case "Microsoft.Network/networkInterfaces": - f, err := client.InterfacesClient.Delete(ctx, resourceGroupName, resourceName) - if err == nil { - err = f.WaitForCompletionRef(ctx, client.InterfacesClient.Client) - } - return err - case "Microsoft.Network/virtualNetworks": - f, err := client.VirtualNetworksClient.Delete(ctx, resourceGroupName, resourceName) - if err == nil { - err = f.WaitForCompletionRef(ctx, client.VirtualNetworksClient.Client) - } - return err - case "Microsoft.Network/networkSecurityGroups": - f, err := client.SecurityGroupsClient.Delete(ctx, resourceGroupName, resourceName) - if err == nil { - err = f.WaitForCompletionRef(ctx, client.SecurityGroupsClient.Client) - } - return err - case "Microsoft.Network/publicIPAddresses": - f, err := client.PublicIPAddressesClient.Delete(ctx, resourceGroupName, resourceName) - if err == nil { - err = f.WaitForCompletionRef(ctx, client.PublicIPAddressesClient.Client) - } - return err - } - return nil -} - -func (s *StepDeployTemplate) deleteImage(ctx context.Context, imageType string, imageName string, resourceGroupName string) error { - // Managed disk - if imageType == "Microsoft.Compute/disks" { - xs := strings.Split(imageName, "/") - diskName := xs[len(xs)-1] - f, err := s.client.DisksClient.Delete(ctx, resourceGroupName, diskName) - if err == nil { - err = f.WaitForCompletionRef(ctx, s.client.DisksClient.Client) - } - return err - } - - // VHD image - u, err := url.Parse(imageName) - if err != nil { - return err - } - xs := strings.Split(u.Path, "/") - if len(xs) < 3 { - return errors.New("Unable to parse path of image " + imageName) - } - var storageAccountName = xs[1] - var blobName = strings.Join(xs[2:], "/") - - blob := s.client.BlobStorageClient.GetContainerReference(storageAccountName).GetBlobReference(blobName) - _, err = blob.BreakLease(nil) - if err != nil && !strings.Contains(err.Error(), "LeaseNotPresentWithLeaseOperation") { - s.say(s.client.LastError.Error()) - return err - } - - return blob.Delete(nil) -} - -func (s *StepDeployTemplate) deleteDeploymentResources(ctx context.Context, deploymentName, resourceGroupName string) error { - var maxResources int32 = 50 - deploymentOperations, err := s.client.DeploymentOperationsClient.ListComplete(ctx, resourceGroupName, deploymentName, &maxResources) - if err != nil { - s.reportIfError(err, resourceGroupName) - return err - } - - resources := map[string]string{} - - for deploymentOperations.NotDone() { - deploymentOperation := deploymentOperations.Value() - // Sometimes an empty operation is added to the list by Azure - if deploymentOperation.Properties.TargetResource == nil { - _ = deploymentOperations.Next() - continue - } - - resourceName := *deploymentOperation.Properties.TargetResource.ResourceName - resourceType := *deploymentOperation.Properties.TargetResource.ResourceType - - s.say(fmt.Sprintf("Adding to deletion queue -> %s : '%s'", resourceType, resourceName)) - resources[resourceType] = resourceName - - if err = deploymentOperations.Next(); err != nil { - return err - } - } - - var wg sync.WaitGroup - wg.Add(len(resources)) - - for resourceType, resourceName := range resources { - go func(resourceType, resourceName string) { - defer wg.Done() - retryConfig := retry.Config{ - Tries: 10, - RetryDelay: (&retry.Backoff{InitialBackoff: 10 * time.Second, MaxBackoff: 600 * time.Second, Multiplier: 2}).Linear, - } - - err = retryConfig.Run(ctx, func(ctx context.Context) error { - s.say(fmt.Sprintf("Attempting deletion -> %s : '%s'", resourceType, resourceName)) - err := deleteResource(ctx, s.client, - resourceType, - resourceName, - resourceGroupName) - if err != nil { - s.say(fmt.Sprintf("Error deleting resource. Will retry.\n"+ - "Name: %s\n"+ - "Error: %s\n", resourceName, err.Error())) - } - return err - }) - if err != nil { - s.reportIfError(err, resourceName) - } - }(resourceType, resourceName) - } - - s.say("Waiting for deletion of all resources...") - wg.Wait() - - return nil -} - -func (s *StepDeployTemplate) reportIfError(err error, resourceName string) { - if err != nil { - s.say(fmt.Sprintf("Error deleting resource. Please delete manually.\n\n"+ - "Name: %s\n"+ - "Error: %s", resourceName, err.Error())) - s.error(err) - } -} diff --git a/builder/azure/arm/step_deploy_template_test.go b/builder/azure/arm/step_deploy_template_test.go deleted file mode 100644 index 088b9901a..000000000 --- a/builder/azure/arm/step_deploy_template_test.go +++ /dev/null @@ -1,209 +0,0 @@ -package arm - -import ( - "context" - "fmt" - "testing" - - "github.com/hashicorp/packer-plugin-sdk/multistep" - packersdk "github.com/hashicorp/packer-plugin-sdk/packer" - "github.com/hashicorp/packer/builder/azure/common/constants" -) - -func TestStepDeployTemplateShouldFailIfDeployFails(t *testing.T) { - var testSubject = &StepDeployTemplate{ - deploy: func(context.Context, string, string) error { - return fmt.Errorf("!! Unit Test FAIL !!") - }, - say: func(message string) {}, - error: func(e error) {}, - } - - stateBag := createTestStateBagStepDeployTemplate() - - var result = testSubject.Run(context.Background(), stateBag) - if result != multistep.ActionHalt { - t.Fatalf("Expected the step to return 'ActionHalt', but got '%d'.", result) - } - - if _, ok := stateBag.GetOk(constants.Error); ok == false { - t.Fatalf("Expected the step to set stateBag['%s'], but it was not.", constants.Error) - } -} - -func TestStepDeployTemplateShouldPassIfDeployPasses(t *testing.T) { - var testSubject = &StepDeployTemplate{ - deploy: func(context.Context, string, string) error { return nil }, - say: func(message string) {}, - error: func(e error) {}, - } - - stateBag := createTestStateBagStepDeployTemplate() - - var result = testSubject.Run(context.Background(), stateBag) - if result != multistep.ActionContinue { - t.Fatalf("Expected the step to return 'ActionContinue', but got '%d'.", result) - } - - if _, ok := stateBag.GetOk(constants.Error); ok == true { - t.Fatalf("Expected the step to not set stateBag['%s'], but it was.", constants.Error) - } -} - -func TestStepDeployTemplateShouldTakeStepArgumentsFromStateBag(t *testing.T) { - var actualResourceGroupName string - var actualDeploymentName string - - var testSubject = &StepDeployTemplate{ - deploy: func(ctx context.Context, resourceGroupName string, deploymentName string) error { - actualResourceGroupName = resourceGroupName - actualDeploymentName = deploymentName - - return nil - }, - say: func(message string) {}, - error: func(e error) {}, - name: "--deployment-name--", - } - - stateBag := createTestStateBagStepValidateTemplate() - var result = testSubject.Run(context.Background(), stateBag) - - if result != multistep.ActionContinue { - t.Fatalf("Expected the step to return 'ActionContinue', but got '%d'.", result) - } - - var expectedResourceGroupName = stateBag.Get(constants.ArmResourceGroupName).(string) - - if actualDeploymentName != "--deployment-name--" { - t.Fatal("Expected StepValidateTemplate to source 'constants.ArmDeploymentName' from the state bag, but it did not.") - } - - if actualResourceGroupName != expectedResourceGroupName { - t.Fatal("Expected the step to source 'constants.ArmResourceGroupName' from the state bag, but it did not.") - } -} - -func TestStepDeployTemplateDeleteImageShouldFailWhenImageUrlCannotBeParsed(t *testing.T) { - var testSubject = &StepDeployTemplate{ - say: func(message string) {}, - error: func(e error) {}, - name: "--deployment-name--", - } - // Invalid URL per https://golang.org/src/net/url/url_test.go - err := testSubject.deleteImage(context.TODO(), "image", "http://[fe80::1%en0]/", "Unit Test: ResourceGroupName") - if err == nil { - t.Fatal("Expected a failure because of the failed image name") - } -} - -func TestStepDeployTemplateDeleteImageShouldFailWithInvalidImage(t *testing.T) { - var testSubject = &StepDeployTemplate{ - say: func(message string) {}, - error: func(e error) {}, - name: "--deployment-name--", - } - err := testSubject.deleteImage(context.TODO(), "image", "storage.blob.core.windows.net/abc", "Unit Test: ResourceGroupName") - if err == nil { - t.Fatal("Expected a failure because of the failed image name") - } -} - -func TestStepDeployTemplateCleanupShouldDeleteManagedOSImageInExistingResourceGroup(t *testing.T) { - var deleteDiskCounter = 0 - var testSubject = createTestStepDeployTemplateDeleteOSImage(&deleteDiskCounter) - - stateBag := createTestStateBagStepDeployTemplate() - stateBag.Put(constants.ArmIsManagedImage, true) - stateBag.Put(constants.ArmIsExistingResourceGroup, true) - stateBag.Put(constants.ArmIsResourceGroupCreated, true) - stateBag.Put(constants.ArmKeepOSDisk, false) - stateBag.Put("ui", packersdk.TestUi(t)) - - testSubject.Cleanup(stateBag) - if deleteDiskCounter != 1 { - t.Fatalf("Expected DeployTemplate Cleanup to invoke deleteDisk 1 time, but invoked %d times", deleteDiskCounter) - } -} - -func TestStepDeployTemplateCleanupShouldDeleteManagedOSImageInTemporaryResourceGroup(t *testing.T) { - var deleteDiskCounter = 0 - var testSubject = createTestStepDeployTemplateDeleteOSImage(&deleteDiskCounter) - - stateBag := createTestStateBagStepDeployTemplate() - stateBag.Put(constants.ArmIsManagedImage, true) - stateBag.Put(constants.ArmIsExistingResourceGroup, false) - stateBag.Put(constants.ArmIsResourceGroupCreated, true) - stateBag.Put(constants.ArmKeepOSDisk, false) - stateBag.Put("ui", packersdk.TestUi(t)) - - testSubject.Cleanup(stateBag) - if deleteDiskCounter != 1 { - t.Fatalf("Expected DeployTemplate Cleanup to invoke deleteDisk 1 times, but invoked %d times", deleteDiskCounter) - } -} - -func TestStepDeployTemplateCleanupShouldDeleteVHDOSImageInExistingResourceGroup(t *testing.T) { - var deleteDiskCounter = 0 - var testSubject = createTestStepDeployTemplateDeleteOSImage(&deleteDiskCounter) - - stateBag := createTestStateBagStepDeployTemplate() - stateBag.Put(constants.ArmIsManagedImage, false) - stateBag.Put(constants.ArmIsExistingResourceGroup, true) - stateBag.Put(constants.ArmIsResourceGroupCreated, true) - stateBag.Put(constants.ArmKeepOSDisk, false) - stateBag.Put("ui", packersdk.TestUi(t)) - - testSubject.Cleanup(stateBag) - if deleteDiskCounter != 1 { - t.Fatalf("Expected DeployTemplate Cleanup to invoke deleteDisk 1 time, but invoked %d times", deleteDiskCounter) - } -} - -func TestStepDeployTemplateCleanupShouldVHDOSImageInTemporaryResourceGroup(t *testing.T) { - var deleteDiskCounter = 0 - var testSubject = createTestStepDeployTemplateDeleteOSImage(&deleteDiskCounter) - - stateBag := createTestStateBagStepDeployTemplate() - stateBag.Put(constants.ArmIsManagedImage, false) - stateBag.Put(constants.ArmIsExistingResourceGroup, false) - stateBag.Put(constants.ArmIsResourceGroupCreated, true) - stateBag.Put(constants.ArmKeepOSDisk, false) - stateBag.Put("ui", packersdk.TestUi(t)) - - testSubject.Cleanup(stateBag) - if deleteDiskCounter != 1 { - t.Fatalf("Expected DeployTemplate Cleanup to invoke deleteDisk 1 times, but invoked %d times", deleteDiskCounter) - } -} - -func createTestStateBagStepDeployTemplate() multistep.StateBag { - stateBag := new(multistep.BasicStateBag) - - stateBag.Put(constants.ArmDeploymentName, "Unit Test: DeploymentName") - stateBag.Put(constants.ArmResourceGroupName, "Unit Test: ResourceGroupName") - stateBag.Put(constants.ArmComputeName, "Unit Test: ComputeName") - - return stateBag -} - -func createTestStepDeployTemplateDeleteOSImage(deleteDiskCounter *int) *StepDeployTemplate { - return &StepDeployTemplate{ - deploy: func(context.Context, string, string) error { return nil }, - say: func(message string) {}, - error: func(e error) {}, - deleteDisk: func(ctx context.Context, imageType string, imageName string, resourceGroupName string) error { - *deleteDiskCounter++ - return nil - }, - disk: func(ctx context.Context, resourceGroupName, computeName string) (string, string, error) { - return "Microsoft.Compute/disks", "", nil - }, - delete: func(ctx context.Context, deploymentName, resourceGroupName string) error { - return nil - }, - deleteDeployment: func(ctx context.Context, state multistep.StateBag) error { - return nil - }, - } -} diff --git a/builder/azure/arm/step_get_additional_disks.go b/builder/azure/arm/step_get_additional_disks.go deleted file mode 100644 index bccc6faa0..000000000 --- a/builder/azure/arm/step_get_additional_disks.go +++ /dev/null @@ -1,78 +0,0 @@ -package arm - -import ( - "context" - "fmt" - - "github.com/Azure/azure-sdk-for-go/services/compute/mgmt/2018-04-01/compute" - - "github.com/hashicorp/packer/builder/azure/common/constants" - - "github.com/hashicorp/packer-plugin-sdk/multistep" - packersdk "github.com/hashicorp/packer-plugin-sdk/packer" -) - -type StepGetDataDisk struct { - client *AzureClient - query func(ctx context.Context, resourceGroupName string, computeName string) (compute.VirtualMachine, error) - say func(message string) - error func(e error) -} - -func NewStepGetAdditionalDisks(client *AzureClient, ui packersdk.Ui) *StepGetDataDisk { - var step = &StepGetDataDisk{ - client: client, - say: func(message string) { ui.Say(message) }, - error: func(e error) { ui.Error(e.Error()) }, - } - - step.query = step.queryCompute - return step -} - -func (s *StepGetDataDisk) queryCompute(ctx context.Context, resourceGroupName string, computeName string) (compute.VirtualMachine, error) { - vm, err := s.client.VirtualMachinesClient.Get(ctx, resourceGroupName, computeName, "") - if err != nil { - s.say(s.client.LastError.Error()) - } - return vm, err -} - -func (s *StepGetDataDisk) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction { - s.say("Querying the machine's additional disks properties ...") - - var resourceGroupName = state.Get(constants.ArmResourceGroupName).(string) - var computeName = state.Get(constants.ArmComputeName).(string) - - s.say(fmt.Sprintf(" -> ResourceGroupName : '%s'", resourceGroupName)) - s.say(fmt.Sprintf(" -> ComputeName : '%s'", computeName)) - - vm, err := s.query(ctx, resourceGroupName, computeName) - if err != nil { - state.Put(constants.Error, err) - s.error(err) - - return multistep.ActionHalt - } - - if vm.StorageProfile.DataDisks != nil { - var vhdUri string - additional_disks := make([]string, len(*vm.StorageProfile.DataDisks)) - for i, additionaldisk := range *vm.StorageProfile.DataDisks { - if additionaldisk.Vhd != nil { - vhdUri = *additionaldisk.Vhd.URI - s.say(fmt.Sprintf(" -> Additional Disk %d : '%s'", i+1, vhdUri)) - } else { - vhdUri = *additionaldisk.ManagedDisk.ID - s.say(fmt.Sprintf(" -> Managed Additional Disk %d : '%s'", i+1, vhdUri)) - } - additional_disks[i] = vhdUri - } - state.Put(constants.ArmAdditionalDiskVhds, additional_disks) - } - - return multistep.ActionContinue -} - -func (*StepGetDataDisk) Cleanup(multistep.StateBag) { -} diff --git a/builder/azure/arm/step_get_additional_disks_test.go b/builder/azure/arm/step_get_additional_disks_test.go deleted file mode 100644 index 511379fd9..000000000 --- a/builder/azure/arm/step_get_additional_disks_test.go +++ /dev/null @@ -1,131 +0,0 @@ -package arm - -import ( - "context" - "fmt" - "testing" - - "github.com/Azure/azure-sdk-for-go/services/compute/mgmt/2018-04-01/compute" - - "github.com/hashicorp/packer/builder/azure/common/constants" - - "github.com/hashicorp/packer-plugin-sdk/multistep" -) - -func TestStepGetAdditionalDiskShouldFailIfGetFails(t *testing.T) { - var testSubject = &StepGetDataDisk{ - query: func(context.Context, string, string) (compute.VirtualMachine, error) { - return createVirtualMachineWithDataDisksFromUri("test.vhd"), fmt.Errorf("!! Unit Test FAIL !!") - }, - say: func(message string) {}, - error: func(e error) {}, - } - - stateBag := createTestStateBagStepGetAdditionalDisks() - - var result = testSubject.Run(context.Background(), stateBag) - if result != multistep.ActionHalt { - t.Fatalf("Expected the step to return 'ActionHalt', but got '%d'.", result) - } - - if _, ok := stateBag.GetOk(constants.Error); ok == false { - t.Fatalf("Expected the step to set stateBag['%s'], but it was not.", constants.Error) - } -} - -func TestStepGetAdditionalDiskShouldPassIfGetPasses(t *testing.T) { - var testSubject = &StepGetDataDisk{ - query: func(context.Context, string, string) (compute.VirtualMachine, error) { - return createVirtualMachineWithDataDisksFromUri("test.vhd"), nil - }, - say: func(message string) {}, - error: func(e error) {}, - } - - stateBag := createTestStateBagStepGetAdditionalDisks() - - var result = testSubject.Run(context.Background(), stateBag) - if result != multistep.ActionContinue { - t.Fatalf("Expected the step to return 'ActionContinue', but got '%d'.", result) - } - - if _, ok := stateBag.GetOk(constants.Error); ok == true { - t.Fatalf("Expected the step to not set stateBag['%s'], but it was.", constants.Error) - } -} - -func TestStepGetAdditionalDiskShouldTakeValidateArgumentsFromStateBag(t *testing.T) { - var actualResourceGroupName string - var actualComputeName string - - var testSubject = &StepGetDataDisk{ - query: func(ctx context.Context, resourceGroupName string, computeName string) (compute.VirtualMachine, error) { - actualResourceGroupName = resourceGroupName - actualComputeName = computeName - - return createVirtualMachineWithDataDisksFromUri("test.vhd"), nil - }, - say: func(message string) {}, - error: func(e error) {}, - } - - stateBag := createTestStateBagStepGetAdditionalDisks() - var result = testSubject.Run(context.Background(), stateBag) - - if result != multistep.ActionContinue { - t.Fatalf("Expected the step to return 'ActionContinue', but got '%d'.", result) - } - - var expectedComputeName = stateBag.Get(constants.ArmComputeName).(string) - var expectedResourceGroupName = stateBag.Get(constants.ArmResourceGroupName).(string) - - if actualComputeName != expectedComputeName { - t.Fatal("Expected the step to source 'constants.ArmResourceGroupName' from the state bag, but it did not.") - } - - if actualResourceGroupName != expectedResourceGroupName { - t.Fatal("Expected the step to source 'constants.ArmResourceGroupName' from the state bag, but it did not.") - } - - expectedAdditionalDiskVhds, ok := stateBag.GetOk(constants.ArmAdditionalDiskVhds) - if !ok { - t.Fatalf("Expected the state bag to have a value for '%s', but it did not.", constants.ArmAdditionalDiskVhds) - } - - expectedAdditionalDiskVhd := expectedAdditionalDiskVhds.([]string) - if expectedAdditionalDiskVhd[0] != "test.vhd" { - t.Fatalf("Expected the value of stateBag[%s] to be 'test.vhd', but got '%s'.", constants.ArmAdditionalDiskVhds, expectedAdditionalDiskVhd[0]) - } -} - -func createTestStateBagStepGetAdditionalDisks() multistep.StateBag { - stateBag := new(multistep.BasicStateBag) - - stateBag.Put(constants.ArmComputeName, "Unit Test: ComputeName") - stateBag.Put(constants.ArmResourceGroupName, "Unit Test: ResourceGroupName") - - return stateBag -} - -func createVirtualMachineWithDataDisksFromUri(vhdUri string) compute.VirtualMachine { - vm := compute.VirtualMachine{ - VirtualMachineProperties: &compute.VirtualMachineProperties{ - StorageProfile: &compute.StorageProfile{ - OsDisk: &compute.OSDisk{ - Vhd: &compute.VirtualHardDisk{ - URI: &vhdUri, - }, - }, - DataDisks: &[]compute.DataDisk{ - { - Vhd: &compute.VirtualHardDisk{ - URI: &vhdUri, - }, - }, - }, - }, - }, - } - - return vm -} diff --git a/builder/azure/arm/step_get_certificate.go b/builder/azure/arm/step_get_certificate.go deleted file mode 100644 index 9102f965a..000000000 --- a/builder/azure/arm/step_get_certificate.go +++ /dev/null @@ -1,77 +0,0 @@ -package arm - -import ( - "context" - "fmt" - "time" - - "github.com/hashicorp/packer-plugin-sdk/multistep" - packersdk "github.com/hashicorp/packer-plugin-sdk/packer" - "github.com/hashicorp/packer/builder/azure/common/constants" -) - -type StepGetCertificate struct { - client *AzureClient - get func(keyVaultName string, secretName string) (string, error) - say func(message string) - error func(e error) - pause func() -} - -func NewStepGetCertificate(client *AzureClient, ui packersdk.Ui) *StepGetCertificate { - var step = &StepGetCertificate{ - client: client, - say: func(message string) { ui.Say(message) }, - error: func(e error) { ui.Error(e.Error()) }, - pause: func() { time.Sleep(30 * time.Second) }, - } - - step.get = step.getCertificateUrl - return step -} - -func (s *StepGetCertificate) getCertificateUrl(keyVaultName string, secretName string) (string, error) { - secret, err := s.client.GetSecret(keyVaultName, secretName) - if err != nil { - s.say(s.client.LastError.Error()) - return "", err - } - - return *secret.ID, err -} - -func (s *StepGetCertificate) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction { - s.say("Getting the certificate's URL ...") - - var keyVaultName = state.Get(constants.ArmKeyVaultName).(string) - - s.say(fmt.Sprintf(" -> Key Vault Name : '%s'", keyVaultName)) - s.say(fmt.Sprintf(" -> Key Vault Secret Name : '%s'", DefaultSecretName)) - - var err error - var url string - for i := 0; i < 5; i++ { - url, err = s.get(keyVaultName, DefaultSecretName) - if err == nil { - break - } - - s.say(fmt.Sprintf(" ...failed to get certificate URL, retry(%d)", i)) - s.pause() - } - - if err != nil { - state.Put(constants.Error, err) - s.error(err) - - return multistep.ActionHalt - } - - s.say(fmt.Sprintf(" -> Certificate URL : '%s'", url)) - state.Put(constants.ArmCertificateUrl, url) - - return multistep.ActionContinue -} - -func (*StepGetCertificate) Cleanup(multistep.StateBag) { -} diff --git a/builder/azure/arm/step_get_certificate_test.go b/builder/azure/arm/step_get_certificate_test.go deleted file mode 100644 index 640fda60a..000000000 --- a/builder/azure/arm/step_get_certificate_test.go +++ /dev/null @@ -1,99 +0,0 @@ -package arm - -import ( - "context" - "fmt" - "testing" - - "github.com/hashicorp/packer-plugin-sdk/multistep" - "github.com/hashicorp/packer/builder/azure/common/constants" -) - -func TestStepGetCertificateShouldFailIfGetFails(t *testing.T) { - var testSubject = &StepGetCertificate{ - get: func(string, string) (string, error) { return "", fmt.Errorf("!! Unit Test FAIL !!") }, - say: func(message string) {}, - error: func(e error) {}, - pause: func() {}, - } - - stateBag := createTestStateBagStepGetCertificate() - - var result = testSubject.Run(context.Background(), stateBag) - if result != multistep.ActionHalt { - t.Fatalf("Expected the step to return 'ActionHalt', but got '%d'.", result) - } - - if _, ok := stateBag.GetOk(constants.Error); ok == false { - t.Fatalf("Expected the step to set stateBag['%s'], but it was not.", constants.Error) - } -} - -func TestStepGetCertificateShouldPassIfGetPasses(t *testing.T) { - var testSubject = &StepGetCertificate{ - get: func(string, string) (string, error) { return "", nil }, - say: func(message string) {}, - error: func(e error) {}, - pause: func() {}, - } - - stateBag := createTestStateBagStepGetCertificate() - - var result = testSubject.Run(context.Background(), stateBag) - if result != multistep.ActionContinue { - t.Fatalf("Expected the step to return 'ActionContinue', but got '%d'.", result) - } - - if _, ok := stateBag.GetOk(constants.Error); ok == true { - t.Fatalf("Expected the step to not set stateBag['%s'], but it was.", constants.Error) - } -} - -func TestStepGetCertificateShouldTakeStepArgumentsFromStateBag(t *testing.T) { - var actualKeyVaultName string - var actualSecretName string - - var testSubject = &StepGetCertificate{ - get: func(keyVaultName string, secretName string) (string, error) { - actualKeyVaultName = keyVaultName - actualSecretName = secretName - - return "http://key.vault/1", nil - }, - say: func(message string) {}, - error: func(e error) {}, - pause: func() {}, - } - - stateBag := createTestStateBagStepGetCertificate() - var result = testSubject.Run(context.Background(), stateBag) - - if result != multistep.ActionContinue { - t.Fatalf("Expected the step to return 'ActionContinue', but got '%d'.", result) - } - - var expectedKeyVaultName = stateBag.Get(constants.ArmKeyVaultName).(string) - - if actualKeyVaultName != expectedKeyVaultName { - t.Fatal("Expected StepGetCertificate to source 'constants.ArmKeyVaultName' from the state bag, but it did not.") - } - if actualSecretName != DefaultSecretName { - t.Fatal("Expected StepGetCertificate to use default value for secret, but it did not.") - } - - expectedCertificateUrl, ok := stateBag.GetOk(constants.ArmCertificateUrl) - if !ok { - t.Fatalf("Expected the state bag to have a value for '%s', but it did not.", constants.ArmCertificateUrl) - } - - if expectedCertificateUrl != "http://key.vault/1" { - t.Fatalf("Expected the value of stateBag[%s] to be 'http://key.vault/1', but got '%s'.", constants.ArmCertificateUrl, expectedCertificateUrl) - } -} - -func createTestStateBagStepGetCertificate() multistep.StateBag { - stateBag := new(multistep.BasicStateBag) - stateBag.Put(constants.ArmKeyVaultName, "Unit Test: KeyVaultName") - - return stateBag -} diff --git a/builder/azure/arm/step_get_ip_address.go b/builder/azure/arm/step_get_ip_address.go deleted file mode 100644 index 6a5ace4c1..000000000 --- a/builder/azure/arm/step_get_ip_address.go +++ /dev/null @@ -1,107 +0,0 @@ -package arm - -import ( - "context" - "fmt" - - "github.com/hashicorp/packer-plugin-sdk/multistep" - packersdk "github.com/hashicorp/packer-plugin-sdk/packer" - "github.com/hashicorp/packer/builder/azure/common/constants" -) - -type EndpointType int - -const ( - PublicEndpoint EndpointType = iota - PrivateEndpoint - PublicEndpointInPrivateNetwork -) - -var ( - EndpointCommunicationText = map[EndpointType]string{ - PublicEndpoint: "PublicEndpoint", - PrivateEndpoint: "PrivateEndpoint", - PublicEndpointInPrivateNetwork: "PublicEndpointInPrivateNetwork", - } -) - -type StepGetIPAddress struct { - client *AzureClient - endpoint EndpointType - get func(ctx context.Context, resourceGroupName string, ipAddressName string, interfaceName string) (string, error) - say func(message string) - error func(e error) -} - -func NewStepGetIPAddress(client *AzureClient, ui packersdk.Ui, endpoint EndpointType) *StepGetIPAddress { - var step = &StepGetIPAddress{ - client: client, - endpoint: endpoint, - say: func(message string) { ui.Say(message) }, - error: func(e error) { ui.Error(e.Error()) }, - } - - switch endpoint { - case PrivateEndpoint: - step.get = step.getPrivateIP - case PublicEndpoint: - step.get = step.getPublicIP - case PublicEndpointInPrivateNetwork: - step.get = step.getPublicIPInPrivateNetwork - } - - return step -} - -func (s *StepGetIPAddress) getPrivateIP(ctx context.Context, resourceGroupName string, ipAddressName string, interfaceName string) (string, error) { - resp, err := s.client.InterfacesClient.Get(ctx, resourceGroupName, interfaceName, "") - if err != nil { - s.say(s.client.LastError.Error()) - return "", err - } - - return *(*resp.IPConfigurations)[0].PrivateIPAddress, nil -} - -func (s *StepGetIPAddress) getPublicIP(ctx context.Context, resourceGroupName string, ipAddressName string, interfaceName string) (string, error) { - resp, err := s.client.PublicIPAddressesClient.Get(ctx, resourceGroupName, ipAddressName, "") - if err != nil { - return "", err - } - - return *resp.IPAddress, nil -} - -func (s *StepGetIPAddress) getPublicIPInPrivateNetwork(ctx context.Context, resourceGroupName string, ipAddressName string, interfaceName string) (string, error) { - s.getPrivateIP(ctx, resourceGroupName, ipAddressName, interfaceName) - return s.getPublicIP(ctx, resourceGroupName, ipAddressName, interfaceName) -} - -func (s *StepGetIPAddress) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction { - s.say("Getting the VM's IP address ...") - - var resourceGroupName = state.Get(constants.ArmResourceGroupName).(string) - var ipAddressName = state.Get(constants.ArmPublicIPAddressName).(string) - var nicName = state.Get(constants.ArmNicName).(string) - - s.say(fmt.Sprintf(" -> ResourceGroupName : '%s'", resourceGroupName)) - s.say(fmt.Sprintf(" -> PublicIPAddressName : '%s'", ipAddressName)) - s.say(fmt.Sprintf(" -> NicName : '%s'", nicName)) - s.say(fmt.Sprintf(" -> Network Connection : '%s'", EndpointCommunicationText[s.endpoint])) - - address, err := s.get(ctx, resourceGroupName, ipAddressName, nicName) - if err != nil { - state.Put(constants.Error, err) - s.error(err) - - return multistep.ActionHalt - } - - state.Put(constants.SSHHost, address) - s.say(fmt.Sprintf(" -> IP Address : '%s'", address)) - - return multistep.ActionContinue -} - -func (*StepGetIPAddress) Cleanup(multistep.StateBag) { -} diff --git a/builder/azure/arm/step_get_ip_address_test.go b/builder/azure/arm/step_get_ip_address_test.go deleted file mode 100644 index bb5beb5bf..000000000 --- a/builder/azure/arm/step_get_ip_address_test.go +++ /dev/null @@ -1,124 +0,0 @@ -package arm - -import ( - "context" - "fmt" - "testing" - - "github.com/hashicorp/packer-plugin-sdk/multistep" - "github.com/hashicorp/packer/builder/azure/common/constants" -) - -func TestStepGetIPAddressShouldFailIfGetFails(t *testing.T) { - endpoints := []EndpointType{PublicEndpoint, PublicEndpointInPrivateNetwork} - - for _, endpoint := range endpoints { - var testSubject = &StepGetIPAddress{ - get: func(context.Context, string, string, string) (string, error) { - return "", fmt.Errorf("!! Unit Test FAIL !!") - }, - endpoint: endpoint, - say: func(message string) {}, - error: func(e error) {}, - } - - stateBag := createTestStateBagStepGetIPAddress() - - var result = testSubject.Run(context.Background(), stateBag) - if result != multistep.ActionHalt { - t.Fatalf("Expected the step to return 'ActionHalt', but got '%d'.", result) - } - - if _, ok := stateBag.GetOk(constants.Error); ok == false { - t.Fatalf("Expected the step to set stateBag['%s'], but it was not.", constants.Error) - } - } -} - -func TestStepGetIPAddressShouldPassIfGetPasses(t *testing.T) { - endpoints := []EndpointType{PublicEndpoint, PublicEndpointInPrivateNetwork} - - for _, endpoint := range endpoints { - var testSubject = &StepGetIPAddress{ - get: func(context.Context, string, string, string) (string, error) { return "", nil }, - endpoint: endpoint, - say: func(message string) {}, - error: func(e error) {}, - } - - stateBag := createTestStateBagStepGetIPAddress() - - var result = testSubject.Run(context.Background(), stateBag) - if result != multistep.ActionContinue { - t.Fatalf("Expected the step to return 'ActionContinue', but got '%d'.", result) - } - - if _, ok := stateBag.GetOk(constants.Error); ok == true { - t.Fatalf("Expected the step to not set stateBag['%s'], but it was.", constants.Error) - } - } -} - -func TestStepGetIPAddressShouldTakeStepArgumentsFromStateBag(t *testing.T) { - var actualResourceGroupName string - var actualIPAddressName string - var actualNicName string - endpoints := []EndpointType{PublicEndpoint, PublicEndpointInPrivateNetwork} - - for _, endpoint := range endpoints { - var testSubject = &StepGetIPAddress{ - get: func(ctx context.Context, resourceGroupName string, ipAddressName string, nicName string) (string, error) { - actualResourceGroupName = resourceGroupName - actualIPAddressName = ipAddressName - actualNicName = nicName - - return "127.0.0.1", nil - }, - endpoint: endpoint, - say: func(message string) {}, - error: func(e error) {}, - } - - stateBag := createTestStateBagStepGetIPAddress() - var result = testSubject.Run(context.Background(), stateBag) - - if result != multistep.ActionContinue { - t.Fatalf("Expected the step to return 'ActionContinue', but got '%d'.", result) - } - - var expectedResourceGroupName = stateBag.Get(constants.ArmResourceGroupName).(string) - var expectedIPAddressName = stateBag.Get(constants.ArmPublicIPAddressName).(string) - var expectedNicName = stateBag.Get(constants.ArmNicName).(string) - - if actualIPAddressName != expectedIPAddressName { - t.Fatal("Expected StepGetIPAddress to source 'constants.ArmIPAddressName' from the state bag, but it did not.") - } - - if actualResourceGroupName != expectedResourceGroupName { - t.Fatal("Expected StepGetIPAddress to source 'constants.ArmResourceGroupName' from the state bag, but it did not.") - } - - if actualNicName != expectedNicName { - t.Fatalf("Expected StepGetIPAddress to source 'constants.ArmNetworkInterfaceName' from the state bag, but it did not.") - } - - expectedIPAddress, ok := stateBag.GetOk(constants.SSHHost) - if !ok { - t.Fatalf("Expected the state bag to have a value for '%s', but it did not.", constants.SSHHost) - } - - if expectedIPAddress != "127.0.0.1" { - t.Fatalf("Expected the value of stateBag[%s] to be '127.0.0.1', but got '%s'.", constants.SSHHost, expectedIPAddress) - } - } -} - -func createTestStateBagStepGetIPAddress() multistep.StateBag { - stateBag := new(multistep.BasicStateBag) - - stateBag.Put(constants.ArmPublicIPAddressName, "Unit Test: PublicIPAddressName") - stateBag.Put(constants.ArmNicName, "Unit Test: NicName") - stateBag.Put(constants.ArmResourceGroupName, "Unit Test: ResourceGroupName") - - return stateBag -} diff --git a/builder/azure/arm/step_get_os_disk.go b/builder/azure/arm/step_get_os_disk.go deleted file mode 100644 index 719f7e3a3..000000000 --- a/builder/azure/arm/step_get_os_disk.go +++ /dev/null @@ -1,72 +0,0 @@ -package arm - -import ( - "context" - "fmt" - - "github.com/Azure/azure-sdk-for-go/services/compute/mgmt/2018-04-01/compute" - - "github.com/hashicorp/packer/builder/azure/common/constants" - - "github.com/hashicorp/packer-plugin-sdk/multistep" - packersdk "github.com/hashicorp/packer-plugin-sdk/packer" -) - -type StepGetOSDisk struct { - client *AzureClient - query func(ctx context.Context, resourceGroupName string, computeName string) (compute.VirtualMachine, error) - say func(message string) - error func(e error) -} - -func NewStepGetOSDisk(client *AzureClient, ui packersdk.Ui) *StepGetOSDisk { - var step = &StepGetOSDisk{ - client: client, - say: func(message string) { ui.Say(message) }, - error: func(e error) { ui.Error(e.Error()) }, - } - - step.query = step.queryCompute - return step -} - -func (s *StepGetOSDisk) queryCompute(ctx context.Context, resourceGroupName string, computeName string) (compute.VirtualMachine, error) { - vm, err := s.client.VirtualMachinesClient.Get(ctx, resourceGroupName, computeName, "") - if err != nil { - s.say(s.client.LastError.Error()) - } - return vm, err -} - -func (s *StepGetOSDisk) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction { - s.say("Querying the machine's properties ...") - - var resourceGroupName = state.Get(constants.ArmResourceGroupName).(string) - var computeName = state.Get(constants.ArmComputeName).(string) - - s.say(fmt.Sprintf(" -> ResourceGroupName : '%s'", resourceGroupName)) - s.say(fmt.Sprintf(" -> ComputeName : '%s'", computeName)) - - vm, err := s.query(ctx, resourceGroupName, computeName) - if err != nil { - state.Put(constants.Error, err) - s.error(err) - - return multistep.ActionHalt - } - - var vhdUri string - if vm.StorageProfile.OsDisk.Vhd != nil { - vhdUri = *vm.StorageProfile.OsDisk.Vhd.URI - s.say(fmt.Sprintf(" -> OS Disk : '%s'", vhdUri)) - } else { - vhdUri = *vm.StorageProfile.OsDisk.ManagedDisk.ID - s.say(fmt.Sprintf(" -> Managed OS Disk : '%s'", vhdUri)) - } - - state.Put(constants.ArmOSDiskVhd, vhdUri) - return multistep.ActionContinue -} - -func (*StepGetOSDisk) Cleanup(multistep.StateBag) { -} diff --git a/builder/azure/arm/step_get_os_disk_test.go b/builder/azure/arm/step_get_os_disk_test.go deleted file mode 100644 index 3c229dced..000000000 --- a/builder/azure/arm/step_get_os_disk_test.go +++ /dev/null @@ -1,123 +0,0 @@ -package arm - -import ( - "context" - "fmt" - "testing" - - "github.com/Azure/azure-sdk-for-go/services/compute/mgmt/2018-04-01/compute" - - "github.com/hashicorp/packer/builder/azure/common/constants" - - "github.com/hashicorp/packer-plugin-sdk/multistep" -) - -func TestStepGetOSDiskShouldFailIfGetFails(t *testing.T) { - var testSubject = &StepGetOSDisk{ - query: func(context.Context, string, string) (compute.VirtualMachine, error) { - return createVirtualMachineFromUri("test.vhd"), fmt.Errorf("!! Unit Test FAIL !!") - }, - say: func(message string) {}, - error: func(e error) {}, - } - - stateBag := createTestStateBagStepGetOSDisk() - - var result = testSubject.Run(context.Background(), stateBag) - if result != multistep.ActionHalt { - t.Fatalf("Expected the step to return 'ActionHalt', but got '%d'.", result) - } - - if _, ok := stateBag.GetOk(constants.Error); ok == false { - t.Fatalf("Expected the step to set stateBag['%s'], but it was not.", constants.Error) - } -} - -func TestStepGetOSDiskShouldPassIfGetPasses(t *testing.T) { - var testSubject = &StepGetOSDisk{ - query: func(context.Context, string, string) (compute.VirtualMachine, error) { - return createVirtualMachineFromUri("test.vhd"), nil - }, - say: func(message string) {}, - error: func(e error) {}, - } - - stateBag := createTestStateBagStepGetOSDisk() - - var result = testSubject.Run(context.Background(), stateBag) - if result != multistep.ActionContinue { - t.Fatalf("Expected the step to return 'ActionContinue', but got '%d'.", result) - } - - if _, ok := stateBag.GetOk(constants.Error); ok == true { - t.Fatalf("Expected the step to not set stateBag['%s'], but it was.", constants.Error) - } -} - -func TestStepGetOSDiskShouldTakeValidateArgumentsFromStateBag(t *testing.T) { - var actualResourceGroupName string - var actualComputeName string - - var testSubject = &StepGetOSDisk{ - query: func(ctx context.Context, resourceGroupName string, computeName string) (compute.VirtualMachine, error) { - actualResourceGroupName = resourceGroupName - actualComputeName = computeName - - return createVirtualMachineFromUri("test.vhd"), nil - }, - say: func(message string) {}, - error: func(e error) {}, - } - - stateBag := createTestStateBagStepGetOSDisk() - var result = testSubject.Run(context.Background(), stateBag) - - if result != multistep.ActionContinue { - t.Fatalf("Expected the step to return 'ActionContinue', but got '%d'.", result) - } - - var expectedComputeName = stateBag.Get(constants.ArmComputeName).(string) - var expectedResourceGroupName = stateBag.Get(constants.ArmResourceGroupName).(string) - - if actualComputeName != expectedComputeName { - t.Fatal("Expected the step to source 'constants.ArmResourceGroupName' from the state bag, but it did not.") - } - - if actualResourceGroupName != expectedResourceGroupName { - t.Fatal("Expected the step to source 'constants.ArmResourceGroupName' from the state bag, but it did not.") - } - - expectedOSDiskVhd, ok := stateBag.GetOk(constants.ArmOSDiskVhd) - if !ok { - t.Fatalf("Expected the state bag to have a value for '%s', but it did not.", constants.ArmOSDiskVhd) - } - - if expectedOSDiskVhd != "test.vhd" { - t.Fatalf("Expected the value of stateBag[%s] to be 'test.vhd', but got '%s'.", constants.ArmOSDiskVhd, expectedOSDiskVhd) - } -} - -func createTestStateBagStepGetOSDisk() multistep.StateBag { - stateBag := new(multistep.BasicStateBag) - - stateBag.Put(constants.ArmComputeName, "Unit Test: ComputeName") - stateBag.Put(constants.ArmResourceGroupName, "Unit Test: ResourceGroupName") - - return stateBag -} - -func createVirtualMachineFromUri(vhdUri string) compute.VirtualMachine { - vm := compute.VirtualMachine{ - VirtualMachineProperties: &compute.VirtualMachineProperties{ - StorageProfile: &compute.StorageProfile{ - OsDisk: &compute.OSDisk{ - Vhd: &compute.VirtualHardDisk{ - URI: &vhdUri, - }, - }, - }, - }, - } - - return vm -} diff --git a/builder/azure/arm/step_power_off_compute.go b/builder/azure/arm/step_power_off_compute.go deleted file mode 100644 index 2cd126aeb..000000000 --- a/builder/azure/arm/step_power_off_compute.go +++ /dev/null @@ -1,56 +0,0 @@ -package arm - -import ( - "context" - "fmt" - - "github.com/hashicorp/packer-plugin-sdk/multistep" - packersdk "github.com/hashicorp/packer-plugin-sdk/packer" - "github.com/hashicorp/packer/builder/azure/common/constants" -) - -type StepPowerOffCompute struct { - client *AzureClient - powerOff func(ctx context.Context, resourceGroupName string, computeName string) error - say func(message string) - error func(e error) -} - -func NewStepPowerOffCompute(client *AzureClient, ui packersdk.Ui) *StepPowerOffCompute { - var step = &StepPowerOffCompute{ - client: client, - say: func(message string) { ui.Say(message) }, - error: func(e error) { ui.Error(e.Error()) }, - } - - step.powerOff = step.powerOffCompute - return step -} - -func (s *StepPowerOffCompute) powerOffCompute(ctx context.Context, resourceGroupName string, computeName string) error { - f, err := s.client.VirtualMachinesClient.Deallocate(ctx, resourceGroupName, computeName) - if err == nil { - err = f.WaitForCompletionRef(ctx, s.client.VirtualMachinesClient.Client) - } - if err != nil { - s.say(s.client.LastError.Error()) - } - return err -} - -func (s *StepPowerOffCompute) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction { - s.say("Powering off machine ...") - - var resourceGroupName = state.Get(constants.ArmResourceGroupName).(string) - var computeName = state.Get(constants.ArmComputeName).(string) - - s.say(fmt.Sprintf(" -> ResourceGroupName : '%s'", resourceGroupName)) - s.say(fmt.Sprintf(" -> ComputeName : '%s'", computeName)) - - err := s.powerOff(ctx, resourceGroupName, computeName) - - return processStepResult(err, s.error, state) -} - -func (*StepPowerOffCompute) Cleanup(multistep.StateBag) { -} diff --git a/builder/azure/arm/step_power_off_compute_test.go b/builder/azure/arm/step_power_off_compute_test.go deleted file mode 100644 index 69235a289..000000000 --- a/builder/azure/arm/step_power_off_compute_test.go +++ /dev/null @@ -1,91 +0,0 @@ -package arm - -import ( - "context" - "fmt" - "testing" - - "github.com/hashicorp/packer-plugin-sdk/multistep" - "github.com/hashicorp/packer/builder/azure/common/constants" -) - -func TestStepPowerOffComputeShouldFailIfPowerOffFails(t *testing.T) { - var testSubject = &StepPowerOffCompute{ - powerOff: func(context.Context, string, string) error { return fmt.Errorf("!! Unit Test FAIL !!") }, - say: func(message string) {}, - error: func(e error) {}, - } - - stateBag := createTestStateBagStepPowerOffCompute() - - var result = testSubject.Run(context.Background(), stateBag) - if result != multistep.ActionHalt { - t.Fatalf("Expected the step to return 'ActionHalt', but got '%d'.", result) - } - - if _, ok := stateBag.GetOk(constants.Error); ok == false { - t.Fatalf("Expected the step to set stateBag['%s'], but it was not.", constants.Error) - } -} - -func TestStepPowerOffComputeShouldPassIfPowerOffPasses(t *testing.T) { - var testSubject = &StepPowerOffCompute{ - powerOff: func(context.Context, string, string) error { return nil }, - say: func(message string) {}, - error: func(e error) {}, - } - - stateBag := createTestStateBagStepPowerOffCompute() - - var result = testSubject.Run(context.Background(), stateBag) - if result != multistep.ActionContinue { - t.Fatalf("Expected the step to return 'ActionContinue', but got '%d'.", result) - } - - if _, ok := stateBag.GetOk(constants.Error); ok == true { - t.Fatalf("Expected the step to not set stateBag['%s'], but it was.", constants.Error) - } -} - -func TestStepPowerOffComputeShouldTakeStepArgumentsFromStateBag(t *testing.T) { - var actualResourceGroupName string - var actualComputeName string - - var testSubject = &StepPowerOffCompute{ - powerOff: func(ctx context.Context, resourceGroupName string, computeName string) error { - actualResourceGroupName = resourceGroupName - actualComputeName = computeName - - return nil - }, - say: func(message string) {}, - error: func(e error) {}, - } - - stateBag := createTestStateBagStepPowerOffCompute() - var result = testSubject.Run(context.Background(), stateBag) - - if result != multistep.ActionContinue { - t.Fatalf("Expected the step to return 'ActionContinue', but got '%d'.", result) - } - - var expectedComputeName = stateBag.Get(constants.ArmComputeName).(string) - var expectedResourceGroupName = stateBag.Get(constants.ArmResourceGroupName).(string) - - if actualComputeName != expectedComputeName { - t.Fatal("Expected the step to source 'constants.ArmResourceGroupName' from the state bag, but it did not.") - } - - if actualResourceGroupName != expectedResourceGroupName { - t.Fatal("Expected the step to source 'constants.ArmResourceGroupName' from the state bag, but it did not.") - } -} - -func createTestStateBagStepPowerOffCompute() multistep.StateBag { - stateBag := new(multistep.BasicStateBag) - - stateBag.Put(constants.ArmComputeName, "Unit Test: ComputeName") - stateBag.Put(constants.ArmResourceGroupName, "Unit Test: ResourceGroupName") - - return stateBag -} diff --git a/builder/azure/arm/step_publish_to_shared_image_gallery.go b/builder/azure/arm/step_publish_to_shared_image_gallery.go deleted file mode 100644 index 629858e4c..000000000 --- a/builder/azure/arm/step_publish_to_shared_image_gallery.go +++ /dev/null @@ -1,192 +0,0 @@ -package arm - -import ( - "context" - "fmt" - - "github.com/Azure/azure-sdk-for-go/services/compute/mgmt/2019-03-01/compute" - "github.com/Azure/go-autorest/autorest/date" - "github.com/hashicorp/packer-plugin-sdk/multistep" - packersdk "github.com/hashicorp/packer-plugin-sdk/packer" - "github.com/hashicorp/packer/builder/azure/common/constants" -) - -type StepPublishToSharedImageGallery struct { - client *AzureClient - publish func(ctx context.Context, mdiID string, sharedImageGallery SharedImageGalleryDestination, miSGImageVersionEndOfLifeDate string, miSGImageVersionExcludeFromLatest bool, miSigReplicaCount int32, location string, tags map[string]*string) (string, error) - say func(message string) - error func(e error) - toSIG func() bool -} - -func NewStepPublishToSharedImageGallery(client *AzureClient, ui packersdk.Ui, config *Config) *StepPublishToSharedImageGallery { - var step = &StepPublishToSharedImageGallery{ - client: client, - say: func(message string) { - ui.Say(message) - }, - error: func(e error) { - ui.Error(e.Error()) - }, - toSIG: func() bool { - return config.isManagedImage() && config.SharedGalleryDestination.SigDestinationGalleryName != "" - }, - } - - step.publish = step.publishToSig - return step -} - -func getSigDestinationStorageAccountType(s string) (compute.StorageAccountType, error) { - switch s { - case "", string(compute.StorageAccountTypeStandardLRS): - return compute.StorageAccountTypeStandardLRS, nil - case string(compute.StorageAccountTypeStandardZRS): - return compute.StorageAccountTypeStandardZRS, nil - default: - return "", fmt.Errorf("not an accepted value for shared_image_gallery_destination.storage_account_type") - } -} - -func getSigDestination(state multistep.StateBag) SharedImageGalleryDestination { - subscription := state.Get(constants.ArmManagedImageSubscription).(string) - resourceGroup := state.Get(constants.ArmManagedImageSigPublishResourceGroup).(string) - galleryName := state.Get(constants.ArmManagedImageSharedGalleryName).(string) - imageName := state.Get(constants.ArmManagedImageSharedGalleryImageName).(string) - imageVersion := state.Get(constants.ArmManagedImageSharedGalleryImageVersion).(string) - replicationRegions := state.Get(constants.ArmManagedImageSharedGalleryReplicationRegions).([]string) - storageAccountType := state.Get(constants.ArmManagedImageSharedGalleryImageVersionStorageAccountType).(string) - - return SharedImageGalleryDestination{ - SigDestinationSubscription: subscription, - SigDestinationResourceGroup: resourceGroup, - SigDestinationGalleryName: galleryName, - SigDestinationImageName: imageName, - SigDestinationImageVersion: imageVersion, - SigDestinationReplicationRegions: replicationRegions, - SigDestinationStorageAccountType: storageAccountType, - } -} - -func (s *StepPublishToSharedImageGallery) publishToSig(ctx context.Context, mdiID string, sharedImageGallery SharedImageGalleryDestination, miSGImageVersionEndOfLifeDate string, miSGImageVersionExcludeFromLatest bool, miSigReplicaCount int32, location string, tags map[string]*string) (string, error) { - replicationRegions := make([]compute.TargetRegion, len(sharedImageGallery.SigDestinationReplicationRegions)) - for i, v := range sharedImageGallery.SigDestinationReplicationRegions { - regionName := v - replicationRegions[i] = compute.TargetRegion{Name: ®ionName} - } - - var endOfLifeDate *date.Time - if miSGImageVersionEndOfLifeDate != "" { - parseDate, err := date.ParseTime("2006-01-02T15:04:05.99Z", miSGImageVersionEndOfLifeDate) - if err != nil { - s.say(fmt.Sprintf("Error parsing date from shared_gallery_image_version_end_of_life_date: %s", err)) - return "", err - } - endOfLifeDate = &date.Time{Time: parseDate} - } else { - endOfLifeDate = (*date.Time)(nil) - } - - storageAccountType, err := getSigDestinationStorageAccountType(string(sharedImageGallery.SigDestinationStorageAccountType)) - if err != nil { - s.error(err) - return "", err - } - - galleryImageVersion := compute.GalleryImageVersion{ - Location: &location, - Tags: tags, - GalleryImageVersionProperties: &compute.GalleryImageVersionProperties{ - PublishingProfile: &compute.GalleryImageVersionPublishingProfile{ - Source: &compute.GalleryArtifactSource{ - ManagedImage: &compute.ManagedArtifact{ - ID: &mdiID, - }, - }, - TargetRegions: &replicationRegions, - EndOfLifeDate: endOfLifeDate, - ExcludeFromLatest: &miSGImageVersionExcludeFromLatest, - ReplicaCount: &miSigReplicaCount, - StorageAccountType: storageAccountType, - }, - }, - } - - f, err := s.client.GalleryImageVersionsClient.CreateOrUpdate(ctx, sharedImageGallery.SigDestinationResourceGroup, sharedImageGallery.SigDestinationGalleryName, sharedImageGallery.SigDestinationImageName, sharedImageGallery.SigDestinationImageVersion, galleryImageVersion) - - if err != nil { - s.say(s.client.LastError.Error()) - return "", err - } - - err = f.WaitForCompletionRef(ctx, s.client.GalleryImageVersionsClient.Client) - - if err != nil { - s.say(s.client.LastError.Error()) - return "", err - } - - createdSGImageVersion, err := f.Result(s.client.GalleryImageVersionsClient) - - if err != nil { - s.say(s.client.LastError.Error()) - return "", err - } - - s.say(fmt.Sprintf(" -> Shared Gallery Image Version ID : '%s'", *(createdSGImageVersion.ID))) - return *(createdSGImageVersion.ID), nil -} - -func (s *StepPublishToSharedImageGallery) Run(ctx context.Context, stateBag multistep.StateBag) multistep.StepAction { - if !s.toSIG() { - return multistep.ActionContinue - } - - s.say("Publishing to Shared Image Gallery ...") - - location := stateBag.Get(constants.ArmLocation).(string) - tags := stateBag.Get(constants.ArmTags).(map[string]*string) - - sharedImageGallery := getSigDestination(stateBag) - targetManagedImageResourceGroupName := stateBag.Get(constants.ArmManagedImageResourceGroupName).(string) - targetManagedImageName := stateBag.Get(constants.ArmManagedImageName).(string) - - managedImageSubscription := stateBag.Get(constants.ArmManagedImageSubscription).(string) - mdiID := fmt.Sprintf("/subscriptions/%s/resourceGroups/%s/providers/Microsoft.Compute/images/%s", managedImageSubscription, targetManagedImageResourceGroupName, targetManagedImageName) - - miSGImageVersionEndOfLifeDate, _ := stateBag.Get(constants.ArmManagedImageSharedGalleryImageVersionEndOfLifeDate).(string) - miSGImageVersionExcludeFromLatest, _ := stateBag.Get(constants.ArmManagedImageSharedGalleryImageVersionExcludeFromLatest).(bool) - miSigReplicaCount, _ := stateBag.Get(constants.ArmManagedImageSharedGalleryImageVersionReplicaCount).(int32) - // Replica count must be between 1 and 10 inclusive. - if miSigReplicaCount <= 0 { - miSigReplicaCount = constants.SharedImageGalleryImageVersionDefaultMinReplicaCount - } else if miSigReplicaCount > 10 { - miSigReplicaCount = constants.SharedImageGalleryImageVersionDefaultMaxReplicaCount - } - - s.say(fmt.Sprintf(" -> MDI ID used for SIG publish : '%s'", mdiID)) - s.say(fmt.Sprintf(" -> SIG publish resource group : '%s'", sharedImageGallery.SigDestinationResourceGroup)) - s.say(fmt.Sprintf(" -> SIG gallery name : '%s'", sharedImageGallery.SigDestinationGalleryName)) - s.say(fmt.Sprintf(" -> SIG image name : '%s'", sharedImageGallery.SigDestinationImageName)) - s.say(fmt.Sprintf(" -> SIG image version : '%s'", sharedImageGallery.SigDestinationImageVersion)) - s.say(fmt.Sprintf(" -> SIG replication regions : '%v'", sharedImageGallery.SigDestinationReplicationRegions)) - s.say(fmt.Sprintf(" -> SIG storage account type : '%s'", sharedImageGallery.SigDestinationStorageAccountType)) - s.say(fmt.Sprintf(" -> SIG image version endoflife date : '%s'", miSGImageVersionEndOfLifeDate)) - s.say(fmt.Sprintf(" -> SIG image version exclude from latest : '%t'", miSGImageVersionExcludeFromLatest)) - s.say(fmt.Sprintf(" -> SIG replica count [1, 10] : '%d'", miSigReplicaCount)) - - createdGalleryImageVersionID, err := s.publish(ctx, mdiID, sharedImageGallery, miSGImageVersionEndOfLifeDate, miSGImageVersionExcludeFromLatest, miSigReplicaCount, location, tags) - - if err != nil { - stateBag.Put(constants.Error, err) - s.error(err) - - return multistep.ActionHalt - } - - stateBag.Put(constants.ArmManagedImageSharedGalleryId, createdGalleryImageVersionID) - return multistep.ActionContinue -} - -func (*StepPublishToSharedImageGallery) Cleanup(multistep.StateBag) { -} diff --git a/builder/azure/arm/step_publish_to_shared_image_gallery_test.go b/builder/azure/arm/step_publish_to_shared_image_gallery_test.go deleted file mode 100644 index 87d636931..000000000 --- a/builder/azure/arm/step_publish_to_shared_image_gallery_test.go +++ /dev/null @@ -1,86 +0,0 @@ -package arm - -import ( - "context" - "testing" - - "github.com/hashicorp/packer-plugin-sdk/multistep" - "github.com/hashicorp/packer/builder/azure/common/constants" -) - -func TestStepPublishToSharedImageGalleryShouldNotPublishForVhd(t *testing.T) { - var testSubject = &StepPublishToSharedImageGallery{ - publish: func(context.Context, string, SharedImageGalleryDestination, string, bool, int32, string, map[string]*string) (string, error) { - return "test", nil - }, - say: func(message string) {}, - error: func(e error) {}, - toSIG: func() bool { return false }, - } - - stateBag := createTestStateBagStepPublishToSharedImageGalleryForVhd() - var result = testSubject.Run(context.Background(), stateBag) - if result != multistep.ActionContinue { - t.Fatalf("Expected the step to return 'ActionContinue', but got '%d'.", result) - } - - if _, ok := stateBag.GetOk(constants.Error); ok == true { - t.Fatalf("Expected the step to not set stateBag['%s'], but it was.", constants.Error) - } -} - -func TestStepPublishToSharedImageGalleryShouldPublishForManagedImageWithSig(t *testing.T) { - var testSubject = &StepPublishToSharedImageGallery{ - publish: func(context.Context, string, SharedImageGalleryDestination, string, bool, int32, string, map[string]*string) (string, error) { - return "", nil - }, - say: func(message string) {}, - error: func(e error) {}, - toSIG: func() bool { return true }, - } - - stateBag := createTestStateBagStepPublishToSharedImageGallery() - var result = testSubject.Run(context.Background(), stateBag) - if result != multistep.ActionContinue { - t.Fatalf("Expected the step to return 'ActionContinue', but got '%d'.", result) - } - - if _, ok := stateBag.GetOk(constants.Error); ok == true { - t.Fatalf("Expected the step to not set stateBag['%s'], but it was.", constants.Error) - } -} - -func createTestStateBagStepPublishToSharedImageGallery() multistep.StateBag { - stateBag := new(multistep.BasicStateBag) - - stateBag.Put(constants.ArmManagedImageSigPublishResourceGroup, "Unit Test: ManagedImageSigPublishResourceGroup") - stateBag.Put(constants.ArmManagedImageSharedGalleryName, "Unit Test: ManagedImageSharedGalleryName") - stateBag.Put(constants.ArmManagedImageSharedGalleryImageName, "Unit Test: ManagedImageSharedGalleryImageName") - stateBag.Put(constants.ArmManagedImageSharedGalleryImageVersion, "Unit Test: ManagedImageSharedGalleryImageVersion") - stateBag.Put(constants.ArmLocation, "Unit Test: Location") - value := "Unit Test: Tags" - tags := map[string]*string{ - "tag01": &value, - } - stateBag.Put(constants.ArmTags, tags) - stateBag.Put(constants.ArmManagedImageSharedGalleryReplicationRegions, []string{"ManagedImageSharedGalleryReplicationRegionA", "ManagedImageSharedGalleryReplicationRegionB"}) - stateBag.Put(constants.ArmManagedImageSharedGalleryImageVersionStorageAccountType, "Standard_LRS") - stateBag.Put(constants.ArmManagedImageResourceGroupName, "Unit Test: ManagedImageResourceGroupName") - stateBag.Put(constants.ArmManagedImageName, "Unit Test: ManagedImageName") - stateBag.Put(constants.ArmManagedImageSubscription, "Unit Test: ManagedImageSubscription") - - return stateBag -} - -func createTestStateBagStepPublishToSharedImageGalleryForVhd() multistep.StateBag { - stateBag := new(multistep.BasicStateBag) - - stateBag.Put(constants.ArmLocation, "Unit Test: Location") - value := "Unit Test: Tags" - tags := map[string]*string{ - "tag01": &value, - } - stateBag.Put(constants.ArmTags, tags) - - return stateBag -} diff --git a/builder/azure/arm/step_set_certificate.go b/builder/azure/arm/step_set_certificate.go deleted file mode 100644 index de8845275..000000000 --- a/builder/azure/arm/step_set_certificate.go +++ /dev/null @@ -1,37 +0,0 @@ -package arm - -import ( - "context" - - "github.com/hashicorp/packer-plugin-sdk/multistep" - packersdk "github.com/hashicorp/packer-plugin-sdk/packer" - "github.com/hashicorp/packer/builder/azure/common/constants" -) - -type StepSetCertificate struct { - config *Config - say func(message string) - error func(e error) -} - -func NewStepSetCertificate(config *Config, ui packersdk.Ui) *StepSetCertificate { - var step = &StepSetCertificate{ - config: config, - say: func(message string) { ui.Say(message) }, - error: func(e error) { ui.Error(e.Error()) }, - } - - return step -} - -func (s *StepSetCertificate) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction { - s.say("Setting the certificate's URL ...") - - var winRMCertificateUrl = state.Get(constants.ArmCertificateUrl).(string) - s.config.tmpWinRMCertificateUrl = winRMCertificateUrl - - return multistep.ActionContinue -} - -func (*StepSetCertificate) Cleanup(multistep.StateBag) { -} diff --git a/builder/azure/arm/step_set_certificate_test.go b/builder/azure/arm/step_set_certificate_test.go deleted file mode 100644 index 59c0a0fc1..000000000 --- a/builder/azure/arm/step_set_certificate_test.go +++ /dev/null @@ -1,54 +0,0 @@ -package arm - -import ( - "context" - "testing" - - "github.com/hashicorp/packer-plugin-sdk/multistep" - "github.com/hashicorp/packer/builder/azure/common/constants" -) - -func TestStepSetCertificateShouldPassIfGetPasses(t *testing.T) { - var testSubject = &StepSetCertificate{ - config: new(Config), - say: func(message string) {}, - error: func(e error) {}, - } - - stateBag := createTestStateBagStepSetCertificate() - - var result = testSubject.Run(context.Background(), stateBag) - if result != multistep.ActionContinue { - t.Fatalf("Expected the step to return 'ActionContinue', but got '%d'.", result) - } - - if _, ok := stateBag.GetOk(constants.Error); ok == true { - t.Fatalf("Expected the step to not set stateBag['%s'], but it was.", constants.Error) - } -} - -func TestStepSetCertificateShouldTakeStepArgumentsFromStateBag(t *testing.T) { - config := new(Config) - var testSubject = &StepSetCertificate{ - config: config, - say: func(message string) {}, - error: func(e error) {}, - } - - stateBag := createTestStateBagStepSetCertificate() - var result = testSubject.Run(context.Background(), stateBag) - - if result != multistep.ActionContinue { - t.Fatalf("Expected the step to return 'ActionContinue', but got '%d'.", result) - } - - if config.tmpWinRMCertificateUrl != stateBag.Get(constants.ArmCertificateUrl) { - t.Fatalf("Expected config.tmpWinRMCertificateUrl to be %s, but got %s'", stateBag.Get(constants.ArmCertificateUrl), config.tmpWinRMCertificateUrl) - } -} - -func createTestStateBagStepSetCertificate() multistep.StateBag { - stateBag := new(multistep.BasicStateBag) - stateBag.Put(constants.ArmCertificateUrl, "Unit Test: Certificate URL") - return stateBag -} diff --git a/builder/azure/arm/step_snapshot_data_disks.go b/builder/azure/arm/step_snapshot_data_disks.go deleted file mode 100644 index a18e20e24..000000000 --- a/builder/azure/arm/step_snapshot_data_disks.go +++ /dev/null @@ -1,108 +0,0 @@ -package arm - -import ( - "context" - "fmt" - "strconv" - - "github.com/Azure/azure-sdk-for-go/services/compute/mgmt/2018-04-01/compute" - "github.com/Azure/go-autorest/autorest/to" - "github.com/hashicorp/packer-plugin-sdk/multistep" - packersdk "github.com/hashicorp/packer-plugin-sdk/packer" - "github.com/hashicorp/packer/builder/azure/common/constants" -) - -type StepSnapshotDataDisks struct { - client *AzureClient - create func(ctx context.Context, resourceGroupName string, srcUriVhd string, location string, tags map[string]*string, dstSnapshotName string) error - say func(message string) - error func(e error) - enable func() bool -} - -func NewStepSnapshotDataDisks(client *AzureClient, ui packersdk.Ui, config *Config) *StepSnapshotDataDisks { - var step = &StepSnapshotDataDisks{ - client: client, - say: func(message string) { ui.Say(message) }, - error: func(e error) { ui.Error(e.Error()) }, - enable: func() bool { return config.isManagedImage() && config.ManagedImageDataDiskSnapshotPrefix != "" }, - } - - step.create = step.createDataDiskSnapshot - return step -} - -func (s *StepSnapshotDataDisks) createDataDiskSnapshot(ctx context.Context, resourceGroupName string, srcUriVhd string, location string, tags map[string]*string, dstSnapshotName string) error { - - srcVhdToSnapshot := compute.Snapshot{ - DiskProperties: &compute.DiskProperties{ - CreationData: &compute.CreationData{ - CreateOption: compute.Copy, - SourceResourceID: to.StringPtr(srcUriVhd), - }, - }, - Location: to.StringPtr(location), - Tags: tags, - } - - f, err := s.client.SnapshotsClient.CreateOrUpdate(ctx, resourceGroupName, dstSnapshotName, srcVhdToSnapshot) - - if err != nil { - s.say(s.client.LastError.Error()) - return err - } - - err = f.WaitForCompletionRef(ctx, s.client.SnapshotsClient.Client) - - if err != nil { - s.say(s.client.LastError.Error()) - return err - } - - createdSnapshot, err := f.Result(s.client.SnapshotsClient) - - if err != nil { - s.say(s.client.LastError.Error()) - return err - } - - s.say(fmt.Sprintf(" -> Snapshot ID : '%s'", *(createdSnapshot.ID))) - return nil -} - -func (s *StepSnapshotDataDisks) Run(ctx context.Context, stateBag multistep.StateBag) multistep.StepAction { - if !s.enable() { - return multistep.ActionContinue - } - - var resourceGroupName = stateBag.Get(constants.ArmManagedImageResourceGroupName).(string) - var location = stateBag.Get(constants.ArmLocation).(string) - var tags = stateBag.Get(constants.ArmTags).(map[string]*string) - var additionalDisks = stateBag.Get(constants.ArmAdditionalDiskVhds).([]string) - var dstSnapshotPrefix = stateBag.Get(constants.ArmManagedImageDataDiskSnapshotPrefix).(string) - - if len(additionalDisks) == 1 { - s.say(fmt.Sprintf("Snapshotting data disk ...")) - } else { - s.say(fmt.Sprintf("Snapshotting data disks ...")) - } - - for i, disk := range additionalDisks { - s.say(fmt.Sprintf(" -> Data Disk : '%s'", disk)) - - dstSnapshotName := dstSnapshotPrefix + strconv.Itoa(i) - err := s.create(ctx, resourceGroupName, disk, location, tags, dstSnapshotName) - - if err != nil { - stateBag.Put(constants.Error, err) - s.error(err) - - return multistep.ActionHalt - } - } - - return multistep.ActionContinue -} - -func (*StepSnapshotDataDisks) Cleanup(multistep.StateBag) { -} diff --git a/builder/azure/arm/step_snapshot_data_disks_test.go b/builder/azure/arm/step_snapshot_data_disks_test.go deleted file mode 100644 index 344b24fb7..000000000 --- a/builder/azure/arm/step_snapshot_data_disks_test.go +++ /dev/null @@ -1,88 +0,0 @@ -package arm - -import ( - "context" - "fmt" - "testing" - - "github.com/hashicorp/packer-plugin-sdk/multistep" - "github.com/hashicorp/packer/builder/azure/common/constants" -) - -func TestStepSnapshotDataDisksShouldFailIfSnapshotFails(t *testing.T) { - var testSubject = &StepSnapshotDataDisks{ - create: func(context.Context, string, string, string, map[string]*string, string) error { - return fmt.Errorf("!! Unit Test FAIL !!") - }, - say: func(message string) {}, - error: func(e error) {}, - enable: func() bool { return true }, - } - - stateBag := createTestStateBagStepSnapshotDataDisks() - - var result = testSubject.Run(context.Background(), stateBag) - if result != multistep.ActionHalt { - t.Fatalf("Expected the step to return 'ActionHalt', but got '%d'.", result) - } - - if _, ok := stateBag.GetOk(constants.Error); ok == false { - t.Fatalf("Expected the step to set stateBag['%s'], but it was not.", constants.Error) - } -} - -func TestStepSnapshotDataDisksShouldNotExecute(t *testing.T) { - var testSubject = &StepSnapshotDataDisks{ - create: func(context.Context, string, string, string, map[string]*string, string) error { - return fmt.Errorf("!! Unit Test FAIL !!") - }, - say: func(message string) {}, - error: func(e error) {}, - enable: func() bool { return false }, - } - - var result = testSubject.Run(context.Background(), nil) - if result != multistep.ActionContinue { - t.Fatalf("Expected the step to return 'ActionContinue', but got '%d'.", result) - } -} - -func TestStepSnapshotDataDisksShouldPassIfSnapshotPasses(t *testing.T) { - var testSubject = &StepSnapshotDataDisks{ - create: func(context.Context, string, string, string, map[string]*string, string) error { - return nil - }, - say: func(message string) {}, - error: func(e error) {}, - enable: func() bool { return true }, - } - - stateBag := createTestStateBagStepSnapshotDataDisks() - - var result = testSubject.Run(context.Background(), stateBag) - if result != multistep.ActionContinue { - t.Fatalf("Expected the step to return 'ActionContinue', but got '%d'.", result) - } - - if _, ok := stateBag.GetOk(constants.Error); ok == true { - t.Fatalf("Expected the step to not set stateBag['%s'], but it was.", constants.Error) - } -} - -func createTestStateBagStepSnapshotDataDisks() multistep.StateBag { - stateBag := new(multistep.BasicStateBag) - - stateBag.Put(constants.ArmManagedImageResourceGroupName, "Unit Test: ResourceGroupName") - stateBag.Put(constants.ArmLocation, "Unit Test: Location") - - value := "Unit Test: Tags" - tags := map[string]*string{ - "tag01": &value, - } - stateBag.Put(constants.ArmTags, tags) - - stateBag.Put(constants.ArmAdditionalDiskVhds, []string{"subscriptions/123-456-789/resourceGroups/existingresourcegroup/providers/Microsoft.Compute/disks/osdisk"}) - stateBag.Put(constants.ArmManagedImageDataDiskSnapshotPrefix, "Unit Test: ManagedImageDataDiskSnapshotPrefix") - - return stateBag -} diff --git a/builder/azure/arm/step_snapshot_os_disk.go b/builder/azure/arm/step_snapshot_os_disk.go deleted file mode 100644 index 03c4090ed..000000000 --- a/builder/azure/arm/step_snapshot_os_disk.go +++ /dev/null @@ -1,99 +0,0 @@ -package arm - -import ( - "context" - "fmt" - - "github.com/Azure/azure-sdk-for-go/services/compute/mgmt/2018-04-01/compute" - "github.com/Azure/go-autorest/autorest/to" - "github.com/hashicorp/packer-plugin-sdk/multistep" - packersdk "github.com/hashicorp/packer-plugin-sdk/packer" - "github.com/hashicorp/packer/builder/azure/common/constants" -) - -type StepSnapshotOSDisk struct { - client *AzureClient - create func(ctx context.Context, resourceGroupName string, srcUriVhd string, location string, tags map[string]*string, dstSnapshotName string) error - say func(message string) - error func(e error) - enable func() bool -} - -func NewStepSnapshotOSDisk(client *AzureClient, ui packersdk.Ui, config *Config) *StepSnapshotOSDisk { - var step = &StepSnapshotOSDisk{ - client: client, - say: func(message string) { ui.Say(message) }, - error: func(e error) { ui.Error(e.Error()) }, - enable: func() bool { return config.isManagedImage() && config.ManagedImageOSDiskSnapshotName != "" }, - } - - step.create = step.createSnapshot - return step -} - -func (s *StepSnapshotOSDisk) createSnapshot(ctx context.Context, resourceGroupName string, srcUriVhd string, location string, tags map[string]*string, dstSnapshotName string) error { - - srcVhdToSnapshot := compute.Snapshot{ - DiskProperties: &compute.DiskProperties{ - CreationData: &compute.CreationData{ - CreateOption: compute.Copy, - SourceResourceID: to.StringPtr(srcUriVhd), - }, - }, - Location: to.StringPtr(location), - Tags: tags, - } - - f, err := s.client.SnapshotsClient.CreateOrUpdate(ctx, resourceGroupName, dstSnapshotName, srcVhdToSnapshot) - - if err != nil { - s.say(s.client.LastError.Error()) - return err - } - - err = f.WaitForCompletionRef(ctx, s.client.SnapshotsClient.Client) - - if err != nil { - s.say(s.client.LastError.Error()) - return err - } - - createdSnapshot, err := f.Result(s.client.SnapshotsClient) - - if err != nil { - s.say(s.client.LastError.Error()) - return err - } - - s.say(fmt.Sprintf(" -> Snapshot ID : '%s'", *(createdSnapshot.ID))) - return nil -} - -func (s *StepSnapshotOSDisk) Run(ctx context.Context, stateBag multistep.StateBag) multistep.StepAction { - if !s.enable() { - return multistep.ActionContinue - } - - s.say("Snapshotting OS disk ...") - - var resourceGroupName = stateBag.Get(constants.ArmManagedImageResourceGroupName).(string) - var location = stateBag.Get(constants.ArmLocation).(string) - var tags = stateBag.Get(constants.ArmTags).(map[string]*string) - var srcUriVhd = stateBag.Get(constants.ArmOSDiskVhd).(string) - var dstSnapshotName = stateBag.Get(constants.ArmManagedImageOSDiskSnapshotName).(string) - - s.say(fmt.Sprintf(" -> OS Disk : '%s'", srcUriVhd)) - err := s.create(ctx, resourceGroupName, srcUriVhd, location, tags, dstSnapshotName) - - if err != nil { - stateBag.Put(constants.Error, err) - s.error(err) - - return multistep.ActionHalt - } - - return multistep.ActionContinue -} - -func (*StepSnapshotOSDisk) Cleanup(multistep.StateBag) { -} diff --git a/builder/azure/arm/step_snapshot_os_disk_test.go b/builder/azure/arm/step_snapshot_os_disk_test.go deleted file mode 100644 index 9cbcd89e0..000000000 --- a/builder/azure/arm/step_snapshot_os_disk_test.go +++ /dev/null @@ -1,89 +0,0 @@ -package arm - -import ( - "context" - "fmt" - "testing" - - "github.com/hashicorp/packer-plugin-sdk/multistep" - "github.com/hashicorp/packer/builder/azure/common/constants" -) - -func TestStepSnapshotOSDiskShouldFailIfSnapshotFails(t *testing.T) { - var testSubject = &StepSnapshotOSDisk{ - create: func(context.Context, string, string, string, map[string]*string, string) error { - return fmt.Errorf("!! Unit Test FAIL !!") - }, - say: func(message string) {}, - error: func(e error) {}, - enable: func() bool { return true }, - } - - stateBag := createTestStateBagStepSnapshotOSDisk() - - var result = testSubject.Run(context.Background(), stateBag) - if result != multistep.ActionHalt { - t.Fatalf("Expected the step to return 'ActionHalt', but got '%d'.", result) - } - - if _, ok := stateBag.GetOk(constants.Error); ok == false { - t.Fatalf("Expected the step to set stateBag['%s'], but it was not.", constants.Error) - } -} - -func TestStepSnapshotOSDiskShouldNotExecute(t *testing.T) { - var testSubject = &StepSnapshotOSDisk{ - create: func(context.Context, string, string, string, map[string]*string, string) error { - return fmt.Errorf("!! Unit Test FAIL !!") - }, - say: func(message string) {}, - error: func(e error) {}, - enable: func() bool { return false }, - } - - var result = testSubject.Run(context.Background(), nil) - if result != multistep.ActionContinue { - t.Fatalf("Expected the step to return 'ActionContinue', but got '%d'.", result) - } -} - -func TestStepSnapshotOSDiskShouldPassIfSnapshotPasses(t *testing.T) { - var testSubject = &StepSnapshotOSDisk{ - create: func(context.Context, string, string, string, map[string]*string, string) error { - return nil - }, - say: func(message string) {}, - error: func(e error) {}, - enable: func() bool { return true }, - } - - stateBag := createTestStateBagStepSnapshotOSDisk() - - var result = testSubject.Run(context.Background(), stateBag) - if result != multistep.ActionContinue { - t.Fatalf("Expected the step to return 'ActionContinue', but got '%d'.", result) - } - - if _, ok := stateBag.GetOk(constants.Error); ok == true { - t.Fatalf("Expected the step to not set stateBag['%s'], but it was.", constants.Error) - } -} - -func createTestStateBagStepSnapshotOSDisk() multistep.StateBag { - stateBag := new(multistep.BasicStateBag) - - stateBag.Put(constants.ArmManagedImageResourceGroupName, "Unit Test: ResourceGroupName") - stateBag.Put(constants.ArmLocation, "Unit Test: Location") - - value := "Unit Test: Tags" - tags := map[string]*string{ - "tag01": &value, - } - - stateBag.Put(constants.ArmTags, tags) - - stateBag.Put(constants.ArmOSDiskVhd, "subscriptions/123-456-789/resourceGroups/existingresourcegroup/providers/Microsoft.Compute/disks/osdisk") - stateBag.Put(constants.ArmManagedImageOSDiskSnapshotName, "Unit Test: ManagedImageOSDiskSnapshotName") - - return stateBag -} diff --git a/builder/azure/arm/step_test.go b/builder/azure/arm/step_test.go deleted file mode 100644 index 6d53cf957..000000000 --- a/builder/azure/arm/step_test.go +++ /dev/null @@ -1,40 +0,0 @@ -package arm - -import ( - "fmt" - "testing" - - "github.com/hashicorp/packer-plugin-sdk/multistep" - "github.com/hashicorp/packer/builder/azure/common/constants" -) - -func TestProcessStepResultShouldContinueForNonErrors(t *testing.T) { - stateBag := new(multistep.BasicStateBag) - - code := processStepResult(nil, func(error) { t.Fatal("Should not be called!") }, stateBag) - if _, ok := stateBag.GetOk(constants.Error); ok { - t.Errorf("Error was nil, but was still in the state bag.") - } - - if code != multistep.ActionContinue { - t.Errorf("Expected ActionContinue(%d), but got=%d", multistep.ActionContinue, code) - } -} - -func TestProcessStepResultShouldHaltOnError(t *testing.T) { - stateBag := new(multistep.BasicStateBag) - isSaidError := false - - code := processStepResult(fmt.Errorf("boom"), func(error) { isSaidError = true }, stateBag) - if _, ok := stateBag.GetOk(constants.Error); !ok { - t.Errorf("Error was non nil, but was not in the state bag.") - } - - if !isSaidError { - t.Errorf("Expected error to be said, but it was not.") - } - - if code != multistep.ActionHalt { - t.Errorf("Expected ActionHalt(%d), but got=%d", multistep.ActionHalt, code) - } -} diff --git a/builder/azure/arm/step_validate_template.go b/builder/azure/arm/step_validate_template.go deleted file mode 100644 index 415f1ff36..000000000 --- a/builder/azure/arm/step_validate_template.go +++ /dev/null @@ -1,61 +0,0 @@ -package arm - -import ( - "context" - "fmt" - - "github.com/hashicorp/packer-plugin-sdk/multistep" - packersdk "github.com/hashicorp/packer-plugin-sdk/packer" - "github.com/hashicorp/packer/builder/azure/common/constants" -) - -type StepValidateTemplate struct { - client *AzureClient - validate func(ctx context.Context, resourceGroupName string, deploymentName string) error - say func(message string) - error func(e error) - config *Config - factory templateFactoryFunc -} - -func NewStepValidateTemplate(client *AzureClient, ui packersdk.Ui, config *Config, factory templateFactoryFunc) *StepValidateTemplate { - var step = &StepValidateTemplate{ - client: client, - say: func(message string) { ui.Say(message) }, - error: func(e error) { ui.Error(e.Error()) }, - config: config, - factory: factory, - } - - step.validate = step.validateTemplate - return step -} - -func (s *StepValidateTemplate) validateTemplate(ctx context.Context, resourceGroupName string, deploymentName string) error { - deployment, err := s.factory(s.config) - if err != nil { - return err - } - - _, err = s.client.DeploymentsClient.Validate(ctx, resourceGroupName, deploymentName, *deployment) - if err != nil { - s.say(s.client.LastError.Error()) - } - return err -} - -func (s *StepValidateTemplate) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction { - s.say("Validating deployment template ...") - - var resourceGroupName = state.Get(constants.ArmResourceGroupName).(string) - var deploymentName = state.Get(constants.ArmDeploymentName).(string) - - s.say(fmt.Sprintf(" -> ResourceGroupName : '%s'", resourceGroupName)) - s.say(fmt.Sprintf(" -> DeploymentName : '%s'", deploymentName)) - - err := s.validate(ctx, resourceGroupName, deploymentName) - return processStepResult(err, s.error, state) -} - -func (*StepValidateTemplate) Cleanup(multistep.StateBag) { -} diff --git a/builder/azure/arm/step_validate_template_test.go b/builder/azure/arm/step_validate_template_test.go deleted file mode 100644 index 972bbd692..000000000 --- a/builder/azure/arm/step_validate_template_test.go +++ /dev/null @@ -1,91 +0,0 @@ -package arm - -import ( - "context" - "fmt" - "testing" - - "github.com/hashicorp/packer-plugin-sdk/multistep" - "github.com/hashicorp/packer/builder/azure/common/constants" -) - -func TestStepValidateTemplateShouldFailIfValidateFails(t *testing.T) { - var testSubject = &StepValidateTemplate{ - validate: func(context.Context, string, string) error { return fmt.Errorf("!! Unit Test FAIL !!") }, - say: func(message string) {}, - error: func(e error) {}, - } - - stateBag := createTestStateBagStepValidateTemplate() - - var result = testSubject.Run(context.Background(), stateBag) - if result != multistep.ActionHalt { - t.Fatalf("Expected the step to return 'ActionHalt', but got '%d'.", result) - } - - if _, ok := stateBag.GetOk(constants.Error); ok == false { - t.Fatalf("Expected the step to set stateBag['%s'], but it was not.", constants.Error) - } -} - -func TestStepValidateTemplateShouldPassIfValidatePasses(t *testing.T) { - var testSubject = &StepValidateTemplate{ - validate: func(context.Context, string, string) error { return nil }, - say: func(message string) {}, - error: func(e error) {}, - } - - stateBag := createTestStateBagStepValidateTemplate() - - var result = testSubject.Run(context.Background(), stateBag) - if result != multistep.ActionContinue { - t.Fatalf("Expected the step to return 'ActionContinue', but got '%d'.", result) - } - - if _, ok := stateBag.GetOk(constants.Error); ok == true { - t.Fatalf("Expected the step to not set stateBag['%s'], but it was.", constants.Error) - } -} - -func TestStepValidateTemplateShouldTakeStepArgumentsFromStateBag(t *testing.T) { - var actualResourceGroupName string - var actualDeploymentName string - - var testSubject = &StepValidateTemplate{ - validate: func(ctx context.Context, resourceGroupName string, deploymentName string) error { - actualResourceGroupName = resourceGroupName - actualDeploymentName = deploymentName - - return nil - }, - say: func(message string) {}, - error: func(e error) {}, - } - - stateBag := createTestStateBagStepValidateTemplate() - var result = testSubject.Run(context.Background(), stateBag) - - if result != multistep.ActionContinue { - t.Fatalf("Expected the step to return 'ActionContinue', but got '%d'.", result) - } - - var expectedDeploymentName = stateBag.Get(constants.ArmDeploymentName).(string) - var expectedResourceGroupName = stateBag.Get(constants.ArmResourceGroupName).(string) - - if actualDeploymentName != expectedDeploymentName { - t.Fatal("Expected the step to source 'constants.ArmDeploymentName' from the state bag, but it did not.") - } - - if actualResourceGroupName != expectedResourceGroupName { - t.Fatal("Expected the step to source 'constants.ArmResourceGroupName' from the state bag, but it did not.") - } -} - -func createTestStateBagStepValidateTemplate() multistep.StateBag { - stateBag := new(multistep.BasicStateBag) - - stateBag.Put(constants.ArmDeploymentName, "Unit Test: DeploymentName") - stateBag.Put(constants.ArmResourceGroupName, "Unit Test: ResourceGroupName") - - return stateBag -} diff --git a/builder/azure/arm/template_factory.go b/builder/azure/arm/template_factory.go deleted file mode 100644 index e8ee00f0b..000000000 --- a/builder/azure/arm/template_factory.go +++ /dev/null @@ -1,213 +0,0 @@ -package arm - -import ( - "encoding/json" - - "github.com/Azure/azure-sdk-for-go/services/compute/mgmt/2018-04-01/compute" - "github.com/Azure/azure-sdk-for-go/services/resources/mgmt/2018-02-01/resources" - - "fmt" - - "github.com/hashicorp/packer/builder/azure/common/constants" - "github.com/hashicorp/packer/builder/azure/common/template" -) - -type templateFactoryFunc func(*Config) (*resources.Deployment, error) - -func GetKeyVaultDeployment(config *Config) (*resources.Deployment, error) { - params := &template.TemplateParameters{ - KeyVaultName: &template.TemplateParameter{Value: config.tmpKeyVaultName}, - KeyVaultSKU: &template.TemplateParameter{Value: config.BuildKeyVaultSKU}, - KeyVaultSecretValue: &template.TemplateParameter{Value: config.winrmCertificate}, - ObjectId: &template.TemplateParameter{Value: config.ClientConfig.ObjectID}, - TenantId: &template.TemplateParameter{Value: config.ClientConfig.TenantID}, - } - - builder, _ := template.NewTemplateBuilder(template.KeyVault) - builder.SetTags(&config.AzureTags) - - doc, _ := builder.ToJSON() - return createDeploymentParameters(*doc, params) -} - -func GetVirtualMachineDeployment(config *Config) (*resources.Deployment, error) { - params := &template.TemplateParameters{ - AdminUsername: &template.TemplateParameter{Value: config.UserName}, - AdminPassword: &template.TemplateParameter{Value: config.Password}, - DnsNameForPublicIP: &template.TemplateParameter{Value: config.tmpComputeName}, - NicName: &template.TemplateParameter{Value: config.tmpNicName}, - OSDiskName: &template.TemplateParameter{Value: config.tmpOSDiskName}, - DataDiskName: &template.TemplateParameter{Value: config.tmpDataDiskName}, - PublicIPAddressName: &template.TemplateParameter{Value: config.tmpPublicIPAddressName}, - SubnetName: &template.TemplateParameter{Value: config.tmpSubnetName}, - StorageAccountBlobEndpoint: &template.TemplateParameter{Value: config.storageAccountBlobEndpoint}, - VirtualNetworkName: &template.TemplateParameter{Value: config.tmpVirtualNetworkName}, - NsgName: &template.TemplateParameter{Value: config.tmpNsgName}, - VMSize: &template.TemplateParameter{Value: config.VMSize}, - VMName: &template.TemplateParameter{Value: config.tmpComputeName}, - } - - builder, err := template.NewTemplateBuilder(template.BasicTemplate) - if err != nil { - return nil, err - } - osType := compute.Linux - - switch config.OSType { - case constants.Target_Linux: - err = builder.BuildLinux(config.sshAuthorizedKey, config.Comm.SSHPassword == "") // if ssh password is not explicitly specified, disable password auth - if err != nil { - return nil, err - } - case constants.Target_Windows: - osType = compute.Windows - err = builder.BuildWindows(config.tmpKeyVaultName, config.tmpWinRMCertificateUrl) - if err != nil { - return nil, err - } - } - - if len(config.UserAssignedManagedIdentities) != 0 { - if err := builder.SetIdentity(config.UserAssignedManagedIdentities); err != nil { - return nil, err - } - } - - if config.ImageUrl != "" { - err = builder.SetImageUrl(config.ImageUrl, osType, config.diskCachingType) - if err != nil { - return nil, err - } - } else if config.CustomManagedImageName != "" { - err = builder.SetManagedDiskUrl(config.customManagedImageID, config.managedImageStorageAccountType, config.diskCachingType) - if err != nil { - return nil, err - } - } else if config.ManagedImageName != "" && config.ImagePublisher != "" { - imageID := fmt.Sprintf("/subscriptions/%s/providers/Microsoft.Compute/locations/%s/publishers/%s/ArtifactTypes/vmimage/offers/%s/skus/%s/versions/%s", - config.ClientConfig.SubscriptionID, - config.Location, - config.ImagePublisher, - config.ImageOffer, - config.ImageSku, - config.ImageVersion) - - builder.SetManagedMarketplaceImage(config.Location, config.ImagePublisher, config.ImageOffer, config.ImageSku, config.ImageVersion, imageID, config.managedImageStorageAccountType, config.diskCachingType) - } else if config.SharedGallery.Subscription != "" { - imageID := fmt.Sprintf("/subscriptions/%s/resourceGroups/%s/providers/Microsoft.Compute/galleries/%s/images/%s", - config.SharedGallery.Subscription, - config.SharedGallery.ResourceGroup, - config.SharedGallery.GalleryName, - config.SharedGallery.ImageName) - if config.SharedGallery.ImageVersion != "" { - imageID += fmt.Sprintf("/versions/%s", - config.SharedGallery.ImageVersion) - } - - err = builder.SetSharedGalleryImage(config.Location, imageID, config.diskCachingType) - if err != nil { - return nil, err - } - } else { - err = builder.SetMarketPlaceImage(config.ImagePublisher, config.ImageOffer, config.ImageSku, config.ImageVersion, config.diskCachingType) - if err != nil { - return nil, err - } - } - - if config.OSDiskSizeGB > 0 { - err = builder.SetOSDiskSizeGB(config.OSDiskSizeGB) - if err != nil { - return nil, err - } - } - - if len(config.AdditionalDiskSize) > 0 { - isManaged := config.CustomManagedImageName != "" || (config.ManagedImageName != "" && config.ImagePublisher != "") || config.SharedGallery.Subscription != "" - err = builder.SetAdditionalDisks(config.AdditionalDiskSize, config.tmpDataDiskName, isManaged, config.diskCachingType) - if err != nil { - return nil, err - } - } - - if config.customData != "" { - err = builder.SetCustomData(config.customData) - if err != nil { - return nil, err - } - } - - if config.PlanInfo.PlanName != "" { - err = builder.SetPlanInfo(config.PlanInfo.PlanName, config.PlanInfo.PlanProduct, config.PlanInfo.PlanPublisher, config.PlanInfo.PlanPromotionCode) - if err != nil { - return nil, err - } - } - - if config.VirtualNetworkName != "" && DefaultPrivateVirtualNetworkWithPublicIp != config.PrivateVirtualNetworkWithPublicIp { - err = builder.SetPrivateVirtualNetworkWithPublicIp( - config.VirtualNetworkResourceGroupName, - config.VirtualNetworkName, - config.VirtualNetworkSubnetName) - if err != nil { - return nil, err - } - } else if config.VirtualNetworkName != "" { - err = builder.SetVirtualNetwork( - config.VirtualNetworkResourceGroupName, - config.VirtualNetworkName, - config.VirtualNetworkSubnetName) - if err != nil { - return nil, err - } - } - - if config.AllowedInboundIpAddresses != nil && len(config.AllowedInboundIpAddresses) >= 1 && config.Comm.Port() != 0 { - err = builder.SetNetworkSecurityGroup(config.AllowedInboundIpAddresses, config.Comm.Port()) - if err != nil { - return nil, err - } - } - - if config.BootDiagSTGAccount != "" { - err = builder.SetBootDiagnostics(config.BootDiagSTGAccount) - if err != nil { - return nil, err - } - } - - err = builder.SetTags(&config.AzureTags) - if err != nil { - return nil, err - } - - doc, _ := builder.ToJSON() - return createDeploymentParameters(*doc, params) -} - -func createDeploymentParameters(doc string, parameters *template.TemplateParameters) (*resources.Deployment, error) { - var template map[string]interface{} - err := json.Unmarshal(([]byte)(doc), &template) - if err != nil { - return nil, err - } - - bs, err := json.Marshal(*parameters) - if err != nil { - return nil, err - } - - var templateParameters map[string]interface{} - err = json.Unmarshal(bs, &templateParameters) - if err != nil { - return nil, err - } - - return &resources.Deployment{ - Properties: &resources.DeploymentProperties{ - Mode: resources.Incremental, - Template: &template, - Parameters: &templateParameters, - }, - }, nil -} diff --git a/builder/azure/arm/template_factory_test.TestKeyVaultDeployment03.approved.json b/builder/azure/arm/template_factory_test.TestKeyVaultDeployment03.approved.json deleted file mode 100644 index c4f85c6a8..000000000 --- a/builder/azure/arm/template_factory_test.TestKeyVaultDeployment03.approved.json +++ /dev/null @@ -1,76 +0,0 @@ -{ - "$schema": "http://schema.management.azure.com/schemas/2014-04-01-preview/deploymentTemplate.json", - "contentVersion": "1.0.0.0", - "parameters": { - "keyVaultName": { - "type": "string" - }, - "keyVaultSKU": { - "type": "string" - }, - "keyVaultSecretValue": { - "type": "securestring" - }, - "objectId": { - "type": "string" - }, - "tenantId": { - "type": "string" - } - }, - "resources": [ - { - "apiVersion": "[variables('apiVersion')]", - "location": "[variables('location')]", - "name": "[parameters('keyVaultName')]", - "properties": { - "accessPolicies": [ - { - "objectId": "[parameters('objectId')]", - "permissions": { - "keys": [ - "all" - ], - "secrets": [ - "all" - ] - }, - "tenantId": "[parameters('tenantId')]" - } - ], - "enableSoftDelete": "true", - "enabledForDeployment": "true", - "enabledForTemplateDeployment": "true", - "sku": { - "family": "A", - "name": "[parameters('keyVaultSKU')]" - }, - "tenantId": "[parameters('tenantId')]" - }, - "resources": [ - { - "apiVersion": "[variables('apiVersion')]", - "dependsOn": [ - "[concat('Microsoft.KeyVault/vaults/', parameters('keyVaultName'))]" - ], - "name": "[variables('keyVaultSecretName')]", - "properties": { - "value": "[parameters('keyVaultSecretValue')]" - }, - "type": "secrets" - } - ], - "tags": { - "tag01": "value01", - "tag02": "value02", - "tag03": "value03" - }, - "type": "Microsoft.KeyVault/vaults" - } - ], - "variables": { - "apiVersion": "2015-06-01", - "keyVaultSecretName": "packerKeyVaultSecret", - "location": "[resourceGroup().location]" - } -} \ No newline at end of file diff --git a/builder/azure/arm/template_factory_test.TestPlanInfo01.approved.json b/builder/azure/arm/template_factory_test.TestPlanInfo01.approved.json deleted file mode 100644 index 1b9d40d93..000000000 --- a/builder/azure/arm/template_factory_test.TestPlanInfo01.approved.json +++ /dev/null @@ -1,211 +0,0 @@ -{ - "$schema": "http://schema.management.azure.com/schemas/2014-04-01-preview/deploymentTemplate.json", - "contentVersion": "1.0.0.0", - "parameters": { - "adminPassword": { - "type": "string" - }, - "adminUsername": { - "type": "string" - }, - "dataDiskName": { - "type": "string" - }, - "dnsNameForPublicIP": { - "type": "string" - }, - "nicName": { - "type": "string" - }, - "nsgName": { - "type": "string" - }, - "osDiskName": { - "type": "string" - }, - "publicIPAddressName": { - "type": "string" - }, - "storageAccountBlobEndpoint": { - "type": "string" - }, - "subnetName": { - "type": "string" - }, - "virtualNetworkName": { - "type": "string" - }, - "vmName": { - "type": "string" - }, - "vmSize": { - "type": "string" - } - }, - "resources": [ - { - "apiVersion": "[variables('publicIPAddressApiVersion')]", - "location": "[variables('location')]", - "name": "[parameters('publicIPAddressName')]", - "properties": { - "dnsSettings": { - "domainNameLabel": "[parameters('dnsNameForPublicIP')]" - }, - "publicIPAllocationMethod": "[variables('publicIPAddressType')]" - }, - "tags": { - "PlanInfo": "planName00", - "PlanProduct": "planProduct00", - "PlanPromotionCode": "", - "PlanPublisher": "planPublisher00" - }, - "type": "Microsoft.Network/publicIPAddresses" - }, - { - "apiVersion": "[variables('virtualNetworksApiVersion')]", - "location": "[variables('location')]", - "name": "[variables('virtualNetworkName')]", - "properties": { - "addressSpace": { - "addressPrefixes": [ - "[variables('addressPrefix')]" - ] - }, - "subnets": [ - { - "name": "[variables('subnetName')]", - "properties": { - "addressPrefix": "[variables('subnetAddressPrefix')]" - } - } - ] - }, - "tags": { - "PlanInfo": "planName00", - "PlanProduct": "planProduct00", - "PlanPromotionCode": "", - "PlanPublisher": "planPublisher00" - }, - "type": "Microsoft.Network/virtualNetworks" - }, - { - "apiVersion": "[variables('networkInterfacesApiVersion')]", - "dependsOn": [ - "[concat('Microsoft.Network/publicIPAddresses/', parameters('publicIPAddressName'))]", - "[concat('Microsoft.Network/virtualNetworks/', variables('virtualNetworkName'))]" - ], - "location": "[variables('location')]", - "name": "[parameters('nicName')]", - "properties": { - "ipConfigurations": [ - { - "name": "ipconfig", - "properties": { - "privateIPAllocationMethod": "Dynamic", - "publicIPAddress": { - "id": "[resourceId('Microsoft.Network/publicIPAddresses', parameters('publicIPAddressName'))]" - }, - "subnet": { - "id": "[variables('subnetRef')]" - } - } - } - ] - }, - "tags": { - "PlanInfo": "planName00", - "PlanProduct": "planProduct00", - "PlanPromotionCode": "", - "PlanPublisher": "planPublisher00" - }, - "type": "Microsoft.Network/networkInterfaces" - }, - { - "apiVersion": "[variables('apiVersion')]", - "dependsOn": [ - "[concat('Microsoft.Network/networkInterfaces/', parameters('nicName'))]" - ], - "location": "[variables('location')]", - "name": "[parameters('vmName')]", - "plan": { - "name": "planName00", - "product": "planProduct00", - "publisher": "planPublisher00" - }, - "properties": { - "diagnosticsProfile": { - "bootDiagnostics": { - "enabled": false - } - }, - "hardwareProfile": { - "vmSize": "[parameters('vmSize')]" - }, - "networkProfile": { - "networkInterfaces": [ - { - "id": "[resourceId('Microsoft.Network/networkInterfaces', parameters('nicName'))]" - } - ] - }, - "osProfile": { - "adminUsername": "[parameters('adminUsername')]", - "computerName": "[parameters('vmName')]", - "linuxConfiguration": { - "disablePasswordAuthentication": true, - "ssh": { - "publicKeys": [ - { - "keyData": "", - "path": "[variables('sshKeyPath')]" - } - ] - } - } - }, - "storageProfile": { - "imageReference": { - "offer": "ignored00", - "publisher": "ignored00", - "sku": "ignored00", - "version": "latest" - }, - "osDisk": { - "caching": "ReadWrite", - "createOption": "FromImage", - "name": "[parameters('osDiskName')]", - "vhd": { - "uri": "[concat(parameters('storageAccountBlobEndpoint'),variables('vmStorageAccountContainerName'),'/', parameters('osDiskName'),'.vhd')]" - } - } - } - }, - "tags": { - "PlanInfo": "planName00", - "PlanProduct": "planProduct00", - "PlanPromotionCode": "", - "PlanPublisher": "planPublisher00" - }, - "type": "Microsoft.Compute/virtualMachines" - } - ], - "variables": { - "addressPrefix": "10.0.0.0/16", - "apiVersion": "2017-03-30", - "location": "[resourceGroup().location]", - "managedDiskApiVersion": "2017-03-30", - "networkInterfacesApiVersion": "2017-04-01", - "networkSecurityGroupsApiVersion": "2019-04-01", - "publicIPAddressApiVersion": "2017-04-01", - "publicIPAddressType": "Dynamic", - "sshKeyPath": "[concat('/home/',parameters('adminUsername'),'/.ssh/authorized_keys')]", - "subnetAddressPrefix": "10.0.0.0/24", - "subnetName": "[parameters('subnetName')]", - "subnetRef": "[concat(variables('vnetID'),'/subnets/',variables('subnetName'))]", - "virtualNetworkName": "[parameters('virtualNetworkName')]", - "virtualNetworkResourceGroup": "[resourceGroup().name]", - "virtualNetworksApiVersion": "2017-04-01", - "vmStorageAccountContainerName": "images", - "vnetID": "[resourceId(variables('virtualNetworkResourceGroup'), 'Microsoft.Network/virtualNetworks', variables('virtualNetworkName'))]" - } -} \ No newline at end of file diff --git a/builder/azure/arm/template_factory_test.TestPlanInfo02.approved.json b/builder/azure/arm/template_factory_test.TestPlanInfo02.approved.json deleted file mode 100644 index 20eda3180..000000000 --- a/builder/azure/arm/template_factory_test.TestPlanInfo02.approved.json +++ /dev/null @@ -1,216 +0,0 @@ -{ - "$schema": "http://schema.management.azure.com/schemas/2014-04-01-preview/deploymentTemplate.json", - "contentVersion": "1.0.0.0", - "parameters": { - "adminPassword": { - "type": "string" - }, - "adminUsername": { - "type": "string" - }, - "dataDiskName": { - "type": "string" - }, - "dnsNameForPublicIP": { - "type": "string" - }, - "nicName": { - "type": "string" - }, - "nsgName": { - "type": "string" - }, - "osDiskName": { - "type": "string" - }, - "publicIPAddressName": { - "type": "string" - }, - "storageAccountBlobEndpoint": { - "type": "string" - }, - "subnetName": { - "type": "string" - }, - "virtualNetworkName": { - "type": "string" - }, - "vmName": { - "type": "string" - }, - "vmSize": { - "type": "string" - } - }, - "resources": [ - { - "apiVersion": "[variables('publicIPAddressApiVersion')]", - "location": "[variables('location')]", - "name": "[parameters('publicIPAddressName')]", - "properties": { - "dnsSettings": { - "domainNameLabel": "[parameters('dnsNameForPublicIP')]" - }, - "publicIPAllocationMethod": "[variables('publicIPAddressType')]" - }, - "tags": { - "PlanInfo": "planName00", - "PlanProduct": "planProduct00", - "PlanPromotionCode": "planPromotionCode00", - "PlanPublisher": "planPublisher00", - "dept": "engineering" - }, - "type": "Microsoft.Network/publicIPAddresses" - }, - { - "apiVersion": "[variables('virtualNetworksApiVersion')]", - "location": "[variables('location')]", - "name": "[variables('virtualNetworkName')]", - "properties": { - "addressSpace": { - "addressPrefixes": [ - "[variables('addressPrefix')]" - ] - }, - "subnets": [ - { - "name": "[variables('subnetName')]", - "properties": { - "addressPrefix": "[variables('subnetAddressPrefix')]" - } - } - ] - }, - "tags": { - "PlanInfo": "planName00", - "PlanProduct": "planProduct00", - "PlanPromotionCode": "planPromotionCode00", - "PlanPublisher": "planPublisher00", - "dept": "engineering" - }, - "type": "Microsoft.Network/virtualNetworks" - }, - { - "apiVersion": "[variables('networkInterfacesApiVersion')]", - "dependsOn": [ - "[concat('Microsoft.Network/publicIPAddresses/', parameters('publicIPAddressName'))]", - "[concat('Microsoft.Network/virtualNetworks/', variables('virtualNetworkName'))]" - ], - "location": "[variables('location')]", - "name": "[parameters('nicName')]", - "properties": { - "ipConfigurations": [ - { - "name": "ipconfig", - "properties": { - "privateIPAllocationMethod": "Dynamic", - "publicIPAddress": { - "id": "[resourceId('Microsoft.Network/publicIPAddresses', parameters('publicIPAddressName'))]" - }, - "subnet": { - "id": "[variables('subnetRef')]" - } - } - } - ] - }, - "tags": { - "PlanInfo": "planName00", - "PlanProduct": "planProduct00", - "PlanPromotionCode": "planPromotionCode00", - "PlanPublisher": "planPublisher00", - "dept": "engineering" - }, - "type": "Microsoft.Network/networkInterfaces" - }, - { - "apiVersion": "[variables('apiVersion')]", - "dependsOn": [ - "[concat('Microsoft.Network/networkInterfaces/', parameters('nicName'))]" - ], - "location": "[variables('location')]", - "name": "[parameters('vmName')]", - "plan": { - "name": "planName00", - "product": "planProduct00", - "promotionCode": "planPromotionCode00", - "publisher": "planPublisher00" - }, - "properties": { - "diagnosticsProfile": { - "bootDiagnostics": { - "enabled": false - } - }, - "hardwareProfile": { - "vmSize": "[parameters('vmSize')]" - }, - "networkProfile": { - "networkInterfaces": [ - { - "id": "[resourceId('Microsoft.Network/networkInterfaces', parameters('nicName'))]" - } - ] - }, - "osProfile": { - "adminUsername": "[parameters('adminUsername')]", - "computerName": "[parameters('vmName')]", - "linuxConfiguration": { - "disablePasswordAuthentication": true, - "ssh": { - "publicKeys": [ - { - "keyData": "", - "path": "[variables('sshKeyPath')]" - } - ] - } - } - }, - "storageProfile": { - "imageReference": { - "offer": "ignored00", - "publisher": "ignored00", - "sku": "ignored00", - "version": "latest" - }, - "osDisk": { - "caching": "ReadWrite", - "createOption": "FromImage", - "name": "[parameters('osDiskName')]", - "vhd": { - "uri": "[concat(parameters('storageAccountBlobEndpoint'),variables('vmStorageAccountContainerName'),'/', parameters('osDiskName'),'.vhd')]" - } - } - } - }, - "tags": { - "PlanInfo": "planName00", - "PlanProduct": "planProduct00", - "PlanPromotionCode": "planPromotionCode00", - "PlanPublisher": "planPublisher00", - "dept": "engineering" - }, - "type": "Microsoft.Compute/virtualMachines" - } - ], - "variables": { - "addressPrefix": "10.0.0.0/16", - "apiVersion": "2017-03-30", - "location": "[resourceGroup().location]", - "managedDiskApiVersion": "2017-03-30", - "networkInterfacesApiVersion": "2017-04-01", - "networkSecurityGroupsApiVersion": "2019-04-01", - "publicIPAddressApiVersion": "2017-04-01", - "publicIPAddressType": "Dynamic", - "sshKeyPath": "[concat('/home/',parameters('adminUsername'),'/.ssh/authorized_keys')]", - "subnetAddressPrefix": "10.0.0.0/24", - "subnetName": "[parameters('subnetName')]", - "subnetRef": "[concat(variables('vnetID'),'/subnets/',variables('subnetName'))]", - "virtualNetworkName": "[parameters('virtualNetworkName')]", - "virtualNetworkResourceGroup": "[resourceGroup().name]", - "virtualNetworksApiVersion": "2017-04-01", - "vmStorageAccountContainerName": "images", - "vnetID": "[resourceId(variables('virtualNetworkResourceGroup'), 'Microsoft.Network/virtualNetworks', variables('virtualNetworkName'))]" - } -} \ No newline at end of file diff --git a/builder/azure/arm/template_factory_test.TestVirtualMachineDeployment03.approved.json b/builder/azure/arm/template_factory_test.TestVirtualMachineDeployment03.approved.json deleted file mode 100644 index 1f0e43265..000000000 --- a/builder/azure/arm/template_factory_test.TestVirtualMachineDeployment03.approved.json +++ /dev/null @@ -1,182 +0,0 @@ -{ - "$schema": "http://schema.management.azure.com/schemas/2014-04-01-preview/deploymentTemplate.json", - "contentVersion": "1.0.0.0", - "parameters": { - "adminPassword": { - "type": "string" - }, - "adminUsername": { - "type": "string" - }, - "dataDiskName": { - "type": "string" - }, - "dnsNameForPublicIP": { - "type": "string" - }, - "nicName": { - "type": "string" - }, - "nsgName": { - "type": "string" - }, - "osDiskName": { - "type": "string" - }, - "publicIPAddressName": { - "type": "string" - }, - "storageAccountBlobEndpoint": { - "type": "string" - }, - "subnetName": { - "type": "string" - }, - "virtualNetworkName": { - "type": "string" - }, - "vmName": { - "type": "string" - }, - "vmSize": { - "type": "string" - } - }, - "resources": [ - { - "apiVersion": "[variables('publicIPAddressApiVersion')]", - "location": "[variables('location')]", - "name": "[parameters('publicIPAddressName')]", - "properties": { - "dnsSettings": { - "domainNameLabel": "[parameters('dnsNameForPublicIP')]" - }, - "publicIPAllocationMethod": "[variables('publicIPAddressType')]" - }, - "type": "Microsoft.Network/publicIPAddresses" - }, - { - "apiVersion": "[variables('virtualNetworksApiVersion')]", - "location": "[variables('location')]", - "name": "[variables('virtualNetworkName')]", - "properties": { - "addressSpace": { - "addressPrefixes": [ - "[variables('addressPrefix')]" - ] - }, - "subnets": [ - { - "name": "[variables('subnetName')]", - "properties": { - "addressPrefix": "[variables('subnetAddressPrefix')]" - } - } - ] - }, - "type": "Microsoft.Network/virtualNetworks" - }, - { - "apiVersion": "[variables('networkInterfacesApiVersion')]", - "dependsOn": [ - "[concat('Microsoft.Network/publicIPAddresses/', parameters('publicIPAddressName'))]", - "[concat('Microsoft.Network/virtualNetworks/', variables('virtualNetworkName'))]" - ], - "location": "[variables('location')]", - "name": "[parameters('nicName')]", - "properties": { - "ipConfigurations": [ - { - "name": "ipconfig", - "properties": { - "privateIPAllocationMethod": "Dynamic", - "publicIPAddress": { - "id": "[resourceId('Microsoft.Network/publicIPAddresses', parameters('publicIPAddressName'))]" - }, - "subnet": { - "id": "[variables('subnetRef')]" - } - } - } - ] - }, - "type": "Microsoft.Network/networkInterfaces" - }, - { - "apiVersion": "[variables('apiVersion')]", - "dependsOn": [ - "[concat('Microsoft.Network/networkInterfaces/', parameters('nicName'))]" - ], - "location": "[variables('location')]", - "name": "[parameters('vmName')]", - "properties": { - "diagnosticsProfile": { - "bootDiagnostics": { - "enabled": false - } - }, - "hardwareProfile": { - "vmSize": "[parameters('vmSize')]" - }, - "networkProfile": { - "networkInterfaces": [ - { - "id": "[resourceId('Microsoft.Network/networkInterfaces', parameters('nicName'))]" - } - ] - }, - "osProfile": { - "adminPassword": "[parameters('adminPassword')]", - "adminUsername": "[parameters('adminUsername')]", - "computerName": "[parameters('vmName')]", - "linuxConfiguration": { - "ssh": { - "publicKeys": [ - { - "keyData": "", - "path": "[variables('sshKeyPath')]" - } - ] - } - } - }, - "storageProfile": { - "imageReference": { - "offer": "ImageOffer", - "publisher": "ImagePublisher", - "sku": "ImageSku", - "version": "ImageVersion" - }, - "osDisk": { - "caching": "ReadWrite", - "createOption": "FromImage", - "name": "[parameters('osDiskName')]", - "vhd": { - "uri": "[concat(parameters('storageAccountBlobEndpoint'),variables('vmStorageAccountContainerName'),'/', parameters('osDiskName'),'.vhd')]" - } - } - } - }, - "type": "Microsoft.Compute/virtualMachines" - } - ], - "variables": { - "addressPrefix": "10.0.0.0/16", - "apiVersion": "2017-03-30", - "location": "[resourceGroup().location]", - "managedDiskApiVersion": "2017-03-30", - "networkInterfacesApiVersion": "2017-04-01", - "networkSecurityGroupsApiVersion": "2019-04-01", - "publicIPAddressApiVersion": "2017-04-01", - "publicIPAddressType": "Dynamic", - "sshKeyPath": "[concat('/home/',parameters('adminUsername'),'/.ssh/authorized_keys')]", - "subnetAddressPrefix": "10.0.0.0/24", - "subnetName": "[parameters('subnetName')]", - "subnetRef": "[concat(variables('vnetID'),'/subnets/',variables('subnetName'))]", - "virtualNetworkName": "[parameters('virtualNetworkName')]", - "virtualNetworkResourceGroup": "[resourceGroup().name]", - "virtualNetworksApiVersion": "2017-04-01", - "vmStorageAccountContainerName": "images", - "vnetID": "[resourceId(variables('virtualNetworkResourceGroup'), 'Microsoft.Network/virtualNetworks', variables('virtualNetworkName'))]" - } -} \ No newline at end of file diff --git a/builder/azure/arm/template_factory_test.TestVirtualMachineDeployment04.approved.json b/builder/azure/arm/template_factory_test.TestVirtualMachineDeployment04.approved.json deleted file mode 100644 index 4c69b352a..000000000 --- a/builder/azure/arm/template_factory_test.TestVirtualMachineDeployment04.approved.json +++ /dev/null @@ -1,180 +0,0 @@ -{ - "$schema": "http://schema.management.azure.com/schemas/2014-04-01-preview/deploymentTemplate.json", - "contentVersion": "1.0.0.0", - "parameters": { - "adminPassword": { - "type": "string" - }, - "adminUsername": { - "type": "string" - }, - "dataDiskName": { - "type": "string" - }, - "dnsNameForPublicIP": { - "type": "string" - }, - "nicName": { - "type": "string" - }, - "nsgName": { - "type": "string" - }, - "osDiskName": { - "type": "string" - }, - "publicIPAddressName": { - "type": "string" - }, - "storageAccountBlobEndpoint": { - "type": "string" - }, - "subnetName": { - "type": "string" - }, - "virtualNetworkName": { - "type": "string" - }, - "vmName": { - "type": "string" - }, - "vmSize": { - "type": "string" - } - }, - "resources": [ - { - "apiVersion": "[variables('publicIPAddressApiVersion')]", - "location": "[variables('location')]", - "name": "[parameters('publicIPAddressName')]", - "properties": { - "dnsSettings": { - "domainNameLabel": "[parameters('dnsNameForPublicIP')]" - }, - "publicIPAllocationMethod": "[variables('publicIPAddressType')]" - }, - "type": "Microsoft.Network/publicIPAddresses" - }, - { - "apiVersion": "[variables('virtualNetworksApiVersion')]", - "location": "[variables('location')]", - "name": "[variables('virtualNetworkName')]", - "properties": { - "addressSpace": { - "addressPrefixes": [ - "[variables('addressPrefix')]" - ] - }, - "subnets": [ - { - "name": "[variables('subnetName')]", - "properties": { - "addressPrefix": "[variables('subnetAddressPrefix')]" - } - } - ] - }, - "type": "Microsoft.Network/virtualNetworks" - }, - { - "apiVersion": "[variables('networkInterfacesApiVersion')]", - "dependsOn": [ - "[concat('Microsoft.Network/publicIPAddresses/', parameters('publicIPAddressName'))]", - "[concat('Microsoft.Network/virtualNetworks/', variables('virtualNetworkName'))]" - ], - "location": "[variables('location')]", - "name": "[parameters('nicName')]", - "properties": { - "ipConfigurations": [ - { - "name": "ipconfig", - "properties": { - "privateIPAllocationMethod": "Dynamic", - "publicIPAddress": { - "id": "[resourceId('Microsoft.Network/publicIPAddresses', parameters('publicIPAddressName'))]" - }, - "subnet": { - "id": "[variables('subnetRef')]" - } - } - } - ] - }, - "type": "Microsoft.Network/networkInterfaces" - }, - { - "apiVersion": "[variables('apiVersion')]", - "dependsOn": [ - "[concat('Microsoft.Network/networkInterfaces/', parameters('nicName'))]" - ], - "location": "[variables('location')]", - "name": "[parameters('vmName')]", - "properties": { - "diagnosticsProfile": { - "bootDiagnostics": { - "enabled": false - } - }, - "hardwareProfile": { - "vmSize": "[parameters('vmSize')]" - }, - "networkProfile": { - "networkInterfaces": [ - { - "id": "[resourceId('Microsoft.Network/networkInterfaces', parameters('nicName'))]" - } - ] - }, - "osProfile": { - "adminUsername": "[parameters('adminUsername')]", - "computerName": "[parameters('vmName')]", - "linuxConfiguration": { - "disablePasswordAuthentication": true, - "ssh": { - "publicKeys": [ - { - "keyData": "", - "path": "[variables('sshKeyPath')]" - } - ] - } - } - }, - "storageProfile": { - "osDisk": { - "caching": "ReadWrite", - "createOption": "FromImage", - "image": { - "uri": "https://localhost/custom.vhd" - }, - "name": "[parameters('osDiskName')]", - "osType": "Linux", - "vhd": { - "uri": "[concat(parameters('storageAccountBlobEndpoint'),variables('vmStorageAccountContainerName'),'/', parameters('osDiskName'),'.vhd')]" - } - } - } - }, - "type": "Microsoft.Compute/virtualMachines" - } - ], - "variables": { - "addressPrefix": "10.0.0.0/16", - "apiVersion": "2017-03-30", - "location": "[resourceGroup().location]", - "managedDiskApiVersion": "2017-03-30", - "networkInterfacesApiVersion": "2017-04-01", - "networkSecurityGroupsApiVersion": "2019-04-01", - "publicIPAddressApiVersion": "2017-04-01", - "publicIPAddressType": "Dynamic", - "sshKeyPath": "[concat('/home/',parameters('adminUsername'),'/.ssh/authorized_keys')]", - "subnetAddressPrefix": "10.0.0.0/24", - "subnetName": "[parameters('subnetName')]", - "subnetRef": "[concat(variables('vnetID'),'/subnets/',variables('subnetName'))]", - "virtualNetworkName": "[parameters('virtualNetworkName')]", - "virtualNetworkResourceGroup": "[resourceGroup().name]", - "virtualNetworksApiVersion": "2017-04-01", - "vmStorageAccountContainerName": "images", - "vnetID": "[resourceId(variables('virtualNetworkResourceGroup'), 'Microsoft.Network/virtualNetworks', variables('virtualNetworkName'))]" - } -} \ No newline at end of file diff --git a/builder/azure/arm/template_factory_test.TestVirtualMachineDeployment05.approved.json b/builder/azure/arm/template_factory_test.TestVirtualMachineDeployment05.approved.json deleted file mode 100644 index f4cc6f3ab..000000000 --- a/builder/azure/arm/template_factory_test.TestVirtualMachineDeployment05.approved.json +++ /dev/null @@ -1,141 +0,0 @@ -{ - "$schema": "http://schema.management.azure.com/schemas/2014-04-01-preview/deploymentTemplate.json", - "contentVersion": "1.0.0.0", - "parameters": { - "adminPassword": { - "type": "string" - }, - "adminUsername": { - "type": "string" - }, - "dataDiskName": { - "type": "string" - }, - "dnsNameForPublicIP": { - "type": "string" - }, - "nicName": { - "type": "string" - }, - "nsgName": { - "type": "string" - }, - "osDiskName": { - "type": "string" - }, - "publicIPAddressName": { - "type": "string" - }, - "storageAccountBlobEndpoint": { - "type": "string" - }, - "subnetName": { - "type": "string" - }, - "virtualNetworkName": { - "type": "string" - }, - "vmName": { - "type": "string" - }, - "vmSize": { - "type": "string" - } - }, - "resources": [ - { - "apiVersion": "[variables('networkInterfacesApiVersion')]", - "dependsOn": [], - "location": "[variables('location')]", - "name": "[parameters('nicName')]", - "properties": { - "ipConfigurations": [ - { - "name": "ipconfig", - "properties": { - "privateIPAllocationMethod": "Dynamic", - "subnet": { - "id": "[variables('subnetRef')]" - } - } - } - ] - }, - "type": "Microsoft.Network/networkInterfaces" - }, - { - "apiVersion": "[variables('apiVersion')]", - "dependsOn": [ - "[concat('Microsoft.Network/networkInterfaces/', parameters('nicName'))]" - ], - "location": "[variables('location')]", - "name": "[parameters('vmName')]", - "properties": { - "diagnosticsProfile": { - "bootDiagnostics": { - "enabled": false - } - }, - "hardwareProfile": { - "vmSize": "[parameters('vmSize')]" - }, - "networkProfile": { - "networkInterfaces": [ - { - "id": "[resourceId('Microsoft.Network/networkInterfaces', parameters('nicName'))]" - } - ] - }, - "osProfile": { - "adminPassword": "[parameters('adminPassword')]", - "adminUsername": "[parameters('adminUsername')]", - "computerName": "[parameters('vmName')]", - "linuxConfiguration": { - "ssh": { - "publicKeys": [ - { - "keyData": "", - "path": "[variables('sshKeyPath')]" - } - ] - } - } - }, - "storageProfile": { - "osDisk": { - "caching": "ReadWrite", - "createOption": "FromImage", - "image": { - "uri": "https://localhost/custom.vhd" - }, - "name": "[parameters('osDiskName')]", - "osType": "Linux", - "vhd": { - "uri": "[concat(parameters('storageAccountBlobEndpoint'),variables('vmStorageAccountContainerName'),'/', parameters('osDiskName'),'.vhd')]" - } - } - } - }, - "type": "Microsoft.Compute/virtualMachines" - } - ], - "variables": { - "addressPrefix": "10.0.0.0/16", - "apiVersion": "2017-03-30", - "location": "[resourceGroup().location]", - "managedDiskApiVersion": "2017-03-30", - "networkInterfacesApiVersion": "2017-04-01", - "networkSecurityGroupsApiVersion": "2019-04-01", - "publicIPAddressApiVersion": "2017-04-01", - "publicIPAddressType": "Dynamic", - "sshKeyPath": "[concat('/home/',parameters('adminUsername'),'/.ssh/authorized_keys')]", - "subnetAddressPrefix": "10.0.0.0/24", - "subnetName": "virtualNetworkSubnetName", - "subnetRef": "[concat(variables('vnetID'),'/subnets/',variables('subnetName'))]", - "virtualNetworkName": "virtualNetworkName", - "virtualNetworkResourceGroup": "virtualNetworkResourceGroupName", - "virtualNetworksApiVersion": "2017-04-01", - "vmStorageAccountContainerName": "images", - "vnetID": "[resourceId(variables('virtualNetworkResourceGroup'), 'Microsoft.Network/virtualNetworks', variables('virtualNetworkName'))]" - } -} \ No newline at end of file diff --git a/builder/azure/arm/template_factory_test.TestVirtualMachineDeployment06.approved.json b/builder/azure/arm/template_factory_test.TestVirtualMachineDeployment06.approved.json deleted file mode 100644 index 74774714a..000000000 --- a/builder/azure/arm/template_factory_test.TestVirtualMachineDeployment06.approved.json +++ /dev/null @@ -1,200 +0,0 @@ -{ - "$schema": "http://schema.management.azure.com/schemas/2014-04-01-preview/deploymentTemplate.json", - "contentVersion": "1.0.0.0", - "parameters": { - "adminPassword": { - "type": "string" - }, - "adminUsername": { - "type": "string" - }, - "dataDiskName": { - "type": "string" - }, - "dnsNameForPublicIP": { - "type": "string" - }, - "nicName": { - "type": "string" - }, - "nsgName": { - "type": "string" - }, - "osDiskName": { - "type": "string" - }, - "publicIPAddressName": { - "type": "string" - }, - "storageAccountBlobEndpoint": { - "type": "string" - }, - "subnetName": { - "type": "string" - }, - "virtualNetworkName": { - "type": "string" - }, - "vmName": { - "type": "string" - }, - "vmSize": { - "type": "string" - } - }, - "resources": [ - { - "apiVersion": "[variables('publicIPAddressApiVersion')]", - "location": "[variables('location')]", - "name": "[parameters('publicIPAddressName')]", - "properties": { - "dnsSettings": { - "domainNameLabel": "[parameters('dnsNameForPublicIP')]" - }, - "publicIPAllocationMethod": "[variables('publicIPAddressType')]" - }, - "tags": { - "tag01": "value01", - "tag02": "value02", - "tag03": "value03" - }, - "type": "Microsoft.Network/publicIPAddresses" - }, - { - "apiVersion": "[variables('virtualNetworksApiVersion')]", - "location": "[variables('location')]", - "name": "[variables('virtualNetworkName')]", - "properties": { - "addressSpace": { - "addressPrefixes": [ - "[variables('addressPrefix')]" - ] - }, - "subnets": [ - { - "name": "[variables('subnetName')]", - "properties": { - "addressPrefix": "[variables('subnetAddressPrefix')]" - } - } - ] - }, - "tags": { - "tag01": "value01", - "tag02": "value02", - "tag03": "value03" - }, - "type": "Microsoft.Network/virtualNetworks" - }, - { - "apiVersion": "[variables('networkInterfacesApiVersion')]", - "dependsOn": [ - "[concat('Microsoft.Network/publicIPAddresses/', parameters('publicIPAddressName'))]", - "[concat('Microsoft.Network/virtualNetworks/', variables('virtualNetworkName'))]" - ], - "location": "[variables('location')]", - "name": "[parameters('nicName')]", - "properties": { - "ipConfigurations": [ - { - "name": "ipconfig", - "properties": { - "privateIPAllocationMethod": "Dynamic", - "publicIPAddress": { - "id": "[resourceId('Microsoft.Network/publicIPAddresses', parameters('publicIPAddressName'))]" - }, - "subnet": { - "id": "[variables('subnetRef')]" - } - } - } - ] - }, - "tags": { - "tag01": "value01", - "tag02": "value02", - "tag03": "value03" - }, - "type": "Microsoft.Network/networkInterfaces" - }, - { - "apiVersion": "[variables('apiVersion')]", - "dependsOn": [ - "[concat('Microsoft.Network/networkInterfaces/', parameters('nicName'))]" - ], - "location": "[variables('location')]", - "name": "[parameters('vmName')]", - "properties": { - "diagnosticsProfile": { - "bootDiagnostics": { - "enabled": false - } - }, - "hardwareProfile": { - "vmSize": "[parameters('vmSize')]" - }, - "networkProfile": { - "networkInterfaces": [ - { - "id": "[resourceId('Microsoft.Network/networkInterfaces', parameters('nicName'))]" - } - ] - }, - "osProfile": { - "adminUsername": "[parameters('adminUsername')]", - "computerName": "[parameters('vmName')]", - "linuxConfiguration": { - "disablePasswordAuthentication": true, - "ssh": { - "publicKeys": [ - { - "keyData": "", - "path": "[variables('sshKeyPath')]" - } - ] - } - } - }, - "storageProfile": { - "osDisk": { - "caching": "ReadWrite", - "createOption": "FromImage", - "image": { - "uri": "https://localhost/custom.vhd" - }, - "name": "[parameters('osDiskName')]", - "osType": "Linux", - "vhd": { - "uri": "[concat(parameters('storageAccountBlobEndpoint'),variables('vmStorageAccountContainerName'),'/', parameters('osDiskName'),'.vhd')]" - } - } - } - }, - "tags": { - "tag01": "value01", - "tag02": "value02", - "tag03": "value03" - }, - "type": "Microsoft.Compute/virtualMachines" - } - ], - "variables": { - "addressPrefix": "10.0.0.0/16", - "apiVersion": "2017-03-30", - "location": "[resourceGroup().location]", - "managedDiskApiVersion": "2017-03-30", - "networkInterfacesApiVersion": "2017-04-01", - "networkSecurityGroupsApiVersion": "2019-04-01", - "publicIPAddressApiVersion": "2017-04-01", - "publicIPAddressType": "Dynamic", - "sshKeyPath": "[concat('/home/',parameters('adminUsername'),'/.ssh/authorized_keys')]", - "subnetAddressPrefix": "10.0.0.0/24", - "subnetName": "[parameters('subnetName')]", - "subnetRef": "[concat(variables('vnetID'),'/subnets/',variables('subnetName'))]", - "virtualNetworkName": "[parameters('virtualNetworkName')]", - "virtualNetworkResourceGroup": "[resourceGroup().name]", - "virtualNetworksApiVersion": "2017-04-01", - "vmStorageAccountContainerName": "images", - "vnetID": "[resourceId(variables('virtualNetworkResourceGroup'), 'Microsoft.Network/virtualNetworks', variables('virtualNetworkName'))]" - } -} \ No newline at end of file diff --git a/builder/azure/arm/template_factory_test.TestVirtualMachineDeployment07.approved.json b/builder/azure/arm/template_factory_test.TestVirtualMachineDeployment07.approved.json deleted file mode 100644 index 191719eec..000000000 --- a/builder/azure/arm/template_factory_test.TestVirtualMachineDeployment07.approved.json +++ /dev/null @@ -1,181 +0,0 @@ -{ - "$schema": "http://schema.management.azure.com/schemas/2014-04-01-preview/deploymentTemplate.json", - "contentVersion": "1.0.0.0", - "parameters": { - "adminPassword": { - "type": "string" - }, - "adminUsername": { - "type": "string" - }, - "dataDiskName": { - "type": "string" - }, - "dnsNameForPublicIP": { - "type": "string" - }, - "nicName": { - "type": "string" - }, - "nsgName": { - "type": "string" - }, - "osDiskName": { - "type": "string" - }, - "publicIPAddressName": { - "type": "string" - }, - "storageAccountBlobEndpoint": { - "type": "string" - }, - "subnetName": { - "type": "string" - }, - "virtualNetworkName": { - "type": "string" - }, - "vmName": { - "type": "string" - }, - "vmSize": { - "type": "string" - } - }, - "resources": [ - { - "apiVersion": "[variables('publicIPAddressApiVersion')]", - "location": "[variables('location')]", - "name": "[parameters('publicIPAddressName')]", - "properties": { - "dnsSettings": { - "domainNameLabel": "[parameters('dnsNameForPublicIP')]" - }, - "publicIPAllocationMethod": "[variables('publicIPAddressType')]" - }, - "type": "Microsoft.Network/publicIPAddresses" - }, - { - "apiVersion": "[variables('virtualNetworksApiVersion')]", - "location": "[variables('location')]", - "name": "[variables('virtualNetworkName')]", - "properties": { - "addressSpace": { - "addressPrefixes": [ - "[variables('addressPrefix')]" - ] - }, - "subnets": [ - { - "name": "[variables('subnetName')]", - "properties": { - "addressPrefix": "[variables('subnetAddressPrefix')]" - } - } - ] - }, - "type": "Microsoft.Network/virtualNetworks" - }, - { - "apiVersion": "[variables('networkInterfacesApiVersion')]", - "dependsOn": [ - "[concat('Microsoft.Network/publicIPAddresses/', parameters('publicIPAddressName'))]", - "[concat('Microsoft.Network/virtualNetworks/', variables('virtualNetworkName'))]" - ], - "location": "[variables('location')]", - "name": "[parameters('nicName')]", - "properties": { - "ipConfigurations": [ - { - "name": "ipconfig", - "properties": { - "privateIPAllocationMethod": "Dynamic", - "publicIPAddress": { - "id": "[resourceId('Microsoft.Network/publicIPAddresses', parameters('publicIPAddressName'))]" - }, - "subnet": { - "id": "[variables('subnetRef')]" - } - } - } - ] - }, - "type": "Microsoft.Network/networkInterfaces" - }, - { - "apiVersion": "[variables('apiVersion')]", - "dependsOn": [ - "[concat('Microsoft.Network/networkInterfaces/', parameters('nicName'))]" - ], - "location": "[variables('location')]", - "name": "[parameters('vmName')]", - "properties": { - "diagnosticsProfile": { - "bootDiagnostics": { - "enabled": false - } - }, - "hardwareProfile": { - "vmSize": "[parameters('vmSize')]" - }, - "networkProfile": { - "networkInterfaces": [ - { - "id": "[resourceId('Microsoft.Network/networkInterfaces', parameters('nicName'))]" - } - ] - }, - "osProfile": { - "adminPassword": "[parameters('adminPassword')]", - "adminUsername": "[parameters('adminUsername')]", - "computerName": "[parameters('vmName')]", - "customData": "I2Nsb3VkLWNvbmZpZwpncm93cGFydDoKICBtb2RlOiBvZmYK", - "linuxConfiguration": { - "ssh": { - "publicKeys": [ - { - "keyData": "", - "path": "[variables('sshKeyPath')]" - } - ] - } - } - }, - "storageProfile": { - "osDisk": { - "caching": "ReadWrite", - "createOption": "FromImage", - "image": { - "uri": "https://localhost/custom.vhd" - }, - "name": "[parameters('osDiskName')]", - "osType": "Linux", - "vhd": { - "uri": "[concat(parameters('storageAccountBlobEndpoint'),variables('vmStorageAccountContainerName'),'/', parameters('osDiskName'),'.vhd')]" - } - } - } - }, - "type": "Microsoft.Compute/virtualMachines" - } - ], - "variables": { - "addressPrefix": "10.0.0.0/16", - "apiVersion": "2017-03-30", - "location": "[resourceGroup().location]", - "managedDiskApiVersion": "2017-03-30", - "networkInterfacesApiVersion": "2017-04-01", - "networkSecurityGroupsApiVersion": "2019-04-01", - "publicIPAddressApiVersion": "2017-04-01", - "publicIPAddressType": "Dynamic", - "sshKeyPath": "[concat('/home/',parameters('adminUsername'),'/.ssh/authorized_keys')]", - "subnetAddressPrefix": "10.0.0.0/24", - "subnetName": "[parameters('subnetName')]", - "subnetRef": "[concat(variables('vnetID'),'/subnets/',variables('subnetName'))]", - "virtualNetworkName": "[parameters('virtualNetworkName')]", - "virtualNetworkResourceGroup": "[resourceGroup().name]", - "virtualNetworksApiVersion": "2017-04-01", - "vmStorageAccountContainerName": "images", - "vnetID": "[resourceId(variables('virtualNetworkResourceGroup'), 'Microsoft.Network/virtualNetworks', variables('virtualNetworkName'))]" - } -} \ No newline at end of file diff --git a/builder/azure/arm/template_factory_test.TestVirtualMachineDeployment08.approved.json b/builder/azure/arm/template_factory_test.TestVirtualMachineDeployment08.approved.json deleted file mode 100644 index bd1445920..000000000 --- a/builder/azure/arm/template_factory_test.TestVirtualMachineDeployment08.approved.json +++ /dev/null @@ -1,180 +0,0 @@ -{ - "$schema": "http://schema.management.azure.com/schemas/2014-04-01-preview/deploymentTemplate.json", - "contentVersion": "1.0.0.0", - "parameters": { - "adminPassword": { - "type": "string" - }, - "adminUsername": { - "type": "string" - }, - "dataDiskName": { - "type": "string" - }, - "dnsNameForPublicIP": { - "type": "string" - }, - "nicName": { - "type": "string" - }, - "nsgName": { - "type": "string" - }, - "osDiskName": { - "type": "string" - }, - "publicIPAddressName": { - "type": "string" - }, - "storageAccountBlobEndpoint": { - "type": "string" - }, - "subnetName": { - "type": "string" - }, - "virtualNetworkName": { - "type": "string" - }, - "vmName": { - "type": "string" - }, - "vmSize": { - "type": "string" - } - }, - "resources": [ - { - "apiVersion": "[variables('publicIPAddressApiVersion')]", - "location": "[variables('location')]", - "name": "[parameters('publicIPAddressName')]", - "properties": { - "dnsSettings": { - "domainNameLabel": "[parameters('dnsNameForPublicIP')]" - }, - "publicIPAllocationMethod": "[variables('publicIPAddressType')]" - }, - "type": "Microsoft.Network/publicIPAddresses" - }, - { - "apiVersion": "[variables('virtualNetworksApiVersion')]", - "location": "[variables('location')]", - "name": "[variables('virtualNetworkName')]", - "properties": { - "addressSpace": { - "addressPrefixes": [ - "[variables('addressPrefix')]" - ] - }, - "subnets": [ - { - "name": "[variables('subnetName')]", - "properties": { - "addressPrefix": "[variables('subnetAddressPrefix')]" - } - } - ] - }, - "type": "Microsoft.Network/virtualNetworks" - }, - { - "apiVersion": "[variables('networkInterfacesApiVersion')]", - "dependsOn": [ - "[concat('Microsoft.Network/publicIPAddresses/', parameters('publicIPAddressName'))]", - "[concat('Microsoft.Network/virtualNetworks/', variables('virtualNetworkName'))]" - ], - "location": "[variables('location')]", - "name": "[parameters('nicName')]", - "properties": { - "ipConfigurations": [ - { - "name": "ipconfig", - "properties": { - "privateIPAllocationMethod": "Dynamic", - "publicIPAddress": { - "id": "[resourceId('Microsoft.Network/publicIPAddresses', parameters('publicIPAddressName'))]" - }, - "subnet": { - "id": "[variables('subnetRef')]" - } - } - } - ] - }, - "type": "Microsoft.Network/networkInterfaces" - }, - { - "apiVersion": "[variables('apiVersion')]", - "dependsOn": [ - "[concat('Microsoft.Network/networkInterfaces/', parameters('nicName'))]" - ], - "location": "[variables('location')]", - "name": "[parameters('vmName')]", - "properties": { - "diagnosticsProfile": { - "bootDiagnostics": { - "enabled": false - } - }, - "hardwareProfile": { - "vmSize": "[parameters('vmSize')]" - }, - "networkProfile": { - "networkInterfaces": [ - { - "id": "[resourceId('Microsoft.Network/networkInterfaces', parameters('nicName'))]" - } - ] - }, - "osProfile": { - "adminUsername": "[parameters('adminUsername')]", - "computerName": "[parameters('vmName')]", - "linuxConfiguration": { - "disablePasswordAuthentication": true, - "ssh": { - "publicKeys": [ - { - "keyData": "", - "path": "[variables('sshKeyPath')]" - } - ] - } - } - }, - "storageProfile": { - "imageReference": { - "id": "" - }, - "osDisk": { - "caching": "ReadWrite", - "createOption": "FromImage", - "managedDisk": { - "storageAccountType": "Standard_LRS" - }, - "name": "[parameters('osDiskName')]", - "osType": "Linux" - } - } - }, - "type": "Microsoft.Compute/virtualMachines" - } - ], - "variables": { - "addressPrefix": "10.0.0.0/16", - "apiVersion": "2017-03-30", - "location": "[resourceGroup().location]", - "managedDiskApiVersion": "2017-03-30", - "networkInterfacesApiVersion": "2017-04-01", - "networkSecurityGroupsApiVersion": "2019-04-01", - "publicIPAddressApiVersion": "2017-04-01", - "publicIPAddressType": "Dynamic", - "sshKeyPath": "[concat('/home/',parameters('adminUsername'),'/.ssh/authorized_keys')]", - "subnetAddressPrefix": "10.0.0.0/24", - "subnetName": "[parameters('subnetName')]", - "subnetRef": "[concat(variables('vnetID'),'/subnets/',variables('subnetName'))]", - "virtualNetworkName": "[parameters('virtualNetworkName')]", - "virtualNetworkResourceGroup": "[resourceGroup().name]", - "virtualNetworksApiVersion": "2017-04-01", - "vmStorageAccountContainerName": "images", - "vnetID": "[resourceId(variables('virtualNetworkResourceGroup'), 'Microsoft.Network/virtualNetworks', variables('virtualNetworkName'))]" - } -} \ No newline at end of file diff --git a/builder/azure/arm/template_factory_test.TestVirtualMachineDeployment09.approved.json b/builder/azure/arm/template_factory_test.TestVirtualMachineDeployment09.approved.json deleted file mode 100644 index b9a8c8d79..000000000 --- a/builder/azure/arm/template_factory_test.TestVirtualMachineDeployment09.approved.json +++ /dev/null @@ -1,183 +0,0 @@ -{ - "$schema": "http://schema.management.azure.com/schemas/2014-04-01-preview/deploymentTemplate.json", - "contentVersion": "1.0.0.0", - "parameters": { - "adminPassword": { - "type": "string" - }, - "adminUsername": { - "type": "string" - }, - "dataDiskName": { - "type": "string" - }, - "dnsNameForPublicIP": { - "type": "string" - }, - "nicName": { - "type": "string" - }, - "nsgName": { - "type": "string" - }, - "osDiskName": { - "type": "string" - }, - "publicIPAddressName": { - "type": "string" - }, - "storageAccountBlobEndpoint": { - "type": "string" - }, - "subnetName": { - "type": "string" - }, - "virtualNetworkName": { - "type": "string" - }, - "vmName": { - "type": "string" - }, - "vmSize": { - "type": "string" - } - }, - "resources": [ - { - "apiVersion": "[variables('publicIPAddressApiVersion')]", - "location": "[variables('location')]", - "name": "[parameters('publicIPAddressName')]", - "properties": { - "dnsSettings": { - "domainNameLabel": "[parameters('dnsNameForPublicIP')]" - }, - "publicIPAllocationMethod": "[variables('publicIPAddressType')]" - }, - "type": "Microsoft.Network/publicIPAddresses" - }, - { - "apiVersion": "[variables('virtualNetworksApiVersion')]", - "location": "[variables('location')]", - "name": "[variables('virtualNetworkName')]", - "properties": { - "addressSpace": { - "addressPrefixes": [ - "[variables('addressPrefix')]" - ] - }, - "subnets": [ - { - "name": "[variables('subnetName')]", - "properties": { - "addressPrefix": "[variables('subnetAddressPrefix')]" - } - } - ] - }, - "type": "Microsoft.Network/virtualNetworks" - }, - { - "apiVersion": "[variables('networkInterfacesApiVersion')]", - "dependsOn": [ - "[concat('Microsoft.Network/publicIPAddresses/', parameters('publicIPAddressName'))]", - "[concat('Microsoft.Network/virtualNetworks/', variables('virtualNetworkName'))]" - ], - "location": "[variables('location')]", - "name": "[parameters('nicName')]", - "properties": { - "ipConfigurations": [ - { - "name": "ipconfig", - "properties": { - "privateIPAllocationMethod": "Dynamic", - "publicIPAddress": { - "id": "[resourceId('Microsoft.Network/publicIPAddresses', parameters('publicIPAddressName'))]" - }, - "subnet": { - "id": "[variables('subnetRef')]" - } - } - } - ] - }, - "type": "Microsoft.Network/networkInterfaces" - }, - { - "apiVersion": "[variables('apiVersion')]", - "dependsOn": [ - "[concat('Microsoft.Network/networkInterfaces/', parameters('nicName'))]" - ], - "location": "[variables('location')]", - "name": "[parameters('vmName')]", - "properties": { - "diagnosticsProfile": { - "bootDiagnostics": { - "enabled": false - } - }, - "hardwareProfile": { - "vmSize": "[parameters('vmSize')]" - }, - "networkProfile": { - "networkInterfaces": [ - { - "id": "[resourceId('Microsoft.Network/networkInterfaces', parameters('nicName'))]" - } - ] - }, - "osProfile": { - "adminPassword": "[parameters('adminPassword')]", - "adminUsername": "[parameters('adminUsername')]", - "computerName": "[parameters('vmName')]", - "linuxConfiguration": { - "ssh": { - "publicKeys": [ - { - "keyData": "", - "path": "[variables('sshKeyPath')]" - } - ] - } - } - }, - "storageProfile": { - "imageReference": { - "offer": "--image-offer--", - "publisher": "--image-publisher--", - "sku": "--image-sku--", - "version": "--version--" - }, - "osDisk": { - "caching": "ReadWrite", - "createOption": "FromImage", - "managedDisk": { - "storageAccountType": "Standard_LRS" - }, - "name": "[parameters('osDiskName')]", - "osType": "Linux" - } - } - }, - "type": "Microsoft.Compute/virtualMachines" - } - ], - "variables": { - "addressPrefix": "10.0.0.0/16", - "apiVersion": "2017-03-30", - "location": "[resourceGroup().location]", - "managedDiskApiVersion": "2017-03-30", - "networkInterfacesApiVersion": "2017-04-01", - "networkSecurityGroupsApiVersion": "2019-04-01", - "publicIPAddressApiVersion": "2017-04-01", - "publicIPAddressType": "Dynamic", - "sshKeyPath": "[concat('/home/',parameters('adminUsername'),'/.ssh/authorized_keys')]", - "subnetAddressPrefix": "10.0.0.0/24", - "subnetName": "[parameters('subnetName')]", - "subnetRef": "[concat(variables('vnetID'),'/subnets/',variables('subnetName'))]", - "virtualNetworkName": "[parameters('virtualNetworkName')]", - "virtualNetworkResourceGroup": "[resourceGroup().name]", - "virtualNetworksApiVersion": "2017-04-01", - "vmStorageAccountContainerName": "images", - "vnetID": "[resourceId(variables('virtualNetworkResourceGroup'), 'Microsoft.Network/virtualNetworks', variables('virtualNetworkName'))]" - } -} \ No newline at end of file diff --git a/builder/azure/arm/template_factory_test.TestVirtualMachineDeployment10.approved.json b/builder/azure/arm/template_factory_test.TestVirtualMachineDeployment10.approved.json deleted file mode 100644 index d87964955..000000000 --- a/builder/azure/arm/template_factory_test.TestVirtualMachineDeployment10.approved.json +++ /dev/null @@ -1,161 +0,0 @@ -{ - "$schema": "http://schema.management.azure.com/schemas/2014-04-01-preview/deploymentTemplate.json", - "contentVersion": "1.0.0.0", - "parameters": { - "adminPassword": { - "type": "string" - }, - "adminUsername": { - "type": "string" - }, - "dataDiskName": { - "type": "string" - }, - "dnsNameForPublicIP": { - "type": "string" - }, - "nicName": { - "type": "string" - }, - "nsgName": { - "type": "string" - }, - "osDiskName": { - "type": "string" - }, - "publicIPAddressName": { - "type": "string" - }, - "storageAccountBlobEndpoint": { - "type": "string" - }, - "subnetName": { - "type": "string" - }, - "virtualNetworkName": { - "type": "string" - }, - "vmName": { - "type": "string" - }, - "vmSize": { - "type": "string" - } - }, - "resources": [ - { - "apiVersion": "[variables('publicIPAddressApiVersion')]", - "location": "[variables('location')]", - "name": "[parameters('publicIPAddressName')]", - "properties": { - "dnsSettings": { - "domainNameLabel": "[parameters('dnsNameForPublicIP')]" - }, - "publicIPAllocationMethod": "[variables('publicIPAddressType')]" - }, - "type": "Microsoft.Network/publicIPAddresses" - }, - { - "apiVersion": "[variables('networkInterfacesApiVersion')]", - "dependsOn": [ - "[concat('Microsoft.Network/publicIPAddresses/', parameters('publicIPAddressName'))]" - ], - "location": "[variables('location')]", - "name": "[parameters('nicName')]", - "properties": { - "ipConfigurations": [ - { - "name": "ipconfig", - "properties": { - "privateIPAllocationMethod": "Dynamic", - "publicIPAddress": { - "id": "[resourceId('Microsoft.Network/publicIPAddresses', parameters('publicIPAddressName'))]" - }, - "subnet": { - "id": "[variables('subnetRef')]" - } - } - } - ] - }, - "type": "Microsoft.Network/networkInterfaces" - }, - { - "apiVersion": "[variables('apiVersion')]", - "dependsOn": [ - "[concat('Microsoft.Network/networkInterfaces/', parameters('nicName'))]" - ], - "location": "[variables('location')]", - "name": "[parameters('vmName')]", - "properties": { - "diagnosticsProfile": { - "bootDiagnostics": { - "enabled": false - } - }, - "hardwareProfile": { - "vmSize": "[parameters('vmSize')]" - }, - "networkProfile": { - "networkInterfaces": [ - { - "id": "[resourceId('Microsoft.Network/networkInterfaces', parameters('nicName'))]" - } - ] - }, - "osProfile": { - "adminUsername": "[parameters('adminUsername')]", - "computerName": "[parameters('vmName')]", - "linuxConfiguration": { - "disablePasswordAuthentication": true, - "ssh": { - "publicKeys": [ - { - "keyData": "", - "path": "[variables('sshKeyPath')]" - } - ] - } - } - }, - "storageProfile": { - "imageReference": { - "offer": "--image-offer--", - "publisher": "--image-publisher--", - "sku": "--image-sku--", - "version": "--version--" - }, - "osDisk": { - "caching": "ReadWrite", - "createOption": "FromImage", - "managedDisk": { - "storageAccountType": "Standard_LRS" - }, - "name": "[parameters('osDiskName')]", - "osType": "Linux" - } - } - }, - "type": "Microsoft.Compute/virtualMachines" - } - ], - "variables": { - "addressPrefix": "10.0.0.0/16", - "apiVersion": "2017-03-30", - "location": "[resourceGroup().location]", - "managedDiskApiVersion": "2017-03-30", - "networkInterfacesApiVersion": "2017-04-01", - "networkSecurityGroupsApiVersion": "2019-04-01", - "publicIPAddressApiVersion": "2017-04-01", - "publicIPAddressType": "Dynamic", - "sshKeyPath": "[concat('/home/',parameters('adminUsername'),'/.ssh/authorized_keys')]", - "subnetAddressPrefix": "10.0.0.0/24", - "subnetName": "--virtual_network_subnet_name--", - "subnetRef": "[concat(variables('vnetID'),'/subnets/',variables('subnetName'))]", - "virtualNetworkName": "--virtual_network_name--", - "virtualNetworkResourceGroup": "--virtual_network_resource_group_name--", - "virtualNetworksApiVersion": "2017-04-01", - "vmStorageAccountContainerName": "images", - "vnetID": "[resourceId(variables('virtualNetworkResourceGroup'), 'Microsoft.Network/virtualNetworks', variables('virtualNetworkName'))]" - } -} \ No newline at end of file diff --git a/builder/azure/arm/template_factory_test.TestVirtualMachineDeployment11.approved.json b/builder/azure/arm/template_factory_test.TestVirtualMachineDeployment11.approved.json deleted file mode 100644 index 96af5d2e2..000000000 --- a/builder/azure/arm/template_factory_test.TestVirtualMachineDeployment11.approved.json +++ /dev/null @@ -1,194 +0,0 @@ -{ - "$schema": "http://schema.management.azure.com/schemas/2014-04-01-preview/deploymentTemplate.json", - "contentVersion": "1.0.0.0", - "parameters": { - "adminPassword": { - "type": "string" - }, - "adminUsername": { - "type": "string" - }, - "dataDiskName": { - "type": "string" - }, - "dnsNameForPublicIP": { - "type": "string" - }, - "nicName": { - "type": "string" - }, - "nsgName": { - "type": "string" - }, - "osDiskName": { - "type": "string" - }, - "publicIPAddressName": { - "type": "string" - }, - "storageAccountBlobEndpoint": { - "type": "string" - }, - "subnetName": { - "type": "string" - }, - "virtualNetworkName": { - "type": "string" - }, - "vmName": { - "type": "string" - }, - "vmSize": { - "type": "string" - } - }, - "resources": [ - { - "apiVersion": "[variables('publicIPAddressApiVersion')]", - "location": "[variables('location')]", - "name": "[parameters('publicIPAddressName')]", - "properties": { - "dnsSettings": { - "domainNameLabel": "[parameters('dnsNameForPublicIP')]" - }, - "publicIPAllocationMethod": "[variables('publicIPAddressType')]" - }, - "type": "Microsoft.Network/publicIPAddresses" - }, - { - "apiVersion": "[variables('virtualNetworksApiVersion')]", - "location": "[variables('location')]", - "name": "[variables('virtualNetworkName')]", - "properties": { - "addressSpace": { - "addressPrefixes": [ - "[variables('addressPrefix')]" - ] - }, - "subnets": [ - { - "name": "[variables('subnetName')]", - "properties": { - "addressPrefix": "[variables('subnetAddressPrefix')]" - } - } - ] - }, - "type": "Microsoft.Network/virtualNetworks" - }, - { - "apiVersion": "[variables('networkInterfacesApiVersion')]", - "dependsOn": [ - "[concat('Microsoft.Network/publicIPAddresses/', parameters('publicIPAddressName'))]", - "[concat('Microsoft.Network/virtualNetworks/', variables('virtualNetworkName'))]" - ], - "location": "[variables('location')]", - "name": "[parameters('nicName')]", - "properties": { - "ipConfigurations": [ - { - "name": "ipconfig", - "properties": { - "privateIPAllocationMethod": "Dynamic", - "publicIPAddress": { - "id": "[resourceId('Microsoft.Network/publicIPAddresses', parameters('publicIPAddressName'))]" - }, - "subnet": { - "id": "[variables('subnetRef')]" - } - } - } - ] - }, - "type": "Microsoft.Network/networkInterfaces" - }, - { - "apiVersion": "[variables('apiVersion')]", - "dependsOn": [ - "[concat('Microsoft.Network/networkInterfaces/', parameters('nicName'))]" - ], - "location": "[variables('location')]", - "name": "[parameters('vmName')]", - "properties": { - "diagnosticsProfile": { - "bootDiagnostics": { - "enabled": false - } - }, - "hardwareProfile": { - "vmSize": "[parameters('vmSize')]" - }, - "networkProfile": { - "networkInterfaces": [ - { - "id": "[resourceId('Microsoft.Network/networkInterfaces', parameters('nicName'))]" - } - ] - }, - "osProfile": { - "adminPassword": "[parameters('adminPassword')]", - "adminUsername": "[parameters('adminUsername')]", - "computerName": "[parameters('vmName')]", - "linuxConfiguration": { - "ssh": { - "publicKeys": [ - { - "keyData": "", - "path": "[variables('sshKeyPath')]" - } - ] - } - } - }, - "storageProfile": { - "dataDisks": [ - { - "caching": "ReadWrite", - "createOption": "Empty", - "diskSizeGB": 32, - "lun": 0, - "name": "[concat(parameters('dataDiskName'),'-1')]", - "vhd": { - "uri": "[concat(parameters('storageAccountBlobEndpoint'),variables('vmStorageAccountContainerName'),'/',parameters('dataDiskName'),'-1','.vhd')]" - } - } - ], - "imageReference": { - "offer": "--image-offer--", - "publisher": "--image-publisher--", - "sku": "--image-sku--", - "version": "--version--" - }, - "osDisk": { - "caching": "ReadWrite", - "createOption": "FromImage", - "name": "[parameters('osDiskName')]", - "vhd": { - "uri": "[concat(parameters('storageAccountBlobEndpoint'),variables('vmStorageAccountContainerName'),'/', parameters('osDiskName'),'.vhd')]" - } - } - } - }, - "type": "Microsoft.Compute/virtualMachines" - } - ], - "variables": { - "addressPrefix": "10.0.0.0/16", - "apiVersion": "2017-03-30", - "location": "[resourceGroup().location]", - "managedDiskApiVersion": "2017-03-30", - "networkInterfacesApiVersion": "2017-04-01", - "networkSecurityGroupsApiVersion": "2019-04-01", - "publicIPAddressApiVersion": "2017-04-01", - "publicIPAddressType": "Dynamic", - "sshKeyPath": "[concat('/home/',parameters('adminUsername'),'/.ssh/authorized_keys')]", - "subnetAddressPrefix": "10.0.0.0/24", - "subnetName": "[parameters('subnetName')]", - "subnetRef": "[concat(variables('vnetID'),'/subnets/',variables('subnetName'))]", - "virtualNetworkName": "[parameters('virtualNetworkName')]", - "virtualNetworkResourceGroup": "[resourceGroup().name]", - "virtualNetworksApiVersion": "2017-04-01", - "vmStorageAccountContainerName": "images", - "vnetID": "[resourceId(variables('virtualNetworkResourceGroup'), 'Microsoft.Network/virtualNetworks', variables('virtualNetworkName'))]" - } -} \ No newline at end of file diff --git a/builder/azure/arm/template_factory_test.TestVirtualMachineDeployment12.approved.json b/builder/azure/arm/template_factory_test.TestVirtualMachineDeployment12.approved.json deleted file mode 100644 index c6addd27a..000000000 --- a/builder/azure/arm/template_factory_test.TestVirtualMachineDeployment12.approved.json +++ /dev/null @@ -1,195 +0,0 @@ -{ - "$schema": "http://schema.management.azure.com/schemas/2014-04-01-preview/deploymentTemplate.json", - "contentVersion": "1.0.0.0", - "parameters": { - "adminPassword": { - "type": "string" - }, - "adminUsername": { - "type": "string" - }, - "dataDiskName": { - "type": "string" - }, - "dnsNameForPublicIP": { - "type": "string" - }, - "nicName": { - "type": "string" - }, - "nsgName": { - "type": "string" - }, - "osDiskName": { - "type": "string" - }, - "publicIPAddressName": { - "type": "string" - }, - "storageAccountBlobEndpoint": { - "type": "string" - }, - "subnetName": { - "type": "string" - }, - "virtualNetworkName": { - "type": "string" - }, - "vmName": { - "type": "string" - }, - "vmSize": { - "type": "string" - } - }, - "resources": [ - { - "apiVersion": "[variables('publicIPAddressApiVersion')]", - "location": "[variables('location')]", - "name": "[parameters('publicIPAddressName')]", - "properties": { - "dnsSettings": { - "domainNameLabel": "[parameters('dnsNameForPublicIP')]" - }, - "publicIPAllocationMethod": "[variables('publicIPAddressType')]" - }, - "type": "Microsoft.Network/publicIPAddresses" - }, - { - "apiVersion": "[variables('virtualNetworksApiVersion')]", - "location": "[variables('location')]", - "name": "[variables('virtualNetworkName')]", - "properties": { - "addressSpace": { - "addressPrefixes": [ - "[variables('addressPrefix')]" - ] - }, - "subnets": [ - { - "name": "[variables('subnetName')]", - "properties": { - "addressPrefix": "[variables('subnetAddressPrefix')]" - } - } - ] - }, - "type": "Microsoft.Network/virtualNetworks" - }, - { - "apiVersion": "[variables('networkInterfacesApiVersion')]", - "dependsOn": [ - "[concat('Microsoft.Network/publicIPAddresses/', parameters('publicIPAddressName'))]", - "[concat('Microsoft.Network/virtualNetworks/', variables('virtualNetworkName'))]" - ], - "location": "[variables('location')]", - "name": "[parameters('nicName')]", - "properties": { - "ipConfigurations": [ - { - "name": "ipconfig", - "properties": { - "privateIPAllocationMethod": "Dynamic", - "publicIPAddress": { - "id": "[resourceId('Microsoft.Network/publicIPAddresses', parameters('publicIPAddressName'))]" - }, - "subnet": { - "id": "[variables('subnetRef')]" - } - } - } - ] - }, - "type": "Microsoft.Network/networkInterfaces" - }, - { - "apiVersion": "[variables('apiVersion')]", - "dependsOn": [ - "[concat('Microsoft.Network/networkInterfaces/', parameters('nicName'))]" - ], - "location": "[variables('location')]", - "name": "[parameters('vmName')]", - "properties": { - "diagnosticsProfile": { - "bootDiagnostics": { - "enabled": false - } - }, - "hardwareProfile": { - "vmSize": "[parameters('vmSize')]" - }, - "networkProfile": { - "networkInterfaces": [ - { - "id": "[resourceId('Microsoft.Network/networkInterfaces', parameters('nicName'))]" - } - ] - }, - "osProfile": { - "adminUsername": "[parameters('adminUsername')]", - "computerName": "[parameters('vmName')]", - "linuxConfiguration": { - "disablePasswordAuthentication": true, - "ssh": { - "publicKeys": [ - { - "keyData": "", - "path": "[variables('sshKeyPath')]" - } - ] - } - } - }, - "storageProfile": { - "dataDisks": [ - { - "caching": "ReadWrite", - "createOption": "Empty", - "diskSizeGB": 32, - "lun": 0, - "managedDisk": { - "storageAccountType": "Standard_LRS" - }, - "name": "[concat(parameters('dataDiskName'),'-1')]" - } - ], - "imageReference": { - "offer": "--image-offer--", - "publisher": "--image-publisher--", - "sku": "--image-sku--", - "version": "--version--" - }, - "osDisk": { - "caching": "ReadWrite", - "createOption": "FromImage", - "managedDisk": { - "storageAccountType": "Standard_LRS" - }, - "name": "[parameters('osDiskName')]", - "osType": "Linux" - } - } - }, - "type": "Microsoft.Compute/virtualMachines" - } - ], - "variables": { - "addressPrefix": "10.0.0.0/16", - "apiVersion": "2017-03-30", - "location": "[resourceGroup().location]", - "managedDiskApiVersion": "2017-03-30", - "networkInterfacesApiVersion": "2017-04-01", - "networkSecurityGroupsApiVersion": "2019-04-01", - "publicIPAddressApiVersion": "2017-04-01", - "publicIPAddressType": "Dynamic", - "sshKeyPath": "[concat('/home/',parameters('adminUsername'),'/.ssh/authorized_keys')]", - "subnetAddressPrefix": "10.0.0.0/24", - "subnetName": "[parameters('subnetName')]", - "subnetRef": "[concat(variables('vnetID'),'/subnets/',variables('subnetName'))]", - "virtualNetworkName": "[parameters('virtualNetworkName')]", - "virtualNetworkResourceGroup": "[resourceGroup().name]", - "virtualNetworksApiVersion": "2017-04-01", - "vmStorageAccountContainerName": "images", - "vnetID": "[resourceId(variables('virtualNetworkResourceGroup'), 'Microsoft.Network/virtualNetworks', variables('virtualNetworkName'))]" - } -} \ No newline at end of file diff --git a/builder/azure/arm/template_factory_test.TestVirtualMachineDeployment13.approved.json b/builder/azure/arm/template_factory_test.TestVirtualMachineDeployment13.approved.json deleted file mode 100644 index 66d3689c5..000000000 --- a/builder/azure/arm/template_factory_test.TestVirtualMachineDeployment13.approved.json +++ /dev/null @@ -1,230 +0,0 @@ -{ - "$schema": "http://schema.management.azure.com/schemas/2014-04-01-preview/deploymentTemplate.json", - "contentVersion": "1.0.0.0", - "parameters": { - "adminPassword": { - "type": "string" - }, - "adminUsername": { - "type": "string" - }, - "dataDiskName": { - "type": "string" - }, - "dnsNameForPublicIP": { - "type": "string" - }, - "nicName": { - "type": "string" - }, - "nsgName": { - "type": "string" - }, - "osDiskName": { - "type": "string" - }, - "publicIPAddressName": { - "type": "string" - }, - "storageAccountBlobEndpoint": { - "type": "string" - }, - "subnetName": { - "type": "string" - }, - "virtualNetworkName": { - "type": "string" - }, - "vmName": { - "type": "string" - }, - "vmSize": { - "type": "string" - } - }, - "resources": [ - { - "apiVersion": "[variables('publicIPAddressApiVersion')]", - "location": "[variables('location')]", - "name": "[parameters('publicIPAddressName')]", - "properties": { - "dnsSettings": { - "domainNameLabel": "[parameters('dnsNameForPublicIP')]" - }, - "publicIPAllocationMethod": "[variables('publicIPAddressType')]" - }, - "type": "Microsoft.Network/publicIPAddresses" - }, - { - "apiVersion": "[variables('networkInterfacesApiVersion')]", - "dependsOn": [ - "[concat('Microsoft.Network/publicIPAddresses/', parameters('publicIPAddressName'))]", - "[concat('Microsoft.Network/virtualNetworks/', variables('virtualNetworkName'))]" - ], - "location": "[variables('location')]", - "name": "[parameters('nicName')]", - "properties": { - "ipConfigurations": [ - { - "name": "ipconfig", - "properties": { - "privateIPAllocationMethod": "Dynamic", - "publicIPAddress": { - "id": "[resourceId('Microsoft.Network/publicIPAddresses', parameters('publicIPAddressName'))]" - }, - "subnet": { - "id": "[variables('subnetRef')]" - } - } - } - ] - }, - "type": "Microsoft.Network/networkInterfaces" - }, - { - "apiVersion": "[variables('apiVersion')]", - "dependsOn": [ - "[concat('Microsoft.Network/networkInterfaces/', parameters('nicName'))]" - ], - "location": "[variables('location')]", - "name": "[parameters('vmName')]", - "properties": { - "diagnosticsProfile": { - "bootDiagnostics": { - "enabled": false - } - }, - "hardwareProfile": { - "vmSize": "[parameters('vmSize')]" - }, - "networkProfile": { - "networkInterfaces": [ - { - "id": "[resourceId('Microsoft.Network/networkInterfaces', parameters('nicName'))]" - } - ] - }, - "osProfile": { - "adminPassword": "[parameters('adminPassword')]", - "adminUsername": "[parameters('adminUsername')]", - "computerName": "[parameters('vmName')]", - "secrets": [ - { - "sourceVault": { - "id": "[resourceId(resourceGroup().name, 'Microsoft.KeyVault/vaults', '--keyvault-name--')]" - }, - "vaultCertificates": [ - { - "certificateStore": "My", - "certificateUrl": "" - } - ] - } - ], - "windowsConfiguration": { - "provisionVMAgent": true, - "winRM": { - "listeners": [ - { - "certificateUrl": "", - "protocol": "https" - } - ] - } - } - }, - "storageProfile": { - "imageReference": { - "offer": "--image-offer--", - "publisher": "--image-publisher--", - "sku": "--image-sku--", - "version": "--version--" - }, - "osDisk": { - "caching": "ReadWrite", - "createOption": "FromImage", - "managedDisk": { - "storageAccountType": "Standard_LRS" - }, - "name": "[parameters('osDiskName')]", - "osType": "Windows" - } - } - }, - "type": "Microsoft.Compute/virtualMachines" - }, - { - "apiVersion": "[variables('networkSecurityGroupsApiVersion')]", - "location": "[variables('location')]", - "name": "[parameters('nsgName')]", - "properties": { - "securityRules": [ - { - "name": "AllowIPsToSshWinRMInbound", - "properties": { - "access": "Allow", - "description": "Allow inbound traffic from specified IP addresses", - "destinationAddressPrefix": "VirtualNetwork", - "destinationPortRange": "5985", - "direction": "Inbound", - "priority": 100, - "protocol": "Tcp", - "sourceAddressPrefixes": [ - "127.0.0.1", - "192.168.100.0/24" - ], - "sourcePortRange": "*" - } - } - ] - }, - "type": "Microsoft.Network/networkSecurityGroups" - }, - { - "apiVersion": "[variables('virtualNetworksApiVersion')]", - "dependsOn": [ - "[concat('Microsoft.Network/networkSecurityGroups/', parameters('nsgName'))]" - ], - "location": "[variables('location')]", - "name": "[variables('virtualNetworkName')]", - "properties": { - "addressSpace": { - "addressPrefixes": [ - "[variables('addressPrefix')]" - ] - }, - "subnets": [ - { - "name": "[variables('subnetName')]", - "properties": { - "addressPrefix": "[variables('subnetAddressPrefix')]", - "networkSecurityGroup": { - "id": "[resourceId('Microsoft.Network/networkSecurityGroups', parameters('nsgName'))]" - } - } - } - ] - }, - "type": "Microsoft.Network/virtualNetworks" - } - ], - "variables": { - "addressPrefix": "10.0.0.0/16", - "apiVersion": "2017-03-30", - "location": "[resourceGroup().location]", - "managedDiskApiVersion": "2017-03-30", - "networkInterfacesApiVersion": "2017-04-01", - "networkSecurityGroupsApiVersion": "2019-04-01", - "publicIPAddressApiVersion": "2017-04-01", - "publicIPAddressType": "Dynamic", - "sshKeyPath": "[concat('/home/',parameters('adminUsername'),'/.ssh/authorized_keys')]", - "subnetAddressPrefix": "10.0.0.0/24", - "subnetName": "[parameters('subnetName')]", - "subnetRef": "[concat(variables('vnetID'),'/subnets/',variables('subnetName'))]", - "virtualNetworkName": "[parameters('virtualNetworkName')]", - "virtualNetworkResourceGroup": "[resourceGroup().name]", - "virtualNetworksApiVersion": "2017-04-01", - "vmStorageAccountContainerName": "images", - "vnetID": "[resourceId(variables('virtualNetworkResourceGroup'), 'Microsoft.Network/virtualNetworks', variables('virtualNetworkName'))]" - } -} \ No newline at end of file diff --git a/builder/azure/arm/template_factory_test.TestVirtualMachineDeployment14.approved.json b/builder/azure/arm/template_factory_test.TestVirtualMachineDeployment14.approved.json deleted file mode 100644 index 36182b82d..000000000 --- a/builder/azure/arm/template_factory_test.TestVirtualMachineDeployment14.approved.json +++ /dev/null @@ -1,181 +0,0 @@ -{ - "$schema": "http://schema.management.azure.com/schemas/2014-04-01-preview/deploymentTemplate.json", - "contentVersion": "1.0.0.0", - "parameters": { - "adminPassword": { - "type": "string" - }, - "adminUsername": { - "type": "string" - }, - "dataDiskName": { - "type": "string" - }, - "dnsNameForPublicIP": { - "type": "string" - }, - "nicName": { - "type": "string" - }, - "nsgName": { - "type": "string" - }, - "osDiskName": { - "type": "string" - }, - "publicIPAddressName": { - "type": "string" - }, - "storageAccountBlobEndpoint": { - "type": "string" - }, - "subnetName": { - "type": "string" - }, - "virtualNetworkName": { - "type": "string" - }, - "vmName": { - "type": "string" - }, - "vmSize": { - "type": "string" - } - }, - "resources": [ - { - "apiVersion": "[variables('publicIPAddressApiVersion')]", - "location": "[variables('location')]", - "name": "[parameters('publicIPAddressName')]", - "properties": { - "dnsSettings": { - "domainNameLabel": "[parameters('dnsNameForPublicIP')]" - }, - "publicIPAllocationMethod": "[variables('publicIPAddressType')]" - }, - "type": "Microsoft.Network/publicIPAddresses" - }, - { - "apiVersion": "[variables('virtualNetworksApiVersion')]", - "location": "[variables('location')]", - "name": "[variables('virtualNetworkName')]", - "properties": { - "addressSpace": { - "addressPrefixes": [ - "[variables('addressPrefix')]" - ] - }, - "subnets": [ - { - "name": "[variables('subnetName')]", - "properties": { - "addressPrefix": "[variables('subnetAddressPrefix')]" - } - } - ] - }, - "type": "Microsoft.Network/virtualNetworks" - }, - { - "apiVersion": "[variables('networkInterfacesApiVersion')]", - "dependsOn": [ - "[concat('Microsoft.Network/publicIPAddresses/', parameters('publicIPAddressName'))]", - "[concat('Microsoft.Network/virtualNetworks/', variables('virtualNetworkName'))]" - ], - "location": "[variables('location')]", - "name": "[parameters('nicName')]", - "properties": { - "ipConfigurations": [ - { - "name": "ipconfig", - "properties": { - "privateIPAllocationMethod": "Dynamic", - "publicIPAddress": { - "id": "[resourceId('Microsoft.Network/publicIPAddresses', parameters('publicIPAddressName'))]" - }, - "subnet": { - "id": "[variables('subnetRef')]" - } - } - } - ] - }, - "type": "Microsoft.Network/networkInterfaces" - }, - { - "apiVersion": "[variables('apiVersion')]", - "dependsOn": [ - "[concat('Microsoft.Network/networkInterfaces/', parameters('nicName'))]" - ], - "location": "[variables('location')]", - "name": "[parameters('vmName')]", - "properties": { - "diagnosticsProfile": { - "bootDiagnostics": { - "enabled": true, - "storageUri": "https://diagstgaccnt.blob.core.windows.net" - } - }, - "hardwareProfile": { - "vmSize": "[parameters('vmSize')]" - }, - "networkProfile": { - "networkInterfaces": [ - { - "id": "[resourceId('Microsoft.Network/networkInterfaces', parameters('nicName'))]" - } - ] - }, - "osProfile": { - "adminUsername": "[parameters('adminUsername')]", - "computerName": "[parameters('vmName')]", - "linuxConfiguration": { - "disablePasswordAuthentication": true, - "ssh": { - "publicKeys": [ - { - "keyData": "", - "path": "[variables('sshKeyPath')]" - } - ] - } - } - }, - "storageProfile": { - "imageReference": { - "id": "" - }, - "osDisk": { - "caching": "ReadWrite", - "createOption": "FromImage", - "managedDisk": { - "storageAccountType": "Standard_LRS" - }, - "name": "[parameters('osDiskName')]", - "osType": "Linux" - } - } - }, - "type": "Microsoft.Compute/virtualMachines" - } - ], - "variables": { - "addressPrefix": "10.0.0.0/16", - "apiVersion": "2017-03-30", - "location": "[resourceGroup().location]", - "managedDiskApiVersion": "2017-03-30", - "networkInterfacesApiVersion": "2017-04-01", - "networkSecurityGroupsApiVersion": "2019-04-01", - "publicIPAddressApiVersion": "2017-04-01", - "publicIPAddressType": "Dynamic", - "sshKeyPath": "[concat('/home/',parameters('adminUsername'),'/.ssh/authorized_keys')]", - "subnetAddressPrefix": "10.0.0.0/24", - "subnetName": "[parameters('subnetName')]", - "subnetRef": "[concat(variables('vnetID'),'/subnets/',variables('subnetName'))]", - "virtualNetworkName": "[parameters('virtualNetworkName')]", - "virtualNetworkResourceGroup": "[resourceGroup().name]", - "virtualNetworksApiVersion": "2017-04-01", - "vmStorageAccountContainerName": "images", - "vnetID": "[resourceId(variables('virtualNetworkResourceGroup'), 'Microsoft.Network/virtualNetworks', variables('virtualNetworkName'))]" - } -} \ No newline at end of file diff --git a/builder/azure/arm/template_factory_test.go b/builder/azure/arm/template_factory_test.go deleted file mode 100644 index f0e026a26..000000000 --- a/builder/azure/arm/template_factory_test.go +++ /dev/null @@ -1,659 +0,0 @@ -package arm - -import ( - "encoding/base64" - "encoding/json" - "testing" - - "github.com/Azure/azure-sdk-for-go/services/resources/mgmt/2018-02-01/resources" - approvaltests "github.com/approvals/go-approval-tests" - "github.com/hashicorp/packer/builder/azure/common/constants" - "github.com/hashicorp/packer/builder/azure/common/template" -) - -// Ensure the link values are not set, and the concrete values are set. -func TestVirtualMachineDeployment00(t *testing.T) { - var c Config - c.Prepare(getArmBuilderConfiguration(), getPackerConfiguration()) - deployment, err := GetVirtualMachineDeployment(&c) - if err != nil { - t.Fatal(err) - } - - if deployment.Properties.Mode != resources.Incremental { - t.Errorf("Expected deployment.Properties.Mode to be %s, but got %s", resources.Incremental, deployment.Properties.Mode) - } - - if deployment.Properties.ParametersLink != nil { - t.Error("Expected the ParametersLink to be nil!") - } - - if deployment.Properties.TemplateLink != nil { - t.Error("Expected the TemplateLink to be nil!") - } - - if deployment.Properties.Parameters == nil { - t.Error("Expected the Parameters to not be nil!") - } - - if deployment.Properties.Template == nil { - t.Error("Expected the Template to not be nil!") - } -} - -// Ensure the Virtual Machine template is a valid JSON document. -func TestVirtualMachineDeployment01(t *testing.T) { - var c Config - c.Prepare(getArmBuilderConfiguration(), getPackerConfiguration()) - deployment, err := GetVirtualMachineDeployment(&c) - if err != nil { - t.Fatal(err) - } - - _, err = json.Marshal(deployment.Properties.Template) - if err != nil { - t.Fatal(err) - } -} - -// Ensure the Virtual Machine template parameters are correct. -func TestVirtualMachineDeployment02(t *testing.T) { - var c Config - c.Prepare(getArmBuilderConfiguration(), getPackerConfiguration()) - deployment, err := GetVirtualMachineDeployment(&c) - if err != nil { - t.Fatal(err) - } - - bs, err := json.Marshal(deployment.Properties.Parameters) - if err != nil { - t.Fatal(err) - } - - var params template.TemplateParameters - err = json.Unmarshal(bs, ¶ms) - if err != nil { - t.Fatal(err) - } - - if params.AdminUsername.Value != c.UserName { - t.Errorf("Expected template parameter 'AdminUsername' to be %s, but got %s.", params.AdminUsername.Value, c.UserName) - } - if params.AdminPassword.Value != c.tmpAdminPassword { - t.Errorf("Expected template parameter 'AdminPassword' to be %s, but got %s.", params.AdminPassword.Value, c.tmpAdminPassword) - } - if params.DnsNameForPublicIP.Value != c.tmpComputeName { - t.Errorf("Expected template parameter 'DnsNameForPublicIP' to be %s, but got %s.", params.DnsNameForPublicIP.Value, c.tmpComputeName) - } - if params.OSDiskName.Value != c.tmpOSDiskName { - t.Errorf("Expected template parameter 'OSDiskName' to be %s, but got %s.", params.OSDiskName.Value, c.tmpOSDiskName) - } - if params.StorageAccountBlobEndpoint.Value != c.storageAccountBlobEndpoint { - t.Errorf("Expected template parameter 'StorageAccountBlobEndpoint' to be %s, but got %s.", params.StorageAccountBlobEndpoint.Value, c.storageAccountBlobEndpoint) - } - if params.VMSize.Value != c.VMSize { - t.Errorf("Expected template parameter 'VMSize' to be %s, but got %s.", params.VMSize.Value, c.VMSize) - } - if params.VMName.Value != c.tmpComputeName { - t.Errorf("Expected template parameter 'VMName' to be %s, but got %s.", params.VMName.Value, c.tmpComputeName) - } -} - -// Ensure the VM template is correct when using a market place image. -func TestVirtualMachineDeployment03(t *testing.T) { - m := getArmBuilderConfiguration() - m["image_publisher"] = "ImagePublisher" - m["image_offer"] = "ImageOffer" - m["image_sku"] = "ImageSku" - m["image_version"] = "ImageVersion" - - var c Config - _, err := c.Prepare(m, getPackerConfiguration(), getPackerSSHPasswordCommunicatorConfiguration()) - if err != nil { - t.Fatal(err) - } - deployment, err := GetVirtualMachineDeployment(&c) - if err != nil { - t.Fatal(err) - } - - err = approvaltests.VerifyJSONStruct(t, deployment.Properties.Template) - if err != nil { - t.Fatal(err) - } -} - -// Ensure the VM template is correct when using a custom image. -func TestVirtualMachineDeployment04(t *testing.T) { - config := map[string]string{ - "capture_name_prefix": "ignore", - "capture_container_name": "ignore", - "location": "ignore", - "image_url": "https://localhost/custom.vhd", - "resource_group_name": "ignore", - "storage_account": "ignore", - "subscription_id": "ignore", - "os_type": constants.Target_Linux, - "communicator": "none", - } - - var c Config - _, err := c.Prepare(config, getPackerConfiguration()) - if err != nil { - t.Fatal(err) - } - - deployment, err := GetVirtualMachineDeployment(&c) - if err != nil { - t.Fatal(err) - } - - err = approvaltests.VerifyJSONStruct(t, deployment.Properties.Template) - if err != nil { - t.Fatal(err) - } -} - -func TestVirtualMachineDeployment05(t *testing.T) { - config := map[string]string{ - "capture_name_prefix": "ignore", - "capture_container_name": "ignore", - "location": "ignore", - "image_url": "https://localhost/custom.vhd", - "resource_group_name": "ignore", - "storage_account": "ignore", - "subscription_id": "ignore", - "os_type": constants.Target_Linux, - "communicator": "none", - "virtual_network_name": "virtualNetworkName", - "virtual_network_resource_group_name": "virtualNetworkResourceGroupName", - "virtual_network_subnet_name": "virtualNetworkSubnetName", - } - - var c Config - _, err := c.Prepare(config, getPackerConfiguration(), getPackerSSHPasswordCommunicatorConfiguration()) - if err != nil { - t.Fatal(err) - } - - deployment, err := GetVirtualMachineDeployment(&c) - if err != nil { - t.Fatal(err) - } - - err = approvaltests.VerifyJSONStruct(t, deployment.Properties.Template) - if err != nil { - t.Fatal(err) - } -} - -// Verify that tags are properly applied to every resource -func TestVirtualMachineDeployment06(t *testing.T) { - config := map[string]interface{}{ - "capture_name_prefix": "ignore", - "capture_container_name": "ignore", - "location": "ignore", - "image_url": "https://localhost/custom.vhd", - "resource_group_name": "ignore", - "storage_account": "ignore", - "subscription_id": "ignore", - "os_type": constants.Target_Linux, - "communicator": "none", - "azure_tags": map[string]string{ - "tag01": "value01", - "tag02": "value02", - "tag03": "value03", - }, - } - - var c Config - _, err := c.Prepare(config, getPackerConfiguration()) - if err != nil { - t.Fatal(err) - } - - deployment, err := GetVirtualMachineDeployment(&c) - if err != nil { - t.Fatal(err) - } - - err = approvaltests.VerifyJSONStruct(t, deployment.Properties.Template) - if err != nil { - t.Fatal(err) - } -} - -// Verify that custom data are properly inserted -func TestVirtualMachineDeployment07(t *testing.T) { - config := map[string]interface{}{ - "capture_name_prefix": "ignore", - "capture_container_name": "ignore", - "location": "ignore", - "image_url": "https://localhost/custom.vhd", - "resource_group_name": "ignore", - "storage_account": "ignore", - "subscription_id": "ignore", - "os_type": constants.Target_Linux, - "communicator": "none", - } - - var c Config - _, err := c.Prepare(config, getPackerConfiguration(), getPackerSSHPasswordCommunicatorConfiguration()) - if err != nil { - t.Fatal(err) - } - - // The user specifies a configuration value for the setting custom_data_file. - // The config type will read that file, and base64 encode it. The encoded - // contents are then assigned to Config's customData property, which are directly - // injected into the template. - // - // I am not aware of an easy to mimic this situation in a test without having - // a file on disk, which I am loathe to do. The alternative is to inject base64 - // encoded data myself, which is what I am doing here. - customData := `#cloud-config -growpart: - mode: off -` - base64CustomData := base64.StdEncoding.EncodeToString([]byte(customData)) - c.customData = base64CustomData - - deployment, err := GetVirtualMachineDeployment(&c) - if err != nil { - t.Fatal(err) - } - - err = approvaltests.VerifyJSONStruct(t, deployment.Properties.Template) - if err != nil { - t.Fatal(err) - } -} - -// Ensure the VM template is correct when building from a custom managed image. -func TestVirtualMachineDeployment08(t *testing.T) { - config := map[string]interface{}{ - "location": "ignore", - "subscription_id": "ignore", - "os_type": constants.Target_Linux, - "communicator": "none", - "custom_managed_image_resource_group_name": "CustomManagedImageResourceGroupName", - "custom_managed_image_name": "CustomManagedImageName", - "managed_image_name": "ManagedImageName", - "managed_image_resource_group_name": "ManagedImageResourceGroupName", - } - - var c Config - _, err := c.Prepare(config, getPackerConfiguration()) - if err != nil { - t.Fatal(err) - } - - deployment, err := GetVirtualMachineDeployment(&c) - if err != nil { - t.Fatal(err) - } - - err = approvaltests.VerifyJSONStruct(t, deployment.Properties.Template) - if err != nil { - t.Fatal(err) - } -} - -// Ensure the VM template is correct when building from a platform managed image. -func TestVirtualMachineDeployment09(t *testing.T) { - config := map[string]interface{}{ - "location": "ignore", - "subscription_id": "ignore", - "os_type": constants.Target_Linux, - "communicator": "none", - "image_publisher": "--image-publisher--", - "image_offer": "--image-offer--", - "image_sku": "--image-sku--", - "image_version": "--version--", - "managed_image_name": "ManagedImageName", - "managed_image_resource_group_name": "ManagedImageResourceGroupName", - } - - var c Config - _, err := c.Prepare(config, getPackerConfiguration(), getPackerSSHPasswordCommunicatorConfiguration()) - if err != nil { - t.Fatal(err) - } - - deployment, err := GetVirtualMachineDeployment(&c) - if err != nil { - t.Fatal(err) - } - - err = approvaltests.VerifyJSONStruct(t, deployment.Properties.Template) - if err != nil { - t.Fatal(err) - } -} - -// Ensure the VM template is correct when building with PublicIp and connect to Private Network -func TestVirtualMachineDeployment10(t *testing.T) { - config := map[string]interface{}{ - "location": "ignore", - "subscription_id": "ignore", - "os_type": constants.Target_Linux, - "communicator": "none", - "image_publisher": "--image-publisher--", - "image_offer": "--image-offer--", - "image_sku": "--image-sku--", - "image_version": "--version--", - - "virtual_network_resource_group_name": "--virtual_network_resource_group_name--", - "virtual_network_name": "--virtual_network_name--", - "virtual_network_subnet_name": "--virtual_network_subnet_name--", - "private_virtual_network_with_public_ip": true, - - "managed_image_name": "ManagedImageName", - "managed_image_resource_group_name": "ManagedImageResourceGroupName", - } - - var c Config - _, err := c.Prepare(config, getPackerConfiguration()) - if err != nil { - t.Fatal(err) - } - - deployment, err := GetVirtualMachineDeployment(&c) - if err != nil { - t.Fatal(err) - } - - err = approvaltests.VerifyJSONStruct(t, deployment.Properties.Template) - if err != nil { - t.Fatal(err) - } -} - -// Ensure the VM template is correct when building with additional unmanaged disks -func TestVirtualMachineDeployment11(t *testing.T) { - config := map[string]interface{}{ - "location": "ignore", - "subscription_id": "ignore", - "os_type": constants.Target_Linux, - "communicator": "none", - "image_publisher": "--image-publisher--", - "image_offer": "--image-offer--", - "image_sku": "--image-sku--", - "image_version": "--version--", - - "disk_additional_size": []uint{32}, - - "resource_group_name": "packergroup", - "storage_account": "packerartifacts", - "capture_name_prefix": "packer", - "capture_container_name": "packerimages", - } - - var c Config - _, err := c.Prepare(config, getPackerConfiguration(), getPackerSSHPasswordCommunicatorConfiguration()) - if err != nil { - t.Fatal(err) - } - - deployment, err := GetVirtualMachineDeployment(&c) - if err != nil { - t.Fatal(err) - } - - err = approvaltests.VerifyJSONStruct(t, deployment.Properties.Template) - if err != nil { - t.Fatal(err) - } -} - -// Ensure the VM template is correct when building with additional managed disks -func TestVirtualMachineDeployment12(t *testing.T) { - config := map[string]interface{}{ - "location": "ignore", - "subscription_id": "ignore", - "os_type": constants.Target_Linux, - "communicator": "none", - "image_publisher": "--image-publisher--", - "image_offer": "--image-offer--", - "image_sku": "--image-sku--", - "image_version": "--version--", - - "disk_additional_size": []uint{32}, - - "managed_image_name": "ManagedImageName", - "managed_image_resource_group_name": "ManagedImageResourceGroupName", - } - - var c Config - _, err := c.Prepare(config, getPackerConfiguration()) - if err != nil { - t.Fatal(err) - } - - deployment, err := GetVirtualMachineDeployment(&c) - if err != nil { - t.Fatal(err) - } - - err = approvaltests.VerifyJSONStruct(t, deployment.Properties.Template) - if err != nil { - t.Fatal(err) - } -} - -// Ensure the VM template is correct when building with list of allowed IP addresses -func TestVirtualMachineDeployment13(t *testing.T) { - config := map[string]interface{}{ - "location": "ignore", - "subscription_id": "ignore", - "os_type": constants.Target_Windows, - "communicator": "winrm", - "winrm_username": "ignore", - "image_publisher": "--image-publisher--", - "image_offer": "--image-offer--", - "image_sku": "--image-sku--", - "image_version": "--version--", - "managed_image_name": "ManagedImageName", - "managed_image_resource_group_name": "ManagedImageResourceGroupName", - "allowed_inbound_ip_addresses": []string{"127.0.0.1", "192.168.100.0/24"}, - } - - var c Config - _, err := c.Prepare(config, getPackerConfiguration()) - if err != nil { - t.Fatal(err) - } - c.tmpKeyVaultName = "--keyvault-name--" - - deployment, err := GetVirtualMachineDeployment(&c) - if err != nil { - t.Fatal(err) - } - - err = approvaltests.VerifyJSONStruct(t, deployment.Properties.Template) - if err != nil { - t.Fatal(err) - } -} - -// Ensure the VM template is correct when building with bootdiagnostics -func TestVirtualMachineDeployment14(t *testing.T) { - config := map[string]interface{}{ - "location": "ignore", - "subscription_id": "ignore", - "os_type": constants.Target_Linux, - "communicator": "none", - "custom_managed_image_resource_group_name": "CustomManagedImageResourceGroupName", - "custom_managed_image_name": "CustomManagedImageName", - "managed_image_name": "ManagedImageName", - "managed_image_resource_group_name": "ManagedImageResourceGroupName", - "boot_diag_storage_account": "diagstgaccnt", - } - - var c Config - _, err := c.Prepare(config, getPackerConfiguration()) - if err != nil { - t.Fatal(err) - } - - deployment, err := GetVirtualMachineDeployment(&c) - if err != nil { - t.Fatal(err) - } - - err = approvaltests.VerifyJSONStruct(t, deployment.Properties.Template) - if err != nil { - t.Fatal(err) - } -} - -// Ensure the link values are not set, and the concrete values are set. -func TestKeyVaultDeployment00(t *testing.T) { - var c Config - c.Prepare(getArmBuilderConfiguration(), getPackerConfiguration()) - deployment, err := GetKeyVaultDeployment(&c) - if err != nil { - t.Fatal(err) - } - - if deployment.Properties.Mode != resources.Incremental { - t.Errorf("Expected deployment.Properties.Mode to be %s, but got %s", resources.Incremental, deployment.Properties.Mode) - } - - if deployment.Properties.ParametersLink != nil { - t.Error("Expected the ParametersLink to be nil!") - } - - if deployment.Properties.TemplateLink != nil { - t.Error("Expected the TemplateLink to be nil!") - } - - if deployment.Properties.Parameters == nil { - t.Error("Expected the Parameters to not be nil!") - } - - if deployment.Properties.Template == nil { - t.Error("Expected the Template to not be nil!") - } -} - -// Ensure the KeyVault template is a valid JSON document. -func TestKeyVaultDeployment01(t *testing.T) { - var c Config - c.Prepare(getArmBuilderConfiguration(), getPackerConfiguration()) - deployment, err := GetKeyVaultDeployment(&c) - if err != nil { - t.Fatal(err) - } - - _, err = json.Marshal(deployment.Properties.Template) - if err != nil { - t.Fatal(err) - } -} - -// Ensure the KeyVault template parameters are correct. -func TestKeyVaultDeployment02(t *testing.T) { - var c Config - c.Prepare(getArmBuilderConfigurationWithWindows(), getPackerConfiguration()) - - deployment, err := GetKeyVaultDeployment(&c) - if err != nil { - t.Fatal(err) - } - - bs, err := json.Marshal(deployment.Properties.Parameters) - if err != nil { - t.Fatal(err) - } - - var params template.TemplateParameters - err = json.Unmarshal(bs, ¶ms) - if err != nil { - t.Fatal(err) - } - - if params.ObjectId.Value != c.ClientConfig.ObjectID { - t.Errorf("Expected template parameter 'ObjectId' to be %s, but got %s.", params.ObjectId.Value, c.ClientConfig.ObjectID) - } - if params.TenantId.Value != c.ClientConfig.TenantID { - t.Errorf("Expected template parameter 'TenantId' to be %s, but got %s.", params.TenantId.Value, c.ClientConfig.TenantID) - } - if params.KeyVaultName.Value != c.tmpKeyVaultName { - t.Errorf("Expected template parameter 'KeyVaultName' to be %s, but got %s.", params.KeyVaultName.Value, c.tmpKeyVaultName) - } - if params.KeyVaultSecretValue.Value != c.winrmCertificate { - t.Errorf("Expected template parameter 'KeyVaultSecretValue' to be %s, but got %s.", params.KeyVaultSecretValue.Value, c.winrmCertificate) - } -} - -// Ensure the KeyVault template is correct when tags are supplied. -func TestKeyVaultDeployment03(t *testing.T) { - tags := map[string]interface{}{ - "azure_tags": map[string]string{ - "tag01": "value01", - "tag02": "value02", - "tag03": "value03", - }, - } - - var c Config - c.Prepare(tags, getArmBuilderConfigurationWithWindows(), getPackerConfiguration()) - deployment, err := GetKeyVaultDeployment(&c) - if err != nil { - t.Fatal(err) - } - - err = approvaltests.VerifyJSONStruct(t, deployment.Properties.Template) - if err != nil { - t.Fatal(err) - } -} - -func TestPlanInfo01(t *testing.T) { - planInfo := map[string]interface{}{ - "plan_info": map[string]string{ - "plan_name": "planName00", - "plan_product": "planProduct00", - "plan_publisher": "planPublisher00", - }, - } - - var c Config - c.Prepare(planInfo, getArmBuilderConfiguration(), getPackerConfiguration()) - deployment, err := GetVirtualMachineDeployment(&c) - if err != nil { - t.Fatal(err) - } - - err = approvaltests.VerifyJSONStruct(t, deployment.Properties.Template) - if err != nil { - t.Fatal(err) - } -} - -func TestPlanInfo02(t *testing.T) { - planInfo := map[string]interface{}{ - "azure_tags": map[string]string{ - "dept": "engineering", - }, - "plan_info": map[string]string{ - "plan_name": "planName00", - "plan_product": "planProduct00", - "plan_publisher": "planPublisher00", - "plan_promotion_code": "planPromotionCode00", - }, - } - - var c Config - c.Prepare(planInfo, getArmBuilderConfiguration(), getPackerConfiguration()) - deployment, err := GetVirtualMachineDeployment(&c) - if err != nil { - t.Fatal(err) - } - - err = approvaltests.VerifyJSONStruct(t, deployment.Properties.Template) - if err != nil { - t.Fatal(err) - } -} diff --git a/builder/azure/arm/tempname.go b/builder/azure/arm/tempname.go deleted file mode 100644 index f566e267c..000000000 --- a/builder/azure/arm/tempname.go +++ /dev/null @@ -1,80 +0,0 @@ -package arm - -import ( - "fmt" - "strings" - - "github.com/hashicorp/packer-plugin-sdk/random" -) - -type TempName struct { - AdminPassword string - CertificatePassword string - ComputeName string - DeploymentName string - KeyVaultName string - ResourceGroupName string - OSDiskName string - DataDiskName string - NicName string - SubnetName string - PublicIPAddressName string - VirtualNetworkName string - NsgName string -} - -func NewTempName(p string) *TempName { - tempName := &TempName{} - - suffix := random.AlphaNumLower(5) - if p == "" { - p = "pkr" - suffix = random.AlphaNumLower(10) - } - - tempName.ComputeName = fmt.Sprintf("%svm%s", p, suffix) - tempName.DeploymentName = fmt.Sprintf("%sdp%s", p, suffix) - tempName.KeyVaultName = fmt.Sprintf("%skv%s", p, suffix) - tempName.OSDiskName = fmt.Sprintf("%sos%s", p, suffix) - tempName.DataDiskName = fmt.Sprintf("%sdd%s", p, suffix) - tempName.NicName = fmt.Sprintf("%sni%s", p, suffix) - tempName.PublicIPAddressName = fmt.Sprintf("%sip%s", p, suffix) - tempName.SubnetName = fmt.Sprintf("%ssn%s", p, suffix) - tempName.VirtualNetworkName = fmt.Sprintf("%svn%s", p, suffix) - tempName.NsgName = fmt.Sprintf("%ssg%s", p, suffix) - tempName.ResourceGroupName = fmt.Sprintf("%s-Resource-Group-%s", p, suffix) - - tempName.AdminPassword = generatePassword() - tempName.CertificatePassword = random.AlphaNum(32) - - return tempName -} - -// generate a password that is acceptable to Azure -// Three of the four items must be met. -// 1. Contains an uppercase character -// 2. Contains a lowercase character -// 3. Contains a numeric digit -// 4. Contains a special character -func generatePassword() string { - var s string - for i := 0; i < 100; i++ { - s := random.AlphaNum(32) - if !strings.ContainsAny(s, random.PossibleNumbers) { - continue - } - - if !strings.ContainsAny(s, random.PossibleLowerCase) { - continue - } - - if !strings.ContainsAny(s, random.PossibleUpperCase) { - continue - } - - return s - } - - // if an acceptable password cannot be generated in 100 tries, give up - return s -} diff --git a/builder/azure/arm/tempname_test.go b/builder/azure/arm/tempname_test.go deleted file mode 100644 index e982a5ad2..000000000 --- a/builder/azure/arm/tempname_test.go +++ /dev/null @@ -1,143 +0,0 @@ -package arm - -import ( - "strings" - "testing" - - "github.com/hashicorp/packer-plugin-sdk/random" -) - -func TestTempNameShouldCreatePrefixedRandomNames(t *testing.T) { - tempName := NewTempName("") - - if strings.Index(tempName.ComputeName, "pkrvm") != 0 { - t.Errorf("Expected ComputeName to begin with 'pkrvm', but got '%s'!", tempName.ComputeName) - } - - if strings.Index(tempName.DeploymentName, "pkrdp") != 0 { - t.Errorf("Expected ComputeName to begin with 'pkrdp', but got '%s'!", tempName.ComputeName) - } - - if strings.Index(tempName.OSDiskName, "pkros") != 0 { - t.Errorf("Expected OSDiskName to begin with 'pkros', but got '%s'!", tempName.OSDiskName) - } - - if strings.Index(tempName.NicName, "pkrni") != 0 { - t.Errorf("Expected NicName to begin with 'pkrni', but got '%s'!", tempName.NicName) - } - - if strings.Index(tempName.PublicIPAddressName, "pkrip") != 0 { - t.Errorf("Expected PublicIPAddressName to begin with 'pkrip', but got '%s'!", tempName.PublicIPAddressName) - } - - if strings.Index(tempName.ResourceGroupName, "pkr-Resource-Group-") != 0 { - t.Errorf("Expected ResourceGroupName to begin with 'pkr-Resource-Group-', but got '%s'!", tempName.ResourceGroupName) - } - - if strings.Index(tempName.SubnetName, "pkrsn") != 0 { - t.Errorf("Expected SubnetName to begin with 'pkrip', but got '%s'!", tempName.SubnetName) - } - - if strings.Index(tempName.VirtualNetworkName, "pkrvn") != 0 { - t.Errorf("Expected VirtualNetworkName to begin with 'pkrvn', but got '%s'!", tempName.VirtualNetworkName) - } - - if strings.Index(tempName.NsgName, "pkrsg") != 0 { - t.Errorf("Expected NsgName to begin with 'pkrsg', but got '%s'!", tempName.NsgName) - } -} - -func TestTempAdminPassword(t *testing.T) { - tempName := NewTempName("") - - if !strings.ContainsAny(tempName.AdminPassword, random.PossibleNumbers) { - t.Errorf("Expected AdminPassword to contain at least one of '%s'!", random.PossibleNumbers) - } - if !strings.ContainsAny(tempName.AdminPassword, random.PossibleLowerCase) { - t.Errorf("Expected AdminPassword to contain at least one of '%s'!", random.PossibleLowerCase) - } - if !strings.ContainsAny(tempName.AdminPassword, random.PossibleUpperCase) { - t.Errorf("Expected AdminPassword to contain at least one of '%s'!", random.PossibleUpperCase) - } -} - -func TestTempNameShouldHaveSameSuffix(t *testing.T) { - tempName := NewTempName("") - suffix := tempName.ComputeName[5:] - - if strings.HasSuffix(tempName.ComputeName, suffix) != true { - t.Errorf("Expected ComputeName to end with '%s', but the value is '%s'!", suffix, tempName.ComputeName) - } - - if strings.HasSuffix(tempName.DeploymentName, suffix) != true { - t.Errorf("Expected DeploymentName to end with '%s', but the value is '%s'!", suffix, tempName.DeploymentName) - } - - if strings.HasSuffix(tempName.OSDiskName, suffix) != true { - t.Errorf("Expected OSDiskName to end with '%s', but the value is '%s'!", suffix, tempName.OSDiskName) - } - - if strings.HasSuffix(tempName.NicName, suffix) != true { - t.Errorf("Expected NicName to end with '%s', but the value is '%s'!", suffix, tempName.PublicIPAddressName) - } - - if strings.HasSuffix(tempName.PublicIPAddressName, suffix) != true { - t.Errorf("Expected PublicIPAddressName to end with '%s', but the value is '%s'!", suffix, tempName.PublicIPAddressName) - } - - if strings.HasSuffix(tempName.ResourceGroupName, suffix) != true { - t.Errorf("Expected ResourceGroupName to end with '%s', but the value is '%s'!", suffix, tempName.ResourceGroupName) - } - - if strings.HasSuffix(tempName.SubnetName, suffix) != true { - t.Errorf("Expected SubnetName to end with '%s', but the value is '%s'!", suffix, tempName.SubnetName) - } - - if strings.HasSuffix(tempName.VirtualNetworkName, suffix) != true { - t.Errorf("Expected VirtualNetworkName to end with '%s', but the value is '%s'!", suffix, tempName.VirtualNetworkName) - } - - if strings.HasSuffix(tempName.NsgName, suffix) != true { - t.Errorf("Expected NsgName to end with '%s', but the value is '%s'!", suffix, tempName.NsgName) - } -} - -func TestTempNameShouldCreateCustomPrefix(t *testing.T) { - tempName := NewTempName("CustPrefix") - - if strings.Index(tempName.ComputeName, "CustPrefixvm") != 0 { - t.Errorf("Expected ComputeName to begin with 'CustPrefixvm', but got '%s'!", tempName.ComputeName) - } - - if strings.Index(tempName.DeploymentName, "CustPrefixdp") != 0 { - t.Errorf("Expected ComputeName to begin with 'CustPrefixdp', but got '%s'!", tempName.ComputeName) - } - - if strings.Index(tempName.OSDiskName, "CustPrefixos") != 0 { - t.Errorf("Expected OSDiskName to begin with 'CustPrefixos', but got '%s'!", tempName.OSDiskName) - } - - if strings.Index(tempName.NicName, "CustPrefixni") != 0 { - t.Errorf("Expected NicName to begin with 'CustPrefixni', but got '%s'!", tempName.NicName) - } - - if strings.Index(tempName.PublicIPAddressName, "CustPrefixip") != 0 { - t.Errorf("Expected PublicIPAddressName to begin with 'CustPrefixip', but got '%s'!", tempName.PublicIPAddressName) - } - - if strings.Index(tempName.ResourceGroupName, "CustPrefix-Resource-Group-") != 0 { - t.Errorf("Expected ResourceGroupName to begin with 'packer-Resource-Group-', but got '%s'!", tempName.ResourceGroupName) - } - - if strings.Index(tempName.SubnetName, "CustPrefixsn") != 0 { - t.Errorf("Expected SubnetName to begin with 'pkrip', but got '%s'!", tempName.SubnetName) - } - - if strings.Index(tempName.VirtualNetworkName, "CustPrefixvn") != 0 { - t.Errorf("Expected VirtualNetworkName to begin with 'CustPrefixvn', but got '%s'!", tempName.VirtualNetworkName) - } - - if strings.Index(tempName.NsgName, "CustPrefixsg") != 0 { - t.Errorf("Expected NsgName to begin with 'CustPrefixsg', but got '%s'!", tempName.NsgName) - } -} diff --git a/builder/azure/chroot/builder.go b/builder/azure/chroot/builder.go deleted file mode 100644 index 9130cb461..000000000 --- a/builder/azure/chroot/builder.go +++ /dev/null @@ -1,622 +0,0 @@ -//go:generate packer-sdc struct-markdown -//go:generate packer-sdc mapstructure-to-hcl2 -type Config - -// Package chroot is able to create an Azure managed image without requiring the -// launch of a new virtual machine for every build. It does this by attaching and -// mounting the root disk and chrooting into that directory. -// It then creates a managed image from that attached disk. -package chroot - -import ( - "context" - "errors" - "fmt" - "log" - "runtime" - "strings" - - "github.com/hashicorp/hcl/v2/hcldec" - "github.com/hashicorp/packer-plugin-sdk/chroot" - "github.com/hashicorp/packer-plugin-sdk/common" - "github.com/hashicorp/packer-plugin-sdk/multistep" - "github.com/hashicorp/packer-plugin-sdk/multistep/commonsteps" - packersdk "github.com/hashicorp/packer-plugin-sdk/packer" - "github.com/hashicorp/packer-plugin-sdk/template/config" - "github.com/hashicorp/packer-plugin-sdk/template/interpolate" - azcommon "github.com/hashicorp/packer/builder/azure/common" - "github.com/hashicorp/packer/builder/azure/common/client" - - "github.com/Azure/azure-sdk-for-go/services/compute/mgmt/2019-12-01/compute" - "github.com/Azure/go-autorest/autorest/azure" - "github.com/mitchellh/mapstructure" -) - -// BuilderID is the unique ID for this builder -const BuilderID = "azure.chroot" - -// Config is the configuration that is chained through the steps and settable -// from the template. -type Config struct { - common.PackerConfig `mapstructure:",squash"` - - ClientConfig client.Config `mapstructure:",squash"` - - // When set to `true`, starts with an empty, unpartitioned disk. Defaults to `false`. - FromScratch bool `mapstructure:"from_scratch"` - // One of the following can be used as a source for an image: - // - a shared image version resource ID - // - a managed disk resource ID - // - a publisher:offer:sku:version specifier for plaform image sources. - Source string `mapstructure:"source" required:"true"` - sourceType sourceType - - // How to run shell commands. This may be useful to set environment variables or perhaps run - // a command with sudo or so on. This is a configuration template where the `.Command` variable - // is replaced with the command to be run. Defaults to `{{.Command}}`. - CommandWrapper string `mapstructure:"command_wrapper"` - // A series of commands to execute after attaching the root volume and before mounting the chroot. - // This is not required unless using `from_scratch`. If so, this should include any partitioning - // and filesystem creation commands. The path to the device is provided by `{{.Device}}`. - PreMountCommands []string `mapstructure:"pre_mount_commands"` - // Options to supply the `mount` command when mounting devices. Each option will be prefixed with - // `-o` and supplied to the `mount` command ran by Packer. Because this command is ran in a shell, - // user discretion is advised. See this manual page for the `mount` command for valid file system specific options. - MountOptions []string `mapstructure:"mount_options"` - // The partition number containing the / partition. By default this is the first partition of the volume. - MountPartition string `mapstructure:"mount_partition"` - // The path where the volume will be mounted. This is where the chroot environment will be. This defaults - // to `/mnt/packer-amazon-chroot-volumes/{{.Device}}`. This is a configuration template where the `.Device` - // variable is replaced with the name of the device where the volume is attached. - MountPath string `mapstructure:"mount_path"` - // As `pre_mount_commands`, but the commands are executed after mounting the root device and before the - // extra mount and copy steps. The device and mount path are provided by `{{.Device}}` and `{{.MountPath}}`. - PostMountCommands []string `mapstructure:"post_mount_commands"` - // This is a list of devices to mount into the chroot environment. This configuration parameter requires - // some additional documentation which is in the "Chroot Mounts" section below. Please read that section - // for more information on how to use this. - ChrootMounts [][]string `mapstructure:"chroot_mounts"` - // Paths to files on the running Azure instance that will be copied into the chroot environment prior to - // provisioning. Defaults to `/etc/resolv.conf` so that DNS lookups work. Pass an empty list to skip copying - // `/etc/resolv.conf`. You may need to do this if you're building an image that uses systemd. - CopyFiles []string `mapstructure:"copy_files"` - - // Try to resize the OS disk to this size on the first copy. Disks can only be englarged. If not specified, - // the disk will keep its original size. Required when using `from_scratch` - OSDiskSizeGB int32 `mapstructure:"os_disk_size_gb"` - // The [storage SKU](https://docs.microsoft.com/en-us/rest/api/compute/disks/createorupdate#diskstorageaccounttypes) - // to use for the OS Disk. Defaults to `Standard_LRS`. - OSDiskStorageAccountType string `mapstructure:"os_disk_storage_account_type"` - // The [cache type](https://docs.microsoft.com/en-us/rest/api/compute/images/createorupdate#cachingtypes) - // specified in the resulting image and for attaching it to the Packer VM. Defaults to `ReadOnly` - OSDiskCacheType string `mapstructure:"os_disk_cache_type"` - - // The [storage SKU](https://docs.microsoft.com/en-us/rest/api/compute/disks/createorupdate#diskstorageaccounttypes) - // to use for datadisks. Defaults to `Standard_LRS`. - DataDiskStorageAccountType string `mapstructure:"data_disk_storage_account_type"` - // The [cache type](https://docs.microsoft.com/en-us/rest/api/compute/images/createorupdate#cachingtypes) - // specified in the resulting image and for attaching it to the Packer VM. Defaults to `ReadOnly` - DataDiskCacheType string `mapstructure:"data_disk_cache_type"` - - // The [Hyper-V generation type](https://docs.microsoft.com/en-us/rest/api/compute/images/createorupdate#hypervgenerationtypes) for Managed Image output. - // Defaults to `V1`. - ImageHyperVGeneration string `mapstructure:"image_hyperv_generation"` - - // The id of the temporary OS disk that will be created. Will be generated if not set. - TemporaryOSDiskID string `mapstructure:"temporary_os_disk_id"` - - // The id of the temporary OS disk snapshot that will be created. Will be generated if not set. - TemporaryOSDiskSnapshotID string `mapstructure:"temporary_os_disk_snapshot_id"` - - // The prefix for the resource ids of the temporary data disks that will be created. The disks will be suffixed with a number. Will be generated if not set. - TemporaryDataDiskIDPrefix string `mapstructure:"temporary_data_disk_id_prefix"` - - // The prefix for the resource ids of the temporary data disk snapshots that will be created. The snapshots will be suffixed with a number. Will be generated if not set. - TemporaryDataDiskSnapshotIDPrefix string `mapstructure:"temporary_data_disk_snapshot_id"` - - // If set to `true`, leaves the temporary disks and snapshots behind in the Packer VM resource group. Defaults to `false` - SkipCleanup bool `mapstructure:"skip_cleanup"` - - // The managed image to create using this build. - ImageResourceID string `mapstructure:"image_resource_id"` - - // The shared image to create using this build. - SharedImageGalleryDestination SharedImageGalleryDestination `mapstructure:"shared_image_destination"` - - ctx interpolate.Context -} - -type sourceType string - -const ( - sourcePlatformImage sourceType = "PlatformImage" - sourceDisk sourceType = "Disk" - sourceSharedImage sourceType = "SharedImage" -) - -// GetContext implements ContextProvider to allow steps to use the config context -// for template interpolation -func (c *Config) GetContext() interpolate.Context { - return c.ctx -} - -type Builder struct { - config Config - runner multistep.Runner -} - -// verify interface implementation -var _ packersdk.Builder = &Builder{} - -func (b *Builder) ConfigSpec() hcldec.ObjectSpec { return b.config.FlatMapstructure().HCL2Spec() } - -func (b *Builder) Prepare(raws ...interface{}) ([]string, []string, error) { - b.config.ctx.Funcs = azcommon.TemplateFuncs - b.config.ctx.Funcs["vm"] = CreateVMMetadataTemplateFunc() - md := &mapstructure.Metadata{} - err := config.Decode(&b.config, &config.DecodeOpts{ - PluginType: BuilderID, - Interpolate: true, - InterpolateContext: &b.config.ctx, - InterpolateFilter: &interpolate.RenderFilter{ - Exclude: []string{ - // these fields are interpolated in the steps, - // when more information is available - "command_wrapper", - "post_mount_commands", - "pre_mount_commands", - "mount_path", - }, - }, - Metadata: md, - }, raws...) - if err != nil { - return nil, nil, err - } - - var errs *packersdk.MultiError - var warns []string - - // Defaults - err = b.config.ClientConfig.SetDefaultValues() - if err != nil { - return nil, nil, err - } - - if b.config.ChrootMounts == nil { - b.config.ChrootMounts = make([][]string, 0) - } - - if len(b.config.ChrootMounts) == 0 { - b.config.ChrootMounts = [][]string{ - {"proc", "proc", "/proc"}, - {"sysfs", "sysfs", "/sys"}, - {"bind", "/dev", "/dev"}, - {"devpts", "devpts", "/dev/pts"}, - {"binfmt_misc", "binfmt_misc", "/proc/sys/fs/binfmt_misc"}, - } - } - - // set default copy file if we're not giving our own - if b.config.CopyFiles == nil { - if !b.config.FromScratch { - b.config.CopyFiles = []string{"/etc/resolv.conf"} - } - } - - if b.config.CommandWrapper == "" { - b.config.CommandWrapper = "{{.Command}}" - } - - if b.config.MountPath == "" { - b.config.MountPath = "/mnt/packer-azure-chroot-disks/{{.Device}}" - } - - if b.config.MountPartition == "" { - b.config.MountPartition = "1" - } - - if b.config.TemporaryOSDiskID == "" { - if def, err := interpolate.Render( - "/subscriptions/{{ vm `subscription_id` }}/resourceGroups/{{ vm `resource_group` }}/providers/Microsoft.Compute/disks/PackerTemp-osdisk-{{timestamp}}", - &b.config.ctx); err == nil { - b.config.TemporaryOSDiskID = def - } else { - errs = packersdk.MultiErrorAppend(errs, fmt.Errorf("unable to render temporary disk id: %s", err)) - } - } - - if b.config.TemporaryOSDiskSnapshotID == "" { - if def, err := interpolate.Render( - "/subscriptions/{{ vm `subscription_id` }}/resourceGroups/{{ vm `resource_group` }}/providers/Microsoft.Compute/snapshots/PackerTemp-osdisk-snapshot-{{timestamp}}", - &b.config.ctx); err == nil { - b.config.TemporaryOSDiskSnapshotID = def - } else { - errs = packersdk.MultiErrorAppend(errs, fmt.Errorf("unable to render temporary snapshot id: %s", err)) - } - } - - if b.config.TemporaryDataDiskIDPrefix == "" { - if def, err := interpolate.Render( - "/subscriptions/{{ vm `subscription_id` }}/resourceGroups/{{ vm `resource_group` }}/providers/Microsoft.Compute/disks/PackerTemp-datadisk-{{timestamp}}-", - &b.config.ctx); err == nil { - b.config.TemporaryDataDiskIDPrefix = def - } else { - errs = packersdk.MultiErrorAppend(errs, fmt.Errorf("unable to render temporary data disk id prefix: %s", err)) - } - } - - if b.config.TemporaryDataDiskSnapshotIDPrefix == "" { - if def, err := interpolate.Render( - "/subscriptions/{{ vm `subscription_id` }}/resourceGroups/{{ vm `resource_group` }}/providers/Microsoft.Compute/snapshots/PackerTemp-datadisk-snapshot-{{timestamp}}-", - &b.config.ctx); err == nil { - b.config.TemporaryDataDiskSnapshotIDPrefix = def - } else { - errs = packersdk.MultiErrorAppend(errs, fmt.Errorf("unable to render temporary data disk snapshot id prefix: %s", err)) - } - } - - if b.config.OSDiskStorageAccountType == "" { - b.config.OSDiskStorageAccountType = string(compute.PremiumLRS) - } - - if b.config.OSDiskCacheType == "" { - b.config.OSDiskCacheType = string(compute.CachingTypesReadOnly) - } - - if b.config.DataDiskStorageAccountType == "" { - b.config.DataDiskStorageAccountType = string(compute.PremiumLRS) - } - - if b.config.DataDiskCacheType == "" { - b.config.DataDiskCacheType = string(compute.CachingTypesReadOnly) - } - - if b.config.ImageHyperVGeneration == "" { - b.config.ImageHyperVGeneration = string(compute.V1) - } - - // checks, accumulate any errors or warnings - - if b.config.FromScratch { - if b.config.Source != "" { - errs = packersdk.MultiErrorAppend( - errs, errors.New("source cannot be specified when building from_scratch")) - } - if b.config.OSDiskSizeGB == 0 { - errs = packersdk.MultiErrorAppend( - errs, errors.New("os_disk_size_gb is required with from_scratch")) - } - if len(b.config.PreMountCommands) == 0 { - errs = packersdk.MultiErrorAppend( - errs, errors.New("pre_mount_commands is required with from_scratch")) - } - } else { - if _, err := client.ParsePlatformImageURN(b.config.Source); err == nil { - log.Println("Source is platform image:", b.config.Source) - b.config.sourceType = sourcePlatformImage - } else if id, err := client.ParseResourceID(b.config.Source); err == nil && - strings.EqualFold(id.Provider, "Microsoft.Compute") && - strings.EqualFold(id.ResourceType.String(), "disks") { - log.Println("Source is a disk resource ID:", b.config.Source) - b.config.sourceType = sourceDisk - } else if id, err := client.ParseResourceID(b.config.Source); err == nil && - strings.EqualFold(id.Provider, "Microsoft.Compute") && - strings.EqualFold(id.ResourceType.String(), "galleries/images/versions") { - log.Println("Source is a shared image ID:", b.config.Source) - b.config.sourceType = sourceSharedImage - } else { - errs = packersdk.MultiErrorAppend( - errs, fmt.Errorf("source: %q is not a valid platform image specifier, nor is it a disk resource ID", b.config.Source)) - } - } - - if err := checkDiskCacheType(b.config.OSDiskCacheType); err != nil { - errs = packersdk.MultiErrorAppend(errs, fmt.Errorf("os_disk_cache_type: %v", err)) - } - - if err := checkStorageAccountType(b.config.OSDiskStorageAccountType); err != nil { - errs = packersdk.MultiErrorAppend(errs, fmt.Errorf("os_disk_storage_account_type: %v", err)) - } - - if err := checkDiskCacheType(b.config.DataDiskCacheType); err != nil { - errs = packersdk.MultiErrorAppend(errs, fmt.Errorf("data_disk_cache_type: %v", err)) - } - - if err := checkStorageAccountType(b.config.DataDiskStorageAccountType); err != nil { - errs = packersdk.MultiErrorAppend(errs, fmt.Errorf("data_disk_storage_account_type: %v", err)) - } - - if b.config.ImageResourceID != "" { - r, err := azure.ParseResourceID(b.config.ImageResourceID) - if err != nil || - !strings.EqualFold(r.Provider, "Microsoft.Compute") || - !strings.EqualFold(r.ResourceType, "images") { - errs = packersdk.MultiErrorAppend(fmt.Errorf( - "image_resource_id: %q is not a valid image resource id", b.config.ImageResourceID)) - } - } - - if azcommon.StringsContains(md.Keys, "shared_image_destination") { - e, w := b.config.SharedImageGalleryDestination.Validate("shared_image_destination") - if len(e) > 0 { - errs = packersdk.MultiErrorAppend(errs, e...) - } - if len(w) > 0 { - warns = append(warns, w...) - } - } - - if !azcommon.StringsContains(md.Keys, "shared_image_destination") && b.config.ImageResourceID == "" { - errs = packersdk.MultiErrorAppend(errs, errors.New("image_resource_id or shared_image_destination is required")) - } - - if err := checkHyperVGeneration(b.config.ImageHyperVGeneration); err != nil { - errs = packersdk.MultiErrorAppend(errs, fmt.Errorf("image_hyperv_generation: %v", err)) - } - - if errs != nil { - return nil, warns, errs - } - - packersdk.LogSecretFilter.Set(b.config.ClientConfig.ClientSecret, b.config.ClientConfig.ClientJWT) - return nil, warns, nil -} - -func checkDiskCacheType(s string) interface{} { - for _, v := range compute.PossibleCachingTypesValues() { - if compute.CachingTypes(s) == v { - return nil - } - } - return fmt.Errorf("%q is not a valid value %v", - s, compute.PossibleCachingTypesValues()) -} - -func checkStorageAccountType(s string) interface{} { - for _, v := range compute.PossibleDiskStorageAccountTypesValues() { - if compute.DiskStorageAccountTypes(s) == v { - return nil - } - } - return fmt.Errorf("%q is not a valid value %v", - s, compute.PossibleDiskStorageAccountTypesValues()) -} - -func checkHyperVGeneration(s string) interface{} { - for _, v := range compute.PossibleHyperVGenerationValues() { - if compute.HyperVGeneration(s) == v { - return nil - } - } - return fmt.Errorf("%q is not a valid value %v", - s, compute.PossibleHyperVGenerationValues()) -} - -func (b *Builder) Run(ctx context.Context, ui packersdk.Ui, hook packersdk.Hook) (packersdk.Artifact, error) { - switch runtime.GOOS { - case "linux", "freebsd": - break - default: - return nil, errors.New("the azure-chroot builder only works on Linux and FreeBSD environments") - } - - err := b.config.ClientConfig.FillParameters() - if err != nil { - return nil, fmt.Errorf("error setting Azure client defaults: %v", err) - } - azcli, err := client.New(b.config.ClientConfig, ui.Say) - if err != nil { - return nil, fmt.Errorf("error creating Azure client: %v", err) - } - - wrappedCommand := func(command string) (string, error) { - ictx := b.config.ctx - ictx.Data = &struct{ Command string }{Command: command} - return interpolate.Render(b.config.CommandWrapper, &ictx) - } - - // Setup the state bag and initial state for the steps - state := new(multistep.BasicStateBag) - state.Put("config", &b.config) - state.Put("hook", hook) - state.Put("ui", ui) - state.Put("azureclient", azcli) - state.Put("wrappedCommand", common.CommandWrapper(wrappedCommand)) - - info, err := azcli.MetadataClient().GetComputeInfo() - if err != nil { - log.Printf("MetadataClient().GetComputeInfo(): error: %+v", err) - err := fmt.Errorf( - "Error retrieving information ARM resource ID and location" + - "of the VM that Packer is running on.\n" + - "Please verify that Packer is running on a proper Azure VM.") - ui.Error(err.Error()) - return nil, err - } - - state.Put("instance", info) - - // Build the step array from the config - steps := buildsteps(b.config, info) - - // Run! - b.runner = commonsteps.NewRunner(steps, b.config.PackerConfig, ui) - b.runner.Run(ctx, state) - - // If there was an error, return that - if rawErr, ok := state.GetOk("error"); ok { - return nil, rawErr.(error) - } - - // Build the artifact and return it - artifact := &azcommon.Artifact{ - BuilderIdValue: BuilderID, - StateData: map[string]interface{}{"generated_data": state.Get("generated_data")}, - AzureClientSet: azcli, - } - if b.config.ImageResourceID != "" { - artifact.Resources = append(artifact.Resources, b.config.ImageResourceID) - } - if e, _ := b.config.SharedImageGalleryDestination.Validate(""); len(e) == 0 { - artifact.Resources = append(artifact.Resources, b.config.SharedImageGalleryDestination.ResourceID(info.SubscriptionID)) - } - if b.config.SkipCleanup { - if d, ok := state.GetOk(stateBagKey_Diskset); ok { - for _, disk := range d.(Diskset) { - artifact.Resources = append(artifact.Resources, disk.String()) - } - } - if d, ok := state.GetOk(stateBagKey_Snapshotset); ok { - for _, snapshot := range d.(Diskset) { - artifact.Resources = append(artifact.Resources, snapshot.String()) - } - } - } - - return artifact, nil -} - -func buildsteps(config Config, info *client.ComputeInfo) []multistep.Step { - // Build the steps - var steps []multistep.Step - addSteps := func(s ...multistep.Step) { // convenience function - steps = append(steps, s...) - } - - e, _ := config.SharedImageGalleryDestination.Validate("") - hasValidSharedImage := len(e) == 0 - - if hasValidSharedImage { - // validate destination early - addSteps( - &StepVerifySharedImageDestination{ - Image: config.SharedImageGalleryDestination, - Location: info.Location, - }, - ) - } - - if config.FromScratch { - addSteps(&StepCreateNewDiskset{ - OSDiskID: config.TemporaryOSDiskID, - OSDiskSizeGB: config.OSDiskSizeGB, - OSDiskStorageAccountType: config.OSDiskStorageAccountType, - HyperVGeneration: config.ImageHyperVGeneration, - Location: info.Location}) - } else { - switch config.sourceType { - case sourcePlatformImage: - if pi, err := client.ParsePlatformImageURN(config.Source); err == nil { - if strings.EqualFold(pi.Version, "latest") { - addSteps( - &StepResolvePlatformImageVersion{ - PlatformImage: pi, - Location: info.Location, - }) - } - addSteps( - &StepCreateNewDiskset{ - OSDiskID: config.TemporaryOSDiskID, - OSDiskSizeGB: config.OSDiskSizeGB, - OSDiskStorageAccountType: config.OSDiskStorageAccountType, - HyperVGeneration: config.ImageHyperVGeneration, - Location: info.Location, - SourcePlatformImage: pi, - - SkipCleanup: config.SkipCleanup, - }) - } else { - panic("Couldn't parse platfrom image urn: " + config.Source + " err: " + err.Error()) - } - - case sourceDisk: - addSteps( - &StepVerifySourceDisk{ - SourceDiskResourceID: config.Source, - Location: info.Location, - }, - &StepCreateNewDiskset{ - OSDiskID: config.TemporaryOSDiskID, - OSDiskSizeGB: config.OSDiskSizeGB, - OSDiskStorageAccountType: config.OSDiskStorageAccountType, - HyperVGeneration: config.ImageHyperVGeneration, - SourceOSDiskResourceID: config.Source, - Location: info.Location, - - SkipCleanup: config.SkipCleanup, - }) - - case sourceSharedImage: - addSteps( - &StepVerifySharedImageSource{ - SharedImageID: config.Source, - SubscriptionID: info.SubscriptionID, - Location: info.Location, - }, - &StepCreateNewDiskset{ - OSDiskID: config.TemporaryOSDiskID, - DataDiskIDPrefix: config.TemporaryDataDiskIDPrefix, - OSDiskSizeGB: config.OSDiskSizeGB, - OSDiskStorageAccountType: config.OSDiskStorageAccountType, - DataDiskStorageAccountType: config.DataDiskStorageAccountType, - SourceImageResourceID: config.Source, - Location: info.Location, - - SkipCleanup: config.SkipCleanup, - }) - - default: - panic(fmt.Errorf("Unknown source type: %+q", config.sourceType)) - } - } - - addSteps( - &StepAttachDisk{}, // uses os_disk_resource_id and sets 'device' in stateBag - &chroot.StepPreMountCommands{ - Commands: config.PreMountCommands, - }, - &StepMountDevice{ - MountOptions: config.MountOptions, - MountPartition: config.MountPartition, - MountPath: config.MountPath, - }, - &chroot.StepPostMountCommands{ - Commands: config.PostMountCommands, - }, - &chroot.StepMountExtra{ - ChrootMounts: config.ChrootMounts, - }, - &chroot.StepCopyFiles{ - Files: config.CopyFiles, - }, - &chroot.StepChrootProvision{}, - &chroot.StepEarlyCleanup{}, - ) - - if config.ImageResourceID != "" { - addSteps(&StepCreateImage{ - ImageResourceID: config.ImageResourceID, - ImageOSState: string(compute.Generalized), - OSDiskCacheType: config.OSDiskCacheType, - OSDiskStorageAccountType: config.OSDiskStorageAccountType, - Location: info.Location, - }) - } - if hasValidSharedImage { - addSteps( - &StepCreateSnapshotset{ - OSDiskSnapshotID: config.TemporaryOSDiskSnapshotID, - DataDiskSnapshotIDPrefix: config.TemporaryDataDiskSnapshotIDPrefix, - Location: info.Location, - SkipCleanup: config.SkipCleanup, - }, - &StepCreateSharedImageVersion{ - Destination: config.SharedImageGalleryDestination, - OSDiskCacheType: config.OSDiskCacheType, - Location: info.Location, - }, - ) - } - - return steps -} diff --git a/builder/azure/chroot/builder.hcl2spec.go b/builder/azure/chroot/builder.hcl2spec.go deleted file mode 100644 index 96f4c1ae9..000000000 --- a/builder/azure/chroot/builder.hcl2spec.go +++ /dev/null @@ -1,111 +0,0 @@ -// Code generated by "packer-sdc mapstructure-to-hcl2"; DO NOT EDIT. - -package chroot - -import ( - "github.com/hashicorp/hcl/v2/hcldec" - "github.com/zclconf/go-cty/cty" -) - -// FlatConfig is an auto-generated flat version of Config. -// Where the contents of a field with a `mapstructure:,squash` tag are bubbled up. -type FlatConfig struct { - PackerBuildName *string `mapstructure:"packer_build_name" cty:"packer_build_name" hcl:"packer_build_name"` - PackerBuilderType *string `mapstructure:"packer_builder_type" cty:"packer_builder_type" hcl:"packer_builder_type"` - PackerCoreVersion *string `mapstructure:"packer_core_version" cty:"packer_core_version" hcl:"packer_core_version"` - PackerDebug *bool `mapstructure:"packer_debug" cty:"packer_debug" hcl:"packer_debug"` - PackerForce *bool `mapstructure:"packer_force" cty:"packer_force" hcl:"packer_force"` - PackerOnError *string `mapstructure:"packer_on_error" cty:"packer_on_error" hcl:"packer_on_error"` - PackerUserVars map[string]string `mapstructure:"packer_user_variables" cty:"packer_user_variables" hcl:"packer_user_variables"` - PackerSensitiveVars []string `mapstructure:"packer_sensitive_variables" cty:"packer_sensitive_variables" hcl:"packer_sensitive_variables"` - CloudEnvironmentName *string `mapstructure:"cloud_environment_name" required:"false" cty:"cloud_environment_name" hcl:"cloud_environment_name"` - ClientID *string `mapstructure:"client_id" cty:"client_id" hcl:"client_id"` - ClientSecret *string `mapstructure:"client_secret" cty:"client_secret" hcl:"client_secret"` - ClientCertPath *string `mapstructure:"client_cert_path" cty:"client_cert_path" hcl:"client_cert_path"` - ClientCertExpireTimeout *string `mapstructure:"client_cert_token_timeout" required:"false" cty:"client_cert_token_timeout" hcl:"client_cert_token_timeout"` - ClientJWT *string `mapstructure:"client_jwt" cty:"client_jwt" hcl:"client_jwt"` - ObjectID *string `mapstructure:"object_id" cty:"object_id" hcl:"object_id"` - TenantID *string `mapstructure:"tenant_id" required:"false" cty:"tenant_id" hcl:"tenant_id"` - SubscriptionID *string `mapstructure:"subscription_id" cty:"subscription_id" hcl:"subscription_id"` - UseAzureCLIAuth *bool `mapstructure:"use_azure_cli_auth" required:"false" cty:"use_azure_cli_auth" hcl:"use_azure_cli_auth"` - FromScratch *bool `mapstructure:"from_scratch" cty:"from_scratch" hcl:"from_scratch"` - Source *string `mapstructure:"source" required:"true" cty:"source" hcl:"source"` - CommandWrapper *string `mapstructure:"command_wrapper" cty:"command_wrapper" hcl:"command_wrapper"` - PreMountCommands []string `mapstructure:"pre_mount_commands" cty:"pre_mount_commands" hcl:"pre_mount_commands"` - MountOptions []string `mapstructure:"mount_options" cty:"mount_options" hcl:"mount_options"` - MountPartition *string `mapstructure:"mount_partition" cty:"mount_partition" hcl:"mount_partition"` - MountPath *string `mapstructure:"mount_path" cty:"mount_path" hcl:"mount_path"` - PostMountCommands []string `mapstructure:"post_mount_commands" cty:"post_mount_commands" hcl:"post_mount_commands"` - ChrootMounts [][]string `mapstructure:"chroot_mounts" cty:"chroot_mounts" hcl:"chroot_mounts"` - CopyFiles []string `mapstructure:"copy_files" cty:"copy_files" hcl:"copy_files"` - OSDiskSizeGB *int32 `mapstructure:"os_disk_size_gb" cty:"os_disk_size_gb" hcl:"os_disk_size_gb"` - OSDiskStorageAccountType *string `mapstructure:"os_disk_storage_account_type" cty:"os_disk_storage_account_type" hcl:"os_disk_storage_account_type"` - OSDiskCacheType *string `mapstructure:"os_disk_cache_type" cty:"os_disk_cache_type" hcl:"os_disk_cache_type"` - DataDiskStorageAccountType *string `mapstructure:"data_disk_storage_account_type" cty:"data_disk_storage_account_type" hcl:"data_disk_storage_account_type"` - DataDiskCacheType *string `mapstructure:"data_disk_cache_type" cty:"data_disk_cache_type" hcl:"data_disk_cache_type"` - ImageHyperVGeneration *string `mapstructure:"image_hyperv_generation" cty:"image_hyperv_generation" hcl:"image_hyperv_generation"` - TemporaryOSDiskID *string `mapstructure:"temporary_os_disk_id" cty:"temporary_os_disk_id" hcl:"temporary_os_disk_id"` - TemporaryOSDiskSnapshotID *string `mapstructure:"temporary_os_disk_snapshot_id" cty:"temporary_os_disk_snapshot_id" hcl:"temporary_os_disk_snapshot_id"` - TemporaryDataDiskIDPrefix *string `mapstructure:"temporary_data_disk_id_prefix" cty:"temporary_data_disk_id_prefix" hcl:"temporary_data_disk_id_prefix"` - TemporaryDataDiskSnapshotIDPrefix *string `mapstructure:"temporary_data_disk_snapshot_id" cty:"temporary_data_disk_snapshot_id" hcl:"temporary_data_disk_snapshot_id"` - SkipCleanup *bool `mapstructure:"skip_cleanup" cty:"skip_cleanup" hcl:"skip_cleanup"` - ImageResourceID *string `mapstructure:"image_resource_id" cty:"image_resource_id" hcl:"image_resource_id"` - SharedImageGalleryDestination *FlatSharedImageGalleryDestination `mapstructure:"shared_image_destination" cty:"shared_image_destination" hcl:"shared_image_destination"` -} - -// FlatMapstructure returns a new FlatConfig. -// FlatConfig is an auto-generated flat version of Config. -// Where the contents a fields with a `mapstructure:,squash` tag are bubbled up. -func (*Config) FlatMapstructure() interface{ HCL2Spec() map[string]hcldec.Spec } { - return new(FlatConfig) -} - -// HCL2Spec returns the hcl spec of a Config. -// This spec is used by HCL to read the fields of Config. -// The decoded values from this spec will then be applied to a FlatConfig. -func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec { - s := map[string]hcldec.Spec{ - "packer_build_name": &hcldec.AttrSpec{Name: "packer_build_name", Type: cty.String, Required: false}, - "packer_builder_type": &hcldec.AttrSpec{Name: "packer_builder_type", Type: cty.String, Required: false}, - "packer_core_version": &hcldec.AttrSpec{Name: "packer_core_version", Type: cty.String, Required: false}, - "packer_debug": &hcldec.AttrSpec{Name: "packer_debug", Type: cty.Bool, Required: false}, - "packer_force": &hcldec.AttrSpec{Name: "packer_force", Type: cty.Bool, Required: false}, - "packer_on_error": &hcldec.AttrSpec{Name: "packer_on_error", Type: cty.String, Required: false}, - "packer_user_variables": &hcldec.AttrSpec{Name: "packer_user_variables", Type: cty.Map(cty.String), Required: false}, - "packer_sensitive_variables": &hcldec.AttrSpec{Name: "packer_sensitive_variables", Type: cty.List(cty.String), Required: false}, - "cloud_environment_name": &hcldec.AttrSpec{Name: "cloud_environment_name", Type: cty.String, Required: false}, - "client_id": &hcldec.AttrSpec{Name: "client_id", Type: cty.String, Required: false}, - "client_secret": &hcldec.AttrSpec{Name: "client_secret", Type: cty.String, Required: false}, - "client_cert_path": &hcldec.AttrSpec{Name: "client_cert_path", Type: cty.String, Required: false}, - "client_cert_token_timeout": &hcldec.AttrSpec{Name: "client_cert_token_timeout", Type: cty.String, Required: false}, - "client_jwt": &hcldec.AttrSpec{Name: "client_jwt", Type: cty.String, Required: false}, - "object_id": &hcldec.AttrSpec{Name: "object_id", Type: cty.String, Required: false}, - "tenant_id": &hcldec.AttrSpec{Name: "tenant_id", Type: cty.String, Required: false}, - "subscription_id": &hcldec.AttrSpec{Name: "subscription_id", Type: cty.String, Required: false}, - "use_azure_cli_auth": &hcldec.AttrSpec{Name: "use_azure_cli_auth", Type: cty.Bool, Required: false}, - "from_scratch": &hcldec.AttrSpec{Name: "from_scratch", Type: cty.Bool, Required: false}, - "source": &hcldec.AttrSpec{Name: "source", Type: cty.String, Required: false}, - "command_wrapper": &hcldec.AttrSpec{Name: "command_wrapper", Type: cty.String, Required: false}, - "pre_mount_commands": &hcldec.AttrSpec{Name: "pre_mount_commands", Type: cty.List(cty.String), Required: false}, - "mount_options": &hcldec.AttrSpec{Name: "mount_options", Type: cty.List(cty.String), Required: false}, - "mount_partition": &hcldec.AttrSpec{Name: "mount_partition", Type: cty.String, Required: false}, - "mount_path": &hcldec.AttrSpec{Name: "mount_path", Type: cty.String, Required: false}, - "post_mount_commands": &hcldec.AttrSpec{Name: "post_mount_commands", Type: cty.List(cty.String), Required: false}, - "chroot_mounts": &hcldec.AttrSpec{Name: "chroot_mounts", Type: cty.List(cty.List(cty.String)), Required: false}, - "copy_files": &hcldec.AttrSpec{Name: "copy_files", Type: cty.List(cty.String), Required: false}, - "os_disk_size_gb": &hcldec.AttrSpec{Name: "os_disk_size_gb", Type: cty.Number, Required: false}, - "os_disk_storage_account_type": &hcldec.AttrSpec{Name: "os_disk_storage_account_type", Type: cty.String, Required: false}, - "os_disk_cache_type": &hcldec.AttrSpec{Name: "os_disk_cache_type", Type: cty.String, Required: false}, - "data_disk_storage_account_type": &hcldec.AttrSpec{Name: "data_disk_storage_account_type", Type: cty.String, Required: false}, - "data_disk_cache_type": &hcldec.AttrSpec{Name: "data_disk_cache_type", Type: cty.String, Required: false}, - "image_hyperv_generation": &hcldec.AttrSpec{Name: "image_hyperv_generation", Type: cty.String, Required: false}, - "temporary_os_disk_id": &hcldec.AttrSpec{Name: "temporary_os_disk_id", Type: cty.String, Required: false}, - "temporary_os_disk_snapshot_id": &hcldec.AttrSpec{Name: "temporary_os_disk_snapshot_id", Type: cty.String, Required: false}, - "temporary_data_disk_id_prefix": &hcldec.AttrSpec{Name: "temporary_data_disk_id_prefix", Type: cty.String, Required: false}, - "temporary_data_disk_snapshot_id": &hcldec.AttrSpec{Name: "temporary_data_disk_snapshot_id", Type: cty.String, Required: false}, - "skip_cleanup": &hcldec.AttrSpec{Name: "skip_cleanup", Type: cty.Bool, Required: false}, - "image_resource_id": &hcldec.AttrSpec{Name: "image_resource_id", Type: cty.String, Required: false}, - "shared_image_destination": &hcldec.BlockSpec{TypeName: "shared_image_destination", Nested: hcldec.ObjectSpec((*FlatSharedImageGalleryDestination)(nil).HCL2Spec())}, - } - return s -} diff --git a/builder/azure/chroot/builder_test.go b/builder/azure/chroot/builder_test.go deleted file mode 100644 index 88a38cc8e..000000000 --- a/builder/azure/chroot/builder_test.go +++ /dev/null @@ -1,234 +0,0 @@ -package chroot - -import ( - "strings" - "testing" - - "github.com/hashicorp/packer-plugin-sdk/multistep" - "github.com/hashicorp/packer/builder/azure/common/client" - - "github.com/Azure/azure-sdk-for-go/services/compute/mgmt/2019-12-01/compute" -) - -func TestBuilder_Prepare(t *testing.T) { - type config map[string]interface{} - type regexMatchers map[string]string // map of regex : error message - - tests := []struct { - name string - config config - validate func(Config) - wantErr bool - }{ - { - name: "platform image to managed disk", - config: config{ - "client_id": "123", - "client_secret": "456", - "subscription_id": "789", - "source": "credativ:Debian:9:latest", - "image_resource_id": "/subscriptions/789/resourceGroups/otherrgname/providers/Microsoft.Compute/images/MyDebianOSImage-{{timestamp}}", - "shared_image_destination": config{ - "resource_group": "otherrgname", - "gallery_name": "myGallery", - "image_name": "imageName", - "image_version": "1.0.2", - }, - }, - validate: func(c Config) { - if c.OSDiskSizeGB != 0 { - t.Errorf("Expected OSDiskSizeGB to be 0, was %+v", c.OSDiskSizeGB) - } - if c.MountPartition != "1" { - t.Errorf("Expected MountPartition to be %s, but found %s", "1", c.MountPartition) - } - if c.OSDiskStorageAccountType != string(compute.PremiumLRS) { - t.Errorf("Expected OSDiskStorageAccountType to be %s, but found %s", string(compute.PremiumLRS), c.OSDiskStorageAccountType) - } - if c.OSDiskCacheType != string(compute.CachingTypesReadOnly) { - t.Errorf("Expected OSDiskCacheType to be %s, but found %s", string(compute.CachingTypesReadOnly), c.OSDiskCacheType) - } - if c.ImageHyperVGeneration != string(compute.V1) { - t.Errorf("Expected ImageHyperVGeneration to be %s, but found %s", string(compute.V1), c.ImageHyperVGeneration) - } - }, - }, - { - name: "disk to managed image, validate temp disk id expansion", - config: config{ - "source": "/subscriptions/789/resourceGroups/testrg/providers/Microsoft.Compute/disks/diskname", - "image_resource_id": "/subscriptions/789/resourceGroups/otherrgname/providers/Microsoft.Compute/images/MyDebianOSImage-{{timestamp}}", - }, - validate: func(c Config) { - prefix := "/subscriptions/testSubscriptionID/resourceGroups/testResourceGroup/providers/Microsoft.Compute/disks/PackerTemp-osdisk-" - if !strings.HasPrefix(c.TemporaryOSDiskID, prefix) { - t.Errorf("Expected TemporaryOSDiskID to start with %q, but got %q", prefix, c.TemporaryOSDiskID) - } - }, - }, - { - name: "disk to both managed image and shared image", - config: config{ - "source": "/subscriptions/789/resourceGroups/testrg/providers/Microsoft.Compute/disks/diskname", - "image_resource_id": "/subscriptions/789/resourceGroups/otherrgname/providers/Microsoft.Compute/images/MyDebianOSImage-{{timestamp}}", - "shared_image_destination": config{ - "resource_group": "rg", - "gallery_name": "galleryName", - "image_name": "imageName", - "image_version": "0.1.0", - }, - }, - }, - { - name: "disk to both managed image and shared image with missing property", - config: config{ - "source": "/subscriptions/789/resourceGroups/testrg/providers/Microsoft.Compute/disks/diskname", - "image_resource_id": "/subscriptions/789/resourceGroups/otherrgname/providers/Microsoft.Compute/images/MyDebianOSImage-{{timestamp}}", - "shared_image_destination": config{ - "resource_group": "rg", - "gallery_name": "galleryName", - "image_version": "0.1.0", - }, - }, - wantErr: true, - }, - { - name: "from shared image", - config: config{ - "shared_image_destination": config{ - "resource_group": "otherrgname", - "gallery_name": "myGallery", - "image_name": "imageName", - "image_version": "1.0.2", - }, - "source": "/subscriptions/789/resourceGroups/testrg/providers/Microsoft.Compute/disks/diskname", - }, - wantErr: false, - }, - { - name: "err: no output", - config: config{ - "source": "/subscriptions/789/resourceGroups/testrg/providers/Microsoft.Compute/disks/diskname", - }, - wantErr: true, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - withMetadataStub(func() { - b := &Builder{} - - _, _, err := b.Prepare(tt.config) - - if (err != nil) != tt.wantErr { - t.Errorf("Builder.Prepare() error = %v, wantErr %v", err, tt.wantErr) - return - } - - if tt.validate != nil { - tt.validate(b.config) - } - }) - }) - } -} - -func Test_buildsteps(t *testing.T) { - info := &client.ComputeInfo{ - Location: "northpole", - Name: "unittestVM", - ResourceGroupName: "unittestResourceGroup", - SubscriptionID: "96854241-60c7-426d-9a27-3fdeec8957f4", - } - - tests := []struct { - name string - config Config - verify func([]multistep.Step, *testing.T) - }{ - { - name: "Source FromScrath creates empty disk", - config: Config{FromScratch: true}, - verify: func(steps []multistep.Step, _ *testing.T) { - for _, s := range steps { - if s, ok := s.(*StepCreateNewDiskset); ok { - if s.SourceOSDiskResourceID == "" && - s.SourcePlatformImage == nil { - return - } - t.Errorf("found misconfigured StepCreateNewDisk: %+v", s) - } - } - t.Error("did not find a StepCreateNewDisk") - }}, - { - name: "Source Platform image disk creation", - config: Config{Source: "publisher:offer:sku:version", sourceType: sourcePlatformImage}, - verify: func(steps []multistep.Step, _ *testing.T) { - for _, s := range steps { - if s, ok := s.(*StepCreateNewDiskset); ok { - if s.SourceOSDiskResourceID == "" && - s.SourcePlatformImage != nil && - s.SourcePlatformImage.Publisher == "publisher" { - return - } - t.Errorf("found misconfigured StepCreateNewDisk: %+v", s) - } - } - t.Error("did not find a StepCreateNewDisk") - }}, - { - name: "Source Platform image with version latest adds StepResolvePlatformImageVersion", - config: Config{Source: "publisher:offer:sku:latest", sourceType: sourcePlatformImage}, - verify: func(steps []multistep.Step, _ *testing.T) { - for _, s := range steps { - if s, ok := s.(*StepResolvePlatformImageVersion); ok { - if s.PlatformImage != nil && - s.Location == info.Location { - return - } - t.Errorf("found misconfigured StepResolvePlatformImageVersion: %+v", s) - } - } - t.Error("did not find a StepResolvePlatformImageVersion") - }}, - { - name: "Source Disk adds correct disk creation", - config: Config{Source: "diskresourceid", sourceType: sourceDisk}, - verify: func(steps []multistep.Step, _ *testing.T) { - for _, s := range steps { - if s, ok := s.(*StepCreateNewDiskset); ok { - if s.SourceOSDiskResourceID == "diskresourceid" && - s.SourcePlatformImage == nil { - return - } - t.Errorf("found misconfigured StepCreateNewDisk: %+v", s) - } - } - t.Error("did not find a StepCreateNewDisk") - }}, - { - name: "Source disk adds StepVerifySourceDisk", - config: Config{Source: "diskresourceid", sourceType: sourceDisk}, - verify: func(steps []multistep.Step, _ *testing.T) { - for _, s := range steps { - if s, ok := s.(*StepVerifySourceDisk); ok { - if s.SourceDiskResourceID == "diskresourceid" && - s.Location == info.Location { - return - } - t.Errorf("found misconfigured StepVerifySourceDisk: %+v", s) - } - } - t.Error("did not find a StepVerifySourceDisk") - }}, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - withMetadataStub(func() { // ensure that values are taken from info, instead of retrieved again - got := buildsteps(tt.config, info) - tt.verify(got, t) - }) - }) - } -} diff --git a/builder/azure/chroot/const.go b/builder/azure/chroot/const.go deleted file mode 100644 index e99cf6284..000000000 --- a/builder/azure/chroot/const.go +++ /dev/null @@ -1,6 +0,0 @@ -package chroot - -const ( - stateBagKey_Diskset = "diskset" - stateBagKey_Snapshotset = "snapshotset" -) diff --git a/builder/azure/chroot/diskattacher.go b/builder/azure/chroot/diskattacher.go deleted file mode 100644 index a6516e3e3..000000000 --- a/builder/azure/chroot/diskattacher.go +++ /dev/null @@ -1,190 +0,0 @@ -package chroot - -import ( - "context" - "errors" - "log" - "strings" - "time" - - "github.com/Azure/azure-sdk-for-go/services/compute/mgmt/2019-12-01/compute" - "github.com/Azure/go-autorest/autorest/azure" - "github.com/Azure/go-autorest/autorest/to" - "github.com/hashicorp/packer/builder/azure/common/client" -) - -type DiskAttacher interface { - AttachDisk(ctx context.Context, disk string) (lun int32, err error) - WaitForDevice(ctx context.Context, i int32) (device string, err error) - DetachDisk(ctx context.Context, disk string) (err error) - WaitForDetach(ctx context.Context, diskID string) error -} - -var NewDiskAttacher = func(azureClient client.AzureClientSet) DiskAttacher { - return &diskAttacher{ - azcli: azureClient, - } -} - -type diskAttacher struct { - azcli client.AzureClientSet - - vm *client.ComputeInfo // store info about this VM so that we don't have to ask metadata service on every call -} - -var DiskNotFoundError = errors.New("Disk not found") - -func (da *diskAttacher) DetachDisk(ctx context.Context, diskID string) error { - log.Println("Fetching list of disks currently attached to VM") - currentDisks, err := da.getDisks(ctx) - if err != nil { - return err - } - - log.Printf("Removing %q from list of disks currently attached to VM", diskID) - newDisks := []compute.DataDisk{} - for _, disk := range currentDisks { - if disk.ManagedDisk != nil && - !strings.EqualFold(to.String(disk.ManagedDisk.ID), diskID) { - newDisks = append(newDisks, disk) - } - } - if len(currentDisks) == len(newDisks) { - return DiskNotFoundError - } - - log.Println("Updating new list of disks attached to VM") - err = da.setDisks(ctx, newDisks) - if err != nil { - return err - } - - return nil -} - -func (da *diskAttacher) WaitForDetach(ctx context.Context, diskID string) error { - for { // loop until disk is not attached, timeout or error - list, err := da.getDisks(ctx) - if err != nil { - return err - } - if findDiskInList(list, diskID) == nil { - log.Println("Disk is no longer in VM model, assuming detached") - return nil - } - - select { - case <-time.After(time.Second): //continue - case <-ctx.Done(): - return ctx.Err() - } - } -} - -func (da *diskAttacher) AttachDisk(ctx context.Context, diskID string) (int32, error) { - dataDisks, err := da.getDisks(ctx) - if err != nil { - return -1, err - } - - // check to see if disk is already attached, remember lun if found - if disk := findDiskInList(dataDisks, diskID); disk != nil { - // disk is already attached, just take this lun - if disk.Lun == nil { - return -1, errors.New("disk is attached, but lun was not set in VM model (possibly an error in the Azure APIs)") - } - return to.Int32(disk.Lun), nil - } - - // disk was not found on VM, go and actually attach it - - var lun int32 = -1 -findFreeLun: - for lun = 0; lun < 64; lun++ { - for _, v := range dataDisks { - if to.Int32(v.Lun) == lun { - continue findFreeLun - } - } - // no datadisk is using this lun - break - } - - // append new data disk to collection - dataDisks = append(dataDisks, compute.DataDisk{ - CreateOption: compute.DiskCreateOptionTypesAttach, - ManagedDisk: &compute.ManagedDiskParameters{ - ID: to.StringPtr(diskID), - }, - Lun: to.Int32Ptr(lun), - }) - - // prepare resource object for update operation - err = da.setDisks(ctx, dataDisks) - if err != nil { - return -1, err - } - - return lun, nil -} - -func (da *diskAttacher) getThisVM(ctx context.Context) (compute.VirtualMachine, error) { - // getting resource info for this VM - if da.vm == nil { - vm, err := da.azcli.MetadataClient().GetComputeInfo() - if err != nil { - return compute.VirtualMachine{}, err - } - da.vm = vm - } - - // retrieve actual VM - vmResource, err := da.azcli.VirtualMachinesClient().Get(ctx, da.vm.ResourceGroupName, da.vm.Name, "") - if err != nil { - return compute.VirtualMachine{}, err - } - if vmResource.StorageProfile == nil { - return compute.VirtualMachine{}, errors.New("properties.storageProfile is not set on VM, this is unexpected") - } - - return vmResource, nil -} - -func (da diskAttacher) getDisks(ctx context.Context) ([]compute.DataDisk, error) { - vmResource, err := da.getThisVM(ctx) - if err != nil { - return []compute.DataDisk{}, err - } - - return *vmResource.StorageProfile.DataDisks, nil -} - -func (da diskAttacher) setDisks(ctx context.Context, disks []compute.DataDisk) error { - vmResource, err := da.getThisVM(ctx) - if err != nil { - return err - } - - id, err := azure.ParseResourceID(to.String(vmResource.ID)) - if err != nil { - return err - } - - vmResource.StorageProfile.DataDisks = &disks - vmResource.Resources = nil - - // update the VM resource, attach disk - _, err = da.azcli.VirtualMachinesClient().CreateOrUpdate(ctx, id.ResourceGroup, id.ResourceName, vmResource) - - return err -} - -func findDiskInList(list []compute.DataDisk, diskID string) *compute.DataDisk { - for _, disk := range list { - if disk.ManagedDisk != nil && - strings.EqualFold(to.String(disk.ManagedDisk.ID), diskID) { - return &disk - } - } - return nil -} diff --git a/builder/azure/chroot/diskattacher_freebsd.go b/builder/azure/chroot/diskattacher_freebsd.go deleted file mode 100644 index ecfc5cf60..000000000 --- a/builder/azure/chroot/diskattacher_freebsd.go +++ /dev/null @@ -1,54 +0,0 @@ -package chroot - -import ( - "bufio" - "bytes" - "context" - "fmt" - "os/exec" - "regexp" - "strings" - "time" -) - -func (da diskAttacher) WaitForDevice(ctx context.Context, lun int32) (device string, err error) { - // This builder will always be running in Azure, where data disks show up - // on scbus5 target 0. The camcontrol command always outputs LUNs in - // unpadded hexadecimal format. - regexStr := fmt.Sprintf(`at scbus5 target 0 lun %x \(.*?da([\d]+)`, lun) - devRegex, err := regexp.Compile(regexStr) - if err != nil { - return "", err - } - for { - cmd := exec.Command("camcontrol", "devlist") - var out bytes.Buffer - cmd.Stdout = &out - err = cmd.Run() - if err != nil { - return "", err - } - outString := out.String() - scanner := bufio.NewScanner(strings.NewReader(outString)) - for scanner.Scan() { - line := scanner.Text() - // Check if this is the correct bus, target, and LUN. - if matches := devRegex.FindStringSubmatch(line); matches != nil { - // If this function immediately returns, devfs won't have - // created the device yet. - time.Sleep(1000 * time.Millisecond) - return fmt.Sprintf("/dev/da%s", matches[1]), nil - } - } - if err = scanner.Err(); err != nil { - return "", err - } - - select { - case <-time.After(100 * time.Millisecond): - // continue - case <-ctx.Done(): - return "", ctx.Err() - } - } -} diff --git a/builder/azure/chroot/diskattacher_linux.go b/builder/azure/chroot/diskattacher_linux.go deleted file mode 100644 index 3d1403691..000000000 --- a/builder/azure/chroot/diskattacher_linux.go +++ /dev/null @@ -1,36 +0,0 @@ -package chroot - -import ( - "context" - "fmt" - "os" - "path/filepath" - "syscall" - "time" -) - -func diskPathForLun(lun int32) string { - return fmt.Sprintf("/dev/disk/azure/scsi1/lun%d", lun) -} - -func (da diskAttacher) WaitForDevice(ctx context.Context, lun int32) (device string, err error) { - path := diskPathForLun(lun) - - for { - link, err := os.Readlink(path) - if err == nil { - return filepath.Abs("/dev/disk/azure/scsi1/" + link) - } else if err != os.ErrNotExist { - if pe, ok := err.(*os.PathError); ok && pe.Err != syscall.ENOENT { - return "", err - } - } - - select { - case <-time.After(100 * time.Millisecond): - // continue - case <-ctx.Done(): - return "", ctx.Err() - } - } -} diff --git a/builder/azure/chroot/diskattacher_other.go b/builder/azure/chroot/diskattacher_other.go deleted file mode 100644 index 3fea09037..000000000 --- a/builder/azure/chroot/diskattacher_other.go +++ /dev/null @@ -1,11 +0,0 @@ -// +build !linux,!freebsd - -package chroot - -import ( - "context" -) - -func (da diskAttacher) WaitForDevice(ctx context.Context, lun int32) (device string, err error) { - panic("The azure-chroot builder does not work on this platform.") -} diff --git a/builder/azure/chroot/diskattacher_test.go b/builder/azure/chroot/diskattacher_test.go deleted file mode 100644 index 9e617f59b..000000000 --- a/builder/azure/chroot/diskattacher_test.go +++ /dev/null @@ -1,87 +0,0 @@ -package chroot - -import ( - "context" - "testing" - - "github.com/Azure/go-autorest/autorest/to" - - "github.com/Azure/azure-sdk-for-go/services/compute/mgmt/2019-12-01/compute" - "github.com/hashicorp/packer/builder/azure/common/client" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" -) - -const ( - testvm = "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/testGroup/Microsoft.Compute/virtualMachines/testVM" - testdisk = "/subscriptions/00000000-0000-0000-0000-000000000001/resourceGroups/testGroup2/Microsoft.Compute/disks/testDisk" -) - -// Tests assume current machine is capable of running chroot builder (i.e. an Azure VM) - -func Test_DiskAttacherAttachesDiskToVM(t *testing.T) { - azcli, err := client.GetTestClientSet(t) // integration test - require.Nil(t, err) - da := NewDiskAttacher(azcli) - testDiskName := t.Name() - - vm, err := azcli.MetadataClient().GetComputeInfo() - require.Nil(t, err, "Test needs to run on an Azure VM, unable to retrieve VM information") - t.Log("Creating new disk '", testDiskName, "' in ", vm.ResourceGroupName) - - disk, err := azcli.DisksClient().Get(context.TODO(), vm.ResourceGroupName, testDiskName) - if err == nil { - t.Log("Disk already exists") - if disk.DiskState == compute.Attached { - t.Log("Disk is attached, assuming to this machine, trying to detach") - err = da.DetachDisk(context.TODO(), to.String(disk.ID)) - require.Nil(t, err) - } - t.Log("Deleting disk") - result, err := azcli.DisksClient().Delete(context.TODO(), vm.ResourceGroupName, testDiskName) - require.Nil(t, err) - err = result.WaitForCompletionRef(context.TODO(), azcli.PollClient()) - require.Nil(t, err) - } - - t.Log("Creating disk") - r, err := azcli.DisksClient().CreateOrUpdate(context.TODO(), vm.ResourceGroupName, testDiskName, compute.Disk{ - Location: to.StringPtr(vm.Location), - Sku: &compute.DiskSku{ - Name: compute.StandardLRS, - }, - DiskProperties: &compute.DiskProperties{ - DiskSizeGB: to.Int32Ptr(30), - CreationData: &compute.CreationData{CreateOption: compute.Empty}, - }, - }) - require.Nil(t, err) - err = r.WaitForCompletionRef(context.TODO(), azcli.PollClient()) - require.Nil(t, err) - - t.Log("Retrieving disk properties") - d, err := azcli.DisksClient().Get(context.TODO(), vm.ResourceGroupName, testDiskName) - require.Nil(t, err) - assert.NotNil(t, d) - - t.Log("Attaching disk") - lun, err := da.AttachDisk(context.TODO(), to.String(d.ID)) - assert.Nil(t, err) - - t.Log("Waiting for device") - dev, err := da.WaitForDevice(context.TODO(), lun) - assert.Nil(t, err) - - t.Log("Device path:", dev) - - t.Log("Detaching disk") - err = da.DetachDisk(context.TODO(), to.String(d.ID)) - require.Nil(t, err) - - t.Log("Deleting disk") - result, err := azcli.DisksClient().Delete(context.TODO(), vm.ResourceGroupName, testDiskName) - if err == nil { - err = result.WaitForCompletionRef(context.TODO(), azcli.PollClient()) - } - require.Nil(t, err) -} diff --git a/builder/azure/chroot/diskset.go b/builder/azure/chroot/diskset.go deleted file mode 100644 index 0d7adb22f..000000000 --- a/builder/azure/chroot/diskset.go +++ /dev/null @@ -1,23 +0,0 @@ -package chroot - -import "github.com/hashicorp/packer/builder/azure/common/client" - -// Diskset represents all of the disks or snapshots associated with an image. -// It maps lun to resource ids. The OS disk is stored with lun=-1. -type Diskset map[int32]client.Resource - -// OS return the OS disk resource ID or nil if it is not assigned -func (ds Diskset) OS() *client.Resource { - if r, ok := ds[-1]; ok { - return &r - } - return nil -} - -// Data return the data disk resource ID or nil if it is not assigned -func (ds Diskset) Data(lun int32) *client.Resource { - if r, ok := ds[lun]; ok { - return &r - } - return nil -} diff --git a/builder/azure/chroot/diskset_test.go b/builder/azure/chroot/diskset_test.go deleted file mode 100644 index 7adc170ab..000000000 --- a/builder/azure/chroot/diskset_test.go +++ /dev/null @@ -1,16 +0,0 @@ -package chroot - -import "github.com/hashicorp/packer/builder/azure/common/client" - -// diskset easily creates a diskset for testing -func diskset(ids ...string) Diskset { - diskset := make(Diskset) - for i, id := range ids { - r, err := client.ParseResourceID(id) - if err != nil { - panic(err) - } - diskset[int32(i-1)] = r - } - return diskset -} diff --git a/builder/azure/chroot/metadatastub_test.go b/builder/azure/chroot/metadatastub_test.go deleted file mode 100644 index 575fcdafc..000000000 --- a/builder/azure/chroot/metadatastub_test.go +++ /dev/null @@ -1,18 +0,0 @@ -package chroot - -import "github.com/hashicorp/packer/builder/azure/common/client" - -func withMetadataStub(f func()) { - mdc := client.DefaultMetadataClient - defer func() { client.DefaultMetadataClient = mdc }() - client.DefaultMetadataClient = client.MetadataClientStub{ - ComputeInfo: client.ComputeInfo{ - SubscriptionID: "testSubscriptionID", - ResourceGroupName: "testResourceGroup", - Name: "testVM", - Location: "testLocation", - }, - } - - f() -} diff --git a/builder/azure/chroot/packerui_test.go b/builder/azure/chroot/packerui_test.go deleted file mode 100644 index 250d7063c..000000000 --- a/builder/azure/chroot/packerui_test.go +++ /dev/null @@ -1,19 +0,0 @@ -package chroot - -import ( - "io/ioutil" - "strings" - - packersdk "github.com/hashicorp/packer-plugin-sdk/packer" -) - -// testUI returns a test ui plus a function to retrieve the errors written to the ui -func testUI() (packersdk.Ui, func() string) { - errorBuffer := &strings.Builder{} - ui := &packersdk.BasicUi{ - Reader: strings.NewReader(""), - Writer: ioutil.Discard, - ErrorWriter: errorBuffer, - } - return ui, errorBuffer.String -} diff --git a/builder/azure/chroot/shared_image_gallery_destination.go b/builder/azure/chroot/shared_image_gallery_destination.go deleted file mode 100644 index de124f356..000000000 --- a/builder/azure/chroot/shared_image_gallery_destination.go +++ /dev/null @@ -1,71 +0,0 @@ -//go:generate packer-sdc struct-markdown -//go:generate packer-sdc mapstructure-to-hcl2 -type SharedImageGalleryDestination,TargetRegion - -package chroot - -import ( - "fmt" - "regexp" -) - -// SharedImageGalleryDestination models an image version in a Shared -// Image Gallery that can be used as a destination. -type SharedImageGalleryDestination struct { - ResourceGroup string `mapstructure:"resource_group" required:"true"` - GalleryName string `mapstructure:"gallery_name" required:"true"` - ImageName string `mapstructure:"image_name" required:"true"` - ImageVersion string `mapstructure:"image_version" required:"true"` - - TargetRegions []TargetRegion `mapstructure:"target_regions"` - ExcludeFromLatest bool `mapstructure:"exclude_from_latest"` - ExcludeFromLatestTypo bool `mapstructure:"exlude_from_latest" undocumented:"true"` -} - -// TargetRegion describes a region where the shared image should be replicated -type TargetRegion struct { - // Name of the Azure region - Name string `mapstructure:"name" required:"true"` - // Number of replicas in this region. Default: 1 - ReplicaCount int32 `mapstructure:"replicas"` - // Storage account type: Standard_LRS or Standard_ZRS. Default: Standard_ZRS - StorageAccountType string `mapstructure:"storage_account_type"` -} - -// ResourceID returns the resource ID string -func (sigd SharedImageGalleryDestination) ResourceID(subscriptionID string) string { - return fmt.Sprintf("/subscriptions/%s/resourceGroups/%s/providers/Microsoft.Compute/galleries/%s/images/%s/versions/%s", - subscriptionID, - sigd.ResourceGroup, - sigd.GalleryName, - sigd.ImageName, - sigd.ImageVersion) -} - -// Validate validates that the values in the shared image are valid (without checking them on the network) -func (sigd *SharedImageGalleryDestination) Validate(prefix string) (errs []error, warns []string) { - if sigd.ResourceGroup == "" { - errs = append(errs, fmt.Errorf("%s.resource_group is required", prefix)) - } - if sigd.GalleryName == "" { - errs = append(errs, fmt.Errorf("%s.gallery_name is required", prefix)) - } - if sigd.ImageName == "" { - errs = append(errs, fmt.Errorf("%s.image_name is required", prefix)) - } - if match, err := regexp.MatchString("^[0-9]+\\.[0-9]+\\.[0-9]+$", sigd.ImageVersion); !match { - if err != nil { - warns = append(warns, fmt.Sprintf("Error matching pattern for %s.image_version: %s (this is probably a bug)", prefix, err)) - } - errs = append(errs, fmt.Errorf("%s.image_version should match '^[0-9]+\\.[0-9]+\\.[0-9]+$'", prefix)) - } - if len(sigd.TargetRegions) == 0 { - warns = append(warns, - fmt.Sprintf("%s.target_regions is empty; image will only be available in the region of the gallery", prefix)) - } - if sigd.ExcludeFromLatestTypo == true && sigd.ExcludeFromLatest == false { - warns = append(warns, - fmt.Sprintf("%s.exlude_from_latest is being deprecated, please use exclude_from_latest", prefix)) - sigd.ExcludeFromLatest = sigd.ExcludeFromLatestTypo - } - return -} diff --git a/builder/azure/chroot/shared_image_gallery_destination.hcl2spec.go b/builder/azure/chroot/shared_image_gallery_destination.hcl2spec.go deleted file mode 100644 index 3da1bc72d..000000000 --- a/builder/azure/chroot/shared_image_gallery_destination.hcl2spec.go +++ /dev/null @@ -1,70 +0,0 @@ -// Code generated by "packer-sdc mapstructure-to-hcl2"; DO NOT EDIT. - -package chroot - -import ( - "github.com/hashicorp/hcl/v2/hcldec" - "github.com/zclconf/go-cty/cty" -) - -// FlatSharedImageGalleryDestination is an auto-generated flat version of SharedImageGalleryDestination. -// Where the contents of a field with a `mapstructure:,squash` tag are bubbled up. -type FlatSharedImageGalleryDestination struct { - ResourceGroup *string `mapstructure:"resource_group" required:"true" cty:"resource_group" hcl:"resource_group"` - GalleryName *string `mapstructure:"gallery_name" required:"true" cty:"gallery_name" hcl:"gallery_name"` - ImageName *string `mapstructure:"image_name" required:"true" cty:"image_name" hcl:"image_name"` - ImageVersion *string `mapstructure:"image_version" required:"true" cty:"image_version" hcl:"image_version"` - TargetRegions []FlatTargetRegion `mapstructure:"target_regions" cty:"target_regions" hcl:"target_regions"` - ExcludeFromLatest *bool `mapstructure:"exclude_from_latest" cty:"exclude_from_latest" hcl:"exclude_from_latest"` - ExcludeFromLatestTypo *bool `mapstructure:"exlude_from_latest" undocumented:"true" cty:"exlude_from_latest" hcl:"exlude_from_latest"` -} - -// FlatMapstructure returns a new FlatSharedImageGalleryDestination. -// FlatSharedImageGalleryDestination is an auto-generated flat version of SharedImageGalleryDestination. -// Where the contents a fields with a `mapstructure:,squash` tag are bubbled up. -func (*SharedImageGalleryDestination) FlatMapstructure() interface{ HCL2Spec() map[string]hcldec.Spec } { - return new(FlatSharedImageGalleryDestination) -} - -// HCL2Spec returns the hcl spec of a SharedImageGalleryDestination. -// This spec is used by HCL to read the fields of SharedImageGalleryDestination. -// The decoded values from this spec will then be applied to a FlatSharedImageGalleryDestination. -func (*FlatSharedImageGalleryDestination) HCL2Spec() map[string]hcldec.Spec { - s := map[string]hcldec.Spec{ - "resource_group": &hcldec.AttrSpec{Name: "resource_group", Type: cty.String, Required: false}, - "gallery_name": &hcldec.AttrSpec{Name: "gallery_name", Type: cty.String, Required: false}, - "image_name": &hcldec.AttrSpec{Name: "image_name", Type: cty.String, Required: false}, - "image_version": &hcldec.AttrSpec{Name: "image_version", Type: cty.String, Required: false}, - "target_regions": &hcldec.BlockListSpec{TypeName: "target_regions", Nested: hcldec.ObjectSpec((*FlatTargetRegion)(nil).HCL2Spec())}, - "exclude_from_latest": &hcldec.AttrSpec{Name: "exclude_from_latest", Type: cty.Bool, Required: false}, - "exlude_from_latest": &hcldec.AttrSpec{Name: "exlude_from_latest", Type: cty.Bool, Required: false}, - } - return s -} - -// FlatTargetRegion is an auto-generated flat version of TargetRegion. -// Where the contents of a field with a `mapstructure:,squash` tag are bubbled up. -type FlatTargetRegion struct { - Name *string `mapstructure:"name" required:"true" cty:"name" hcl:"name"` - ReplicaCount *int32 `mapstructure:"replicas" cty:"replicas" hcl:"replicas"` - StorageAccountType *string `mapstructure:"storage_account_type" cty:"storage_account_type" hcl:"storage_account_type"` -} - -// FlatMapstructure returns a new FlatTargetRegion. -// FlatTargetRegion is an auto-generated flat version of TargetRegion. -// Where the contents a fields with a `mapstructure:,squash` tag are bubbled up. -func (*TargetRegion) FlatMapstructure() interface{ HCL2Spec() map[string]hcldec.Spec } { - return new(FlatTargetRegion) -} - -// HCL2Spec returns the hcl spec of a TargetRegion. -// This spec is used by HCL to read the fields of TargetRegion. -// The decoded values from this spec will then be applied to a FlatTargetRegion. -func (*FlatTargetRegion) HCL2Spec() map[string]hcldec.Spec { - s := map[string]hcldec.Spec{ - "name": &hcldec.AttrSpec{Name: "name", Type: cty.String, Required: false}, - "replicas": &hcldec.AttrSpec{Name: "replicas", Type: cty.Number, Required: false}, - "storage_account_type": &hcldec.AttrSpec{Name: "storage_account_type", Type: cty.String, Required: false}, - } - return s -} diff --git a/builder/azure/chroot/shared_image_gallery_destination_test.go b/builder/azure/chroot/shared_image_gallery_destination_test.go deleted file mode 100644 index 480c8ac7b..000000000 --- a/builder/azure/chroot/shared_image_gallery_destination_test.go +++ /dev/null @@ -1,158 +0,0 @@ -package chroot - -import ( - "reflect" - "strings" - "testing" -) - -func TestSharedImageGalleryDestination_ResourceID(t *testing.T) { - sigd := SharedImageGalleryDestination{ - ResourceGroup: "ResourceGroup", - GalleryName: "GalleryName", - ImageName: "ImageName", - ImageVersion: "ImageVersion", - } - want := "/subscriptions/SubscriptionID/resourceGroups/ResourceGroup/providers/Microsoft.Compute/galleries/GalleryName/images/ImageName/versions/ImageVersion" - if got := sigd.ResourceID("SubscriptionID"); !strings.EqualFold(got, want) { - t.Errorf("SharedImageGalleryDestination.ResourceID() = %v, want %v", got, want) - } -} - -func TestSharedImageGalleryDestination_Validate(t *testing.T) { - type fields struct { - ResourceGroup string - GalleryName string - ImageName string - ImageVersion string - TargetRegions []TargetRegion - ExcludeFromLatest bool - ExcludeFromLatestTypo bool - } - tests := []struct { - name string - fields fields - wantErrs []string - wantWarns []string - }{ - { - name: "complete", - fields: fields{ - ResourceGroup: "ResourceGroup", - GalleryName: "GalleryName", - ImageName: "ImageName", - ImageVersion: "0.1.2", - TargetRegions: []TargetRegion{ - TargetRegion{ - Name: "region1", - ReplicaCount: 5, - StorageAccountType: "Standard_ZRS", - }, - TargetRegion{ - Name: "region2", - ReplicaCount: 3, - StorageAccountType: "Standard_LRS", - }, - }, - ExcludeFromLatest: true, - }, - }, - { - name: "warn if target regions not specified", - fields: fields{ - ResourceGroup: "ResourceGroup", - GalleryName: "GalleryName", - ImageName: "ImageName", - ImageVersion: "0.1.2", - }, - wantWarns: []string{"sigdest.target_regions is empty; image will only be available in the region of the gallery"}, - }, - { - name: "warn if using exlude_from_latest", - fields: fields{ - ResourceGroup: "ResourceGroup", - GalleryName: "GalleryName", - ImageName: "ImageName", - ImageVersion: "0.1.2", - TargetRegions: []TargetRegion{ - TargetRegion{ - Name: "region1", - ReplicaCount: 5, - StorageAccountType: "Standard_ZRS", - }, - TargetRegion{ - Name: "region2", - ReplicaCount: 3, - StorageAccountType: "Standard_LRS", - }, - }, - ExcludeFromLatestTypo: true, - }, - wantWarns: []string{"sigdest.exlude_from_latest is being deprecated, please use exclude_from_latest"}, - }, - { - name: "version format", - wantErrs: []string{ - "sigdest.image_version should match '^[0-9]+\\.[0-9]+\\.[0-9]+$'", - }, - fields: fields{ - ResourceGroup: "ResourceGroup", - GalleryName: "GalleryName", - ImageName: "ImageName", - ImageVersion: "0.1.2alpha", - TargetRegions: []TargetRegion{ - TargetRegion{ - Name: "region1", - ReplicaCount: 5, - StorageAccountType: "Standard_ZRS", - }, - TargetRegion{ - Name: "region2", - ReplicaCount: 3, - StorageAccountType: "Standard_LRS", - }, - }, - ExcludeFromLatest: true, - }, - }, - { - name: "required fields", - wantErrs: []string{ - "sigdest.resource_group is required", - "sigdest.gallery_name is required", - "sigdest.image_name is required", - "sigdest.image_version should match '^[0-9]+\\.[0-9]+\\.[0-9]+$'", - }, - wantWarns: []string{"sigdest.target_regions is empty; image will only be available in the region of the gallery"}, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - sigd := &SharedImageGalleryDestination{ - ResourceGroup: tt.fields.ResourceGroup, - GalleryName: tt.fields.GalleryName, - ImageName: tt.fields.ImageName, - ImageVersion: tt.fields.ImageVersion, - TargetRegions: tt.fields.TargetRegions, - ExcludeFromLatest: tt.fields.ExcludeFromLatest, - ExcludeFromLatestTypo: tt.fields.ExcludeFromLatestTypo, - } - gotErrs, gotWarns := sigd.Validate("sigdest") - - var gotStrErrs []string - if gotErrs != nil { - gotStrErrs = make([]string, len(gotErrs)) - for i, e := range gotErrs { - gotStrErrs[i] = e.Error() - } - } - - if !reflect.DeepEqual(gotStrErrs, tt.wantErrs) { - t.Errorf("SharedImageGalleryDestination.Validate() gotErrs = %q, want %q", gotStrErrs, tt.wantErrs) - } - if !reflect.DeepEqual(gotWarns, tt.wantWarns) { - t.Errorf("SharedImageGalleryDestination.Validate() gotWarns = %q, want %q", gotWarns, tt.wantWarns) - } - }) - } -} diff --git a/builder/azure/chroot/step_attach_disk.go b/builder/azure/chroot/step_attach_disk.go deleted file mode 100644 index 7d8c83425..000000000 --- a/builder/azure/chroot/step_attach_disk.go +++ /dev/null @@ -1,85 +0,0 @@ -package chroot - -import ( - "context" - "fmt" - "log" - "time" - - "github.com/hashicorp/packer-plugin-sdk/multistep" - packersdk "github.com/hashicorp/packer-plugin-sdk/packer" - "github.com/hashicorp/packer/builder/azure/common/client" -) - -var _ multistep.Step = &StepAttachDisk{} - -type StepAttachDisk struct { - attached bool -} - -func (s *StepAttachDisk) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction { - azcli := state.Get("azureclient").(client.AzureClientSet) - ui := state.Get("ui").(packersdk.Ui) - diskset := state.Get(stateBagKey_Diskset).(Diskset) - diskResourceID := diskset.OS().String() - - ui.Say(fmt.Sprintf("Attaching disk '%s'", diskResourceID)) - - da := NewDiskAttacher(azcli) - lun, err := da.AttachDisk(ctx, diskResourceID) - if err != nil { - log.Printf("StepAttachDisk.Run: error: %+v", err) - err := fmt.Errorf( - "error attaching disk '%s': %v", diskResourceID, err) - state.Put("error", err) - ui.Error(err.Error()) - return multistep.ActionHalt - } - - ui.Say("Disk attached, waiting for device to show up") - ctx, cancel := context.WithTimeout(ctx, time.Minute*3) // in case is not configured correctly - defer cancel() - device, err := da.WaitForDevice(ctx, lun) - if err != nil { - log.Printf("StepAttachDisk.Run: error: %+v", err) - err := fmt.Errorf( - "error attaching disk '%s': %v", diskResourceID, err) - state.Put("error", err) - ui.Error(err.Error()) - return multistep.ActionHalt - } - - ui.Say(fmt.Sprintf("Disk available at %q", device)) - s.attached = true - state.Put("device", device) - state.Put("attach_cleanup", s) - return multistep.ActionContinue -} - -func (s *StepAttachDisk) Cleanup(state multistep.StateBag) { - ui := state.Get("ui").(packersdk.Ui) - if err := s.CleanupFunc(state); err != nil { - ui.Error(err.Error()) - } -} - -func (s *StepAttachDisk) CleanupFunc(state multistep.StateBag) error { - - if s.attached { - azcli := state.Get("azureclient").(client.AzureClientSet) - ui := state.Get("ui").(packersdk.Ui) - diskset := state.Get(stateBagKey_Diskset).(Diskset) - diskResourceID := diskset.OS().String() - - ui.Say(fmt.Sprintf("Detaching disk '%s'", diskResourceID)) - - da := NewDiskAttacher(azcli) - err := da.DetachDisk(context.Background(), diskResourceID) - if err != nil { - return fmt.Errorf("error detaching %q: %v", diskResourceID, err) - } - s.attached = false - } - - return nil -} diff --git a/builder/azure/chroot/step_attach_disk_test.go b/builder/azure/chroot/step_attach_disk_test.go deleted file mode 100644 index f512c015c..000000000 --- a/builder/azure/chroot/step_attach_disk_test.go +++ /dev/null @@ -1,131 +0,0 @@ -package chroot - -import ( - "context" - "errors" - "io/ioutil" - "net/http" - "reflect" - "strings" - "testing" - - "github.com/Azure/azure-sdk-for-go/services/compute/mgmt/2019-12-01/compute" - "github.com/Azure/go-autorest/autorest" - "github.com/hashicorp/packer-plugin-sdk/multistep" - packersdk "github.com/hashicorp/packer-plugin-sdk/packer" - "github.com/hashicorp/packer/builder/azure/common/client" -) - -func TestStepAttachDisk_Run(t *testing.T) { - type fields struct { - GetDiskResponseCode int - GetDiskResponseBody string - - attachError error - waitForDeviceError error - } - tests := []struct { - name string - fields fields - want multistep.StepAction - }{ - { - name: "HappyPath", - want: multistep.ActionContinue, - }, - { - name: "AttachError", - fields: fields{ - attachError: errors.New("unit test"), - }, - want: multistep.ActionHalt, - }, - { - name: "WaitForDeviceError", - fields: fields{ - waitForDeviceError: errors.New("unit test"), - }, - want: multistep.ActionHalt, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - s := &StepAttachDisk{} - - NewDiskAttacher = func(azcli client.AzureClientSet) DiskAttacher { - return &fakeDiskAttacher{ - attachError: tt.fields.attachError, - waitForDeviceError: tt.fields.waitForDeviceError, - } - } - - dm := compute.NewDisksClient("subscriptionId") - dm.Sender = autorest.SenderFunc(func(r *http.Request) (*http.Response, error) { - return &http.Response{ - Request: r, - Body: ioutil.NopCloser(strings.NewReader(tt.fields.GetDiskResponseBody)), - StatusCode: tt.fields.GetDiskResponseCode, - }, nil - }) - - errorBuffer := &strings.Builder{} - ui := &packersdk.BasicUi{ - Reader: strings.NewReader(""), - Writer: ioutil.Discard, - ErrorWriter: errorBuffer, - } - - state := new(multistep.BasicStateBag) - state.Put("azureclient", &client.AzureClientSetMock{}) - state.Put("ui", ui) - state.Put(stateBagKey_Diskset, diskset("/subscriptions/12345/resourceGroups/group1/providers/Microsoft.Compute/disks/disk1")) - - got := s.Run(context.TODO(), state) - if !reflect.DeepEqual(got, tt.want) { - t.Errorf("StepAttachDisk.Run() = %v, want %v", got, tt.want) - } - - if got == multistep.ActionHalt { - if _, ok := state.GetOk("error"); !ok { - t.Fatal("Expected 'error' to be set in statebag after failure") - } - } - }) - } -} - -type fakeDiskAttacher struct { - attachError error - waitForDeviceError error -} - -var _ DiskAttacher = &fakeDiskAttacher{} - -func (da *fakeDiskAttacher) AttachDisk(ctx context.Context, disk string) (lun int32, err error) { - if da.attachError != nil { - return 0, da.attachError - } - return 3, nil -} - -func (da *fakeDiskAttacher) DiskPathForLun(lun int32) string { - panic("not implemented") -} - -func (da *fakeDiskAttacher) WaitForDevice(ctx context.Context, lun int32) (device string, err error) { - if da.waitForDeviceError != nil { - return "", da.waitForDeviceError - } - if lun == 3 { - return "/dev/sdq", nil - } - panic("expected lun==3") -} - -func (da *fakeDiskAttacher) DetachDisk(ctx context.Context, disk string) (err error) { - panic("not implemented") -} - -func (da *fakeDiskAttacher) WaitForDetach(ctx context.Context, diskID string) error { - panic("not implemented") -} diff --git a/builder/azure/chroot/step_create_image.go b/builder/azure/chroot/step_create_image.go deleted file mode 100644 index 4c61a9b11..000000000 --- a/builder/azure/chroot/step_create_image.go +++ /dev/null @@ -1,112 +0,0 @@ -package chroot - -import ( - "context" - "fmt" - "log" - "sort" - - "github.com/Azure/azure-sdk-for-go/services/compute/mgmt/2019-12-01/compute" - "github.com/Azure/go-autorest/autorest/azure" - "github.com/Azure/go-autorest/autorest/to" - "github.com/hashicorp/packer-plugin-sdk/multistep" - packersdk "github.com/hashicorp/packer-plugin-sdk/packer" - "github.com/hashicorp/packer/builder/azure/common/client" -) - -var _ multistep.Step = &StepCreateImage{} - -type StepCreateImage struct { - ImageResourceID string - ImageOSState string - OSDiskStorageAccountType string - OSDiskCacheType string - DataDiskStorageAccountType string - DataDiskCacheType string - Location string -} - -func (s *StepCreateImage) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction { - azcli := state.Get("azureclient").(client.AzureClientSet) - ui := state.Get("ui").(packersdk.Ui) - diskset := state.Get(stateBagKey_Diskset).(Diskset) - diskResourceID := diskset.OS().String() - - ui.Say(fmt.Sprintf("Creating image %s\n using %s for os disk.", - s.ImageResourceID, - diskResourceID)) - - imageResource, err := azure.ParseResourceID(s.ImageResourceID) - - if err != nil { - log.Printf("StepCreateImage.Run: error: %+v", err) - err := fmt.Errorf( - "error parsing image resource id '%s': %v", s.ImageResourceID, err) - state.Put("error", err) - ui.Error(err.Error()) - return multistep.ActionHalt - } - - image := compute.Image{ - Location: to.StringPtr(s.Location), - ImageProperties: &compute.ImageProperties{ - StorageProfile: &compute.ImageStorageProfile{ - OsDisk: &compute.ImageOSDisk{ - OsState: compute.OperatingSystemStateTypes(s.ImageOSState), - OsType: compute.Linux, - ManagedDisk: &compute.SubResource{ - ID: &diskResourceID, - }, - StorageAccountType: compute.StorageAccountTypes(s.OSDiskStorageAccountType), - Caching: compute.CachingTypes(s.OSDiskCacheType), - }, - // DataDisks: nil, - // ZoneResilient: nil, - }, - }, - // Tags: nil, - } - - var datadisks []compute.ImageDataDisk - for lun, resource := range diskset { - if lun != -1 { - ui.Say(fmt.Sprintf(" using %q for data disk (lun %d).", resource, lun)) - - datadisks = append(datadisks, compute.ImageDataDisk{ - Lun: to.Int32Ptr(lun), - ManagedDisk: &compute.SubResource{ID: to.StringPtr(resource.String())}, - StorageAccountType: compute.StorageAccountTypes(s.DataDiskStorageAccountType), - Caching: compute.CachingTypes(s.DataDiskCacheType), - }) - } - } - if datadisks != nil { - sort.Slice(datadisks, func(i, j int) bool { - return *datadisks[i].Lun < *datadisks[j].Lun - }) - image.ImageProperties.StorageProfile.DataDisks = &datadisks - } - - f, err := azcli.ImagesClient().CreateOrUpdate( - ctx, - imageResource.ResourceGroup, - imageResource.ResourceName, - image) - if err == nil { - log.Println("Image creation in process...") - err = f.WaitForCompletionRef(ctx, azcli.PollClient()) - } - if err != nil { - log.Printf("StepCreateImage.Run: error: %+v", err) - err := fmt.Errorf( - "error creating image '%s': %v", s.ImageResourceID, err) - state.Put("error", err) - ui.Error(err.Error()) - return multistep.ActionHalt - } - log.Printf("Image creation complete: %s", f.Status()) - - return multistep.ActionContinue -} - -func (*StepCreateImage) Cleanup(bag multistep.StateBag) {} // this is the final artifact, don't delete diff --git a/builder/azure/chroot/step_create_image_test.go b/builder/azure/chroot/step_create_image_test.go deleted file mode 100644 index 054771715..000000000 --- a/builder/azure/chroot/step_create_image_test.go +++ /dev/null @@ -1,137 +0,0 @@ -package chroot - -import ( - "context" - "io/ioutil" - "net/http" - "reflect" - "regexp" - "testing" - - "github.com/hashicorp/packer-plugin-sdk/multistep" - packersdk "github.com/hashicorp/packer-plugin-sdk/packer" - "github.com/hashicorp/packer/builder/azure/common/client" - - "github.com/Azure/azure-sdk-for-go/services/compute/mgmt/2019-12-01/compute" - "github.com/Azure/go-autorest/autorest" -) - -func TestStepCreateImage_Run(t *testing.T) { - type fields struct { - ImageResourceID string - ImageOSState string - OSDiskStorageAccountType string - OSDiskCacheType string - DataDiskStorageAccountType string - DataDiskCacheType string - Location string - } - tests := []struct { - name string - fields fields - diskset Diskset - want multistep.StepAction - wantPutBody string - }{ - { - name: "happy path", - fields: fields{ - ImageResourceID: "/subscriptions/12345/resourceGroups/group1/providers/Microsoft.Compute/images/myImage", - Location: "location1", - OSDiskStorageAccountType: "Standard_LRS", - OSDiskCacheType: "ReadWrite", - DataDiskStorageAccountType: "Premium_LRS", - DataDiskCacheType: "ReadOnly", - }, - diskset: diskset( - "/subscriptions/12345/resourceGroups/group1/providers/Microsoft.Compute/disks/osdisk", - "/subscriptions/12345/resourceGroups/group1/providers/Microsoft.Compute/disks/datadisk0", - "/subscriptions/12345/resourceGroups/group1/providers/Microsoft.Compute/disks/datadisk1", - "/subscriptions/12345/resourceGroups/group1/providers/Microsoft.Compute/disks/datadisk2"), - want: multistep.ActionContinue, - wantPutBody: `{ - "location": "location1", - "properties": { - "storageProfile": { - "osDisk": { - "osType": "Linux", - "managedDisk": { - "id": "/subscriptions/12345/resourceGroups/group1/providers/Microsoft.Compute/disks/osdisk" - }, - "caching": "ReadWrite", - "storageAccountType": "Standard_LRS" - }, - "dataDisks": [ - { - "lun": 0, - "managedDisk": { - "id": "/subscriptions/12345/resourceGroups/group1/providers/Microsoft.Compute/disks/datadisk0" - }, - "caching": "ReadOnly", - "storageAccountType": "Premium_LRS" - }, - { - "lun": 1, - "managedDisk": { - "id": "/subscriptions/12345/resourceGroups/group1/providers/Microsoft.Compute/disks/datadisk1" - }, - "caching": "ReadOnly", - "storageAccountType": "Premium_LRS" - }, - { - "lun": 2, - "managedDisk": { - "id": "/subscriptions/12345/resourceGroups/group1/providers/Microsoft.Compute/disks/datadisk2" - }, - "caching": "ReadOnly", - "storageAccountType": "Premium_LRS" - } - ] - } - } - }`, - }, - } - for _, tt := range tests { - - ic := compute.NewImagesClient("subscriptionID") - ic.Sender = autorest.SenderFunc(func(r *http.Request) (*http.Response, error) { - if r.Method != "PUT" { - t.Fatal("Expected only a PUT call") - } - if tt.wantPutBody != "" { - b, _ := ioutil.ReadAll(r.Body) - expectedPutBody := regexp.MustCompile(`[\s\n]`).ReplaceAllString(tt.wantPutBody, "") - if string(b) != expectedPutBody { - t.Errorf("expected body to be %v, but got %v", expectedPutBody, string(b)) - } - } - return &http.Response{ - Request: r, - StatusCode: 200, - }, nil - }) - - state := new(multistep.BasicStateBag) - state.Put("azureclient", &client.AzureClientSetMock{ - ImagesClientMock: ic, - }) - state.Put("ui", packersdk.TestUi(t)) - state.Put(stateBagKey_Diskset, tt.diskset) - - t.Run(tt.name, func(t *testing.T) { - s := &StepCreateImage{ - ImageResourceID: tt.fields.ImageResourceID, - ImageOSState: tt.fields.ImageOSState, - OSDiskStorageAccountType: tt.fields.OSDiskStorageAccountType, - OSDiskCacheType: tt.fields.OSDiskCacheType, - DataDiskStorageAccountType: tt.fields.DataDiskStorageAccountType, - DataDiskCacheType: tt.fields.DataDiskCacheType, - Location: tt.fields.Location, - } - if got := s.Run(context.TODO(), state); !reflect.DeepEqual(got, tt.want) { - t.Errorf("StepCreateImage.Run() = %v, want %v", got, tt.want) - } - }) - } -} diff --git a/builder/azure/chroot/step_create_new_diskset.go b/builder/azure/chroot/step_create_new_diskset.go deleted file mode 100644 index 1eb1612b1..000000000 --- a/builder/azure/chroot/step_create_new_diskset.go +++ /dev/null @@ -1,239 +0,0 @@ -package chroot - -import ( - "context" - "fmt" - "log" - "strings" - "time" - - "github.com/hashicorp/packer-plugin-sdk/multistep" - packersdk "github.com/hashicorp/packer-plugin-sdk/packer" - "github.com/hashicorp/packer/builder/azure/common/client" - - "github.com/Azure/azure-sdk-for-go/services/compute/mgmt/2019-12-01/compute" - "github.com/Azure/go-autorest/autorest/to" -) - -var _ multistep.Step = &StepCreateNewDiskset{} - -type StepCreateNewDiskset struct { - OSDiskID string // Disk ID - OSDiskSizeGB int32 // optional, ignored if 0 - OSDiskStorageAccountType string // from compute.DiskStorageAccountTypes - DataDiskStorageAccountType string // from compute.DiskStorageAccountTypes - - DataDiskIDPrefix string - - disks Diskset - - HyperVGeneration string // For OS disk - - // Copy another disk - SourceOSDiskResourceID string - - // Extract from platform image - SourcePlatformImage *client.PlatformImage - // Extract from shared image - SourceImageResourceID string - // Location is needed for platform and shared images - Location string - - SkipCleanup bool -} - -func (s *StepCreateNewDiskset) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction { - azcli := state.Get("azureclient").(client.AzureClientSet) - ui := state.Get("ui").(packersdk.Ui) - - s.disks = make(Diskset) - - errorMessage := func(format string, params ...interface{}) multistep.StepAction { - err := fmt.Errorf("StepCreateNewDiskset.Run: error: "+format, params...) - state.Put("error", err) - ui.Error(err.Error()) - return multistep.ActionHalt - } - - // we always have an OS disk - osDisk, err := client.ParseResourceID(s.OSDiskID) - if err != nil { - return errorMessage("error parsing resource id '%s': %v", s.OSDiskID, err) - } - if !strings.EqualFold(osDisk.Provider, "Microsoft.Compute") || - !strings.EqualFold(osDisk.ResourceType.String(), "disks") { - return errorMessage("Resource %q is not of type Microsoft.Compute/disks", s.OSDiskID) - } - - // transform step config to disk model - disk := s.getOSDiskDefinition(azcli.SubscriptionID()) - - // Initiate disk creation - f, err := azcli.DisksClient().CreateOrUpdate(ctx, osDisk.ResourceGroup, osDisk.ResourceName.String(), disk) - if err != nil { - return errorMessage("Failed to initiate resource creation: %q", osDisk) - } - s.disks[-1] = osDisk // save the resoure we just create in our disk set - state.Put(stateBagKey_Diskset, s.disks) // update the statebag - ui.Say(fmt.Sprintf("Creating disk %q", s.OSDiskID)) - - type Future struct { - client.Resource - compute.DisksCreateOrUpdateFuture - } - futures := []Future{{osDisk, f}} - - if s.SourceImageResourceID != "" { - // retrieve image to see if there are any datadisks - imageID, err := client.ParseResourceID(s.SourceImageResourceID) - if err != nil { - return errorMessage("could not parse source image id %q: %v", s.SourceImageResourceID, err) - } - if !strings.EqualFold(imageID.Provider+"/"+imageID.ResourceType.String(), - "Microsoft.Compute/galleries/images/versions") { - return errorMessage("source image id is not a shared image version %q, expected type 'Microsoft.Compute/galleries/images/versions'", imageID) - } - image, err := azcli.GalleryImageVersionsClient().Get(ctx, - imageID.ResourceGroup, - imageID.ResourceName[0], imageID.ResourceName[1], imageID.ResourceName[2], "") - if err != nil { - return errorMessage("error retrieving source image %q: %v", imageID, err) - } - if image.GalleryImageVersionProperties != nil && - image.GalleryImageVersionProperties.StorageProfile != nil && - image.GalleryImageVersionProperties.StorageProfile.DataDiskImages != nil { - for i, ddi := range *image.GalleryImageVersionProperties.StorageProfile.DataDiskImages { - if ddi.Lun == nil { - return errorMessage("unexpected: lun is null for data disk # %d", i) - } - datadiskID, err := client.ParseResourceID(fmt.Sprintf("%s%d", s.DataDiskIDPrefix, *ddi.Lun)) - if err != nil { - return errorMessage("unable to construct resource id for datadisk: %v", err) - } - - disk := s.getDatadiskDefinitionFromImage(*ddi.Lun) - // Initiate disk creation - f, err := azcli.DisksClient().CreateOrUpdate(ctx, datadiskID.ResourceGroup, datadiskID.ResourceName.String(), disk) - if err != nil { - return errorMessage("Failed to initiate resource creation: %q", datadiskID) - } - s.disks[*ddi.Lun] = datadiskID // save the resoure we just create in our disk set - state.Put(stateBagKey_Diskset, s.disks) // update the statebag - ui.Say(fmt.Sprintf("Creating disk %q", datadiskID)) - - futures = append(futures, Future{datadiskID, f}) - } - } - } - - ui.Say("Waiting for disks to be created.") - - // Wait for completion - for _, f := range futures { - cli := azcli.PollClient() // quick polling for quick operations - cli.PollingDelay = time.Second - err = f.WaitForCompletionRef(ctx, cli) - if err != nil { - return errorMessage( - "error creating new disk '%s': %v", f.Resource, err) - } - ui.Say(fmt.Sprintf("Disk %q created", f.Resource)) - } - - return multistep.ActionContinue -} - -func (s StepCreateNewDiskset) getOSDiskDefinition(subscriptionID string) compute.Disk { - disk := compute.Disk{ - Location: to.StringPtr(s.Location), - DiskProperties: &compute.DiskProperties{ - OsType: "Linux", - CreationData: &compute.CreationData{}, - }, - } - - if s.OSDiskStorageAccountType != "" { - disk.Sku = &compute.DiskSku{ - Name: compute.DiskStorageAccountTypes(s.OSDiskStorageAccountType), - } - } - - if s.HyperVGeneration != "" { - disk.DiskProperties.HyperVGeneration = compute.HyperVGeneration(s.HyperVGeneration) - } - - if s.OSDiskSizeGB > 0 { - disk.DiskProperties.DiskSizeGB = to.Int32Ptr(s.OSDiskSizeGB) - } - - switch { - case s.SourcePlatformImage != nil: - disk.CreationData.CreateOption = compute.FromImage - disk.CreationData.ImageReference = &compute.ImageDiskReference{ - ID: to.StringPtr(fmt.Sprintf( - "/subscriptions/%s/providers/Microsoft.Compute/locations/%s/publishers/%s/artifacttypes/vmimage/offers/%s/skus/%s/versions/%s", - subscriptionID, s.Location, - s.SourcePlatformImage.Publisher, s.SourcePlatformImage.Offer, s.SourcePlatformImage.Sku, s.SourcePlatformImage.Version)), - } - case s.SourceOSDiskResourceID != "": - disk.CreationData.CreateOption = compute.Copy - disk.CreationData.SourceResourceID = to.StringPtr(s.SourceOSDiskResourceID) - case s.SourceImageResourceID != "": - disk.CreationData.CreateOption = compute.FromImage - disk.CreationData.GalleryImageReference = &compute.ImageDiskReference{ - ID: to.StringPtr(s.SourceImageResourceID), - } - default: - disk.CreationData.CreateOption = compute.Empty - } - return disk -} - -func (s StepCreateNewDiskset) getDatadiskDefinitionFromImage(lun int32) compute.Disk { - disk := compute.Disk{ - Location: to.StringPtr(s.Location), - DiskProperties: &compute.DiskProperties{ - CreationData: &compute.CreationData{}, - }, - } - - disk.CreationData.CreateOption = compute.FromImage - disk.CreationData.GalleryImageReference = &compute.ImageDiskReference{ - ID: to.StringPtr(s.SourceImageResourceID), - Lun: to.Int32Ptr(lun), - } - - if s.DataDiskStorageAccountType != "" { - disk.Sku = &compute.DiskSku{ - Name: compute.DiskStorageAccountTypes(s.DataDiskStorageAccountType), - } - } - return disk -} - -func (s *StepCreateNewDiskset) Cleanup(state multistep.StateBag) { - if !s.SkipCleanup { - azcli := state.Get("azureclient").(client.AzureClientSet) - ui := state.Get("ui").(packersdk.Ui) - - for _, d := range s.disks { - - ui.Say(fmt.Sprintf("Waiting for disk %q detach to complete", d)) - err := NewDiskAttacher(azcli).WaitForDetach(context.Background(), d.String()) - if err != nil { - ui.Error(fmt.Sprintf("error detaching disk %q: %s", d, err)) - } - - ui.Say(fmt.Sprintf("Deleting disk %q", d)) - - f, err := azcli.DisksClient().Delete(context.TODO(), d.ResourceGroup, d.ResourceName.String()) - if err == nil { - err = f.WaitForCompletionRef(context.TODO(), azcli.PollClient()) - } - if err != nil { - log.Printf("StepCreateNewDiskset.Cleanup: error: %+v", err) - ui.Error(fmt.Sprintf("error deleting disk '%s': %v.", d, err)) - } - } - } -} diff --git a/builder/azure/chroot/step_create_new_diskset_test.go b/builder/azure/chroot/step_create_new_diskset_test.go deleted file mode 100644 index 470c25dec..000000000 --- a/builder/azure/chroot/step_create_new_diskset_test.go +++ /dev/null @@ -1,247 +0,0 @@ -package chroot - -import ( - "context" - "io/ioutil" - "net/http" - "reflect" - "regexp" - "strings" - "testing" - - "github.com/hashicorp/packer-plugin-sdk/multistep" - packersdk "github.com/hashicorp/packer-plugin-sdk/packer" - "github.com/hashicorp/packer/builder/azure/common/client" - - "github.com/Azure/azure-sdk-for-go/services/compute/mgmt/2019-12-01/compute" - "github.com/Azure/go-autorest/autorest" -) - -func TestStepCreateNewDisk_Run(t *testing.T) { - tests := []struct { - name string - fields StepCreateNewDiskset - expectedPutDiskBodies []string - want multistep.StepAction - verifyDiskset *Diskset - }{ - { - name: "from disk", - fields: StepCreateNewDiskset{ - OSDiskID: "/subscriptions/SubscriptionID/resourcegroups/ResourceGroupName/providers/Microsoft.Compute/disks/TemporaryOSDiskName", - OSDiskSizeGB: 42, - OSDiskStorageAccountType: string(compute.PremiumLRS), - HyperVGeneration: string(compute.V1), - Location: "westus", - SourceOSDiskResourceID: "SourceDisk", - }, - expectedPutDiskBodies: []string{` - { - "location": "westus", - "properties": { - "osType": "Linux", - "hyperVGeneration": "V1", - "creationData": { - "createOption": "Copy", - "sourceResourceId": "SourceDisk" - }, - "diskSizeGB": 42 - }, - "sku": { - "name": "Premium_LRS" - } - }`}, - want: multistep.ActionContinue, - verifyDiskset: &Diskset{-1: resource("/subscriptions/SubscriptionID/resourceGroups/ResourceGroupName/providers/Microsoft.Compute/disks/TemporaryOSDiskName")}, - }, - { - name: "from platform image", - fields: StepCreateNewDiskset{ - OSDiskID: "/subscriptions/SubscriptionID/resourcegroups/ResourceGroupName/providers/Microsoft.Compute/disks/TemporaryOSDiskName", - OSDiskStorageAccountType: string(compute.StandardLRS), - HyperVGeneration: string(compute.V1), - Location: "westus", - SourcePlatformImage: &client.PlatformImage{ - Publisher: "Microsoft", - Offer: "Windows", - Sku: "2016-DataCenter", - Version: "2016.1.4", - }, - }, - expectedPutDiskBodies: []string{` - { - "location": "westus", - "properties": { - "osType": "Linux", - "hyperVGeneration": "V1", - "creationData": { - "createOption":"FromImage", - "imageReference": { - "id":"/subscriptions/SubscriptionID/providers/Microsoft.Compute/locations/westus/publishers/Microsoft/artifacttypes/vmimage/offers/Windows/skus/2016-DataCenter/versions/2016.1.4" - } - } - }, - "sku": { - "name": "Standard_LRS" - } - }`}, - want: multistep.ActionContinue, - verifyDiskset: &Diskset{-1: resource("/subscriptions/SubscriptionID/resourceGroups/ResourceGroupName/providers/Microsoft.Compute/disks/TemporaryOSDiskName")}, - }, - { - name: "from shared image", - fields: StepCreateNewDiskset{ - OSDiskID: "/subscriptions/SubscriptionID/resourcegroups/ResourceGroupName/providers/Microsoft.Compute/disks/TemporaryOSDiskName", - OSDiskStorageAccountType: string(compute.StandardLRS), - DataDiskStorageAccountType: string(compute.PremiumLRS), - DataDiskIDPrefix: "/subscriptions/SubscriptionID/resourcegroups/ResourceGroupName/providers/Microsoft.Compute/disks/TemporaryDataDisk-", - HyperVGeneration: string(compute.V1), - Location: "westus", - SourceImageResourceID: "/subscriptions/SubscriptionID/resourcegroups/imagegroup/providers/Microsoft.Compute/galleries/MyGallery/images/MyImage/versions/1.2.3", - }, - - expectedPutDiskBodies: []string{` - { - "location": "westus", - "properties": { - "osType": "Linux", - "hyperVGeneration": "V1", - "creationData": { - "createOption":"FromImage", - "galleryImageReference": { - "id":"/subscriptions/SubscriptionID/resourcegroups/imagegroup/providers/Microsoft.Compute/galleries/MyGallery/images/MyImage/versions/1.2.3" - } - } - }, - "sku": { - "name": "Standard_LRS" - } - }`, ` - { - "location": "westus", - "properties": { - "creationData": { - "createOption":"FromImage", - "galleryImageReference": { - "id": "/subscriptions/SubscriptionID/resourcegroups/imagegroup/providers/Microsoft.Compute/galleries/MyGallery/images/MyImage/versions/1.2.3", - "lun": 5 - } - } - }, - "sku": { - "name": "Premium_LRS" - } - }`, ` - { - "location": "westus", - "properties": { - "creationData": { - "createOption":"FromImage", - "galleryImageReference": { - "id": "/subscriptions/SubscriptionID/resourcegroups/imagegroup/providers/Microsoft.Compute/galleries/MyGallery/images/MyImage/versions/1.2.3", - "lun": 9 - } - } - }, - "sku": { - "name": "Premium_LRS" - } - }`, ` - { - "location": "westus", - "properties": { - "creationData": { - "createOption":"FromImage", - "galleryImageReference": { - "id": "/subscriptions/SubscriptionID/resourcegroups/imagegroup/providers/Microsoft.Compute/galleries/MyGallery/images/MyImage/versions/1.2.3", - "lun": 3 - } - } - }, - "sku": { - "name": "Premium_LRS" - } - }`}, - want: multistep.ActionContinue, - verifyDiskset: &Diskset{ - -1: resource("/subscriptions/SubscriptionID/resourceGroups/ResourceGroupName/providers/Microsoft.Compute/disks/TemporaryOSDiskName"), - 3: resource("/subscriptions/SubscriptionID/resourceGroups/ResourceGroupName/providers/Microsoft.Compute/disks/TemporaryDataDisk-3"), - 5: resource("/subscriptions/SubscriptionID/resourceGroups/ResourceGroupName/providers/Microsoft.Compute/disks/TemporaryDataDisk-5"), - 9: resource("/subscriptions/SubscriptionID/resourceGroups/ResourceGroupName/providers/Microsoft.Compute/disks/TemporaryDataDisk-9"), - }, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - s := tt.fields - - bodyCount := 0 - m := compute.NewDisksClient("SubscriptionID") - m.Sender = autorest.SenderFunc(func(r *http.Request) (*http.Response, error) { - if r.Method != "PUT" { - t.Fatal("Expected only a PUT disk call") - } - b, _ := ioutil.ReadAll(r.Body) - expectedPutDiskBody := regexp.MustCompile(`[\s\n]`).ReplaceAllString(tt.expectedPutDiskBodies[bodyCount], "") - bodyCount++ - if string(b) != expectedPutDiskBody { - t.Fatalf("expected body #%d to be %q, but got %q", bodyCount, expectedPutDiskBody, string(b)) - } - return &http.Response{ - Request: r, - StatusCode: 200, - }, nil - }) - - giv := compute.NewGalleryImageVersionsClient("SubscriptionID") - giv.Sender = autorest.SenderFunc(func(r *http.Request) (*http.Response, error) { - if r.Method == "GET" && - regexp.MustCompile(`(?i)/versions/1\.2\.3$`).MatchString(r.URL.Path) { - return &http.Response{ - Request: r, - Body: ioutil.NopCloser(strings.NewReader(`{ - "properties": { "storageProfile": { - "dataDiskImages":[ - { "lun": 5 }, - { "lun": 9 }, - { "lun": 3 } - ] - } } - }`)), - StatusCode: 200, - }, nil - } - return &http.Response{ - Request: r, - Status: "Unexpected request", - StatusCode: 500, - }, nil - }) - - state := new(multistep.BasicStateBag) - state.Put("azureclient", &client.AzureClientSetMock{ - SubscriptionIDMock: "SubscriptionID", - DisksClientMock: m, - GalleryImageVersionsClientMock: giv, - }) - state.Put("ui", packersdk.TestUi(t)) - - if got := s.Run(context.TODO(), state); !reflect.DeepEqual(got, tt.want) { - t.Errorf("StepCreateNewDisk.Run() = %v, want %v", got, tt.want) - } - - ds := state.Get(stateBagKey_Diskset) - if tt.verifyDiskset != nil && !reflect.DeepEqual(*tt.verifyDiskset, ds) { - t.Errorf("Error verifying diskset after Run(), got %v, want %v", ds, *tt.verifyDiskset) - } - }) - } -} - -func resource(id string) client.Resource { - v, err := client.ParseResourceID(id) - if err != nil { - panic(err) - } - return v -} diff --git a/builder/azure/chroot/step_create_shared_image_version.go b/builder/azure/chroot/step_create_shared_image_version.go deleted file mode 100644 index 4e4843442..000000000 --- a/builder/azure/chroot/step_create_shared_image_version.go +++ /dev/null @@ -1,108 +0,0 @@ -package chroot - -import ( - "context" - "fmt" - "log" - "sort" - "time" - - "github.com/Azure/azure-sdk-for-go/services/compute/mgmt/2019-12-01/compute" - "github.com/Azure/go-autorest/autorest/to" - "github.com/hashicorp/packer-plugin-sdk/multistep" - packersdk "github.com/hashicorp/packer-plugin-sdk/packer" - "github.com/hashicorp/packer/builder/azure/common/client" -) - -type StepCreateSharedImageVersion struct { - Destination SharedImageGalleryDestination - OSDiskCacheType string - DataDiskCacheType string - Location string -} - -func (s *StepCreateSharedImageVersion) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction { - azcli := state.Get("azureclient").(client.AzureClientSet) - ui := state.Get("ui").(packersdk.Ui) - snapshotset := state.Get(stateBagKey_Snapshotset).(Diskset) - - ui.Say(fmt.Sprintf("Creating image version %s\n using %q for os disk.", - s.Destination.ResourceID(azcli.SubscriptionID()), - snapshotset.OS())) - - var targetRegions []compute.TargetRegion - // transform target regions to API objects - for _, tr := range s.Destination.TargetRegions { - apiObject := compute.TargetRegion{ - Name: to.StringPtr(tr.Name), - RegionalReplicaCount: to.Int32Ptr(tr.ReplicaCount), - StorageAccountType: compute.StorageAccountType(tr.StorageAccountType), - } - targetRegions = append(targetRegions, apiObject) - } - - imageVersion := compute.GalleryImageVersion{ - Location: to.StringPtr(s.Location), - GalleryImageVersionProperties: &compute.GalleryImageVersionProperties{ - StorageProfile: &compute.GalleryImageVersionStorageProfile{ - OsDiskImage: &compute.GalleryOSDiskImage{ - Source: &compute.GalleryArtifactVersionSource{ID: to.StringPtr(snapshotset.OS().String())}, - HostCaching: compute.HostCaching(s.OSDiskCacheType), - }, - }, - PublishingProfile: &compute.GalleryImageVersionPublishingProfile{ - TargetRegions: &targetRegions, - ExcludeFromLatest: to.BoolPtr(s.Destination.ExcludeFromLatest), - }, - }, - } - - var datadisks []compute.GalleryDataDiskImage - for lun, resource := range snapshotset { - if lun != -1 { - ui.Say(fmt.Sprintf(" using %q for data disk (lun %d).", resource, lun)) - - datadisks = append(datadisks, compute.GalleryDataDiskImage{ - Lun: to.Int32Ptr(lun), - Source: &compute.GalleryArtifactVersionSource{ID: to.StringPtr(resource.String())}, - HostCaching: compute.HostCaching(s.DataDiskCacheType), - }) - } - } - if datadisks != nil { - // sort by lun - sort.Slice(datadisks, func(i, j int) bool { - return *datadisks[i].Lun < *datadisks[j].Lun - }) - imageVersion.GalleryImageVersionProperties.StorageProfile.DataDiskImages = &datadisks - } - - f, err := azcli.GalleryImageVersionsClient().CreateOrUpdate( - ctx, - s.Destination.ResourceGroup, - s.Destination.GalleryName, - s.Destination.ImageName, - s.Destination.ImageVersion, - imageVersion) - if err == nil { - log.Println("Shared image version creation in process...") - pollClient := azcli.PollClient() - pollClient.PollingDelay = 10 * time.Second - ctx, cancel := context.WithTimeout(ctx, time.Hour*12) - defer cancel() - err = f.WaitForCompletionRef(ctx, pollClient) - } - if err != nil { - log.Printf("StepCreateSharedImageVersion.Run: error: %+v", err) - err := fmt.Errorf( - "error creating shared image version '%s': %v", s.Destination.ResourceID(azcli.SubscriptionID()), err) - state.Put("error", err) - ui.Error(err.Error()) - return multistep.ActionHalt - } - log.Printf("Image creation complete: %s", f.Status()) - - return multistep.ActionContinue -} - -func (*StepCreateSharedImageVersion) Cleanup(multistep.StateBag) {} diff --git a/builder/azure/chroot/step_create_shared_image_version_test.go b/builder/azure/chroot/step_create_shared_image_version_test.go deleted file mode 100644 index bdaee7618..000000000 --- a/builder/azure/chroot/step_create_shared_image_version_test.go +++ /dev/null @@ -1,144 +0,0 @@ -package chroot - -import ( - "context" - "io/ioutil" - "net/http" - "reflect" - "regexp" - "testing" - - "github.com/hashicorp/packer-plugin-sdk/multistep" - packersdk "github.com/hashicorp/packer-plugin-sdk/packer" - "github.com/hashicorp/packer/builder/azure/common/client" - - "github.com/Azure/azure-sdk-for-go/services/compute/mgmt/2019-12-01/compute" - "github.com/Azure/go-autorest/autorest" -) - -func TestStepCreateSharedImageVersion_Run(t *testing.T) { - type fields struct { - Destination SharedImageGalleryDestination - OSDiskCacheType string - DataDiskCacheType string - Location string - } - tests := []struct { - name string - fields fields - snapshotset Diskset - want multistep.StepAction - expectedPutBody string - }{ - { - name: "happy path", - fields: fields{ - Destination: SharedImageGalleryDestination{ - ResourceGroup: "ResourceGroup", - GalleryName: "GalleryName", - ImageName: "ImageName", - ImageVersion: "0.1.2", - TargetRegions: []TargetRegion{ - { - Name: "region1", - ReplicaCount: 5, - StorageAccountType: "Standard_ZRS", - }, - }, - ExcludeFromLatest: true, - }, - OSDiskCacheType: "ReadWrite", - DataDiskCacheType: "None", - Location: "region2", - }, - snapshotset: diskset( - "/subscriptions/12345/resourceGroups/group1/providers/Microsoft.Compute/snapshots/osdisksnapshot", - "/subscriptions/12345/resourceGroups/group1/providers/Microsoft.Compute/snapshots/datadisksnapshot0", - "/subscriptions/12345/resourceGroups/group1/providers/Microsoft.Compute/snapshots/datadisksnapshot1", - "/subscriptions/12345/resourceGroups/group1/providers/Microsoft.Compute/snapshots/datadisksnapshot2"), - expectedPutBody: `{ - "location": "region2", - "properties": { - "publishingProfile": { - "targetRegions": [ - { - "name": "region1", - "regionalReplicaCount": 5, - "storageAccountType": "Standard_ZRS" - } - ], - "excludeFromLatest": true - }, - "storageProfile": { - "osDiskImage": { - "hostCaching": "ReadWrite", - "source": { - "id": "/subscriptions/12345/resourceGroups/group1/providers/Microsoft.Compute/snapshots/osdisksnapshot" - } - }, - "dataDiskImages": [ - { - "lun": 0, - "hostCaching": "None", - "source": { - "id": "/subscriptions/12345/resourceGroups/group1/providers/Microsoft.Compute/snapshots/datadisksnapshot0" - } - }, - { - "lun": 1, - "hostCaching": "None", - "source": { - "id": "/subscriptions/12345/resourceGroups/group1/providers/Microsoft.Compute/snapshots/datadisksnapshot1" - } - }, - { - "lun": 2, - "hostCaching": "None", - "source": { - "id": "/subscriptions/12345/resourceGroups/group1/providers/Microsoft.Compute/snapshots/datadisksnapshot2" - } - } - ] - } - } - }`, - }, - } - for _, tt := range tests { - expectedPutBody := regexp.MustCompile(`[\s\n]`).ReplaceAllString(tt.expectedPutBody, "") - - m := compute.NewGalleryImageVersionsClient("subscriptionId") - m.Sender = autorest.SenderFunc(func(r *http.Request) (*http.Response, error) { - if r.Method != "PUT" { - t.Fatal("Expected only a PUT call") - } - b, _ := ioutil.ReadAll(r.Body) - if string(b) != expectedPutBody { - t.Errorf("expected body to be %v, but got %v", expectedPutBody, string(b)) - } - return &http.Response{ - Request: r, - StatusCode: 200, - }, nil - }) - - state := new(multistep.BasicStateBag) - state.Put("azureclient", &client.AzureClientSetMock{ - GalleryImageVersionsClientMock: m, - }) - state.Put("ui", packersdk.TestUi(t)) - state.Put(stateBagKey_Snapshotset, tt.snapshotset) - - t.Run(tt.name, func(t *testing.T) { - s := &StepCreateSharedImageVersion{ - Destination: tt.fields.Destination, - OSDiskCacheType: tt.fields.OSDiskCacheType, - DataDiskCacheType: tt.fields.DataDiskCacheType, - Location: tt.fields.Location, - } - if got := s.Run(context.TODO(), state); !reflect.DeepEqual(got, tt.want) { - t.Errorf("StepCreateSharedImageVersion.Run() = %v, want %v", got, tt.want) - } - }) - } -} diff --git a/builder/azure/chroot/step_create_snapshotset.go b/builder/azure/chroot/step_create_snapshotset.go deleted file mode 100644 index 2e67c6660..000000000 --- a/builder/azure/chroot/step_create_snapshotset.go +++ /dev/null @@ -1,126 +0,0 @@ -package chroot - -import ( - "context" - "fmt" - "log" - "strings" - "time" - - "github.com/hashicorp/packer-plugin-sdk/multistep" - packersdk "github.com/hashicorp/packer-plugin-sdk/packer" - "github.com/hashicorp/packer/builder/azure/common/client" - - "github.com/Azure/azure-sdk-for-go/services/compute/mgmt/2019-12-01/compute" - "github.com/Azure/go-autorest/autorest/to" -) - -var _ multistep.Step = &StepCreateSnapshotset{} - -type StepCreateSnapshotset struct { - OSDiskSnapshotID string - DataDiskSnapshotIDPrefix string - Location string - - SkipCleanup bool - - snapshots Diskset -} - -func (s *StepCreateSnapshotset) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction { - azcli := state.Get("azureclient").(client.AzureClientSet) - ui := state.Get("ui").(packersdk.Ui) - diskset := state.Get(stateBagKey_Diskset).(Diskset) - - s.snapshots = make(Diskset) - - errorMessage := func(format string, params ...interface{}) multistep.StepAction { - err := fmt.Errorf("StepCreateSnapshotset.Run: error: "+format, params...) - state.Put("error", err) - ui.Error(err.Error()) - return multistep.ActionHalt - } - - for lun, resource := range diskset { - snapshotID := fmt.Sprintf("%s%d", s.DataDiskSnapshotIDPrefix, lun) - if lun == -1 { - snapshotID = s.OSDiskSnapshotID - } - ssr, err := client.ParseResourceID(snapshotID) - if err != nil { - errorMessage("Could not create a valid resource id, tried %q: %v", snapshotID, err) - } - if !strings.EqualFold(ssr.Provider, "Microsoft.Compute") || - !strings.EqualFold(ssr.ResourceType.String(), "snapshots") { - return errorMessage("Resource %q is not of type Microsoft.Compute/snapshots", snapshotID) - } - s.snapshots[lun] = ssr - state.Put(stateBagKey_Snapshotset, s.snapshots) - - ui.Say(fmt.Sprintf("Creating snapshot %q", ssr)) - - snapshot := compute.Snapshot{ - Location: to.StringPtr(s.Location), - SnapshotProperties: &compute.SnapshotProperties{ - CreationData: &compute.CreationData{ - CreateOption: compute.Copy, - SourceResourceID: to.StringPtr(resource.String()), - }, - Incremental: to.BoolPtr(false), - }, - } - - f, err := azcli.SnapshotsClient().CreateOrUpdate(ctx, ssr.ResourceGroup, ssr.ResourceName.String(), snapshot) - if err != nil { - return errorMessage("error initiating snapshot %q: %v", ssr, err) - } - - pollClient := azcli.PollClient() - pollClient.PollingDelay = 2 * time.Second - ctx, cancel := context.WithTimeout(ctx, time.Hour*12) - defer cancel() - err = f.WaitForCompletionRef(ctx, pollClient) - - if err != nil { - return errorMessage("error creating snapshot '%s': %v", s.OSDiskSnapshotID, err) - } - } - - return multistep.ActionContinue -} - -func (s *StepCreateSnapshotset) Cleanup(state multistep.StateBag) { - if !s.SkipCleanup { - azcli := state.Get("azureclient").(client.AzureClientSet) - ui := state.Get("ui").(packersdk.Ui) - - for _, resource := range s.snapshots { - - ui.Say(fmt.Sprintf("Removing any active SAS for snapshot %q", resource)) - { - f, err := azcli.SnapshotsClient().RevokeAccess(context.TODO(), resource.ResourceGroup, resource.ResourceName.String()) - if err == nil { - log.Printf("StepCreateSnapshotset.Cleanup: removing SAS...") - err = f.WaitForCompletionRef(context.TODO(), azcli.PollClient()) - } - if err != nil { - log.Printf("StepCreateSnapshotset.Cleanup: error: %+v", err) - ui.Error(fmt.Sprintf("error deleting snapshot %q: %v.", resource, err)) - } - } - - ui.Say(fmt.Sprintf("Deleting snapshot %q", resource)) - { - f, err := azcli.SnapshotsClient().Delete(context.TODO(), resource.ResourceGroup, resource.ResourceName.String()) - if err == nil { - log.Printf("StepCreateSnapshotset.Cleanup: deleting snapshot...") - err = f.WaitForCompletionRef(context.TODO(), azcli.PollClient()) - } - if err != nil { - log.Printf("StepCreateSnapshotset.Cleanup: error: %+v", err) - ui.Error(fmt.Sprintf("error deleting snapshot %q: %v.", resource, err)) - } - } - } - } -} diff --git a/builder/azure/chroot/step_create_snapshotset_test.go b/builder/azure/chroot/step_create_snapshotset_test.go deleted file mode 100644 index 73a183353..000000000 --- a/builder/azure/chroot/step_create_snapshotset_test.go +++ /dev/null @@ -1,230 +0,0 @@ -package chroot - -import ( - "context" - "io/ioutil" - "net/http" - "reflect" - "regexp" - "testing" - - "github.com/Azure/azure-sdk-for-go/services/compute/mgmt/2019-12-01/compute" - "github.com/Azure/go-autorest/autorest" - "github.com/hashicorp/packer-plugin-sdk/multistep" - packersdk "github.com/hashicorp/packer-plugin-sdk/packer" - "github.com/hashicorp/packer/builder/azure/common/client" -) - -func TestStepCreateSnapshot_Run(t *testing.T) { - type fields struct { - OSDiskSnapshotID string - DataDiskSnapshotIDPrefix string - Location string - } - tests := []struct { - name string - fields fields - diskset Diskset - want multistep.StepAction - wantSnapshotset Diskset - expectedPutBody string - }{ - { - name: "happy path", - fields: fields{ - OSDiskSnapshotID: "/subscriptions/1234/resourceGroups/rg/providers/Microsoft.Compute/snapshots/osdisk-snap", - Location: "region1", - }, - diskset: diskset("/subscriptions/12345/resourceGroups/group1/providers/Microsoft.Compute/disks/disk1"), - expectedPutBody: `{ - "location": "region1", - "properties": { - "creationData": { - "createOption": "Copy", - "sourceResourceId": "/subscriptions/12345/resourceGroups/group1/providers/Microsoft.Compute/disks/disk1" - }, - "incremental": false - } - }`, - wantSnapshotset: diskset("/subscriptions/1234/resourceGroups/rg/providers/Microsoft.Compute/snapshots/osdisk-snap"), - }, - { - name: "multi disk", - fields: fields{ - OSDiskSnapshotID: "/subscriptions/1234/resourceGroups/rg/providers/Microsoft.Compute/snapshots/osdisk-snap", - DataDiskSnapshotIDPrefix: "/subscriptions/1234/resourceGroups/rg/providers/Microsoft.Compute/snapshots/datadisk-snap", - Location: "region1", - }, - diskset: diskset( - "/subscriptions/12345/resourceGroups/group1/providers/Microsoft.Compute/disks/osdisk", - "/subscriptions/12345/resourceGroups/group1/providers/Microsoft.Compute/disks/datadisk1", - "/subscriptions/12345/resourceGroups/group1/providers/Microsoft.Compute/disks/datadisk2", - "/subscriptions/12345/resourceGroups/group1/providers/Microsoft.Compute/disks/datadisk3"), - wantSnapshotset: diskset( - "/subscriptions/1234/resourceGroups/rg/providers/Microsoft.Compute/snapshots/osdisk-snap", - "/subscriptions/1234/resourceGroups/rg/providers/Microsoft.Compute/snapshots/datadisk-snap0", - "/subscriptions/1234/resourceGroups/rg/providers/Microsoft.Compute/snapshots/datadisk-snap1", - "/subscriptions/1234/resourceGroups/rg/providers/Microsoft.Compute/snapshots/datadisk-snap2", - ), - }, - { - name: "invalid ResourceID", - fields: fields{ - OSDiskSnapshotID: "notaresourceid", - Location: "region1", - }, - diskset: diskset("/subscriptions/12345/resourceGroups/group1/providers/Microsoft.Compute/disks/disk1"), - want: multistep.ActionHalt, - }, - } - for _, tt := range tests { - expectedPutBody := regexp.MustCompile(`[\s\n]`).ReplaceAllString(tt.expectedPutBody, "") - - m := compute.NewSnapshotsClient("subscriptionId") - m.Sender = autorest.SenderFunc(func(r *http.Request) (*http.Response, error) { - if r.Method != "PUT" { - t.Fatal("Expected only a PUT call") - } - if expectedPutBody != "" { - b, _ := ioutil.ReadAll(r.Body) - if string(b) != expectedPutBody { - t.Errorf("expected body to be %v, but got %v", expectedPutBody, string(b)) - } - } - return &http.Response{ - Request: r, - StatusCode: 200, - }, nil - }) - - state := new(multistep.BasicStateBag) - state.Put("azureclient", &client.AzureClientSetMock{ - SnapshotsClientMock: m, - }) - state.Put("ui", packersdk.TestUi(t)) - state.Put(stateBagKey_Diskset, tt.diskset) - - t.Run(tt.name, func(t *testing.T) { - s := &StepCreateSnapshotset{ - OSDiskSnapshotID: tt.fields.OSDiskSnapshotID, - DataDiskSnapshotIDPrefix: tt.fields.DataDiskSnapshotIDPrefix, - Location: tt.fields.Location, - } - if got := s.Run(context.TODO(), state); !reflect.DeepEqual(got, tt.want) { - t.Errorf("StepCreateSnapshot.Run() = %v, want %v", got, tt.want) - } - - if len(tt.wantSnapshotset) > 0 { - got := state.Get(stateBagKey_Snapshotset).(Diskset) - if !reflect.DeepEqual(got, tt.wantSnapshotset) { - t.Errorf("Snapshotset = %v, want %v", got, tt.wantSnapshotset) - } - } - - }) - } -} - -func TestStepCreateSnapshot_Cleanup_skipped(t *testing.T) { - m := compute.NewSnapshotsClient("subscriptionId") - m.Sender = autorest.SenderFunc(func(r *http.Request) (*http.Response, error) { - t.Fatalf("clean up should be skipped, did not expect HTTP calls") - return nil, nil - }) - - state := new(multistep.BasicStateBag) - state.Put("azureclient", &client.AzureClientSetMock{ - SnapshotsClientMock: m, - }) - state.Put("ui", packersdk.TestUi(t)) - - s := &StepCreateSnapshotset{ - SkipCleanup: true, - } - s.Cleanup(state) -} - -func TestStepCreateSnapshot_Cleanup(t *testing.T) { - m := compute.NewSnapshotsClient("subscriptionId") - { - expectedCalls := []string{ - "POST /subscriptions/subscriptionId/resourceGroups/rg/providers/Microsoft.Compute/snapshots/ossnap/endGetAccess", - "DELETE /subscriptions/subscriptionId/resourceGroups/rg/providers/Microsoft.Compute/snapshots/ossnap", - "POST /subscriptions/subscriptionId/resourceGroups/rg/providers/Microsoft.Compute/snapshots/datasnap1/endGetAccess", - "DELETE /subscriptions/subscriptionId/resourceGroups/rg/providers/Microsoft.Compute/snapshots/datasnap1", - "POST /subscriptions/subscriptionId/resourceGroups/rg/providers/Microsoft.Compute/snapshots/datasnap2/endGetAccess", - "DELETE /subscriptions/subscriptionId/resourceGroups/rg/providers/Microsoft.Compute/snapshots/datasnap2", - } - - m.Sender = autorest.SenderFunc(func(r *http.Request) (*http.Response, error) { - got := r.Method + " " + r.URL.Path - found := false - for i, call := range expectedCalls { - if call == got { - // swap i with last and drop last - expectedCalls[i] = expectedCalls[len(expectedCalls)-1] - expectedCalls = expectedCalls[:len(expectedCalls)-1] - found = true - break - } - } - if !found { - t.Errorf("unexpected HTTP call: %v, wanted one of %q", got, expectedCalls) - return &http.Response{ - Request: r, - StatusCode: 599, // 500 is retried - }, nil - } - return &http.Response{ - Request: r, - StatusCode: 200, - }, nil - }) - } - state := new(multistep.BasicStateBag) - state.Put("azureclient", &client.AzureClientSetMock{ - SnapshotsClientMock: m, - }) - state.Put("ui", packersdk.TestUi(t)) - - s := &StepCreateSnapshotset{ - SkipCleanup: false, - snapshots: diskset( - "/subscriptions/1234/resourceGroups/rg/providers/Microsoft.Compute/snapshots/ossnap", - "/subscriptions/1234/resourceGroups/rg/providers/Microsoft.Compute/snapshots/datasnap1", - "/subscriptions/1234/resourceGroups/rg/providers/Microsoft.Compute/snapshots/datasnap2"), - } - s.Cleanup(state) -} - -func TestStepCreateSnapshotset_Cleanup(t *testing.T) { - type fields struct { - OSDiskSnapshotID string - DataDiskSnapshotIDPrefix string - Location string - SkipCleanup bool - snapshots Diskset - } - type args struct { - state multistep.StateBag - } - tests := []struct { - name string - fields fields - args args - }{ - // TODO: Add test cases. - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - s := &StepCreateSnapshotset{ - OSDiskSnapshotID: tt.fields.OSDiskSnapshotID, - DataDiskSnapshotIDPrefix: tt.fields.DataDiskSnapshotIDPrefix, - Location: tt.fields.Location, - SkipCleanup: tt.fields.SkipCleanup, - snapshots: tt.fields.snapshots, - } - s.Cleanup(tt.args.state) - }) - } -} diff --git a/builder/azure/chroot/step_mount_device.go b/builder/azure/chroot/step_mount_device.go deleted file mode 100644 index 1944ffb51..000000000 --- a/builder/azure/chroot/step_mount_device.go +++ /dev/null @@ -1,140 +0,0 @@ -package chroot - -// mostly borrowed from ./builder/amazon/chroot/step_mount_device.go - -import ( - "bytes" - "context" - "fmt" - "log" - "os" - "path/filepath" - "runtime" - "strings" - - "github.com/hashicorp/packer-plugin-sdk/common" - "github.com/hashicorp/packer-plugin-sdk/multistep" - packersdk "github.com/hashicorp/packer-plugin-sdk/packer" - "github.com/hashicorp/packer-plugin-sdk/template/interpolate" -) - -var _ multistep.Step = &StepMountDevice{} - -type StepMountDevice struct { - MountOptions []string - MountPartition string - MountPath string - - mountPath string -} - -func (s *StepMountDevice) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction { - ui := state.Get("ui").(packersdk.Ui) - device := state.Get("device").(string) - config := state.Get("config").(*Config) - wrappedCommand := state.Get("wrappedCommand").(common.CommandWrapper) - - ictx := config.ctx - - ictx.Data = &struct{ Device string }{Device: filepath.Base(device)} - mountPath, err := interpolate.Render(s.MountPath, &ictx) - - if err != nil { - err := fmt.Errorf("error preparing mount directory: %s", err) - state.Put("error", err) - ui.Error(err.Error()) - return multistep.ActionHalt - } - - mountPath, err = filepath.Abs(mountPath) - if err != nil { - err := fmt.Errorf("error preparing mount directory: %s", err) - state.Put("error", err) - ui.Error(err.Error()) - return multistep.ActionHalt - } - - log.Printf("Mount path: %s", mountPath) - - if err := os.MkdirAll(mountPath, 0755); err != nil { - err := fmt.Errorf("error creating mount directory: %s", err) - state.Put("error", err) - ui.Error(err.Error()) - return multistep.ActionHalt - } - - var deviceMount string - switch runtime.GOOS { - case "freebsd": - deviceMount = fmt.Sprintf("%sp%s", device, s.MountPartition) - default: - deviceMount = fmt.Sprintf("%s%s", device, s.MountPartition) - } - - state.Put("deviceMount", deviceMount) - - ui.Say("Mounting the root device...") - stderr := new(bytes.Buffer) - - // build mount options from mount_options config, useful for nouuid options - // or other specific device type settings for mount - opts := "" - if len(s.MountOptions) > 0 { - opts = "-o " + strings.Join(s.MountOptions, " -o ") - } - mountCommand, err := wrappedCommand( - fmt.Sprintf("mount %s %s %s", opts, deviceMount, mountPath)) - if err != nil { - err := fmt.Errorf("error creating mount command: %s", err) - state.Put("error", err) - ui.Error(err.Error()) - return multistep.ActionHalt - } - log.Printf("[DEBUG] (step mount) mount command is %s", mountCommand) - cmd := common.ShellCommand(mountCommand) - cmd.Stderr = stderr - if err := cmd.Run(); err != nil { - err := fmt.Errorf( - "error mounting root volume: %s\nStderr: %s", err, stderr.String()) - state.Put("error", err) - ui.Error(err.Error()) - return multistep.ActionHalt - } - - // Set the mount path so we remember to unmount it later - s.mountPath = mountPath - state.Put("mount_path", s.mountPath) - state.Put("mount_device_cleanup", s) - - return multistep.ActionContinue -} - -func (s *StepMountDevice) Cleanup(state multistep.StateBag) { - ui := state.Get("ui").(packersdk.Ui) - if err := s.CleanupFunc(state); err != nil { - ui.Error(err.Error()) - } -} - -func (s *StepMountDevice) CleanupFunc(state multistep.StateBag) error { - if s.mountPath == "" { - return nil - } - - ui := state.Get("ui").(packersdk.Ui) - wrappedCommand := state.Get("wrappedCommand").(common.CommandWrapper) - - ui.Say("Unmounting the root device...") - unmountCommand, err := wrappedCommand(fmt.Sprintf("umount %s", s.mountPath)) - if err != nil { - return fmt.Errorf("error creating unmount command: %s", err) - } - - cmd := common.ShellCommand(unmountCommand) - if err := cmd.Run(); err != nil { - return fmt.Errorf("error unmounting root device: %s", err) - } - - s.mountPath = "" - return nil -} diff --git a/builder/azure/chroot/step_mount_device_test.go b/builder/azure/chroot/step_mount_device_test.go deleted file mode 100644 index b1fb07355..000000000 --- a/builder/azure/chroot/step_mount_device_test.go +++ /dev/null @@ -1,72 +0,0 @@ -package chroot - -import ( - "context" - "fmt" - "io/ioutil" - "os" - "runtime" - "testing" - "time" - - "github.com/hashicorp/packer-plugin-sdk/common" - "github.com/hashicorp/packer-plugin-sdk/multistep" -) - -func TestStepMountDevice_Run(t *testing.T) { - switch runtime.GOOS { - case "linux", "freebsd": - break - default: - t.Skip("Unsupported operating system") - } - mountPath, err := ioutil.TempDir("", "stepmountdevicetest") - if err != nil { - t.Errorf("Unable to create a temporary directory: %q", err) - } - step := &StepMountDevice{ - MountOptions: []string{"foo"}, - MountPartition: "42", - MountPath: mountPath, - } - - var gotCommand string - var wrapper common.CommandWrapper - wrapper = func(ran string) (string, error) { - gotCommand = ran - return "", nil - } - - state := new(multistep.BasicStateBag) - state.Put("wrappedCommand", wrapper) - state.Put("device", "/dev/quux") - - ui, getErrs := testUI() - state.Put("ui", ui) - - var config Config - state.Put("config", &config) - - ctx, cancel := context.WithTimeout(context.Background(), time.Second) - defer cancel() - - got := step.Run(ctx, state) - if got != multistep.ActionContinue { - t.Errorf("Expected 'continue', but got '%v'", got) - } - - var expectedMountDevice string - switch runtime.GOOS { - case "freebsd": - expectedMountDevice = "/dev/quuxp42" - default: // currently just Linux - expectedMountDevice = "/dev/quux42" - } - expectedCommand := fmt.Sprintf("mount -o foo %s %s", expectedMountDevice, mountPath) - if gotCommand != expectedCommand { - t.Errorf("Expected '%v', but got '%v'", expectedCommand, gotCommand) - } - - os.Remove(mountPath) - _ = getErrs -} diff --git a/builder/azure/chroot/step_resolve_plaform_image_version.go b/builder/azure/chroot/step_resolve_plaform_image_version.go deleted file mode 100644 index 677eb016c..000000000 --- a/builder/azure/chroot/step_resolve_plaform_image_version.go +++ /dev/null @@ -1,45 +0,0 @@ -package chroot - -import ( - "context" - "fmt" - "log" - "strings" - - "github.com/Azure/go-autorest/autorest/to" - "github.com/hashicorp/packer-plugin-sdk/multistep" - packersdk "github.com/hashicorp/packer-plugin-sdk/packer" - "github.com/hashicorp/packer/builder/azure/common/client" -) - -// StepResolvePlatformImageVersion resolves the exact PIR version when the version is 'latest' -type StepResolvePlatformImageVersion struct { - *client.PlatformImage - Location string -} - -// Run retrieves all available versions of a PIR image and stores the latest in the PlatformImage -func (pi *StepResolvePlatformImageVersion) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction { - ui := state.Get("ui").(packersdk.Ui) - - if strings.EqualFold(pi.Version, "latest") { - azcli := state.Get("azureclient").(client.AzureClientSet) - - vmi, err := azcli.VirtualMachineImagesClient().GetLatest(ctx, pi.Publisher, pi.Offer, pi.Sku, pi.Location) - if err != nil { - log.Printf("StepResolvePlatformImageVersion.Run: error: %+v", err) - err := fmt.Errorf("error retieving latest version of %q: %v", pi.URN(), err) - state.Put("error", err) - ui.Error(err.Error()) - return multistep.ActionHalt - } - pi.Version = to.String(vmi.Name) - ui.Say("Resolved latest version of source image: " + pi.Version) - } else { - ui.Say("Nothing to do, version is not 'latest'") - } - - return multistep.ActionContinue -} - -func (*StepResolvePlatformImageVersion) Cleanup(multistep.StateBag) {} diff --git a/builder/azure/chroot/step_resolve_plaform_image_version_test.go b/builder/azure/chroot/step_resolve_plaform_image_version_test.go deleted file mode 100644 index 60b4e2791..000000000 --- a/builder/azure/chroot/step_resolve_plaform_image_version_test.go +++ /dev/null @@ -1,62 +0,0 @@ -package chroot - -import ( - "context" - "io/ioutil" - "net/http" - "strings" - "testing" - "time" - - "github.com/hashicorp/packer-plugin-sdk/multistep" - "github.com/hashicorp/packer/builder/azure/common/client" - - "github.com/Azure/azure-sdk-for-go/services/compute/mgmt/2019-12-01/compute" - "github.com/Azure/go-autorest/autorest" -) - -func TestStepResolvePlatformImageVersion_Run(t *testing.T) { - - pi := &StepResolvePlatformImageVersion{ - PlatformImage: &client.PlatformImage{ - Version: "latest", - }} - - m := compute.NewVirtualMachineImagesClient("subscriptionId") - m.Sender = autorest.SenderFunc(func(r *http.Request) (*http.Response, error) { - if !strings.Contains(r.URL.String(), "%24orderby=name+desc") { - t.Errorf("Expected url to use odata based sorting, but got %q", r.URL.String()) - } - return &http.Response{ - Request: r, - Body: ioutil.NopCloser(strings.NewReader( - `[ - {"name":"1.2.3"}, - {"name":"4.5.6"} - ]`)), - StatusCode: 200, - }, nil - }) - - state := new(multistep.BasicStateBag) - state.Put("azureclient", &client.AzureClientSetMock{ - VirtualMachineImagesClientMock: client.VirtualMachineImagesClient{ - VirtualMachineImagesClientAPI: m}}) - - ui, getErrs := testUI() - state.Put("ui", ui) - - ctx, cancel := context.WithTimeout(context.Background(), time.Second) - defer cancel() - - got := pi.Run(ctx, state) - if got != multistep.ActionContinue { - t.Errorf("Expected 'continue', but got %q", got) - } - - if pi.PlatformImage.Version != "1.2.3" { - t.Errorf("Expected version '1.2.3', but got %q", pi.PlatformImage.Version) - } - - _ = getErrs -} diff --git a/builder/azure/chroot/step_verify_shared_image_destination.go b/builder/azure/chroot/step_verify_shared_image_destination.go deleted file mode 100644 index a05103b9c..000000000 --- a/builder/azure/chroot/step_verify_shared_image_destination.go +++ /dev/null @@ -1,119 +0,0 @@ -package chroot - -import ( - "context" - "fmt" - "log" - "strings" - - "github.com/Azure/azure-sdk-for-go/services/compute/mgmt/2019-12-01/compute" - "github.com/Azure/go-autorest/autorest/to" - "github.com/hashicorp/packer-plugin-sdk/multistep" - packersdk "github.com/hashicorp/packer-plugin-sdk/packer" - "github.com/hashicorp/packer/builder/azure/common/client" -) - -var _ multistep.Step = &StepVerifySharedImageDestination{} - -// StepVerifySharedImageDestination verifies that the shared image location matches the Location field in the step. -// Also verifies that the OS Type is Linux. -type StepVerifySharedImageDestination struct { - Image SharedImageGalleryDestination - Location string -} - -// Run retrieves the image metadata from Azure and compares the location to Location. Verifies the OS Type. -func (s *StepVerifySharedImageDestination) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction { - azcli := state.Get("azureclient").(client.AzureClientSet) - ui := state.Get("ui").(packersdk.Ui) - - errorMessage := func(message string, parameters ...interface{}) multistep.StepAction { - err := fmt.Errorf(message, parameters...) - log.Printf("StepVerifySharedImageDestination.Run: error: %+v", err) - state.Put("error", err) - ui.Error(err.Error()) - return multistep.ActionHalt - } - - imageURI := fmt.Sprintf("/subscriptions/%s/resourcegroup/%s/providers/Microsoft.Compute/galleries/%s/images/%s", - azcli.SubscriptionID(), - s.Image.ResourceGroup, - s.Image.GalleryName, - s.Image.ImageName, - ) - - ui.Say(fmt.Sprintf("Validating that shared image %s exists", - imageURI)) - - image, err := azcli.GalleryImagesClient().Get(ctx, - s.Image.ResourceGroup, - s.Image.GalleryName, - s.Image.ImageName) - - if err != nil { - return errorMessage("Error retrieving shared image %q: %+v ", imageURI, err) - } - - if image.ID == nil || *image.ID == "" { - return errorMessage("Error retrieving shared image %q: ID field in response is empty", imageURI) - } - if image.GalleryImageProperties == nil { - return errorMessage("Could not retrieve shared image properties for image %q.", to.String(image.ID)) - } - - location := to.String(image.Location) - - log.Printf("StepVerifySharedImageDestination:Run: Image %q, Location: %q, HvGen: %q, osState: %q", - to.String(image.ID), - location, - image.GalleryImageProperties.HyperVGeneration, - image.GalleryImageProperties.OsState) - - if !strings.EqualFold(location, s.Location) { - return errorMessage("Destination shared image resource %q is in a different location (%q) than this VM (%q). "+ - "Packer does not know how to handle that.", - to.String(image.ID), - location, - s.Location) - } - - if image.GalleryImageProperties.OsType != compute.Linux { - return errorMessage("The shared image (%q) is not a Linux image (found %q). Currently only Linux images are supported.", - to.String(image.ID), - image.GalleryImageProperties.OsType) - } - - ui.Say(fmt.Sprintf("Found image %s in location %s", - to.String(image.ID), - to.String(image.Location))) - - versions, err := azcli.GalleryImageVersionsClient().ListByGalleryImageComplete(ctx, - s.Image.ResourceGroup, - s.Image.GalleryName, - s.Image.ImageName) - - if err != nil { - return errorMessage("Could not ListByGalleryImageComplete group:%v gallery:%v image:%v", - s.Image.ResourceGroup, s.Image.GalleryName, s.Image.ImageName) - } - - for versions.NotDone() { - version := versions.Value() - - if version.Name == nil { - return errorMessage("Could not retrieve versions for image %q: unexpected nil name", to.String(image.ID)) - } - if *version.Name == s.Image.ImageVersion { - return errorMessage("Shared image version %q already exists for image %q.", s.Image.ImageVersion, to.String(image.ID)) - } - - err := versions.NextWithContext(ctx) - if err != nil { - return errorMessage("Could not retrieve versions for image %q: %+v", to.String(image.ID), err) - } - } - - return multistep.ActionContinue -} - -func (*StepVerifySharedImageDestination) Cleanup(multistep.StateBag) {} diff --git a/builder/azure/chroot/step_verify_shared_image_destination_test.go b/builder/azure/chroot/step_verify_shared_image_destination_test.go deleted file mode 100644 index 6df5d099b..000000000 --- a/builder/azure/chroot/step_verify_shared_image_destination_test.go +++ /dev/null @@ -1,186 +0,0 @@ -package chroot - -import ( - "context" - "io/ioutil" - "net/http" - "reflect" - "strings" - "testing" - - "github.com/hashicorp/packer-plugin-sdk/multistep" - packersdk "github.com/hashicorp/packer-plugin-sdk/packer" - "github.com/hashicorp/packer/builder/azure/common/client" - - "github.com/Azure/azure-sdk-for-go/services/compute/mgmt/2019-12-01/compute" - "github.com/Azure/go-autorest/autorest" -) - -func TestStepVerifySharedImageDestination_Run(t *testing.T) { - - type fields struct { - Image SharedImageGalleryDestination - Location string - } - tests := []struct { - name string - fields fields - want multistep.StepAction - wantErr string - }{ - { - name: "happy path", - want: multistep.ActionContinue, - fields: fields{ - Image: SharedImageGalleryDestination{ - ResourceGroup: "rg", - GalleryName: "gallery", - ImageName: "image", - ImageVersion: "1.2.3", - }, - Location: "region1", - }, - }, - { - name: "not found", - want: multistep.ActionHalt, - wantErr: `Error retrieving shared image "/subscriptions/subscriptionID/resourcegroup/other-rg/providers/Microsoft.Compute/galleries/gallery/images/image": compute.GalleryImagesClient#Get: Failure responding to request: StatusCode=404 -- Original Error: autorest/azure: Service returned an error. Status=404 Code="NotFound" Message="Not found" `, - fields: fields{ - Image: SharedImageGalleryDestination{ - ResourceGroup: "other-rg", - GalleryName: "gallery", - ImageName: "image", - ImageVersion: "1.2.3", - }, - Location: "region1", - }, - }, - { - name: "wrong region", - want: multistep.ActionHalt, - wantErr: "Destination shared image resource \"image-resourceid-goes-here\" is in a different location (\"region1\") than this VM (\"other-region\"). Packer does not know how to handle that.", - fields: fields{ - Image: SharedImageGalleryDestination{ - ResourceGroup: "rg", - GalleryName: "gallery", - ImageName: "image", - ImageVersion: "1.2.3", - }, - Location: "other-region", - }, - }, - { - name: "version exists", - want: multistep.ActionHalt, - wantErr: "Shared image version \"2.3.4\" already exists for image \"image-resourceid-goes-here\".", - fields: fields{ - Image: SharedImageGalleryDestination{ - ResourceGroup: "rg", - GalleryName: "gallery", - ImageName: "image", - ImageVersion: "2.3.4", - }, - Location: "region1", - }, - }, - { - name: "not Linux", - want: multistep.ActionHalt, - wantErr: "The shared image (\"windows-image-resourceid-goes-here\") is not a Linux image (found \"Windows\"). Currently only Linux images are supported.", - fields: fields{ - Image: SharedImageGalleryDestination{ - ResourceGroup: "rg", - GalleryName: "gallery", - ImageName: "windowsimage", - ImageVersion: "1.2.3", - }, - Location: "region1", - }, - }, - } - for _, tt := range tests { - gi := compute.NewGalleryImagesClient("subscriptionID") - gi.Sender = autorest.SenderFunc(func(r *http.Request) (*http.Response, error) { - switch { - case r.Method == "GET" && strings.HasPrefix(r.URL.RequestURI(), - "/subscriptions/subscriptionID/resourceGroups/rg/providers/Microsoft.Compute/galleries/gallery/images/image"): - return &http.Response{ - Request: r, - Body: ioutil.NopCloser(strings.NewReader(`{ - "id": "image-resourceid-goes-here", - "location": "region1", - "properties": { - "osType": "Linux" - } - }`)), - StatusCode: 200, - }, nil - case r.Method == "GET" && strings.HasPrefix(r.URL.RequestURI(), - "/subscriptions/subscriptionID/resourceGroups/rg/providers/Microsoft.Compute/galleries/gallery/images/windowsimage"): - return &http.Response{ - Request: r, - Body: ioutil.NopCloser(strings.NewReader(`{ - "id": "windows-image-resourceid-goes-here", - "location": "region1", - "properties": { - "osType": "Windows" - } - }`)), - StatusCode: 200, - }, nil - } - return &http.Response{ - Request: r, - Body: ioutil.NopCloser(strings.NewReader(`{ - "Code": "NotFound", - "Message": "Not found" - }`)), - StatusCode: 404, - }, nil - }) - - giv := compute.NewGalleryImageVersionsClient("subscriptionID") - giv.Sender = autorest.SenderFunc(func(r *http.Request) (*http.Response, error) { - if !(r.Method == "GET" && strings.HasPrefix(r.URL.RequestURI(), - "/subscriptions/subscriptionID/resourceGroups/rg/providers/Microsoft.Compute/galleries/gallery/images/image/versions")) { - t.Errorf("Unexpected HTTP call: %s %s", r.Method, r.URL.RequestURI()) - } - return &http.Response{ - Request: r, - Body: ioutil.NopCloser(strings.NewReader(`{ - "value": [ - { - "name": "2.3.4" - } - ] - }`)), - StatusCode: 200, - }, nil - }) - - state := new(multistep.BasicStateBag) - state.Put("azureclient", &client.AzureClientSetMock{ - SubscriptionIDMock: "subscriptionID", - GalleryImagesClientMock: gi, - GalleryImageVersionsClientMock: giv, - }) - state.Put("ui", packersdk.TestUi(t)) - - t.Run(tt.name, func(t *testing.T) { - s := &StepVerifySharedImageDestination{ - Image: tt.fields.Image, - Location: tt.fields.Location, - } - if got := s.Run(context.TODO(), state); !reflect.DeepEqual(got, tt.want) { - t.Errorf("StepVerifySharedImageDestination.Run() = %v, want %v", got, tt.want) - } - }) - if err, ok := state.GetOk("error"); ok { - if err.(error).Error() != tt.wantErr { - t.Errorf("Unexpected error, got: %q, want: %q", err, tt.wantErr) - } - } else if tt.wantErr != "" { - t.Errorf("Expected error, but didn't get any") - } - } -} diff --git a/builder/azure/chroot/step_verify_shared_image_source.go b/builder/azure/chroot/step_verify_shared_image_source.go deleted file mode 100644 index 840160eff..000000000 --- a/builder/azure/chroot/step_verify_shared_image_source.go +++ /dev/null @@ -1,126 +0,0 @@ -package chroot - -import ( - "context" - "fmt" - "log" - "strings" - - "github.com/Azure/azure-sdk-for-go/services/compute/mgmt/2019-12-01/compute" - "github.com/Azure/go-autorest/autorest/to" - "github.com/hashicorp/packer-plugin-sdk/multistep" - packersdk "github.com/hashicorp/packer-plugin-sdk/packer" - "github.com/hashicorp/packer/builder/azure/common/client" -) - -var _ multistep.Step = &StepVerifySharedImageSource{} - -// StepVerifySharedImageSource verifies that the shared image location matches the Location field in the step. -// Also verifies that the OS Type is Linux. -type StepVerifySharedImageSource struct { - SharedImageID string - SubscriptionID string - Location string -} - -// Run retrieves the image metadata from Azure and compares the location to Location. Verifies the OS Type. -func (s *StepVerifySharedImageSource) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction { - azcli := state.Get("azureclient").(client.AzureClientSet) - ui := state.Get("ui").(packersdk.Ui) - - errorMessage := func(message string, parameters ...interface{}) multistep.StepAction { - err := fmt.Errorf(message, parameters...) - log.Printf("StepVerifySharedImageSource.Run: error: %+v", err) - state.Put("error", err) - ui.Error(err.Error()) - return multistep.ActionHalt - } - - resource, err := client.ParseResourceID(s.SharedImageID) - if err != nil { - return errorMessage("Could not parse resource id %q: %w", s.SharedImageID, err) - } - - if !strings.EqualFold(resource.Provider, "Microsoft.Compute") || - !strings.EqualFold(resource.ResourceType.String(), "galleries/images/versions") { - return errorMessage("Resource id %q does not identify a shared image version, expected Microsoft.Compute/galleries/images/versions", s.SharedImageID) - } - - ui.Say(fmt.Sprintf("Validating that shared image version %q exists", - s.SharedImageID)) - - version, err := azcli.GalleryImageVersionsClient().Get(ctx, - resource.ResourceGroup, - resource.ResourceName[0], - resource.ResourceName[1], - resource.ResourceName[2], - "") - - if err != nil { - return errorMessage("Error retrieving shared image version %q: %+v ", s.SharedImageID, err) - } - - if version.ID == nil || *version.ID == "" { - return errorMessage("Error retrieving shared image version %q: ID field in response is empty", s.SharedImageID) - } - - if version.GalleryImageVersionProperties == nil || - version.GalleryImageVersionProperties.PublishingProfile == nil || - version.GalleryImageVersionProperties.PublishingProfile.TargetRegions == nil { - return errorMessage("Could not retrieve shared image version properties for image %q.", s.SharedImageID) - } - - targetLocations := make([]string, 0, len(*version.GalleryImageVersionProperties.PublishingProfile.TargetRegions)) - vmLocation := client.NormalizeLocation(s.Location) - locationFound := false - for _, tr := range *version.GalleryImageVersionProperties.PublishingProfile.TargetRegions { - l := to.String(tr.Name) - l = client.NormalizeLocation(l) - targetLocations = append(targetLocations, l) - if strings.EqualFold(vmLocation, l) { - locationFound = true - break - } - } - if !locationFound { - return errorMessage("Target locations %q for %q does not include VM location %q", - targetLocations, s.SharedImageID, vmLocation) - } - - imageResource, _ := resource.Parent() - image, err := azcli.GalleryImagesClient().Get(ctx, - resource.ResourceGroup, - resource.ResourceName[0], - resource.ResourceName[1]) - - if err != nil { - return errorMessage("Error retrieving shared image %q: %+v ", imageResource.String(), err) - } - - if image.ID == nil || *image.ID == "" { - return errorMessage("Error retrieving shared image %q: ID field in response is empty", imageResource.String()) - } - - if image.GalleryImageProperties == nil { - return errorMessage("Could not retrieve shared image properties for image %q.", imageResource.String()) - } - - log.Printf("StepVerifySharedImageSource:Run: Image %q, HvGen: %q, osState: %q", - to.String(image.ID), - image.GalleryImageProperties.HyperVGeneration, - image.GalleryImageProperties.OsState) - - if image.GalleryImageProperties.OsType != compute.Linux { - return errorMessage("The shared image (%q) is not a Linux image (found %q). Currently only Linux images are supported.", - to.String(image.ID), - image.GalleryImageProperties.OsType) - } - - ui.Say(fmt.Sprintf("Found image source image version %q, available in location %s", - s.SharedImageID, - s.Location)) - - return multistep.ActionContinue -} - -func (*StepVerifySharedImageSource) Cleanup(multistep.StateBag) {} diff --git a/builder/azure/chroot/step_verify_shared_image_source_test.go b/builder/azure/chroot/step_verify_shared_image_source_test.go deleted file mode 100644 index 9950a6cf2..000000000 --- a/builder/azure/chroot/step_verify_shared_image_source_test.go +++ /dev/null @@ -1,188 +0,0 @@ -package chroot - -import ( - "context" - "io/ioutil" - "net/http" - "reflect" - "regexp" - "strings" - "testing" - - "github.com/Azure/azure-sdk-for-go/services/compute/mgmt/2019-12-01/compute" - "github.com/Azure/go-autorest/autorest" - "github.com/hashicorp/packer-plugin-sdk/multistep" - packersdk "github.com/hashicorp/packer-plugin-sdk/packer" - "github.com/hashicorp/packer/builder/azure/common/client" -) - -func TestStepVerifySharedImageSource_Run(t *testing.T) { - type fields struct { - SharedImageID string - SubscriptionID string - Location string - } - tests := []struct { - name string - fields fields - want multistep.StepAction - wantErr string - }{ - { - name: "happy path", - fields: fields{ - SharedImageID: "/subscriptions/subscriptionID/resourceGroups/rg/providers/Microsoft.Compute/galleries/myGallery/images/myImage/versions/1.2.3", - Location: "VM location", - }, - }, - { - name: "resource is not a shared image", - fields: fields{ - SharedImageID: "/subscriptions/subscriptionID/resourceGroups/rg/providers/Microsoft.Compute/disks/myDisk", - Location: "VM location", - }, - want: multistep.ActionHalt, - wantErr: "does not identify a shared image version", - }, - { - name: "error in resource id", - fields: fields{ - SharedImageID: "not-a-resource-id", - }, - want: multistep.ActionHalt, - wantErr: "Could not parse resource id", - }, - { - name: "wrong location", - fields: fields{ - SharedImageID: "/subscriptions/subscriptionID/resourceGroups/rg/providers/Microsoft.Compute/galleries/myGallery/images/myImage/versions/1.2.3", - Location: "other location", - }, - want: multistep.ActionHalt, - wantErr: "does not include VM location", - }, - { - name: "image not found", - fields: fields{ - SharedImageID: "/subscriptions/subscriptionID/resourceGroups/rg/providers/Microsoft.Compute/galleries/myGallery/images/myImage/versions/2.3.4", - Location: "vm location", - }, - want: multistep.ActionHalt, - wantErr: "Error retrieving shared image version", - }, - { - name: "windows image", - fields: fields{ - SharedImageID: "/subscriptions/subscriptionID/resourceGroups/rg/providers/Microsoft.Compute/galleries/myGallery/images/windowsImage/versions/1.2.3", - Location: "VM location", - }, - want: multistep.ActionHalt, - wantErr: "not a Linux image", - }, - } - for _, tt := range tests { - giv := compute.NewGalleryImageVersionsClient("subscriptionID") - giv.Sender = autorest.SenderFunc(func(r *http.Request) (*http.Response, error) { - if r.Method == "GET" { - switch { - case strings.HasSuffix(r.URL.Path, "/versions/1.2.3"): - return &http.Response{ - Request: r, - Body: ioutil.NopCloser(strings.NewReader(`{ - "id": "image-version-id", - "properties": { - "publishingProfile": { - "targetRegions": [ - { "name": "vm Location" } - ] - } - } - }`)), - StatusCode: 200, - }, nil - case regexp.MustCompile(`(?i)^/subscriptions/subscriptionID/resourceGroups/rg/providers/Microsoft.Compute/galleries/myGallery/images/myImage/versions/\d+\.\d+\.\d+$`). - MatchString(r.URL.Path): - return &http.Response{ - Request: r, - Body: ioutil.NopCloser(strings.NewReader(`{"error":{"code":"NotFound"}}`)), - StatusCode: 404, - }, nil - } - } - - t.Errorf("Unexpected HTTP call: %s %s", r.Method, r.URL.RequestURI()) - return &http.Response{ - Request: r, - Status: "Unexpected HTTP call", - Body: ioutil.NopCloser(strings.NewReader(`{"code":"TestError"}`)), - StatusCode: 599, - }, nil - }) - - gi := compute.NewGalleryImagesClient("subscriptionID") - gi.Sender = autorest.SenderFunc(func(r *http.Request) (*http.Response, error) { - if r.Method == "GET" { - switch { - case strings.HasSuffix(r.URL.Path, "/images/myImage"): - return &http.Response{ - Request: r, - Body: ioutil.NopCloser(strings.NewReader(`{ - "id": "image-id", - "properties": { - "osType": "Linux" - } - }`)), - StatusCode: 200, - }, nil - case strings.HasSuffix(r.URL.Path, "/images/windowsImage"): - return &http.Response{ - Request: r, - Body: ioutil.NopCloser(strings.NewReader(`{ - "id": "image-id", - "properties": { - "osType": "Windows" - } - }`)), - StatusCode: 200, - }, nil - } - } - - t.Errorf("Unexpected HTTP call: %s %s", r.Method, r.URL.RequestURI()) - return &http.Response{ - Request: r, - Status: "Unexpected HTTP call", - Body: ioutil.NopCloser(strings.NewReader(`{"error":{"code":"TestError"}}`)), - StatusCode: 599, - }, nil - }) - - state := new(multistep.BasicStateBag) - state.Put("azureclient", &client.AzureClientSetMock{ - SubscriptionIDMock: "subscriptionID", - GalleryImageVersionsClientMock: giv, - GalleryImagesClientMock: gi, - }) - state.Put("ui", packersdk.TestUi(t)) - - t.Run(tt.name, func(t *testing.T) { - s := &StepVerifySharedImageSource{ - SharedImageID: tt.fields.SharedImageID, - SubscriptionID: tt.fields.SubscriptionID, - Location: tt.fields.Location, - } - if got := s.Run(context.TODO(), state); !reflect.DeepEqual(got, tt.want) { - t.Errorf("StepVerifySharedImageSource.Run() = %v, want %v", got, tt.want) - } - d, _ := state.GetOk("error") - err, _ := d.(error) - if tt.wantErr != "" { - if !strings.Contains(err.Error(), tt.wantErr) { - t.Errorf("Wanted error %q, got %q", tt.wantErr, err) - } - } else if err != nil && err.Error() != "" { - t.Errorf("Unexpected error: %v", err) - } - }) - } -} diff --git a/builder/azure/chroot/step_verify_source_disk.go b/builder/azure/chroot/step_verify_source_disk.go deleted file mode 100644 index 5f71fe415..000000000 --- a/builder/azure/chroot/step_verify_source_disk.go +++ /dev/null @@ -1,80 +0,0 @@ -package chroot - -import ( - "context" - "fmt" - "log" - "strings" - - "github.com/Azure/go-autorest/autorest/azure" - "github.com/Azure/go-autorest/autorest/to" - - "github.com/hashicorp/packer-plugin-sdk/multistep" - packersdk "github.com/hashicorp/packer-plugin-sdk/packer" - "github.com/hashicorp/packer/builder/azure/common/client" -) - -type StepVerifySourceDisk struct { - SourceDiskResourceID string - Location string -} - -func (s StepVerifySourceDisk) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction { - azcli := state.Get("azureclient").(client.AzureClientSet) - ui := state.Get("ui").(packersdk.Ui) - - ui.Say("Checking source disk location") - resource, err := azure.ParseResourceID(s.SourceDiskResourceID) - if err != nil { - log.Printf("StepVerifySourceDisk.Run: error: %+v", err) - err := fmt.Errorf("Could not parse resource id %q: %s", s.SourceDiskResourceID, err) - state.Put("error", err) - ui.Error(err.Error()) - return multistep.ActionHalt - } - - if !strings.EqualFold(resource.SubscriptionID, azcli.SubscriptionID()) { - err := fmt.Errorf("Source disk resource %q is in a different subscription than this VM (%q). "+ - "Packer does not know how to handle that.", - s.SourceDiskResourceID, azcli.SubscriptionID()) - log.Printf("StepVerifySourceDisk.Run: error: %+v", err) - state.Put("error", err) - ui.Error(err.Error()) - return multistep.ActionHalt - } - - if !(strings.EqualFold(resource.Provider, "Microsoft.Compute") && strings.EqualFold(resource.ResourceType, "disks")) { - err := fmt.Errorf("Resource ID %q is not a managed disk resource", s.SourceDiskResourceID) - log.Printf("StepVerifySourceDisk.Run: error: %+v", err) - state.Put("error", err) - ui.Error(err.Error()) - return multistep.ActionHalt - } - - disk, err := azcli.DisksClient().Get(ctx, - resource.ResourceGroup, resource.ResourceName) - if err != nil { - err := fmt.Errorf("Unable to retrieve disk (%q): %s", s.SourceDiskResourceID, err) - log.Printf("StepVerifySourceDisk.Run: error: %+v", err) - state.Put("error", err) - ui.Error(err.Error()) - return multistep.ActionHalt - } - - location := to.String(disk.Location) - if !strings.EqualFold(location, s.Location) { - err := fmt.Errorf("Source disk resource %q is in a different location (%q) than this VM (%q). "+ - "Packer does not know how to handle that.", - s.SourceDiskResourceID, - location, - s.Location) - log.Printf("StepVerifySourceDisk.Run: error: %+v", err) - state.Put("error", err) - ui.Error(err.Error()) - return multistep.ActionHalt - } - - return multistep.ActionContinue -} - -func (s StepVerifySourceDisk) Cleanup(state multistep.StateBag) {} diff --git a/builder/azure/chroot/step_verify_source_disk_test.go b/builder/azure/chroot/step_verify_source_disk_test.go deleted file mode 100644 index c9b69dd57..000000000 --- a/builder/azure/chroot/step_verify_source_disk_test.go +++ /dev/null @@ -1,157 +0,0 @@ -package chroot - -import ( - "context" - "io/ioutil" - "net/http" - "reflect" - "regexp" - "strings" - "testing" - - "github.com/Azure/azure-sdk-for-go/services/compute/mgmt/2019-12-01/compute" - "github.com/Azure/go-autorest/autorest" - "github.com/hashicorp/packer-plugin-sdk/multistep" - packersdk "github.com/hashicorp/packer-plugin-sdk/packer" - "github.com/hashicorp/packer/builder/azure/common/client" -) - -func Test_StepVerifySourceDisk_Run(t *testing.T) { - type fields struct { - SourceDiskResourceID string - Location string - - GetDiskResponseCode int - GetDiskResponseBody string - } - type args struct { - state multistep.StateBag - } - tests := []struct { - name string - fields fields - args args - want multistep.StepAction - errormatch string - }{ - { - name: "HappyPath", - fields: fields{ - SourceDiskResourceID: "/subscriptions/subid1/resourcegroups/rg1/providers/Microsoft.Compute/disks/disk1", - Location: "westus2", - - GetDiskResponseCode: 200, - GetDiskResponseBody: `{"location":"westus2"}`, - }, - want: multistep.ActionContinue, - }, - { - name: "NotAResourceID", - fields: fields{ - SourceDiskResourceID: "/other", - Location: "westus2", - - GetDiskResponseCode: 200, - GetDiskResponseBody: `{"location":"westus2"}`, - }, - want: multistep.ActionHalt, - errormatch: "Could not parse resource id", - }, - { - name: "DiskNotFound", - fields: fields{ - SourceDiskResourceID: "/subscriptions/subid1/resourcegroups/rg1/providers/Microsoft.Compute/disks/disk1", - Location: "westus2", - - GetDiskResponseCode: 404, - GetDiskResponseBody: `{}`, - }, - want: multistep.ActionHalt, - errormatch: "Unable to retrieve", - }, - { - name: "NotADisk", - fields: fields{ - SourceDiskResourceID: "/subscriptions/subid1/resourcegroups/rg1/providers/Microsoft.Compute/images/image1", - Location: "westus2", - - GetDiskResponseCode: 404, - }, - want: multistep.ActionHalt, - errormatch: "not a managed disk", - }, - { - name: "OtherSubscription", - fields: fields{ - SourceDiskResourceID: "/subscriptions/subid2/resourcegroups/rg1/providers/Microsoft.Compute/disks/disk1", - Location: "westus2", - - GetDiskResponseCode: 200, - GetDiskResponseBody: `{"location":"westus2"}`, - }, - want: multistep.ActionHalt, - errormatch: "different subscription", - }, - { - name: "OtherLocation", - fields: fields{ - SourceDiskResourceID: "/subscriptions/subid1/resourcegroups/rg1/providers/Microsoft.Compute/disks/disk1", - Location: "eastus", - - GetDiskResponseCode: 200, - GetDiskResponseBody: `{"location":"westus2"}`, - }, - want: multistep.ActionHalt, - errormatch: "different location", - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - s := StepVerifySourceDisk{ - SourceDiskResourceID: tt.fields.SourceDiskResourceID, - Location: tt.fields.Location, - } - - m := compute.NewDisksClient("subscriptionId") - m.Sender = autorest.SenderFunc(func(r *http.Request) (*http.Response, error) { - return &http.Response{ - Request: r, - Body: ioutil.NopCloser(strings.NewReader(tt.fields.GetDiskResponseBody)), - StatusCode: tt.fields.GetDiskResponseCode, - }, nil - }) - - ui, getErr := testUI() - - state := new(multistep.BasicStateBag) - state.Put("azureclient", &client.AzureClientSetMock{ - DisksClientMock: m, - SubscriptionIDMock: "subid1", - }) - state.Put("ui", ui) - - got := s.Run(context.TODO(), state) - if !reflect.DeepEqual(got, tt.want) { - t.Errorf("StepVerifySourceDisk.Run() = %v, want %v", got, tt.want) - } - - if tt.errormatch != "" { - errs := getErr() - if !regexp.MustCompile(tt.errormatch).MatchString(errs) { - t.Errorf("Expected the error output (%q) to match %q", errs, tt.errormatch) - } - } - - if got == multistep.ActionHalt { - if _, ok := state.GetOk("error"); !ok { - t.Fatal("Expected 'error' to be set in statebag after failure") - } - } - }) - } -} - -type uiThatRemebersErrors struct { - packersdk.Ui - LastError string -} diff --git a/builder/azure/chroot/template_funcs.go b/builder/azure/chroot/template_funcs.go deleted file mode 100644 index 7594cf949..000000000 --- a/builder/azure/chroot/template_funcs.go +++ /dev/null @@ -1,37 +0,0 @@ -package chroot - -import ( - "fmt" - "sync" - - "github.com/hashicorp/packer/builder/azure/common/client" -) - -// CreateVMMetadataTemplateFunc returns a template function that retrieves VM metadata. VM metadata is retrieved only once and reused for all executions of the function. -func CreateVMMetadataTemplateFunc() func(string) (string, error) { - var data *client.ComputeInfo - var dataErr error - once := sync.Once{} - return func(key string) (string, error) { - once.Do(func() { - data, dataErr = client.DefaultMetadataClient.GetComputeInfo() - }) - if dataErr != nil { - return "", dataErr - } - switch key { - case "name": - return data.Name, nil - case "subscription_id": - return data.SubscriptionID, nil - case "resource_group": - return data.ResourceGroupName, nil - case "location": - return data.Location, nil - case "resource_id": - return data.ResourceID(), nil - default: - return "", fmt.Errorf("unknown metadata key: %s (supported: name, subscription_id, resource_group, location, resource_id)", key) - } - } -} diff --git a/builder/azure/common/artifact.go b/builder/azure/common/artifact.go deleted file mode 100644 index 498f7292e..000000000 --- a/builder/azure/common/artifact.go +++ /dev/null @@ -1,104 +0,0 @@ -package common - -import ( - "context" - "fmt" - "log" - "sort" - "strings" - - "github.com/Azure/go-autorest/autorest/azure" - packersdk "github.com/hashicorp/packer-plugin-sdk/packer" - "github.com/hashicorp/packer/builder/azure/common/client" -) - -// Artifact is an artifact implementation that contains built Managed Images or Disks. -type Artifact struct { - // Array of the Azure resource IDs that were created. - Resources []string - - // BuilderId is the unique ID for the builder that created this AMI - BuilderIdValue string - - // Azure client for performing API stuff. - AzureClientSet client.AzureClientSet - - // StateData should store data such as GeneratedData - // to be shared with post-processors - StateData map[string]interface{} -} - -func (a *Artifact) BuilderId() string { - return a.BuilderIdValue -} - -func (*Artifact) Files() []string { - // We have no files - return nil -} - -func (a *Artifact) Id() string { - parts := make([]string, 0, len(a.Resources)) - for _, resource := range a.Resources { - parts = append(parts, strings.ToLower(resource)) - } - - sort.Strings(parts) - return strings.Join(parts, ",") -} - -func (a *Artifact) String() string { - parts := make([]string, 0, len(a.Resources)) - for _, resource := range a.Resources { - parts = append(parts, strings.ToLower(resource)) - } - - sort.Strings(parts) - return fmt.Sprintf("Azure resources created:\n%s\n", strings.Join(parts, "\n")) -} - -func (a *Artifact) State(name string) interface{} { - return a.StateData[name] -} - -func (a *Artifact) Destroy() error { - errs := make([]error, 0) - - for _, resource := range a.Resources { - log.Printf("Deleting resource %s", resource) - - id, err := azure.ParseResourceID(resource) - if err != nil { - return fmt.Errorf("Unable to parse resource id (%s): %v", resource, err) - } - - ctx := context.TODO() - restype := strings.ToLower(fmt.Sprintf("%s/%s", id.Provider, id.ResourceType)) - - switch restype { - case "microsoft.compute/images": - res, err := a.AzureClientSet.ImagesClient().Delete(ctx, id.ResourceGroup, id.ResourceName) - if err != nil { - errs = append(errs, fmt.Errorf("Unable to initiate deletion of resource (%s): %v", resource, err)) - } else { - err := res.WaitForCompletionRef(ctx, a.AzureClientSet.PollClient()) - if err != nil { - errs = append(errs, fmt.Errorf("Unable to complete deletion of resource (%s): %v", resource, err)) - } - } - default: - errs = append(errs, fmt.Errorf("Don't know how to delete resources of type %s (%s)", resource, restype)) - } - - } - - if len(errs) > 0 { - if len(errs) == 1 { - return errs[0] - } else { - return &packersdk.MultiError{Errors: errs} - } - } - - return nil -} diff --git a/builder/azure/common/artifact_test.go b/builder/azure/common/artifact_test.go deleted file mode 100644 index a4fe439c6..000000000 --- a/builder/azure/common/artifact_test.go +++ /dev/null @@ -1,21 +0,0 @@ -package common - -import ( - "testing" -) - -func TestArtifact_String(t *testing.T) { - a := &Artifact{ - Resources: []string{ - "/subscriptions/4674464f-6024-43ae-903c-f6eed761be04/resourceGroups/rg/providers/Microsoft.Compute/disks/PackerTemp-osdisk-1586461959", - "/subscriptions/4674464f-6024-43ae-903c-f6eed761be04/resourceGroups/images/providers/Microsoft.Compute/galleries/testgallery/images/myUbuntu/versions/1.0.10", - }, - } - want := `Azure resources created: -/subscriptions/4674464f-6024-43ae-903c-f6eed761be04/resourcegroups/images/providers/microsoft.compute/galleries/testgallery/images/myubuntu/versions/1.0.10 -/subscriptions/4674464f-6024-43ae-903c-f6eed761be04/resourcegroups/rg/providers/microsoft.compute/disks/packertemp-osdisk-1586461959 -` - if got := a.String(); got != want { - t.Errorf("Artifact.String() = %v, want %v", got, want) - } -} diff --git a/builder/azure/common/client/azure_client_set.go b/builder/azure/common/client/azure_client_set.go deleted file mode 100644 index e1dbbe507..000000000 --- a/builder/azure/common/client/azure_client_set.go +++ /dev/null @@ -1,138 +0,0 @@ -package client - -import ( - "log" - "net/http" - "regexp" - "time" - - "github.com/hashicorp/packer-plugin-sdk/useragent" - - "github.com/Azure/azure-sdk-for-go/services/compute/mgmt/2019-12-01/compute" - "github.com/Azure/azure-sdk-for-go/services/compute/mgmt/2019-12-01/compute/computeapi" - "github.com/Azure/go-autorest/autorest" - version "github.com/hashicorp/packer/builder/azure/version" -) - -type AzureClientSet interface { - MetadataClient() MetadataClientAPI - - DisksClient() computeapi.DisksClientAPI - SnapshotsClient() computeapi.SnapshotsClientAPI - ImagesClient() computeapi.ImagesClientAPI - - GalleryImagesClient() computeapi.GalleryImagesClientAPI - GalleryImageVersionsClient() computeapi.GalleryImageVersionsClientAPI - - VirtualMachinesClient() computeapi.VirtualMachinesClientAPI - VirtualMachineImagesClient() VirtualMachineImagesClientAPI - - PollClient() autorest.Client - - // SubscriptionID returns the subscription ID that this client set was created for - SubscriptionID() string -} - -var subscriptionPathRegex = regexp.MustCompile(`/subscriptions/([[:xdigit:]]{8}(-[[:xdigit:]]{4}){3}-[[:xdigit:]]{12})`) - -var _ AzureClientSet = &azureClientSet{} - -type azureClientSet struct { - sender autorest.Sender - authorizer autorest.Authorizer - subscriptionID string - PollingDelay time.Duration -} - -func New(c Config, say func(string)) (AzureClientSet, error) { - return new(c, say) -} - -func new(c Config, say func(string)) (*azureClientSet, error) { - token, err := c.GetServicePrincipalToken(say, c.CloudEnvironment().ResourceManagerEndpoint) - if err != nil { - return nil, err - } - return &azureClientSet{ - authorizer: autorest.NewBearerAuthorizer(token), - subscriptionID: c.SubscriptionID, - sender: http.DefaultClient, - PollingDelay: time.Second, - }, nil -} - -func (s azureClientSet) SubscriptionID() string { - return s.subscriptionID -} - -func (s azureClientSet) configureAutorestClient(c *autorest.Client) { - err := c.AddToUserAgent(useragent.String(version.AzurePluginVersion.FormattedVersion())) - if err != nil { - log.Printf("Error appending Packer plugin version to user agent.") - } - c.Authorizer = s.authorizer - c.Sender = s.sender -} - -func (s azureClientSet) MetadataClient() MetadataClientAPI { - return metadataClient{ - s.sender, - useragent.String(version.AzurePluginVersion.FormattedVersion()), - } -} - -func (s azureClientSet) DisksClient() computeapi.DisksClientAPI { - c := compute.NewDisksClient(s.subscriptionID) - s.configureAutorestClient(&c.Client) - c.PollingDelay = s.PollingDelay - return c -} - -func (s azureClientSet) SnapshotsClient() computeapi.SnapshotsClientAPI { - c := compute.NewSnapshotsClient(s.subscriptionID) - s.configureAutorestClient(&c.Client) - c.PollingDelay = s.PollingDelay - return c -} - -func (s azureClientSet) ImagesClient() computeapi.ImagesClientAPI { - c := compute.NewImagesClient(s.subscriptionID) - s.configureAutorestClient(&c.Client) - c.PollingDelay = s.PollingDelay - return c -} - -func (s azureClientSet) VirtualMachinesClient() computeapi.VirtualMachinesClientAPI { - c := compute.NewVirtualMachinesClient(s.subscriptionID) - s.configureAutorestClient(&c.Client) - c.PollingDelay = s.PollingDelay - return c -} - -func (s azureClientSet) VirtualMachineImagesClient() VirtualMachineImagesClientAPI { - c := compute.NewVirtualMachineImagesClient(s.subscriptionID) - s.configureAutorestClient(&c.Client) - c.PollingDelay = s.PollingDelay - return VirtualMachineImagesClient{c} -} - -func (s azureClientSet) GalleryImagesClient() computeapi.GalleryImagesClientAPI { - c := compute.NewGalleryImagesClient(s.subscriptionID) - s.configureAutorestClient(&c.Client) - c.PollingDelay = s.PollingDelay - return c -} - -func (s azureClientSet) GalleryImageVersionsClient() computeapi.GalleryImageVersionsClientAPI { - c := compute.NewGalleryImageVersionsClient(s.subscriptionID) - s.configureAutorestClient(&c.Client) - c.PollingDelay = s.PollingDelay - return c -} - -func (s azureClientSet) PollClient() autorest.Client { - c := autorest.NewClientWithUserAgent("Packer-Azure-ClientSet") - s.configureAutorestClient(&c) - c.PollingDelay = time.Second * 5 - return c -} diff --git a/builder/azure/common/client/azure_client_set_mock.go b/builder/azure/common/client/azure_client_set_mock.go deleted file mode 100644 index b13b79ed6..000000000 --- a/builder/azure/common/client/azure_client_set_mock.go +++ /dev/null @@ -1,72 +0,0 @@ -package client - -import ( - "github.com/Azure/azure-sdk-for-go/services/compute/mgmt/2019-12-01/compute/computeapi" - "github.com/Azure/go-autorest/autorest" -) - -var _ AzureClientSet = &AzureClientSetMock{} - -// AzureClientSetMock provides a generic mock for AzureClientSet -type AzureClientSetMock struct { - DisksClientMock computeapi.DisksClientAPI - SnapshotsClientMock computeapi.SnapshotsClientAPI - ImagesClientMock computeapi.ImagesClientAPI - VirtualMachineImagesClientMock VirtualMachineImagesClientAPI - VirtualMachinesClientMock computeapi.VirtualMachinesClientAPI - GalleryImagesClientMock computeapi.GalleryImagesClientAPI - GalleryImageVersionsClientMock computeapi.GalleryImageVersionsClientAPI - PollClientMock autorest.Client - MetadataClientMock MetadataClientAPI - SubscriptionIDMock string -} - -// DisksClient returns a DisksClientAPI -func (m *AzureClientSetMock) DisksClient() computeapi.DisksClientAPI { - return m.DisksClientMock -} - -// SnapshotsClient returns a SnapshotsClientAPI -func (m *AzureClientSetMock) SnapshotsClient() computeapi.SnapshotsClientAPI { - return m.SnapshotsClientMock -} - -// ImagesClient returns a ImagesClientAPI -func (m *AzureClientSetMock) ImagesClient() computeapi.ImagesClientAPI { - return m.ImagesClientMock -} - -// VirtualMachineImagesClient returns a VirtualMachineImagesClientAPI -func (m *AzureClientSetMock) VirtualMachineImagesClient() VirtualMachineImagesClientAPI { - return m.VirtualMachineImagesClientMock -} - -// VirtualMachinesClient returns a VirtualMachinesClientAPI -func (m *AzureClientSetMock) VirtualMachinesClient() computeapi.VirtualMachinesClientAPI { - return m.VirtualMachinesClientMock -} - -// GalleryImagesClient returns a GalleryImagesClientAPI -func (m *AzureClientSetMock) GalleryImagesClient() computeapi.GalleryImagesClientAPI { - return m.GalleryImagesClientMock -} - -// GalleryImageVersionsClient returns a GalleryImageVersionsClientAPI -func (m *AzureClientSetMock) GalleryImageVersionsClient() computeapi.GalleryImageVersionsClientAPI { - return m.GalleryImageVersionsClientMock -} - -// PollClient returns an autorest Client that can be used for polling async requests -func (m *AzureClientSetMock) PollClient() autorest.Client { - return m.PollClientMock -} - -// MetadataClient returns a MetadataClientAPI -func (m *AzureClientSetMock) MetadataClient() MetadataClientAPI { - return m.MetadataClientMock -} - -// SubscriptionID returns SubscriptionIDMock -func (m *AzureClientSetMock) SubscriptionID() string { - return m.SubscriptionIDMock -} diff --git a/builder/azure/common/client/config.go b/builder/azure/common/client/config.go deleted file mode 100644 index 8fa077476..000000000 --- a/builder/azure/common/client/config.go +++ /dev/null @@ -1,352 +0,0 @@ -//go:generate packer-sdc struct-markdown - -package client - -import ( - "fmt" - "os" - "strings" - "time" - - "github.com/Azure/go-autorest/autorest/adal" - "github.com/Azure/go-autorest/autorest/azure" - jwt "github.com/dgrijalva/jwt-go" - packersdk "github.com/hashicorp/packer-plugin-sdk/packer" -) - -// Config allows for various ways to authenticate Azure clients. -// When `client_id` and `subscription_id` are specified, Packer will use the -// specified Azure Active Directory (AAD) Service Principal (SP). -// If only `subscription_id` is specified, Packer will try to interactively -// log on the current user (tokens will be cached). -// If none of these options are specified, Packer will attempt to use the -// Managed Identity and subscription of the VM that Packer is running on. -// This will only work if Packer is running on an Azure VM. -type Config struct { - // One of Public, China, Germany, or - // USGovernment. Defaults to Public. Long forms such as - // USGovernmentCloud and AzureUSGovernmentCloud are also supported. - CloudEnvironmentName string `mapstructure:"cloud_environment_name" required:"false"` - cloudEnvironment *azure.Environment - - // Authentication fields - - // The application ID of the AAD Service Principal. - // Requires either `client_secret`, `client_cert_path` or `client_jwt` to be set as well. - ClientID string `mapstructure:"client_id"` - // A password/secret registered for the AAD SP. - ClientSecret string `mapstructure:"client_secret"` - // The path to a pem-encoded certificate that will be used to authenticate - // as the specified AAD SP. - ClientCertPath string `mapstructure:"client_cert_path"` - // The timeout for the JWT Token when using a [client certificate](#client_cert_path). Defaults to 1 hour. - ClientCertExpireTimeout time.Duration `mapstructure:"client_cert_token_timeout" required:"false"` - // A JWT bearer token for client auth (RFC 7523, Sec. 2.2) that will be used - // to authenticate the AAD SP. Provides more control over token the expiration - // when using certificate authentication than when using `client_cert_path`. - ClientJWT string `mapstructure:"client_jwt"` - // The object ID for the AAD SP. Optional, will be derived from the oAuth token if left empty. - ObjectID string `mapstructure:"object_id"` - - // The Active Directory tenant identifier with which your `client_id` and - // `subscription_id` are associated. If not specified, `tenant_id` will be - // looked up using `subscription_id`. - TenantID string `mapstructure:"tenant_id" required:"false"` - // The subscription to use. - SubscriptionID string `mapstructure:"subscription_id"` - - authType string - - // Flag to use Azure CLI authentication. Defaults to false. - // CLI auth will use the information from an active `az login` session to connect to Azure and set the subscription id and tenant id associated to the signed in account. - // If enabled, it will use the authentication provided by the `az` CLI. - // Azure CLI authentication will use the credential marked as `isDefault` and can be verified using `az account show`. - // Works with normal authentication (`az login`) and service principals (`az login --service-principal --username APP_ID --password PASSWORD --tenant TENANT_ID`). - // Ignores all other configurations if enabled. - UseAzureCLIAuth bool `mapstructure:"use_azure_cli_auth" required:"false"` -} - -const ( - authTypeDeviceLogin = "DeviceLogin" - authTypeMSI = "ManagedIdentity" - authTypeClientSecret = "ClientSecret" - authTypeClientCert = "ClientCertificate" - authTypeClientBearerJWT = "ClientBearerJWT" - authTypeAzureCLI = "AzureCLI" -) - -const DefaultCloudEnvironmentName = "Public" - -func (c *Config) SetDefaultValues() error { - if c.CloudEnvironmentName == "" { - c.CloudEnvironmentName = DefaultCloudEnvironmentName - } - return c.setCloudEnvironment() -} - -func (c *Config) CloudEnvironment() *azure.Environment { - return c.cloudEnvironment -} - -func (c *Config) setCloudEnvironment() error { - lookup := map[string]string{ - "CHINA": "AzureChinaCloud", - "CHINACLOUD": "AzureChinaCloud", - "AZURECHINACLOUD": "AzureChinaCloud", - - "GERMAN": "AzureGermanCloud", - "GERMANCLOUD": "AzureGermanCloud", - "AZUREGERMANCLOUD": "AzureGermanCloud", - - "GERMANY": "AzureGermanCloud", - "GERMANYCLOUD": "AzureGermanCloud", - "AZUREGERMANYCLOUD": "AzureGermanCloud", - - "PUBLIC": "AzurePublicCloud", - "PUBLICCLOUD": "AzurePublicCloud", - "AZUREPUBLICCLOUD": "AzurePublicCloud", - - "USGOVERNMENT": "AzureUSGovernmentCloud", - "USGOVERNMENTCLOUD": "AzureUSGovernmentCloud", - "AZUREUSGOVERNMENTCLOUD": "AzureUSGovernmentCloud", - } - - name := strings.ToUpper(c.CloudEnvironmentName) - envName, ok := lookup[name] - if !ok { - return fmt.Errorf("There is no cloud environment matching the name '%s'!", c.CloudEnvironmentName) - } - - env, err := azure.EnvironmentFromName(envName) - c.cloudEnvironment = &env - return err -} - -//nolint:ineffassign //this triggers a false positive because errs is passed by reference -func (c Config) Validate(errs *packersdk.MultiError) { - ///////////////////////////////////////////// - // Authentication via OAUTH - - // Check if device login is being asked for, and is allowed. - // - // Device login is enabled if the user only defines SubscriptionID and not - // ClientID, ClientSecret, and TenantID. - // - // Device login is not enabled for Windows because the WinRM certificate is - // readable by the ObjectID of the App. There may be another way to handle - // this case, but I am not currently aware of it - send feedback. - - if c.UseCLI() { - return - } - - if c.UseMSI() { - return - } - - if c.useDeviceLogin() { - return - } - - if c.SubscriptionID != "" && c.ClientID != "" && - c.ClientSecret != "" && - c.ClientCertPath == "" && - c.ClientJWT == "" { - // Service principal using secret - return - } - - if c.SubscriptionID != "" && c.ClientID != "" && - c.ClientSecret == "" && - c.ClientCertPath != "" && - c.ClientJWT == "" { - // Service principal using certificate - - if _, err := os.Stat(c.ClientCertPath); err != nil { - errs = packersdk.MultiErrorAppend(errs, fmt.Errorf("client_cert_path is not an accessible file: %v", err)) - } - if c.ClientCertExpireTimeout != 0 && c.ClientCertExpireTimeout < 5*time.Minute { - errs = packersdk.MultiErrorAppend(errs, fmt.Errorf("client_cert_token_timeout will expire within 5 minutes, please set a value greater than 5 minutes")) - } - return - } - - if c.SubscriptionID != "" && c.ClientID != "" && - c.ClientSecret == "" && - c.ClientCertPath == "" && - c.ClientJWT != "" { - // Service principal using JWT - // Check that JWT is valid for at least 5 more minutes - - p := jwt.Parser{} - claims := jwt.StandardClaims{} - token, _, err := p.ParseUnverified(c.ClientJWT, &claims) - if err != nil { - errs = packersdk.MultiErrorAppend(errs, fmt.Errorf("client_jwt is not a JWT: %v", err)) - } else { - if claims.ExpiresAt < time.Now().Add(5*time.Minute).Unix() { - errs = packersdk.MultiErrorAppend(errs, fmt.Errorf("client_jwt will expire within 5 minutes, please use a JWT that is valid for at least 5 minutes")) - } - if t, ok := token.Header["x5t"]; !ok || t == "" { - errs = packersdk.MultiErrorAppend(errs, fmt.Errorf("client_jwt is missing the x5t header value, which is required for bearer JWT client authentication to Azure")) - } - } - - return - } - - errs = packersdk.MultiErrorAppend(errs, fmt.Errorf("No valid set of authentication values specified:\n"+ - " to use the Managed Identity of the current machine, do not specify any of the fields below\n"+ - " to use interactive user authentication, specify only subscription_id\n"+ - " to use an Azure Active Directory service principal, specify either:\n"+ - " - subscription_id, client_id and client_secret\n"+ - " - subscription_id, client_id and client_cert_path\n"+ - " - subscription_id, client_id and client_jwt.")) -} - -func (c Config) useDeviceLogin() bool { - return c.SubscriptionID != "" && - c.ClientID == "" && - c.ClientSecret == "" && - c.ClientJWT == "" && - c.ClientCertPath == "" -} - -func (c Config) UseCLI() bool { - return c.UseAzureCLIAuth == true -} - -func (c Config) UseMSI() bool { - return c.SubscriptionID == "" && - c.ClientID == "" && - c.ClientSecret == "" && - c.ClientJWT == "" && - c.ClientCertPath == "" && - c.TenantID == "" -} - -func (c Config) GetServicePrincipalTokens(say func(string)) ( - servicePrincipalToken *adal.ServicePrincipalToken, - servicePrincipalTokenVault *adal.ServicePrincipalToken, - err error) { - - servicePrincipalToken, err = c.GetServicePrincipalToken(say, - c.CloudEnvironment().ResourceManagerEndpoint) - if err != nil { - return nil, nil, err - } - servicePrincipalTokenVault, err = c.GetServicePrincipalToken(say, - strings.TrimRight(c.CloudEnvironment().KeyVaultEndpoint, "/")) - if err != nil { - return nil, nil, err - } - return servicePrincipalToken, servicePrincipalTokenVault, nil -} - -func (c Config) GetServicePrincipalToken( - say func(string), forResource string) ( - servicePrincipalToken *adal.ServicePrincipalToken, - err error) { - - var auth oAuthTokenProvider - switch c.authType { - case authTypeDeviceLogin: - say("Getting tokens using device flow") - auth = NewDeviceFlowOAuthTokenProvider(*c.cloudEnvironment, say, c.TenantID) - case authTypeAzureCLI: - say("Getting tokens using Azure CLI") - auth = NewCliOAuthTokenProvider(*c.cloudEnvironment, say, c.TenantID) - case authTypeMSI: - say("Getting tokens using Managed Identity for Azure") - auth = NewMSIOAuthTokenProvider(*c.cloudEnvironment) - case authTypeClientSecret: - say("Getting tokens using client secret") - auth = NewSecretOAuthTokenProvider(*c.cloudEnvironment, c.ClientID, c.ClientSecret, c.TenantID) - case authTypeClientCert: - say("Getting tokens using client certificate") - auth, err = NewCertOAuthTokenProvider(*c.cloudEnvironment, c.ClientID, c.ClientCertPath, c.TenantID, c.ClientCertExpireTimeout) - if err != nil { - return nil, err - } - case authTypeClientBearerJWT: - say("Getting tokens using client bearer JWT") - auth = NewJWTOAuthTokenProvider(*c.cloudEnvironment, c.ClientID, c.ClientJWT, c.TenantID) - default: - panic("authType not set, call FillParameters, or set explicitly") - } - - servicePrincipalToken, err = auth.getServicePrincipalTokenWithResource(forResource) - if err != nil { - return nil, err - } - - err = servicePrincipalToken.EnsureFresh() - if err != nil { - return nil, err - } - - return servicePrincipalToken, nil -} - -// FillParameters capture the user intent from the supplied parameter set in authType, retrieves the TenantID and CloudEnvironment if not specified. -// The SubscriptionID is also retrieved in case MSI auth is requested. -func (c *Config) FillParameters() error { - if c.authType == "" { - if c.useDeviceLogin() { - c.authType = authTypeDeviceLogin - } else if c.UseCLI() { - c.authType = authTypeAzureCLI - } else if c.UseMSI() { - c.authType = authTypeMSI - } else if c.ClientSecret != "" { - c.authType = authTypeClientSecret - } else if c.ClientCertPath != "" { - c.authType = authTypeClientCert - } else { - c.authType = authTypeClientBearerJWT - } - } - - if c.authType == authTypeMSI && c.SubscriptionID == "" { - - subscriptionID, err := getSubscriptionFromIMDS() - if err != nil { - return fmt.Errorf("error fetching subscriptionID from VM metadata service for Managed Identity authentication: %v", err) - } - c.SubscriptionID = subscriptionID - } - - if c.cloudEnvironment == nil { - err := c.setCloudEnvironment() - if err != nil { - return err - } - } - - if c.authType == authTypeAzureCLI { - tenantID, subscriptionID, err := getIDsFromAzureCLI() - if err != nil { - return fmt.Errorf("error fetching tenantID and subscriptionID from Azure CLI (are you logged on using `az login`?): %v", err) - } - - c.TenantID = tenantID - c.SubscriptionID = subscriptionID - } - - if c.TenantID == "" { - tenantID, err := findTenantID(*c.cloudEnvironment, c.SubscriptionID) - if err != nil { - return err - } - c.TenantID = tenantID - } - - if c.ClientCertExpireTimeout == 0 { - c.ClientCertExpireTimeout = time.Hour - } - - return nil -} - -// allow override for unit tests -var findTenantID = FindTenantID diff --git a/builder/azure/common/client/config_retriever.go b/builder/azure/common/client/config_retriever.go deleted file mode 100644 index b4b25e5fb..000000000 --- a/builder/azure/common/client/config_retriever.go +++ /dev/null @@ -1,37 +0,0 @@ -package client - -import ( - "encoding/json" - "io/ioutil" - "net/http" -) - -// allow override for unit tests -var getSubscriptionFromIMDS = _getSubscriptionFromIMDS - -func _getSubscriptionFromIMDS() (string, error) { - client := &http.Client{} - - req, _ := http.NewRequest("GET", "http://169.254.169.254/metadata/instance/compute", nil) - req.Header.Add("Metadata", "True") - - q := req.URL.Query() - q.Add("format", "json") - q.Add("api-version", "2017-08-01") - - req.URL.RawQuery = q.Encode() - resp, err := client.Do(req) - if err != nil { - return "", err - } - - defer resp.Body.Close() - resp_body, _ := ioutil.ReadAll(resp.Body) - result := map[string]string{} - err = json.Unmarshal(resp_body, &result) - if err != nil { - return "", err - } - - return result["subscriptionId"], nil -} diff --git a/builder/azure/common/client/config_retriever_test.go b/builder/azure/common/client/config_retriever_test.go deleted file mode 100644 index 6c707e95b..000000000 --- a/builder/azure/common/client/config_retriever_test.go +++ /dev/null @@ -1,56 +0,0 @@ -package client - -import ( - "errors" - "testing" - - "github.com/Azure/go-autorest/autorest/azure" -) - -func TestConfigRetrieverFillsTenantIDWhenEmpty(t *testing.T) { - c := Config{CloudEnvironmentName: "AzurePublicCloud"} - if expected := ""; c.TenantID != expected { - t.Errorf("Expected TenantID to be %q but got %q", expected, c.TenantID) - } - - retrievedTid := "my-tenant-id" - findTenantID = func(azure.Environment, string) (string, error) { return retrievedTid, nil } - getSubscriptionFromIMDS = func() (string, error) { return "unittest", nil } - if err := c.FillParameters(); err != nil { - t.Errorf("Unexpected error when calling c.FillParameters: %v", err) - } - - if expected := retrievedTid; c.TenantID != expected { - t.Errorf("Expected TenantID to be %q but got %q", expected, c.TenantID) - } -} - -func TestConfigRetrieverLeavesTenantIDWhenNotEmpty(t *testing.T) { - c := Config{CloudEnvironmentName: "AzurePublicCloud"} - userSpecifiedTid := "not-empty" - c.TenantID = userSpecifiedTid - - findTenantID = nil // assert that this not even called - getSubscriptionFromIMDS = func() (string, error) { return "unittest", nil } - if err := c.FillParameters(); err != nil { - t.Errorf("Unexpected error when calling c.FillParameters: %v", err) - } - - if expected := userSpecifiedTid; c.TenantID != expected { - t.Errorf("Expected TenantID to be %q but got %q", expected, c.TenantID) - } -} - -func TestConfigRetrieverReturnsErrorWhenTenantIDEmptyAndRetrievalFails(t *testing.T) { - c := Config{CloudEnvironmentName: "AzurePublicCloud"} - if expected := ""; c.TenantID != expected { - t.Errorf("Expected TenantID to be %q but got %q", expected, c.TenantID) - } - - errorString := "sorry, I failed" - findTenantID = func(azure.Environment, string) (string, error) { return "", errors.New(errorString) } - getSubscriptionFromIMDS = func() (string, error) { return "unittest", nil } - if err := c.FillParameters(); err != nil && err.Error() != errorString { - t.Errorf("Unexpected error when calling c.FillParameters: %v", err) - } -} diff --git a/builder/azure/common/client/config_test.go b/builder/azure/common/client/config_test.go deleted file mode 100644 index c2bc05c5b..000000000 --- a/builder/azure/common/client/config_test.go +++ /dev/null @@ -1,444 +0,0 @@ -package client - -import ( - crand "crypto/rand" - "crypto/rsa" - "encoding/base64" - "encoding/binary" - "fmt" - "io" - mrand "math/rand" - "os" - "testing" - "time" - - "github.com/Azure/go-autorest/autorest/azure" - jwt "github.com/dgrijalva/jwt-go" - packersdk "github.com/hashicorp/packer-plugin-sdk/packer" -) - -func Test_ClientConfig_RequiredParametersSet(t *testing.T) { - - tests := []struct { - name string - config Config - wantErr bool - }{ - { - name: "no client_id, client_secret or subscription_id should enable MSI auth", - config: Config{}, - wantErr: false, - }, - { - name: "use_azure_cli_auth will trigger Azure CLI auth", - config: Config{ - UseAzureCLIAuth: true, - }, - wantErr: false, - }, - { - name: "subscription_id is set will trigger device flow", - config: Config{ - SubscriptionID: "error", - }, - wantErr: false, - }, - { - name: "client_id without client_secret, client_cert_path or client_jwt should error", - config: Config{ - ClientID: "error", - }, - wantErr: true, - }, - { - name: "client_secret without client_id should error", - config: Config{ - ClientSecret: "error", - }, - wantErr: true, - }, - { - name: "client_cert_path without client_id should error", - config: Config{ - ClientCertPath: "/dev/null", - }, - wantErr: true, - }, - { - name: "client_jwt without client_id should error", - config: Config{ - ClientJWT: "error", - }, - wantErr: true, - }, - { - name: "missing subscription_id when using secret", - config: Config{ - ClientID: "ok", - ClientSecret: "ok", - }, - wantErr: true, - }, - { - name: "missing subscription_id when using certificate", - config: Config{ - ClientID: "ok", - ClientCertPath: "ok", - }, - wantErr: true, - }, - { - name: "missing subscription_id when using JWT", - config: Config{ - ClientID: "ok", - ClientJWT: "ok", - }, - wantErr: true, - }, - { - name: "client_cert_token_timeout should be 5 minutes or more", - config: Config{ - SubscriptionID: "ok", - ClientID: "ok", - ClientCertPath: "/dev/null", - ClientCertExpireTimeout: 1 * time.Minute, - }, - wantErr: true, - }, - { - name: "too many client_* values", - config: Config{ - SubscriptionID: "ok", - ClientID: "ok", - ClientSecret: "ok", - ClientCertPath: "error", - }, - wantErr: true, - }, - { - name: "too many client_* values (2)", - config: Config{ - SubscriptionID: "ok", - ClientID: "ok", - ClientSecret: "ok", - ClientJWT: "error", - }, - wantErr: true, - }, - { - name: "tenant_id alone should fail", - config: Config{ - TenantID: "ok", - }, - wantErr: true, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - - errs := &packersdk.MultiError{} - tt.config.Validate(errs) - if (len(errs.Errors) != 0) != tt.wantErr { - t.Errorf("newConfig() error = %v, wantErr %v", errs, tt.wantErr) - return - } - }) - } -} - -func Test_ClientConfig_DeviceLogin(t *testing.T) { - getEnvOrSkip(t, "AZURE_DEVICE_LOGIN") - cfg := Config{ - SubscriptionID: getEnvOrSkip(t, "AZURE_SUBSCRIPTION"), - cloudEnvironment: getCloud(), - } - assertValid(t, cfg) - - spt, sptkv, err := cfg.GetServicePrincipalTokens( - func(s string) { fmt.Printf("SAY: %s\n", s) }) - if err != nil { - t.Fatalf("Expected nil err, but got: %v", err) - } - token := spt.Token() - if token.AccessToken == "" { - t.Fatal("Expected management token to have non-nil access token") - } - if token.RefreshToken == "" { - t.Fatal("Expected management token to have non-nil refresh token") - } - kvtoken := sptkv.Token() - if kvtoken.AccessToken == "" { - t.Fatal("Expected keyvault token to have non-nil access token") - } - if kvtoken.RefreshToken == "" { - t.Fatal("Expected keyvault token to have non-nil refresh token") - } -} - -func Test_ClientConfig_AzureCli(t *testing.T) { - // Azure CLI tests skipped unless env 'AZURE_CLI_AUTH' is set, and an active `az login` session has been established - getEnvOrSkip(t, "AZURE_CLI_AUTH") - - cfg := Config{ - UseAzureCLIAuth: true, - cloudEnvironment: getCloud(), - } - assertValid(t, cfg) - - err := cfg.FillParameters() - if err != nil { - t.Fatalf("Expected nil err, but got: %v", err) - } - - if cfg.authType != authTypeAzureCLI { - t.Fatalf("Expected authType to be %q, but got: %q", authTypeAzureCLI, cfg.authType) - } -} - -func Test_ClientConfig_ClientPassword(t *testing.T) { - cfg := Config{ - SubscriptionID: getEnvOrSkip(t, "AZURE_SUBSCRIPTION"), - ClientID: getEnvOrSkip(t, "AZURE_CLIENTID"), - ClientSecret: getEnvOrSkip(t, "AZURE_CLIENTSECRET"), - TenantID: getEnvOrSkip(t, "AZURE_TENANTID"), - cloudEnvironment: getCloud(), - } - assertValid(t, cfg) - - spt, sptkv, err := cfg.GetServicePrincipalTokens(func(s string) { fmt.Printf("SAY: %s\n", s) }) - if err != nil { - t.Fatalf("Expected nil err, but got: %v", err) - } - token := spt.Token() - if token.AccessToken == "" { - t.Fatal("Expected management token to have non-nil access token") - } - if token.RefreshToken != "" { - t.Fatal("Expected management token to have no refresh token") - } - kvtoken := sptkv.Token() - if kvtoken.AccessToken == "" { - t.Fatal("Expected keyvault token to have non-nil access token") - } - if kvtoken.RefreshToken != "" { - t.Fatal("Expected keyvault token to have no refresh token") - } -} - -func Test_ClientConfig_ClientCert(t *testing.T) { - cfg := Config{ - SubscriptionID: getEnvOrSkip(t, "AZURE_SUBSCRIPTION"), - ClientID: getEnvOrSkip(t, "AZURE_CLIENTID"), - ClientCertPath: getEnvOrSkip(t, "AZURE_CLIENTCERT"), - TenantID: getEnvOrSkip(t, "AZURE_TENANTID"), - cloudEnvironment: getCloud(), - } - assertValid(t, cfg) - - spt, sptkv, err := cfg.GetServicePrincipalTokens(func(s string) { fmt.Printf("SAY: %s\n", s) }) - if err != nil { - t.Fatalf("Expected nil err, but got: %v", err) - } - token := spt.Token() - if token.AccessToken == "" { - t.Fatal("Expected management token to have non-nil access token") - } - if token.RefreshToken != "" { - t.Fatal("Expected management token to have no refresh token") - } - kvtoken := sptkv.Token() - if kvtoken.AccessToken == "" { - t.Fatal("Expected keyvault token to have non-nil access token") - } - if kvtoken.RefreshToken != "" { - t.Fatal("Expected keyvault token to have no refresh token") - } -} - -func Test_ClientConfig_ClientJWT(t *testing.T) { - cfg := Config{ - SubscriptionID: getEnvOrSkip(t, "AZURE_SUBSCRIPTION"), - ClientID: getEnvOrSkip(t, "AZURE_CLIENTID"), - ClientJWT: getEnvOrSkip(t, "AZURE_CLIENTJWT"), - TenantID: getEnvOrSkip(t, "AZURE_TENANTID"), - cloudEnvironment: getCloud(), - } - assertValid(t, cfg) - - spt, sptkv, err := cfg.GetServicePrincipalTokens(func(s string) { fmt.Printf("SAY: %s\n", s) }) - if err != nil { - t.Fatalf("Expected nil err, but got: %v", err) - } - token := spt.Token() - if token.AccessToken == "" { - t.Fatal("Expected management token to have non-nil access token") - } - if token.RefreshToken != "" { - t.Fatal("Expected management token to have no refresh token") - } - kvtoken := sptkv.Token() - if kvtoken.AccessToken == "" { - t.Fatal("Expected keyvault token to have non-nil access token") - } - if kvtoken.RefreshToken != "" { - t.Fatal("Expected keyvault token to have no refresh token") - } -} - -func getEnvOrSkip(t *testing.T, envVar string) string { - v := os.Getenv(envVar) - if v == "" { - t.Skipf("%s is empty, skipping", envVar) - } - return v -} - -func getCloud() *azure.Environment { - cloudName := os.Getenv("AZURE_CLOUD") - if cloudName == "" { - cloudName = "AZUREPUBLICCLOUD" - } - c, _ := azure.EnvironmentFromName(cloudName) - return &c -} - -// tests for assertRequiredParametersSet - -func Test_ClientConfig_CanUseDeviceCode(t *testing.T) { - // TenantID is optional, but Builder will look up tenant ID before requesting - t.Run("without TenantID", func(t *testing.T) { - cfg := Config{ - SubscriptionID: "12345", - } - assertValid(t, cfg) - }) - t.Run("with TenantID", func(t *testing.T) { - cfg := Config{ - SubscriptionID: "12345", - TenantID: "12345", - } - assertValid(t, cfg) - }) -} - -func assertValid(t *testing.T, cfg Config) { - errs := &packersdk.MultiError{} - cfg.Validate(errs) - if len(errs.Errors) != 0 { - t.Fatal("Expected errs to be empty: ", errs) - } -} - -func assertInvalid(t *testing.T, cfg Config) { - errs := &packersdk.MultiError{} - cfg.Validate(errs) - if len(errs.Errors) == 0 { - t.Fatal("Expected errs to be non-empty") - } -} - -func Test_ClientConfig_CanUseClientSecret(t *testing.T) { - cfg := Config{ - SubscriptionID: "12345", - ClientID: "12345", - ClientSecret: "12345", - } - - assertValid(t, cfg) -} - -func Test_ClientConfig_CanUseClientSecretWithTenantID(t *testing.T) { - cfg := Config{ - SubscriptionID: "12345", - ClientID: "12345", - ClientSecret: "12345", - TenantID: "12345", - } - - assertValid(t, cfg) -} - -func Test_ClientConfig_CanUseClientJWT(t *testing.T) { - cfg := Config{ - SubscriptionID: "12345", - ClientID: "12345", - ClientJWT: getJWT(10*time.Minute, true), - } - - assertValid(t, cfg) -} - -func Test_ClientConfig_CanUseClientJWTWithTenantID(t *testing.T) { - cfg := Config{ - SubscriptionID: "12345", - ClientID: "12345", - ClientJWT: getJWT(10*time.Minute, true), - TenantID: "12345", - } - - assertValid(t, cfg) -} - -func Test_ClientConfig_CannotUseBothClientJWTAndSecret(t *testing.T) { - cfg := Config{ - SubscriptionID: "12345", - ClientID: "12345", - ClientSecret: "12345", - ClientJWT: getJWT(10*time.Minute, true), - } - - assertInvalid(t, cfg) -} - -func Test_ClientConfig_ClientJWTShouldBeValidForAtLeast5Minutes(t *testing.T) { - cfg := Config{ - SubscriptionID: "12345", - ClientID: "12345", - ClientJWT: getJWT(time.Minute, true), - } - - assertInvalid(t, cfg) -} - -func Test_ClientConfig_ClientJWTShouldHaveThumbprint(t *testing.T) { - cfg := Config{ - SubscriptionID: "12345", - ClientID: "12345", - ClientJWT: getJWT(10*time.Minute, false), - } - - assertInvalid(t, cfg) -} - -func Test_getJWT(t *testing.T) { - if getJWT(time.Minute, true) == "" { - t.Fatalf("getJWT is broken") - } -} - -func newRandReader() io.Reader { - var seed int64 - binary.Read(crand.Reader, binary.LittleEndian, &seed) - - return mrand.New(mrand.NewSource(seed)) -} - -func getJWT(validFor time.Duration, withX5tHeader bool) string { - token := jwt.New(jwt.SigningMethodRS256) - key, _ := rsa.GenerateKey(newRandReader(), 2048) - - token.Claims = jwt.MapClaims{ - "aud": "https://login.microsoftonline.com/tenant.onmicrosoft.com/oauth2/token?api-version=1.0", - "iss": "355dff10-cd78-11e8-89fe-000d3afd16e3", - "sub": "355dff10-cd78-11e8-89fe-000d3afd16e3", - "jti": base64.URLEncoding.EncodeToString([]byte{0}), - "nbf": time.Now().Unix(), - "exp": time.Now().Add(validFor).Unix(), - } - if withX5tHeader { - token.Header["x5t"] = base64.URLEncoding.EncodeToString([]byte("thumbprint")) - } - - jwt, _ := token.SignedString(key) - return jwt -} diff --git a/builder/azure/common/client/detect_azure.go b/builder/azure/common/client/detect_azure.go deleted file mode 100644 index fef7a2932..000000000 --- a/builder/azure/common/client/detect_azure.go +++ /dev/null @@ -1,8 +0,0 @@ -// +build !linux - -package client - -// IsAzure returns true if Packer is running on Azure (currently only works on Linux) -func IsAzure() bool { - return false -} diff --git a/builder/azure/common/client/detect_azure_linux.go b/builder/azure/common/client/detect_azure_linux.go deleted file mode 100644 index c2b9a2800..000000000 --- a/builder/azure/common/client/detect_azure_linux.go +++ /dev/null @@ -1,23 +0,0 @@ -package client - -import ( - "bytes" - "io/ioutil" -) - -var ( - smbiosAssetTagFile = "/sys/class/dmi/id/chassis_asset_tag" - azureAssetTag = []byte("7783-7084-3265-9085-8269-3286-77\n") -) - -// IsAzure returns true if Packer is running on Azure -func IsAzure() bool { - return isAzureAssetTag(smbiosAssetTagFile) -} - -func isAzureAssetTag(filename string) bool { - if d, err := ioutil.ReadFile(filename); err == nil { - return bytes.Compare(d, azureAssetTag) == 0 - } - return false -} diff --git a/builder/azure/common/client/detect_azure_linux_test.go b/builder/azure/common/client/detect_azure_linux_test.go deleted file mode 100644 index 5975d7a6b..000000000 --- a/builder/azure/common/client/detect_azure_linux_test.go +++ /dev/null @@ -1,29 +0,0 @@ -package client - -import ( - "io/ioutil" - "os" - "testing" - - "github.com/stretchr/testify/assert" -) - -func TestIsAzure(t *testing.T) { - f, err := ioutil.TempFile("", "TestIsAzure*") - if err != nil { - t.Fatal(err) - } - defer os.Remove(f.Name()) - - f.Seek(0, 0) - f.Truncate(0) - f.Write([]byte("not the azure assettag")) - - assert.False(t, isAzureAssetTag(f.Name()), "asset tag is not Azure's") - - f.Seek(0, 0) - f.Truncate(0) - f.Write(azureAssetTag) - - assert.True(t, isAzureAssetTag(f.Name()), "asset tag is Azure's") -} diff --git a/builder/azure/common/client/devicelogin.go b/builder/azure/common/client/devicelogin.go deleted file mode 100644 index 0833b5587..000000000 --- a/builder/azure/common/client/devicelogin.go +++ /dev/null @@ -1,208 +0,0 @@ -package client - -import ( - "context" - "fmt" - "net/http" - "os" - "os/user" - "path/filepath" - "regexp" - "strings" - - "github.com/Azure/azure-sdk-for-go/services/resources/mgmt/2016-06-01/subscriptions" - "github.com/Azure/go-autorest/autorest" - "github.com/Azure/go-autorest/autorest/adal" - "github.com/Azure/go-autorest/autorest/azure" - "github.com/Azure/go-autorest/autorest/to" - "github.com/hashicorp/packer-plugin-sdk/useragent" - version "github.com/hashicorp/packer/builder/azure/version" -) - -var ( - // AD app id for packer-azure driver. - clientIDs = map[string]string{ - azure.PublicCloud.Name: "04cc58ec-51ab-4833-ac0d-ce3a7912414b", - azure.USGovernmentCloud.Name: "a1479822-da77-46a7-abd0-6edacc8a8fac", - } -) - -// NOTE(ahmetalpbalkan): Azure Active Directory implements OAuth 2.0 Device Flow -// described here: https://tools.ietf.org/html/draft-denniss-oauth-device-flow-00 -// Although it has some gotchas, most of the authentication logic is in Azure SDK -// for Go helper packages. -// -// Device auth prints a message to the screen telling the user to click on URL -// and approve the app on the browser, meanwhile the client polls the auth API -// for a token. Once we have token, we save it locally to a file with proper -// permissions and when the token expires (in Azure case typically 1 hour) SDK -// will automatically refresh the specified token and will call the refresh -// callback function we implement here. This way we will always be storing a -// token with a refresh_token saved on the machine. - -// Authenticate fetches a token from the local file cache or initiates a consent -// flow and waits for token to be obtained. -func Authenticate(env azure.Environment, tenantID string, say func(string), scope string) (*adal.ServicePrincipalToken, error) { - clientID, ok := clientIDs[env.Name] - var resourceid string - - if !ok { - return nil, fmt.Errorf("packer-azure application not set up for Azure environment %q", env.Name) - } - - oauthCfg, err := adal.NewOAuthConfig(env.ActiveDirectoryEndpoint, tenantID) - if err != nil { - return nil, fmt.Errorf("Failed to obtain oauth config for azure environment: %v", err) - } - - // for AzurePublicCloud (https://management.core.windows.net/), this old - // Service Management scope covers both ASM and ARM. - - if strings.Contains(scope, "vault") { - resourceid = "vault" - } else { - resourceid = "mgmt" - } - - tokenPath := tokenCachePath(tenantID + resourceid) - saveToken := mkTokenCallback(tokenPath) - saveTokenCallback := func(t adal.Token) error { - say("Azure token expired. Saving the refreshed token...") - return saveToken(t) - } - - // Lookup the token cache file for an existing token. - spt, err := tokenFromFile(say, *oauthCfg, tokenPath, clientID, scope, saveTokenCallback) - if err != nil { - return nil, err - } - if spt != nil { - say(fmt.Sprintf("Auth token found in file: %s", tokenPath)) - return spt, nil - } - - // Start an OAuth 2.0 device flow - say(fmt.Sprintf("Initiating device flow: %s", tokenPath)) - spt, err = tokenFromDeviceFlow(say, *oauthCfg, clientID, scope) - if err != nil { - return nil, err - } - say("Obtained service principal token.") - if err := saveToken(spt.Token()); err != nil { - say("Error occurred saving token to cache file.") - return nil, err - } - return spt, nil -} - -// tokenFromFile returns a token from the specified file if it is found, otherwise -// returns nil. Any error retrieving or creating the token is returned as an error. -func tokenFromFile(say func(string), oauthCfg adal.OAuthConfig, tokenPath, clientID, resource string, - callback adal.TokenRefreshCallback) (*adal.ServicePrincipalToken, error) { - say(fmt.Sprintf("Loading auth token from file: %s", tokenPath)) - if _, err := os.Stat(tokenPath); err != nil { - if os.IsNotExist(err) { // file not found - return nil, nil - } - return nil, err - } - - token, err := adal.LoadToken(tokenPath) - if err != nil { - return nil, fmt.Errorf("Failed to load token from file: %v", err) - } - - spt, err := adal.NewServicePrincipalTokenFromManualToken(oauthCfg, clientID, resource, *token, callback) - if err != nil { - return nil, fmt.Errorf("Error constructing service principal token: %v", err) - } - return spt, nil -} - -// tokenFromDeviceFlow prints a message to the screen for user to take action to -// consent application on a browser and in the meanwhile the authentication -// endpoint is polled until user gives consent, denies or the flow times out. -// Returned token must be saved. -func tokenFromDeviceFlow(say func(string), oauthCfg adal.OAuthConfig, clientID, resource string) (*adal.ServicePrincipalToken, error) { - cl := autorest.NewClientWithUserAgent(useragent.String(version.AzurePluginVersion.FormattedVersion())) - deviceCode, err := adal.InitiateDeviceAuth(&cl, oauthCfg, clientID, resource) - if err != nil { - return nil, fmt.Errorf("Failed to start device auth: %v", err) - } - - // Example message: “To sign in, open https://aka.ms/devicelogin and enter - // the code 0000000 to authenticate.” - say(fmt.Sprintf("Microsoft Azure: %s", to.String(deviceCode.Message))) - - token, err := adal.WaitForUserCompletion(&cl, deviceCode) - if err != nil { - return nil, fmt.Errorf("Failed to complete device auth: %v", err) - } - - spt, err := adal.NewServicePrincipalTokenFromManualToken(oauthCfg, clientID, resource, *token) - if err != nil { - return nil, fmt.Errorf("Error constructing service principal token: %v", err) - } - return spt, nil -} - -// tokenCachePath returns the full path the OAuth 2.0 token should be saved at -// for given tenant ID. -func tokenCachePath(tenantID string) string { - var dir string - - u, err := user.Current() - if err != nil || u.HomeDir == "" { - dir, _ = filepath.Abs(os.Args[0]) - } else { - dir = u.HomeDir - } - - return filepath.Join(dir, ".azure", "packer", fmt.Sprintf("oauth-%s.json", tenantID)) -} - -// mkTokenCallback returns a callback function that can be used to save the -// token initially or register to the Azure SDK to be called when the token is -// refreshed. -func mkTokenCallback(path string) adal.TokenRefreshCallback { - return func(t adal.Token) error { - if err := adal.SaveToken(path, 0600, t); err != nil { - return err - } - return nil - } -} - -// FindTenantID figures out the AAD tenant ID of the subscription by making an -// unauthenticated request to the Get Subscription Details endpoint and parses -// the value from WWW-Authenticate header. -func FindTenantID(env azure.Environment, subscriptionID string) (string, error) { - const hdrKey = "WWW-Authenticate" - c := subscriptions.NewClientWithBaseURI(env.ResourceManagerEndpoint) - - // we expect this request to fail (err != nil), but we are only interested - // in headers, so surface the error if the Response is not present (i.e. - // network error etc) - subs, err := c.Get(context.TODO(), subscriptionID) - if subs.Response.Response == nil { - return "", fmt.Errorf("Request failed: %v", err) - } - - // Expecting 401 StatusUnauthorized here, just read the header - if subs.StatusCode != http.StatusUnauthorized { - return "", fmt.Errorf("Unexpected response from Get Subscription: %v", err) - } - hdr := subs.Header.Get(hdrKey) - if hdr == "" { - return "", fmt.Errorf("Header %v not found in Get Subscription response", hdrKey) - } - - // Example value for hdr: - // Bearer authorization_uri="https://login.windows.net/996fe9d1-6171-40aa-945b-4c64b63bf655", error="invalid_token", error_description="The authentication failed because of missing 'Authorization' header." - r := regexp.MustCompile(`authorization_uri=".*/([0-9a-f\-]+)"`) - m := r.FindStringSubmatch(hdr) - if m == nil { - return "", fmt.Errorf("Could not find the tenant ID in header: %s %q", hdrKey, hdr) - } - return m[1], nil -} diff --git a/builder/azure/common/client/metadata.go b/builder/azure/common/client/metadata.go deleted file mode 100644 index da8bbef45..000000000 --- a/builder/azure/common/client/metadata.go +++ /dev/null @@ -1,94 +0,0 @@ -package client - -import ( - "fmt" - "net/http" - "time" - - "github.com/Azure/go-autorest/autorest" - "github.com/Azure/go-autorest/autorest/azure" -) - -// DefaultMetadataClient is the default instance metadata client for Azure. Replace this variable for testing purposes only -var DefaultMetadataClient = NewMetadataClient() - -// MetadataClientAPI holds methods that Packer uses to get information about the current VM -type MetadataClientAPI interface { - GetComputeInfo() (*ComputeInfo, error) -} - -// MetadataClientStub is an easy way to put a test hook in DefaultMetadataClient -type MetadataClientStub struct { - ComputeInfo -} - -//GetComputeInfo implements MetadataClientAPI -func (s MetadataClientStub) GetComputeInfo() (*ComputeInfo, error) { - return &s.ComputeInfo, nil -} - -// ComputeInfo defines the Azure VM metadata that is used in Packer -type ComputeInfo struct { - Name string - ResourceGroupName string - SubscriptionID string - Location string -} - -// metadataClient implements MetadataClient -type metadataClient struct { - autorest.Sender - UserAgent string -} - -var _ MetadataClientAPI = metadataClient{} - -const imdsURL = "http://169.254.169.254/metadata/instance?api-version=2017-08-01" - -// VMResourceID returns the resource ID of the current VM -func (client metadataClient) GetComputeInfo() (*ComputeInfo, error) { - req, err := autorest.CreatePreparer( - autorest.AsGet(), - autorest.WithHeader("Metadata", "true"), - autorest.WithUserAgent(client.UserAgent), - autorest.WithBaseURL(imdsURL), - ).Prepare((&http.Request{})) - if err != nil { - return nil, err - } - - res, err := autorest.SendWithSender(client, req, - autorest.DoRetryForDuration(1*time.Minute, 5*time.Second)) - if err != nil { - return nil, err - } - - var vminfo struct { - ComputeInfo `json:"compute"` - } - - err = autorest.Respond( - res, - azure.WithErrorUnlessStatusCode(http.StatusOK), - autorest.ByUnmarshallingJSON(&vminfo), - autorest.ByClosing()) - if err != nil { - return nil, err - } - return &vminfo.ComputeInfo, nil -} - -func (ci ComputeInfo) ResourceID() string { - return fmt.Sprintf("/subscriptions/%s/resourceGroups/%s/providers/Microsoft.Compute/virtualMachines/%s", - ci.SubscriptionID, - ci.ResourceGroupName, - ci.Name, - ) -} - -// NewMetadataClient creates a new instance metadata client -func NewMetadataClient() MetadataClientAPI { - return metadataClient{ - Sender: autorest.CreateSender(), - } -} diff --git a/builder/azure/common/client/metadata_test.go b/builder/azure/common/client/metadata_test.go deleted file mode 100644 index 75353d141..000000000 --- a/builder/azure/common/client/metadata_test.go +++ /dev/null @@ -1,32 +0,0 @@ -package client - -import ( - "fmt" - "testing" - - "github.com/Azure/go-autorest/autorest/azure" - - "github.com/stretchr/testify/assert" -) - -func Test_MetadataReturnsComputeInfo(t *testing.T) { - if !IsAzure() { - t.Skipf("Not running on Azure, skipping live IMDS test") - } - mdc := NewMetadataClient() - info, err := mdc.GetComputeInfo() - assert.Nil(t, err) - - vm, err := azure.ParseResourceID(fmt.Sprintf( - "/subscriptions/%s"+ - "/resourceGroups/%s"+ - "/providers/Microsoft.Compute"+ - "/virtualMachines/%s", - info.SubscriptionID, - info.ResourceGroupName, - info.Name)) - assert.Nil(t, err, "%q is not parsable as an Azure resource info", info) - - assert.Regexp(t, "^[0-9a-fA-F-]{36}$", vm.SubscriptionID) - t.Logf("VM: %+v", vm) -} diff --git a/builder/azure/common/client/normalize_location.go b/builder/azure/common/client/normalize_location.go deleted file mode 100644 index 6a82d73f1..000000000 --- a/builder/azure/common/client/normalize_location.go +++ /dev/null @@ -1,9 +0,0 @@ -package client - -import "strings" - -// NormalizeLocation returns a normalized location string. -// Strings are converted to lower case and spaces are removed. -func NormalizeLocation(loc string) string { - return strings.ReplaceAll(strings.ToLower(loc), " ", "") -} diff --git a/builder/azure/common/client/normalize_location_test.go b/builder/azure/common/client/normalize_location_test.go deleted file mode 100644 index adec5aa04..000000000 --- a/builder/azure/common/client/normalize_location_test.go +++ /dev/null @@ -1,22 +0,0 @@ -package client - -import "testing" - -func TestNormalizeLocation(t *testing.T) { - tests := []struct { - name string - loc string - want string - }{ - {"removes spaces", " with spaces ", "withspaces"}, - {"makes lowercase", "MiXed Case", "mixedcase"}, - {"North East US", "North East US", "northeastus"}, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - if got := NormalizeLocation(tt.loc); got != tt.want { - t.Errorf("NormalizeLocation() = %v, want %v", got, tt.want) - } - }) - } -} diff --git a/builder/azure/common/client/platform_image.go b/builder/azure/common/client/platform_image.go deleted file mode 100644 index d2e798def..000000000 --- a/builder/azure/common/client/platform_image.go +++ /dev/null @@ -1,58 +0,0 @@ -package client - -import ( - "context" - "fmt" - "regexp" - "strings" - - "github.com/Azure/azure-sdk-for-go/services/compute/mgmt/2019-12-01/compute" - "github.com/Azure/azure-sdk-for-go/services/compute/mgmt/2019-12-01/compute/computeapi" - "github.com/Azure/go-autorest/autorest/to" -) - -var platformImageRegex = regexp.MustCompile(`^[-_.a-zA-Z0-9]+:[-_.a-zA-Z0-9]+:[-_.a-zA-Z0-9]+:[-_.a-zA-Z0-9]+$`) - -type VirtualMachineImagesClientAPI interface { - computeapi.VirtualMachineImagesClientAPI - // extensions - GetLatest(ctx context.Context, publisher, offer, sku, location string) (*compute.VirtualMachineImageResource, error) -} - -var _ VirtualMachineImagesClientAPI = VirtualMachineImagesClient{} - -type VirtualMachineImagesClient struct { - computeapi.VirtualMachineImagesClientAPI -} - -func ParsePlatformImageURN(urn string) (image *PlatformImage, err error) { - if !platformImageRegex.Match([]byte(urn)) { - return nil, fmt.Errorf("%q is not a valid platform image specifier", urn) - } - parts := strings.Split(urn, ":") - return &PlatformImage{parts[0], parts[1], parts[2], parts[3]}, nil -} - -func (c VirtualMachineImagesClient) GetLatest(ctx context.Context, publisher, offer, sku, location string) (*compute.VirtualMachineImageResource, error) { - result, err := c.List(ctx, location, publisher, offer, sku, "", to.Int32Ptr(1), "name desc") - if err != nil { - return nil, err - } - if result.Value == nil || len(*result.Value) == 0 { - return nil, fmt.Errorf("%s:%s:%s:latest could not be found in location %s", publisher, offer, sku, location) - } - - return &(*result.Value)[0], nil -} - -type PlatformImage struct { - Publisher, Offer, Sku, Version string -} - -func (pi PlatformImage) URN() string { - return fmt.Sprintf("%s:%s:%s:%s", - pi.Publisher, - pi.Offer, - pi.Sku, - pi.Version) -} diff --git a/builder/azure/common/client/platform_image_test.go b/builder/azure/common/client/platform_image_test.go deleted file mode 100644 index 981031d45..000000000 --- a/builder/azure/common/client/platform_image_test.go +++ /dev/null @@ -1,30 +0,0 @@ -package client - -import ( - "fmt" - "testing" -) - -func Test_platformImageRegex(t *testing.T) { - for i, v := range []string{ - "Publisher:Offer:Sku:Versions", - "Publisher:Offer-name:2.0_alpha:2.0.2019060122", - } { - t.Run(fmt.Sprintf("should_match_%d", i), func(t *testing.T) { - if !platformImageRegex.Match([]byte(v)) { - t.Fatalf("expected %q to match", v) - } - }) - } - - for i, v := range []string{ - "Publ isher:Offer:Sku:Versions", - "Publ/isher:Offer-name:2.0_alpha:2.0.2019060122", - } { - t.Run(fmt.Sprintf("should_not_match_%d", i), func(t *testing.T) { - if platformImageRegex.Match([]byte(v)) { - t.Fatalf("did not expected %q to match", v) - } - }) - } -} diff --git a/builder/azure/common/client/resource.go b/builder/azure/common/client/resource.go deleted file mode 100644 index db1163fa4..000000000 --- a/builder/azure/common/client/resource.go +++ /dev/null @@ -1,125 +0,0 @@ -package client - -import ( - "errors" - "fmt" - "strings" -) - -// ParseResourceID parses an Azure resource ID -func ParseResourceID(resourceID string) (Resource, error) { - resourceID = strings.Trim(resourceID, "/") - segments := strings.Split(resourceID, "/") - if len(segments)%2 != 0 { - return Resource{}, errors.New("Expected even number of segments") - } - - npairs := len(segments) / 2 - - keys := make([]string, npairs) - values := make([]string, npairs) - for i := 0; i < len(segments); i += 2 { - keys[i/2] = segments[i] - values[i/2] = segments[i+1] - - if keys[i/2] == "" { - return Resource{}, fmt.Errorf("Found empty segment (%d)", i) - } - if values[i/2] == "" { - return Resource{}, fmt.Errorf("Found empty segment (%d)", i+1) - } - } - - if !strings.EqualFold(keys[0], "subscriptions") { - return Resource{}, fmt.Errorf("Expected first segment to be 'subscriptions', but found %q", keys[0]) - } - - if !strings.EqualFold(keys[1], "resourceGroups") { - return Resource{}, fmt.Errorf("Expected second segment to be 'resourceGroups', but found %q", keys[1]) - } - - if !strings.EqualFold(keys[2], "providers") { - return Resource{}, fmt.Errorf("Expected third segment to be 'providers', but found %q", keys[1]) - } - - r := Resource{ - values[0], - values[1], - values[2], - CompoundName(keys[3:]), - CompoundName(values[3:]), - } - if err := r.Validate(); err != nil { - return Resource{}, fmt.Errorf("Error validating resource: %w", err) - } - - return r, nil -} - -type Resource struct { - Subscription string - ResourceGroup string - Provider string - ResourceType CompoundName - ResourceName CompoundName -} - -func (r Resource) String() string { - return fmt.Sprintf( - "/subscriptions/%s"+ - "/resourceGroups/%s"+ - "/providers/%s"+ - "/%s", - r.Subscription, - r.ResourceGroup, - r.Provider, - strings.Join(zipstrings(r.ResourceType, r.ResourceName), "/")) -} - -func (r Resource) Validate() error { - if r.Subscription == "" { - return errors.New("subscription is not set") - } - if r.ResourceGroup == "" { - return errors.New("resource group is not set") - } - if r.Provider == "" { - return errors.New("provider is not set") - } - if len(r.ResourceType) > len(r.ResourceName) { - return errors.New("not enough values in resource name") - } - if len(r.ResourceType) < len(r.ResourceName) { - return errors.New("too many values in resource name") - } - return nil -} - -// Parent produces a resource ID representing the parent resource if this is a child resource -func (r Resource) Parent() (Resource, error) { - newLen := len(r.ResourceType) - 1 - if newLen == 0 { - return Resource{}, errors.New("Top-level resource has no parent") - } - return Resource{ - Subscription: r.Subscription, - ResourceGroup: r.ResourceGroup, - Provider: r.Provider, - ResourceType: r.ResourceType[:newLen], - ResourceName: r.ResourceName[:newLen], - }, nil -} - -type CompoundName []string - -func (n CompoundName) String() string { - return strings.Join(n, "/") -} - -func zipstrings(a []string, b []string) []string { - c := make([]string, 0, len(a)+len(b)) - for i := 0; i < len(a) && i < len(b); i++ { - c = append(c, a[i], b[i]) - } - return c -} diff --git a/builder/azure/common/client/resource_test.go b/builder/azure/common/client/resource_test.go deleted file mode 100644 index 10084ef15..000000000 --- a/builder/azure/common/client/resource_test.go +++ /dev/null @@ -1,188 +0,0 @@ -package client - -import ( - "reflect" - "testing" -) - -func TestParseResourceID(t *testing.T) { - tests := []struct { - name string - resourceID string - want Resource - wantErr bool - }{ - { - name: "happy path", - resourceID: "/subscriptions/17c60680-0e49-465b-aa54-ece043ce5571/resourceGroups/rg/providers/Microsoft.Resources/resources/resource", - want: Resource{ - Subscription: "17c60680-0e49-465b-aa54-ece043ce5571", - ResourceGroup: "rg", - Provider: "Microsoft.Resources", - ResourceType: CompoundName{"resources"}, - ResourceName: CompoundName{"resource"}, - }, - }, - { - name: "sub resource", - resourceID: "/subscriptions/17c60680-0e49-465b-aa54-ece043ce5571/resourcegroups/rg/providers/Microsoft.Resources/resources/resource/subResources/child", - want: Resource{ - Subscription: "17c60680-0e49-465b-aa54-ece043ce5571", - ResourceGroup: "rg", - Provider: "Microsoft.Resources", - ResourceType: CompoundName{"resources", "subResources"}, - ResourceName: CompoundName{"resource", "child"}, - }, - }, - { - name: "incomplete", - resourceID: "/subscriptions/17c60680-0e49-465b-aa54-ece043ce5571/resourceGroups/rg/providers/Microsoft.Resources/resources/resource/subResources", - wantErr: true, - }, - { - name: "incomplete 2", - resourceID: "/subscriptions/17c60680-0e49-465b-aa54-ece043ce5571/resourceGroups/rg/providers/Microsoft.Resources/resources/", - wantErr: true, - }, - { - name: "extra slash", - resourceID: "/subscriptions/17c60680-0e49-465b-aa54-ece043ce5571/resourceGroups/rg/providers/Microsoft.Resources/resources//resources", - wantErr: true, - }, - { - name: "empty resource name", - resourceID: "/subscriptions/17c60680-0e49-465b-aa54-ece043ce5571/resourceGroups/rg/providers/Microsoft.Resources/resources//subresources/child", - wantErr: true, - }, - { - name: "empty sub resource type", - resourceID: "/subscriptions/17c60680-0e49-465b-aa54-ece043ce5571/resourceGroups/rg/providers/Microsoft.Resources/resources/resource//child", - wantErr: true, - }, - { - name: "ungrouped resource path", - resourceID: "/subscriptions/17c60680-0e49-465b-aa54-ece043ce5571/providers/Microsoft.Resources/resources/resource", - wantErr: true, - }, - { - name: "misspelled subscriptions", - resourceID: "/subscription/17c60680-0e49-465b-aa54-ece043ce5571/resourceGroups/rg/providers/Microsoft.Resources/resources/resource/subResources/child", - wantErr: true, - }, - { - name: "misspelled resourceGroups", - resourceID: "/subscriptions/17c60680-0e49-465b-aa54-ece043ce5571/resourceGroup/rg/providers/Microsoft.Resources/resources/resource/subResources/child", - wantErr: true, - }, - { - name: "misspelled providers", - resourceID: "/subscriptions/17c60680-0e49-465b-aa54-ece043ce5571/resourceGroups/rg/provider/Microsoft.Resources/resources/resource/subResources/child", - wantErr: true, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - got, err := ParseResourceID(tt.resourceID) - if (err != nil) != tt.wantErr { - t.Errorf("ParseResourceID() error = %v, wantErr %v", err, tt.wantErr) - return - } - if !reflect.DeepEqual(got, tt.want) { - t.Errorf("ParseResourceID() = %v, want %v", got, tt.want) - } - }) - } -} - -func TestResource_String(t *testing.T) { - type fields struct { - Subscription string - ResourceGroup string - Provider string - ResourceType CompoundName - ResourceName CompoundName - } - tests := []struct { - name string - fields fields - want string - }{ - { - name: "happy path", - fields: fields{ - Subscription: "sub", - ResourceGroup: "rg", - Provider: "provider", - ResourceType: CompoundName{"type"}, - ResourceName: CompoundName{"name"}, - }, - want: "/subscriptions/sub/resourceGroups/rg/providers/provider/type/name", - }, - { - name: "happy path - child resource", - fields: fields{ - Subscription: "sub", - ResourceGroup: "rg", - Provider: "provider", - ResourceType: CompoundName{"type", "sub"}, - ResourceName: CompoundName{"name", "child"}, - }, - want: "/subscriptions/sub/resourceGroups/rg/providers/provider/type/name/sub/child", - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - r := Resource{ - Subscription: tt.fields.Subscription, - ResourceGroup: tt.fields.ResourceGroup, - Provider: tt.fields.Provider, - ResourceType: tt.fields.ResourceType, - ResourceName: tt.fields.ResourceName, - } - if got := r.String(); got != tt.want { - t.Errorf("Resource.String() = %v, want %v", got, tt.want) - } - }) - } -} - -func TestResource_Parent(t *testing.T) { - tests := []struct { - name string - resourceID string - want string - wantErr bool - }{ - { - name: "happy path", - resourceID: "/subscriptions/17c60680-0e49-465b-aa54-ece043ce5571/resourceGroups/rg/providers/Microsoft.Resources/resources/resource/sub/child", - want: "/subscriptions/17c60680-0e49-465b-aa54-ece043ce5571/resourceGroups/rg/providers/Microsoft.Resources/resources/resource", - }, - { - name: "sub sub", - resourceID: "/subscriptions/17c60680-0e49-465b-aa54-ece043ce5571/resourceGroups/rg/providers/Microsoft.Resources/resources/resource/sub/child/subsub/grandchild", - want: "/subscriptions/17c60680-0e49-465b-aa54-ece043ce5571/resourceGroups/rg/providers/Microsoft.Resources/resources/resource/sub/child", - }, - { - name: "top level resource", - resourceID: "/subscriptions/17c60680-0e49-465b-aa54-ece043ce5571/resourceGroups/rg/providers/Microsoft.Resources/resources/resource", - wantErr: true, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - r, err := ParseResourceID(tt.resourceID) - if err != nil { - t.Fatalf("Error parsing test resource: %v", err) - } - got, err := r.Parent() - if (err != nil) != tt.wantErr { - t.Errorf("Resource.Parent() error = %v, wantErr %v", err, tt.wantErr) - return - } - if err == nil && got.String() != tt.want { - t.Errorf("Resource.Parent() = %v, want %v", got, tt.want) - } - }) - } -} diff --git a/builder/azure/common/client/testclient.go b/builder/azure/common/client/testclient.go deleted file mode 100644 index afb2156dc..000000000 --- a/builder/azure/common/client/testclient.go +++ /dev/null @@ -1,30 +0,0 @@ -package client - -import ( - "errors" - "net/http" - "os" - "testing" - - "github.com/Azure/go-autorest/autorest/azure/auth" -) - -func GetTestClientSet(t *testing.T) (AzureClientSet, error) { - if os.Getenv("AZURE_INTEGRATION_TEST") == "" { - t.Skip("AZURE_INTEGRATION_TEST not set") - } else { - a, err := auth.NewAuthorizerFromEnvironment() - if err == nil { - cli := azureClientSet{} - cli.authorizer = a - cli.subscriptionID = os.Getenv("AZURE_SUBSCRIPTION_ID") - cli.PollingDelay = 0 - cli.sender = http.DefaultClient - return cli, nil - } else { - t.Skipf("Could not create Azure client: %v", err) - } - } - - return nil, errors.New("Couldn't create client set") -} diff --git a/builder/azure/common/client/tokenprovider.go b/builder/azure/common/client/tokenprovider.go deleted file mode 100644 index 86cd80a9c..000000000 --- a/builder/azure/common/client/tokenprovider.go +++ /dev/null @@ -1,10 +0,0 @@ -package client - -import ( - "github.com/Azure/go-autorest/autorest/adal" -) - -type oAuthTokenProvider interface { - getServicePrincipalToken() (*adal.ServicePrincipalToken, error) - getServicePrincipalTokenWithResource(resource string) (*adal.ServicePrincipalToken, error) -} diff --git a/builder/azure/common/client/tokenprovider_cert.go b/builder/azure/common/client/tokenprovider_cert.go deleted file mode 100644 index 64decad46..000000000 --- a/builder/azure/common/client/tokenprovider_cert.go +++ /dev/null @@ -1,165 +0,0 @@ -package client - -import ( - "crypto/ecdsa" - "crypto/rand" - "crypto/rsa" - "crypto/sha1" - "crypto/x509" - "encoding/base64" - "encoding/pem" - "fmt" - "io/ioutil" - "os" - "time" - - "github.com/Azure/go-autorest/autorest/azure" - "github.com/dgrijalva/jwt-go" - "github.com/hashicorp/packer/builder/azure/pkcs12" -) - -func NewCertOAuthTokenProvider(env azure.Environment, clientID, clientCertPath, tenantID string, certExpireTimeout time.Duration) (oAuthTokenProvider, error) { - cert, key, err := readCert(clientCertPath) - if err != nil { - return nil, fmt.Errorf("Error reading certificate: %v", err) - } - - audience := fmt.Sprintf("%s%s/oauth2/token", env.ActiveDirectoryEndpoint, tenantID) - jwt, err := makeJWT(clientID, audience, cert, key, certExpireTimeout, true) - if err != nil { - return nil, fmt.Errorf("Error generating JWT: %v", err) - } - - return NewJWTOAuthTokenProvider(env, clientID, jwt, tenantID), nil -} - -// Creates a new JSON Web Token to be used as bearer JWT to authenticate -// to the Azure AD token endpoint to retrieve an access token for `audience`. -// If the full certificate is included in the token, then issuer/subject name -// could be used to authenticate if configured by the identity provider (AAD). -func makeJWT(clientID string, audience string, - cert *x509.Certificate, privatekey interface{}, - validFor time.Duration, includeFullCertificate bool) (string, error) { - - // The jti (JWT ID) claim provides a unique identifier for the JWT. - // See https://tools.ietf.org/html/rfc7519#section-4.1.7 - jti := make([]byte, 20) - _, err := rand.Read(jti) - if err != nil { - return "", err - } - - var token *jwt.Token - if cert.PublicKeyAlgorithm == x509.RSA { - token = jwt.New(jwt.SigningMethodRS256) - } else if cert.PublicKeyAlgorithm == x509.ECDSA { - token = jwt.New(jwt.SigningMethodES256) - } else { - return "", fmt.Errorf("Don't know how to handle this type of key algorithm: %v", cert.PublicKeyAlgorithm) - } - - hasher := sha1.New() - if _, err := hasher.Write(cert.Raw); err != nil { - return "", err - } - thumbprint := base64.URLEncoding.EncodeToString(hasher.Sum(nil)) - - // X.509 thumbprint, see https://tools.ietf.org/html/rfc7515#section-4.1.7 - token.Header["x5t"] = thumbprint - if includeFullCertificate { - // X.509 certificate (chain), see https://tools.ietf.org/html/rfc7515#section-4.1.6 - token.Header["x5c"] = []string{base64.StdEncoding.EncodeToString(cert.Raw)} - } - - token.Claims = jwt.MapClaims{ - // See https://tools.ietf.org/html/rfc7519#section-4.1 - "aud": audience, - "iss": clientID, - "sub": clientID, - "jti": base64.URLEncoding.EncodeToString(jti), - "nbf": time.Now().Unix(), - "exp": time.Now().Add(validFor).Unix(), - } - - return token.SignedString(privatekey) -} - -func readCert(file string) (cert *x509.Certificate, key interface{}, err error) { - f, err := os.Open(file) - if err != nil { - return nil, nil, err - } - defer f.Close() - d, err := ioutil.ReadAll(f) - if err != nil { - return nil, nil, err - } - - blocks := []*pem.Block{} - for len(d) > 0 { - var b *pem.Block - b, d = pem.Decode(d) - if b == nil { - break - } - blocks = append(blocks, b) - } - - certs := []*x509.Certificate{} - for _, block := range blocks { - if block.Type == "CERTIFICATE" { - c, err := x509.ParseCertificate(block.Bytes) - if err != nil { - return nil, nil, fmt.Errorf( - "Failed to read certificate block: %v", err) - } - certs = append(certs, c) - } else if block.Type == "PRIVATE KEY" { - key, err = x509.ParsePKCS8PrivateKey(block.Bytes) - if err != nil { - return nil, nil, fmt.Errorf( - "Failed to read private key block: %v", err) - } - } - // Don't care about other types of blocks, ignore - } - - if key == nil { - key, cert, err = pkcs12.Decode(d, "") - if err != nil { - return nil, nil, fmt.Errorf( - "Did not find private key in file, tried to read as PKCS#12 and failed: %v", err) - } - certs = append(certs, cert) - } - - if key == nil { - return nil, nil, fmt.Errorf("Did not find private key in file") - } - - // find the certificate that belongs to the private key by comparing the public keys - switch key := key.(type) { - case *rsa.PrivateKey: - for _, c := range certs { - if cp, ok := c.PublicKey.(*rsa.PublicKey); ok && - (cp.N.Cmp(key.PublicKey.N) == 0) { - cert = c - } - } - - case *ecdsa.PrivateKey: - for _, c := range certs { - if cp, ok := c.PublicKey.(*ecdsa.PublicKey); ok && - (cp.X.Cmp(key.PublicKey.X) == 0) && - (cp.Y.Cmp(key.PublicKey.Y) == 0) { - cert = c - } - } - } - - if cert == nil { - return nil, nil, fmt.Errorf("Did not find certificate belonging to private key in file") - } - - return cert, key, nil -} diff --git a/builder/azure/common/client/tokenprovider_cli.go b/builder/azure/common/client/tokenprovider_cli.go deleted file mode 100644 index b11182e20..000000000 --- a/builder/azure/common/client/tokenprovider_cli.go +++ /dev/null @@ -1,99 +0,0 @@ -package client - -import ( - "context" - "errors" - "fmt" - - "github.com/Azure/go-autorest/autorest/adal" - "github.com/Azure/go-autorest/autorest/azure" - "github.com/Azure/go-autorest/autorest/azure/cli" -) - -// for managed identity auth -type cliOAuthTokenProvider struct { - env azure.Environment - say func(string) - tenantID string -} - -func NewCliOAuthTokenProvider(env azure.Environment, say func(string), tenantID string) oAuthTokenProvider { - return &cliOAuthTokenProvider{ - env: env, - say: say, - tenantID: tenantID, - } -} - -func (tp *cliOAuthTokenProvider) getServicePrincipalToken() (*adal.ServicePrincipalToken, error) { - return tp.getServicePrincipalTokenWithResource(tp.env.ResourceManagerEndpoint) -} - -func (tp *cliOAuthTokenProvider) getServicePrincipalTokenWithResource(resource string) (*adal.ServicePrincipalToken, error) { - token, err := cli.GetTokenFromCLI(resource) - if err != nil { - tp.say(fmt.Sprintf("unable to get token from azure cli: %v", err)) - return nil, err - } - - oAuthConfig, err := adal.NewOAuthConfig(resource, tp.tenantID) - if err != nil { - tp.say(fmt.Sprintf("unable to generate OAuth Config: %v", err)) - return nil, err - } - - adalToken, err := token.ToADALToken() - if err != nil { - tp.say(fmt.Sprintf("unable to get ADAL Token from azure cli token: %v", err)) - return nil, err - } - - spt, err := adal.NewServicePrincipalTokenFromManualToken(*oAuthConfig, clientIDs[tp.env.Name], resource, adalToken) - if err != nil { - tp.say(fmt.Sprintf("unable to get service principal token from adal token: %v", err)) - return nil, err - } - - // Custom refresh function to make it possible to use Azure CLI to refresh tokens. - // Inspired by HashiCorps go-azure-helpers: https://github.com/hashicorp/go-azure-helpers/blob/373622ce2effb0cf299051ea019cb657f357a4d8/authentication/auth_method_azure_cli_token.go#L96-L109 - var customRefreshFunc adal.TokenRefresh = func(ctx context.Context, resource string) (*adal.Token, error) { - token, err := cli.GetTokenFromCLI(resource) - if err != nil { - tp.say(fmt.Sprintf("token refresh - unable to get token from azure cli: %v", err)) - return nil, err - } - - adalToken, err := token.ToADALToken() - if err != nil { - tp.say(fmt.Sprintf("token refresh - unable to get ADAL Token from azure cli token: %v", err)) - return nil, err - } - - return &adalToken, nil - } - - spt.SetCustomRefreshFunc(customRefreshFunc) - - return spt, nil -} - -// getIDsFromAzureCLI returns the TenantID and SubscriptionID from an active Azure CLI login session -func getIDsFromAzureCLI() (string, string, error) { - profilePath, err := cli.ProfilePath() - if err != nil { - return "", "", err - } - - profile, err := cli.LoadProfile(profilePath) - if err != nil { - return "", "", err - } - - for _, p := range profile.Subscriptions { - if p.IsDefault { - return p.TenantID, p.ID, nil - } - } - - return "", "", errors.New("Unable to find default subscription") -} diff --git a/builder/azure/common/client/tokenprovider_devicewflow.go b/builder/azure/common/client/tokenprovider_devicewflow.go deleted file mode 100644 index 00d83488a..000000000 --- a/builder/azure/common/client/tokenprovider_devicewflow.go +++ /dev/null @@ -1,39 +0,0 @@ -package client - -import ( - "fmt" - "strings" - - "github.com/Azure/go-autorest/autorest/adal" - "github.com/Azure/go-autorest/autorest/azure" -) - -func NewDeviceFlowOAuthTokenProvider(env azure.Environment, say func(string), tenantID string) oAuthTokenProvider { - return &deviceflowOauthTokenProvider{ - env: env, - say: say, - tenantID: tenantID, - } -} - -type deviceflowOauthTokenProvider struct { - env azure.Environment - say func(string) - tenantID string -} - -func (tp *deviceflowOauthTokenProvider) getServicePrincipalToken() (*adal.ServicePrincipalToken, error) { - return tp.getServicePrincipalTokenWithResource(tp.env.ResourceManagerEndpoint) -} - -func (tp *deviceflowOauthTokenProvider) getServicePrincipalTokenWithResource(resource string) (*adal.ServicePrincipalToken, error) { - if resource == tp.env.ServiceManagementEndpoint { - tp.say("Getting auth token for Service management endpoint") - } else if resource == strings.TrimRight(tp.env.KeyVaultEndpoint, "/") { - tp.say("Getting token for Vault resource") - } else { - tp.say(fmt.Sprintf("Getting token for %s", resource)) - } - - return Authenticate(tp.env, tp.tenantID, tp.say, resource) -} diff --git a/builder/azure/common/client/tokenprovider_jwt.go b/builder/azure/common/client/tokenprovider_jwt.go deleted file mode 100644 index 905d1f22f..000000000 --- a/builder/azure/common/client/tokenprovider_jwt.go +++ /dev/null @@ -1,43 +0,0 @@ -package client - -import ( - "net/url" - - "github.com/Azure/go-autorest/autorest/adal" - "github.com/Azure/go-autorest/autorest/azure" -) - -// for clientID/bearer JWT auth -type jwtOAuthTokenProvider struct { - env azure.Environment - clientID, clientJWT, tenantID string -} - -func NewJWTOAuthTokenProvider(env azure.Environment, clientID, clientJWT, tenantID string) oAuthTokenProvider { - return &jwtOAuthTokenProvider{env, clientID, clientJWT, tenantID} -} - -func (tp *jwtOAuthTokenProvider) getServicePrincipalToken() (*adal.ServicePrincipalToken, error) { - return tp.getServicePrincipalTokenWithResource(tp.env.ResourceManagerEndpoint) -} - -func (tp *jwtOAuthTokenProvider) getServicePrincipalTokenWithResource(resource string) (*adal.ServicePrincipalToken, error) { - oauthConfig, err := adal.NewOAuthConfig(tp.env.ActiveDirectoryEndpoint, tp.tenantID) - if err != nil { - return nil, err - } - - return adal.NewServicePrincipalTokenWithSecret( - *oauthConfig, - tp.clientID, - resource, - tp) -} - -// implements github.com/Azure/go-autorest/autorest/adal.ServicePrincipalSecret -func (tp *jwtOAuthTokenProvider) SetAuthenticationValues( - t *adal.ServicePrincipalToken, v *url.Values) error { - v.Set("client_assertion", tp.clientJWT) - v.Set("client_assertion_type", "urn:ietf:params:oauth:client-assertion-type:jwt-bearer") - return nil -} diff --git a/builder/azure/common/client/tokenprovider_msi.go b/builder/azure/common/client/tokenprovider_msi.go deleted file mode 100644 index 8c97a821d..000000000 --- a/builder/azure/common/client/tokenprovider_msi.go +++ /dev/null @@ -1,23 +0,0 @@ -package client - -import ( - "github.com/Azure/go-autorest/autorest/adal" - "github.com/Azure/go-autorest/autorest/azure" -) - -// for managed identity auth -type msiOAuthTokenProvider struct { - env azure.Environment -} - -func NewMSIOAuthTokenProvider(env azure.Environment) oAuthTokenProvider { - return &msiOAuthTokenProvider{env} -} - -func (tp *msiOAuthTokenProvider) getServicePrincipalToken() (*adal.ServicePrincipalToken, error) { - return tp.getServicePrincipalTokenWithResource(tp.env.ResourceManagerEndpoint) -} - -func (tp *msiOAuthTokenProvider) getServicePrincipalTokenWithResource(resource string) (*adal.ServicePrincipalToken, error) { - return adal.NewServicePrincipalTokenFromMSI("http://169.254.169.254/metadata/identity/oauth2/token", resource) -} diff --git a/builder/azure/common/client/tokenprovider_secret.go b/builder/azure/common/client/tokenprovider_secret.go deleted file mode 100644 index 7834742bb..000000000 --- a/builder/azure/common/client/tokenprovider_secret.go +++ /dev/null @@ -1,35 +0,0 @@ -package client - -import ( - "github.com/Azure/go-autorest/autorest/adal" - "github.com/Azure/go-autorest/autorest/azure" -) - -// for clientID/secret auth -type secretOAuthTokenProvider struct { - env azure.Environment - clientID, clientSecret, tenantID string -} - -func NewSecretOAuthTokenProvider(env azure.Environment, clientID, clientSecret, tenantID string) oAuthTokenProvider { - return &secretOAuthTokenProvider{env, clientID, clientSecret, tenantID} -} - -func (tp *secretOAuthTokenProvider) getServicePrincipalToken() (*adal.ServicePrincipalToken, error) { - return tp.getServicePrincipalTokenWithResource(tp.env.ResourceManagerEndpoint) -} - -func (tp *secretOAuthTokenProvider) getServicePrincipalTokenWithResource(resource string) (*adal.ServicePrincipalToken, error) { - oauthConfig, err := adal.NewOAuthConfig(tp.env.ActiveDirectoryEndpoint, tp.tenantID) - if err != nil { - return nil, err - } - - spt, err := adal.NewServicePrincipalToken( - *oauthConfig, - tp.clientID, - tp.clientSecret, - resource) - - return spt, err -} diff --git a/builder/azure/common/client/tokenprovider_secret_test.go b/builder/azure/common/client/tokenprovider_secret_test.go deleted file mode 100644 index 9ca685e47..000000000 --- a/builder/azure/common/client/tokenprovider_secret_test.go +++ /dev/null @@ -1,40 +0,0 @@ -package client - -import ( - "testing" - - "github.com/Azure/go-autorest/autorest/azure" -) - -// Behavior is the most important thing to assert for ServicePrincipalToken, but -// that cannot be done in a unit test because it involves network access. Instead, -// I assert the expected inertness of this class. -func TestNewSecretOAuthTokenProvider(t *testing.T) { - testSubject := NewSecretOAuthTokenProvider(azure.PublicCloud, "clientID", "clientString", "tenantID") - spn, err := testSubject.getServicePrincipalToken() - if err != nil { - t.Fatalf(err.Error()) - } - - if spn.Token().AccessToken != "" { - t.Errorf("spn.Token().AccessToken: expected=\"\", actual=%s", spn.Token().AccessToken) - } - if spn.Token().RefreshToken != "" { - t.Errorf("spn.Token().RefreshToken: expected=\"\", actual=%s", spn.Token().RefreshToken) - } - if spn.Token().ExpiresIn != "0" { - t.Errorf("spn.Token().ExpiresIn: expected=\"0\", actual=%s", spn.Token().ExpiresIn) - } - if spn.Token().ExpiresOn != "0" { - t.Errorf("spn.Token().ExpiresOn: expected=\"0\", actual=%s", spn.Token().ExpiresOn) - } - if spn.Token().NotBefore != "0" { - t.Errorf("spn.Token().NotBefore: expected=\"0\", actual=%s", spn.Token().NotBefore) - } - if spn.Token().Resource != "" { - t.Errorf("spn.Token().Resource: expected=\"\", actual=%s", spn.Token().Resource) - } - if spn.Token().Type != "" { - t.Errorf("spn.Token().Type: expected=\"\", actual=%s", spn.Token().Type) - } -} diff --git a/builder/azure/common/constants/stateBag.go b/builder/azure/common/constants/stateBag.go deleted file mode 100644 index 8a8ba1de6..000000000 --- a/builder/azure/common/constants/stateBag.go +++ /dev/null @@ -1,58 +0,0 @@ -package constants - -// complete flags -const ( - AuthorizedKey string = "authorizedKey" - Certificate string = "certificate" - Error string = "error" - SSHHost string = "sshHost" - Thumbprint string = "thumbprint" - Ui string = "ui" -) - -// Default replica count for image versions in shared image gallery -const ( - SharedImageGalleryImageVersionDefaultMinReplicaCount int32 = 1 - SharedImageGalleryImageVersionDefaultMaxReplicaCount int32 = 10 -) - -const ( - ArmCaptureTemplate string = "arm.CaptureTemplate" - ArmComputeName string = "arm.ComputeName" - ArmImageParameters string = "arm.ImageParameters" - ArmCertificateUrl string = "arm.CertificateUrl" - ArmKeyVaultDeploymentName string = "arm.KeyVaultDeploymentName" - ArmDeploymentName string = "arm.DeploymentName" - ArmNicName string = "arm.NicName" - ArmKeyVaultName string = "arm.KeyVaultName" - ArmLocation string = "arm.Location" - ArmOSDiskVhd string = "arm.OSDiskVhd" - ArmAdditionalDiskVhds string = "arm.AdditionalDiskVhds" - ArmPublicIPAddressName string = "arm.PublicIPAddressName" - ArmResourceGroupName string = "arm.ResourceGroupName" - ArmIsResourceGroupCreated string = "arm.IsResourceGroupCreated" - ArmDoubleResourceGroupNameSet string = "arm.DoubleResourceGroupNameSet" - ArmStorageAccountName string = "arm.StorageAccountName" - ArmTags string = "arm.Tags" - ArmVirtualMachineCaptureParameters string = "arm.VirtualMachineCaptureParameters" - ArmIsExistingResourceGroup string = "arm.IsExistingResourceGroup" - ArmIsExistingKeyVault string = "arm.IsExistingKeyVault" - ArmIsManagedImage string = "arm.IsManagedImage" - ArmManagedImageResourceGroupName string = "arm.ManagedImageResourceGroupName" - ArmManagedImageName string = "arm.ManagedImageName" - ArmManagedImageSigPublishResourceGroup string = "arm.ManagedImageSigPublishResourceGroup" - ArmManagedImageSharedGalleryName string = "arm.ManagedImageSharedGalleryName" - ArmManagedImageSharedGalleryImageName string = "arm.ManagedImageSharedGalleryImageName" - ArmManagedImageSharedGalleryImageVersion string = "arm.ManagedImageSharedGalleryImageVersion" - ArmManagedImageSharedGalleryReplicationRegions string = "arm.ManagedImageSharedGalleryReplicationRegions" - ArmManagedImageSharedGalleryId string = "arm.ArmManagedImageSharedGalleryId" - ArmManagedImageSharedGalleryImageVersionEndOfLifeDate string = "arm.ArmManagedImageSharedGalleryImageVersionEndOfLifeDate" - ArmManagedImageSharedGalleryImageVersionReplicaCount string = "arm.ArmManagedImageSharedGalleryImageVersionReplicaCount" - ArmManagedImageSharedGalleryImageVersionExcludeFromLatest string = "arm.ArmManagedImageSharedGalleryImageVersionExcludeFromLatest" - ArmManagedImageSharedGalleryImageVersionStorageAccountType string = "arm.ArmManagedImageSharedGalleryImageVersionStorageAccountType" - ArmManagedImageSubscription string = "arm.ArmManagedImageSubscription" - ArmAsyncResourceGroupDelete string = "arm.AsyncResourceGroupDelete" - ArmManagedImageOSDiskSnapshotName string = "arm.ManagedImageOSDiskSnapshotName" - ArmManagedImageDataDiskSnapshotPrefix string = "arm.ManagedImageDataDiskSnapshotPrefix" - ArmKeepOSDisk string = "arm.KeepOSDisk" -) diff --git a/builder/azure/common/constants/targetplatforms.go b/builder/azure/common/constants/targetplatforms.go deleted file mode 100644 index 515eb7466..000000000 --- a/builder/azure/common/constants/targetplatforms.go +++ /dev/null @@ -1,7 +0,0 @@ -package constants - -// Target types -const ( - Target_Linux string = "Linux" - Target_Windows string = "Windows" -) diff --git a/builder/azure/common/dump_config.go b/builder/azure/common/dump_config.go deleted file mode 100644 index 73e619e76..000000000 --- a/builder/azure/common/dump_config.go +++ /dev/null @@ -1,70 +0,0 @@ -package common - -import ( - "fmt" - "reflect" - "strings" - - "github.com/mitchellh/reflectwalk" -) - -type walker struct { - depth int - say func(string) -} - -func newDumpConfig(say func(string)) *walker { - return &walker{ - depth: 0, - say: say, - } -} - -func (s *walker) Enter(l reflectwalk.Location) error { - s.depth += 1 - return nil -} - -func (s *walker) Exit(l reflectwalk.Location) error { - s.depth -= 1 - return nil -} - -func (s *walker) Struct(v reflect.Value) error { - return nil -} - -func (s *walker) StructField(f reflect.StructField, v reflect.Value) error { - if !s.shouldDump(v) { - return nil - } - - switch v.Kind() { - case reflect.String: - s.say(fmt.Sprintf("%s=%s", f.Name, s.formatValue(f.Name, v.String()))) - } - - return nil -} - -func (s *walker) shouldDump(v reflect.Value) bool { - return s.depth == 2 && v.IsValid() && v.CanInterface() -} - -func (s *walker) formatValue(name, value string) string { - if s.isMaskable(name) { - return strings.Repeat("*", len(value)) - } - - return value -} - -func (s *walker) isMaskable(name string) bool { - up := strings.ToUpper(name) - return strings.Contains(up, "SECRET") || strings.Contains(up, "PASSWORD") -} - -func DumpConfig(config interface{}, say func(string)) { - walker := newDumpConfig(say) - reflectwalk.Walk(config, walker) -} diff --git a/builder/azure/common/dump_config_test.go b/builder/azure/common/dump_config_test.go deleted file mode 100644 index 20f2e488b..000000000 --- a/builder/azure/common/dump_config_test.go +++ /dev/null @@ -1,127 +0,0 @@ -package common - -import "testing" - -func TestShouldDumpPublicValues(t *testing.T) { - type S struct { - MyString string - myString string - } - - data := &S{ - MyString: "value1", - } - - dumps := make([]string, 0, 2) - DumpConfig(data, func(s string) { dumps = append(dumps, s) }) - - if len(dumps) != 1 { - t.Fatalf("Expected len(dumps) to be 1, but got %d", len(dumps)) - - } - if dumps[0] != "MyString=value1" { - t.Errorf("Expected dumps[0] to be 'MyString=value1', but got %s", dumps[0]) - } -} - -func TestShouldOnlyDumpStrings(t *testing.T) { - type S struct { - MyString string - MyInt int - MyFloat32 float32 - MyStringPointer *string - } - - s := "value1" - data := &S{ - MyString: s, - MyInt: 1, - MyFloat32: 2.0, - MyStringPointer: &s, - } - - dumps := make([]string, 0, 4) - DumpConfig(data, func(s string) { dumps = append(dumps, s) }) - - if len(dumps) != 1 { - t.Fatalf("Expected len(dumps) to be 1, but got %d", len(dumps)) - - } - if dumps[0] != "MyString=value1" { - t.Errorf("Expected dumps[0] to be 'MyString=value1', but got %s", dumps[0]) - } -} - -func TestDumpShouldMaskSensitiveFieldValues(t *testing.T) { - type S struct { - MyString string - MySecret string - MySecretValue string - MyPassword string - MyPasswordValue string - } - - data := &S{ - MyString: "my-string", - MySecret: "s3cr3t", - MySecretValue: "s3cr3t-value", - MyPassword: "p@ssw0rd", - MyPasswordValue: "p@ssw0rd-value", - } - - dumps := make([]string, 0, 5) - DumpConfig(data, func(s string) { dumps = append(dumps, s) }) - - if len(dumps) != 5 { - t.Fatalf("Expected len(dumps) to be 5, but got %d", len(dumps)) - - } - if dumps[0] != "MyString=my-string" { - t.Errorf("Expected dumps[0] to be 'MyString=my-string', but got %s", dumps[0]) - } - if dumps[1] != "MySecret=******" { - t.Errorf("Expected dumps[1] to be 'MySecret=******', but got %s", dumps[1]) - } - if dumps[2] != "MySecretValue=************" { - t.Errorf("Expected dumps[2] to be 'MySecret=************', but got %s", dumps[2]) - } - if dumps[3] != "MyPassword=********" { - t.Errorf("Expected dumps[3] to be 'MyPassword=******** but got %s", dumps[3]) - } - if dumps[4] != "MyPasswordValue=**************" { - t.Errorf("Expected dumps[4] to be 'MyPasswordValue=**************' but got %s", dumps[4]) - } -} - -func TestDumpConfigShouldDumpTopLevelValuesOnly(t *testing.T) { - type N struct { - NestedString string - } - - type S struct { - Nested1 N - MyString string - Nested2 N - } - - data := &S{ - Nested1: N{ - NestedString: "nested-string1", - }, - MyString: "my-string", - Nested2: N{ - NestedString: "nested-string2", - }, - } - - dumps := make([]string, 0, 1) - DumpConfig(data, func(s string) { dumps = append(dumps, s) }) - - if len(dumps) != 1 { - t.Fatalf("Expected len(dumps) to be 1, but got %d", len(dumps)) - - } - if dumps[0] != "MyString=my-string" { - t.Errorf("Expected dumps[0] to be 'MyString=my-string', but got %s", dumps[0]) - } -} diff --git a/builder/azure/common/gluestrings.go b/builder/azure/common/gluestrings.go deleted file mode 100644 index e3b6963d3..000000000 --- a/builder/azure/common/gluestrings.go +++ /dev/null @@ -1,19 +0,0 @@ -package common - -// removes overlap between the end of a and the start of b and -// glues them together -func GlueStrings(a, b string) string { - shift := 0 - for shift < len(a) { - i := 0 - for (i+shift < len(a)) && (i < len(b)) && (a[i+shift] == b[i]) { - i++ - } - if i+shift == len(a) { - break - } - shift++ - } - - return a[:shift] + b -} diff --git a/builder/azure/common/gluestrings_test.go b/builder/azure/common/gluestrings_test.go deleted file mode 100644 index 0e7a633d4..000000000 --- a/builder/azure/common/gluestrings_test.go +++ /dev/null @@ -1,30 +0,0 @@ -package common - -import ( - "testing" -) - -func TestGlueStrings(t *testing.T) { - cases := []struct{ a, b, expected string }{ - { - "Some log that starts in a", - "starts in a, but continues in b", - "Some log that starts in a, but continues in b", - }, - { - "", - "starts in b", - "starts in b", - }, - } - for _, testcase := range cases { - t.Logf("testcase: %+v\n", testcase) - - result := GlueStrings(testcase.a, testcase.b) - t.Logf("result: '%s'", result) - - if result != testcase.expected { - t.Errorf("expected %q, got %q", testcase.expected, result) - } - } -} diff --git a/builder/azure/common/lin/ssh.go b/builder/azure/common/lin/ssh.go deleted file mode 100644 index 0b91a41d4..000000000 --- a/builder/azure/common/lin/ssh.go +++ /dev/null @@ -1,11 +0,0 @@ -package lin - -import ( - "github.com/hashicorp/packer-plugin-sdk/multistep" - "github.com/hashicorp/packer/builder/azure/common/constants" -) - -func SSHHost(state multistep.StateBag) (string, error) { - host := state.Get(constants.SSHHost).(string) - return host, nil -} diff --git a/builder/azure/common/logutil/logfields.go b/builder/azure/common/logutil/logfields.go deleted file mode 100644 index b450594de..000000000 --- a/builder/azure/common/logutil/logfields.go +++ /dev/null @@ -1,16 +0,0 @@ -package logutil - -import "fmt" - -type Fields map[string]interface{} - -func (f Fields) String() string { - var s string - for k, v := range f { - if sv, ok := v.(string); ok { - v = fmt.Sprintf("%q", sv) - } - s += fmt.Sprintf(" %s=%v", k, v) - } - return s -} diff --git a/builder/azure/common/map.go b/builder/azure/common/map.go deleted file mode 100644 index 318f2780b..000000000 --- a/builder/azure/common/map.go +++ /dev/null @@ -1,10 +0,0 @@ -package common - -func MapToAzureTags(in map[string]string) map[string]*string { - res := map[string]*string{} - for k := range in { - v := in[k] - res[k] = &v - } - return res -} diff --git a/builder/azure/common/state_bag.go b/builder/azure/common/state_bag.go deleted file mode 100644 index e62969c14..000000000 --- a/builder/azure/common/state_bag.go +++ /dev/null @@ -1,8 +0,0 @@ -package common - -import "github.com/hashicorp/packer-plugin-sdk/multistep" - -func IsStateCancelled(stateBag multistep.StateBag) bool { - _, ok := stateBag.GetOk(multistep.StateCancelled) - return ok -} diff --git a/builder/azure/common/strings_contains.go b/builder/azure/common/strings_contains.go deleted file mode 100644 index 2a8fae416..000000000 --- a/builder/azure/common/strings_contains.go +++ /dev/null @@ -1,13 +0,0 @@ -package common - -import "strings" - -// StringsContains returns true if the `haystack` contains the `needle`. Search is case insensitive. -func StringsContains(haystack []string, needle string) bool { - for _, s := range haystack { - if strings.EqualFold(s, needle) { - return true - } - } - return false -} diff --git a/builder/azure/common/strings_contains_test.go b/builder/azure/common/strings_contains_test.go deleted file mode 100644 index 51a24ff70..000000000 --- a/builder/azure/common/strings_contains_test.go +++ /dev/null @@ -1,39 +0,0 @@ -package common - -import "testing" - -func TestStringsContains(t *testing.T) { - - tests := []struct { - name string - haystack []string - needle string - want bool - }{ - { - name: "found", - haystack: []string{"a", "b", "c"}, - needle: "b", - want: true, - }, - { - name: "missing", - haystack: []string{"a", "b", "c"}, - needle: "D", - want: false, - }, - { - name: "case insensitive", - haystack: []string{"a", "b", "c"}, - needle: "B", - want: true, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - if got := StringsContains(tt.haystack, tt.needle); got != tt.want { - t.Errorf("StringsContains() = %v, want %v", got, tt.want) - } - }) - } -} diff --git a/builder/azure/common/template/TestBuildLinux02.approved.txt b/builder/azure/common/template/TestBuildLinux02.approved.txt deleted file mode 100644 index 97aad4de1..000000000 --- a/builder/azure/common/template/TestBuildLinux02.approved.txt +++ /dev/null @@ -1,120 +0,0 @@ -{ - "$schema": "http://schema.management.azure.com/schemas/2014-04-01-preview/deploymentTemplate.json", - "contentVersion": "1.0.0.0", - "parameters": { - "adminPassword": { - "type": "string" - }, - "adminUsername": { - "type": "string" - }, - "dnsNameForPublicIP": { - "type": "string" - }, - "osDiskName": { - "type": "string" - }, - "storageAccountBlobEndpoint": { - "type": "string" - }, - "vmName": { - "type": "string" - }, - "vmSize": { - "type": "string" - } - }, - "variables": { - "addressPrefix": "10.0.0.0/16", - "apiVersion": "2015-06-15", - "location": "[resourceGroup().location]", - "nicName": "packerNic", - "publicIPAddressName": "packerPublicIP", - "publicIPAddressType": "Dynamic", - "sshKeyPath": "[concat('/home/',parameters('adminUsername'),'/.ssh/authorized_keys')]", - "subnetAddressPrefix": "10.0.0.0/24", - "subnetName": "--subnet-name--", - "subnetRef": "[concat(variables('vnetID'),'/subnets/',variables('subnetName'))]", - "virtualNetworkName": "--virtual-network--", - "virtualNetworkResourceGroup": "--virtual-network-resource-group--", - "vmStorageAccountContainerName": "images", - "vnetID": "[resourceId(variables('virtualNetworkResourceGroup'), 'Microsoft.Network/virtualNetworks', variables('virtualNetworkName'))]" - }, - "resources": [ - { - "apiVersion": "[variables('apiVersion')]", - "name": "[variables('nicName')]", - "type": "Microsoft.Network/networkInterfaces", - "location": "[variables('location')]", - "dependsOn": [], - "properties": { - "ipConfigurations": [ - { - "properties": { - "privateIPAllocationMethod": "Dynamic", - "subnet": { - "id": "[variables('subnetRef')]" - } - }, - "name": "ipconfig" - } - ] - } - }, - { - "apiVersion": "[variables('apiVersion')]", - "name": "[parameters('vmName')]", - "type": "Microsoft.Compute/virtualMachines", - "location": "[variables('location')]", - "dependsOn": [ - "[concat('Microsoft.Network/networkInterfaces/', variables('nicName'))]" - ], - "properties": { - "diagnosticsProfile": { - "bootDiagnostics": { - "enabled": false - } - }, - "hardwareProfile": { - "vmSize": "[parameters('vmSize')]" - }, - "networkProfile": { - "networkInterfaces": [ - { - "id": "[resourceId('Microsoft.Network/networkInterfaces', variables('nicName'))]" - } - ] - }, - "osProfile": { - "computerName": "[parameters('vmName')]", - "adminUsername": "[parameters('adminUsername')]", - "adminPassword": "[parameters('adminPassword')]", - "linuxConfiguration": { - "ssh": { - "publicKeys": [ - { - "path": "[variables('sshKeyPath')]", - "keyData": "--test-ssh-authorized-key--" - } - ] - } - } - }, - "storageProfile": { - "osDisk": { - "osType": "Linux", - "name": "[parameters('osDiskName')]", - "vhd": { - "uri": "[concat(parameters('storageAccountBlobEndpoint'),variables('vmStorageAccountContainerName'),'/', parameters('osDiskName'),'.vhd')]" - }, - "image": { - "uri": "http://azure/custom.vhd" - }, - "caching": "ReadWrite", - "createOption": "FromImage" - } - } - } - } - ] -} \ No newline at end of file diff --git a/builder/azure/common/template/template.go b/builder/azure/common/template/template.go deleted file mode 100644 index 2366b7a24..000000000 --- a/builder/azure/common/template/template.go +++ /dev/null @@ -1,124 +0,0 @@ -package template - -import ( - "github.com/Azure/azure-sdk-for-go/services/compute/mgmt/2018-04-01/compute" - "github.com/Azure/azure-sdk-for-go/services/network/mgmt/2018-01-01/network" -) - -///////////////////////////////////////////////// -// Template -type Template struct { - Schema *string `json:"$schema"` - ContentVersion *string `json:"contentVersion"` - Parameters *map[string]Parameters `json:"parameters"` - Variables *map[string]string `json:"variables"` - Resources []*Resource `json:"resources"` -} - -///////////////////////////////////////////////// -// Template > Parameters -type Parameters struct { - Type *string `json:"type"` - DefaultValue *string `json:"defaultValue,omitempty"` -} - -///////////////////////////////////////////////// -// Template > Resource -type Resource struct { - ApiVersion *string `json:"apiVersion"` - Name *string `json:"name"` - Type *string `json:"type"` - Location *string `json:"location,omitempty"` - DependsOn *[]string `json:"dependsOn,omitempty"` - Plan *Plan `json:"plan,omitempty"` - Properties *Properties `json:"properties,omitempty"` - Tags *map[string]string `json:"tags,omitempty"` - Resources *[]Resource `json:"resources,omitempty"` - Identity *Identity `json:"identity,omitempty"` -} - -type Plan struct { - Name *string `json:"name"` - Product *string `json:"product"` - Publisher *string `json:"publisher"` - PromotionCode *string `json:"promotionCode,omitempty"` -} - -type OSDiskUnion struct { - OsType compute.OperatingSystemTypes `json:"osType,omitempty"` - OsState compute.OperatingSystemStateTypes `json:"osState,omitempty"` - BlobURI *string `json:"blobUri,omitempty"` - Name *string `json:"name,omitempty"` - Vhd *compute.VirtualHardDisk `json:"vhd,omitempty"` - Image *compute.VirtualHardDisk `json:"image,omitempty"` - Caching compute.CachingTypes `json:"caching,omitempty"` - CreateOption compute.DiskCreateOptionTypes `json:"createOption,omitempty"` - DiskSizeGB *int32 `json:"diskSizeGB,omitempty"` - ManagedDisk *compute.ManagedDiskParameters `json:"managedDisk,omitempty"` -} - -type DataDiskUnion struct { - Lun *int `json:"lun,omitempty"` - BlobURI *string `json:"blobUri,omitempty"` - Name *string `json:"name,omitempty"` - Vhd *compute.VirtualHardDisk `json:"vhd,omitempty"` - Image *compute.VirtualHardDisk `json:"image,omitempty"` - Caching compute.CachingTypes `json:"caching,omitempty"` - CreateOption compute.DiskCreateOptionTypes `json:"createOption,omitempty"` - DiskSizeGB *int32 `json:"diskSizeGB,omitempty"` - ManagedDisk *compute.ManagedDiskParameters `json:"managedDisk,omitempty"` -} - -// Union of the StorageProfile and ImageStorageProfile types. -type StorageProfileUnion struct { - ImageReference *compute.ImageReference `json:"imageReference,omitempty"` - OsDisk *OSDiskUnion `json:"osDisk,omitempty"` - DataDisks *[]DataDiskUnion `json:"dataDisks,omitempty"` -} - -///////////////////////////////////////////////// -// Template > Resource > Properties -type Properties struct { - AccessPolicies *[]AccessPolicies `json:"accessPolicies,omitempty"` - AddressSpace *network.AddressSpace `json:"addressSpace,omitempty"` - DiagnosticsProfile *compute.DiagnosticsProfile `json:"diagnosticsProfile,omitempty"` - DNSSettings *network.PublicIPAddressDNSSettings `json:"dnsSettings,omitempty"` - EnabledForDeployment *string `json:"enabledForDeployment,omitempty"` - EnabledForTemplateDeployment *string `json:"enabledForTemplateDeployment,omitempty"` - EnableSoftDelete *string `json:"enableSoftDelete,omitempty"` - HardwareProfile *compute.HardwareProfile `json:"hardwareProfile,omitempty"` - IPConfigurations *[]network.IPConfiguration `json:"ipConfigurations,omitempty"` - NetworkProfile *compute.NetworkProfile `json:"networkProfile,omitempty"` - OsProfile *compute.OSProfile `json:"osProfile,omitempty"` - PublicIPAllocatedMethod *network.IPAllocationMethod `json:"publicIPAllocationMethod,omitempty"` - Sku *Sku `json:"sku,omitempty"` - //StorageProfile3 *compute.StorageProfile `json:"storageProfile,omitempty"` - StorageProfile *StorageProfileUnion `json:"storageProfile,omitempty"` - Subnets *[]network.Subnet `json:"subnets,omitempty"` - SecurityRules *[]network.SecurityRule `json:"securityRules,omitempty"` - TenantId *string `json:"tenantId,omitempty"` - Value *string `json:"value,omitempty"` -} - -// Template > Resource > Identity -// The map values are simplified to struct{} since they are read-only and cannot be set -type Identity struct { - Type *string `json:"type,omitempty"` - UserAssignedIdentities map[string]struct{} `json:"userAssignedIdentities,omitempty"` -} - -type AccessPolicies struct { - ObjectId *string `json:"objectId,omitempty"` - TenantId *string `json:"tenantId,omitempty"` - Permissions *Permissions `json:"permissions,omitempty"` -} - -type Permissions struct { - Keys *[]string `json:"keys,omitempty"` - Secrets *[]string `json:"secrets,omitempty"` -} - -type Sku struct { - Family *string `json:"family,omitempty"` - Name *string `json:"name,omitempty"` -} diff --git a/builder/azure/common/template/template_builder.go b/builder/azure/common/template/template_builder.go deleted file mode 100644 index cdb9f92d1..000000000 --- a/builder/azure/common/template/template_builder.go +++ /dev/null @@ -1,756 +0,0 @@ -package template - -import ( - "encoding/json" - "fmt" - "strconv" - "strings" - - "github.com/Azure/azure-sdk-for-go/services/compute/mgmt/2018-04-01/compute" - "github.com/Azure/azure-sdk-for-go/services/network/mgmt/2018-01-01/network" - "github.com/Azure/go-autorest/autorest/to" -) - -const ( - jsonPrefix = "" - jsonIndent = " " - - resourceKeyVaults = "Microsoft.KeyVault/vaults" - resourceNetworkInterfaces = "Microsoft.Network/networkInterfaces" - resourcePublicIPAddresses = "Microsoft.Network/publicIPAddresses" - resourceVirtualMachine = "Microsoft.Compute/virtualMachines" - resourceVirtualNetworks = "Microsoft.Network/virtualNetworks" - resourceNetworkSecurityGroups = "Microsoft.Network/networkSecurityGroups" - - variableSshKeyPath = "sshKeyPath" -) - -type TemplateBuilder struct { - template *Template - osType compute.OperatingSystemTypes -} - -func NewTemplateBuilder(template string) (*TemplateBuilder, error) { - var t Template - - err := json.Unmarshal([]byte(template), &t) - if err != nil { - return nil, err - } - - return &TemplateBuilder{ - template: &t, - }, nil -} - -func (s *TemplateBuilder) BuildLinux(sshAuthorizedKey string, disablePasswordAuthentication bool) error { - resource, err := s.getResourceByType(resourceVirtualMachine) - if err != nil { - return err - } - - profile := resource.Properties.OsProfile - profile.LinuxConfiguration = &compute.LinuxConfiguration{ - SSH: &compute.SSHConfiguration{ - PublicKeys: &[]compute.SSHPublicKey{ - { - Path: to.StringPtr(s.toVariable(variableSshKeyPath)), - KeyData: to.StringPtr(sshAuthorizedKey), - }, - }, - }, - } - - if disablePasswordAuthentication { - profile.LinuxConfiguration.DisablePasswordAuthentication = to.BoolPtr(true) - profile.AdminPassword = nil - } - - s.osType = compute.Linux - return nil -} - -func (s *TemplateBuilder) BuildWindows(keyVaultName, winRMCertificateUrl string) error { - resource, err := s.getResourceByType(resourceVirtualMachine) - if err != nil { - return err - } - - profile := resource.Properties.OsProfile - - profile.Secrets = &[]compute.VaultSecretGroup{ - { - SourceVault: &compute.SubResource{ - ID: to.StringPtr(s.toResourceID(resourceKeyVaults, keyVaultName)), - }, - VaultCertificates: &[]compute.VaultCertificate{ - { - CertificateStore: to.StringPtr("My"), - CertificateURL: to.StringPtr(winRMCertificateUrl), - }, - }, - }, - } - - profile.WindowsConfiguration = &compute.WindowsConfiguration{ - ProvisionVMAgent: to.BoolPtr(true), - WinRM: &compute.WinRMConfiguration{ - Listeners: &[]compute.WinRMListener{ - { - Protocol: "https", - CertificateURL: to.StringPtr(winRMCertificateUrl), - }, - }, - }, - } - - s.osType = compute.Windows - return nil -} - -func (s *TemplateBuilder) SetIdentity(userAssignedManagedIdentities []string) error { - resource, err := s.getResourceByType(resourceVirtualMachine) - if err != nil { - return err - } - - var id *Identity - - if len(userAssignedManagedIdentities) != 0 { - s.setVariable("apiVersion", "2018-06-01") // Required for user assigned managed identity - id = &Identity{ - Type: to.StringPtr("UserAssigned"), - UserAssignedIdentities: make(map[string]struct{}), - } - for _, uid := range userAssignedManagedIdentities { - id.UserAssignedIdentities[uid] = struct{}{} - } - } - - resource.Identity = id - return nil -} - -func (s *TemplateBuilder) SetManagedDiskUrl(managedImageId string, storageAccountType compute.StorageAccountTypes, cachingType compute.CachingTypes) error { - resource, err := s.getResourceByType(resourceVirtualMachine) - if err != nil { - return err - } - - profile := resource.Properties.StorageProfile - profile.ImageReference = &compute.ImageReference{ - ID: &managedImageId, - } - profile.OsDisk.OsType = s.osType - profile.OsDisk.CreateOption = compute.DiskCreateOptionTypesFromImage - profile.OsDisk.Vhd = nil - profile.OsDisk.Caching = cachingType - profile.OsDisk.ManagedDisk = &compute.ManagedDiskParameters{ - StorageAccountType: storageAccountType, - } - - return nil -} - -func (s *TemplateBuilder) SetManagedMarketplaceImage(location, publisher, offer, sku, version, imageID string, storageAccountType compute.StorageAccountTypes, cachingType compute.CachingTypes) error { - resource, err := s.getResourceByType(resourceVirtualMachine) - if err != nil { - return err - } - - profile := resource.Properties.StorageProfile - profile.ImageReference = &compute.ImageReference{ - Publisher: &publisher, - Offer: &offer, - Sku: &sku, - Version: &version, - } - profile.OsDisk.OsType = s.osType - profile.OsDisk.CreateOption = compute.DiskCreateOptionTypesFromImage - profile.OsDisk.Vhd = nil - profile.OsDisk.Caching = cachingType - profile.OsDisk.ManagedDisk = &compute.ManagedDiskParameters{ - StorageAccountType: storageAccountType, - } - - return nil -} - -func (s *TemplateBuilder) SetSharedGalleryImage(location, imageID string, cachingType compute.CachingTypes) error { - resource, err := s.getResourceByType(resourceVirtualMachine) - if err != nil { - return err - } - - s.setVariable("apiVersion", "2018-06-01") // Required for Shared Image Gallery - profile := resource.Properties.StorageProfile - profile.ImageReference = &compute.ImageReference{ID: &imageID} - profile.OsDisk.OsType = s.osType - profile.OsDisk.Vhd = nil - profile.OsDisk.Caching = cachingType - - return nil -} - -func (s *TemplateBuilder) SetMarketPlaceImage(publisher, offer, sku, version string, cachingType compute.CachingTypes) error { - resource, err := s.getResourceByType(resourceVirtualMachine) - if err != nil { - return err - } - - profile := resource.Properties.StorageProfile - profile.OsDisk.Caching = cachingType - profile.ImageReference = &compute.ImageReference{ - Publisher: to.StringPtr(publisher), - Offer: to.StringPtr(offer), - Sku: to.StringPtr(sku), - Version: to.StringPtr(version), - } - - return nil -} - -func (s *TemplateBuilder) SetImageUrl(imageUrl string, osType compute.OperatingSystemTypes, cachingType compute.CachingTypes) error { - resource, err := s.getResourceByType(resourceVirtualMachine) - if err != nil { - return err - } - - profile := resource.Properties.StorageProfile - profile.OsDisk.OsType = osType - profile.OsDisk.Caching = cachingType - - profile.OsDisk.Image = &compute.VirtualHardDisk{ - URI: to.StringPtr(imageUrl), - } - - return nil -} - -func (s *TemplateBuilder) SetPlanInfo(name, product, publisher, promotionCode string) error { - var promotionCodeVal *string = nil - if promotionCode != "" { - promotionCodeVal = to.StringPtr(promotionCode) - } - - for i, x := range s.template.Resources { - if strings.EqualFold(*x.Type, resourceVirtualMachine) { - s.template.Resources[i].Plan = &Plan{ - Name: to.StringPtr(name), - Product: to.StringPtr(product), - Publisher: to.StringPtr(publisher), - PromotionCode: promotionCodeVal, - } - } - } - - return nil -} - -func (s *TemplateBuilder) SetOSDiskSizeGB(diskSizeGB int32) error { - resource, err := s.getResourceByType(resourceVirtualMachine) - if err != nil { - return err - } - - profile := resource.Properties.StorageProfile - profile.OsDisk.DiskSizeGB = to.Int32Ptr(diskSizeGB) - - return nil -} - -func (s *TemplateBuilder) SetAdditionalDisks(diskSizeGB []int32, dataDiskname string, isManaged bool, cachingType compute.CachingTypes) error { - resource, err := s.getResourceByType(resourceVirtualMachine) - if err != nil { - return err - } - - profile := resource.Properties.StorageProfile - dataDisks := make([]DataDiskUnion, len(diskSizeGB)) - - for i, additionalSize := range diskSizeGB { - dataDisks[i].DiskSizeGB = to.Int32Ptr(additionalSize) - dataDisks[i].Lun = to.IntPtr(i) - // dataDisks[i].Name = to.StringPtr(fmt.Sprintf("%s-%d", dataDiskname, i+1)) - dataDisks[i].Name = to.StringPtr(fmt.Sprintf("[concat(parameters('dataDiskName'),'-%d')]", i+1)) - dataDisks[i].CreateOption = "Empty" - dataDisks[i].Caching = cachingType - if isManaged { - dataDisks[i].Vhd = nil - dataDisks[i].ManagedDisk = profile.OsDisk.ManagedDisk - } else { - dataDisks[i].Vhd = &compute.VirtualHardDisk{ - URI: to.StringPtr(fmt.Sprintf("[concat(parameters('storageAccountBlobEndpoint'),variables('vmStorageAccountContainerName'),'/',parameters('dataDiskName'),'-%d','.vhd')]", i+1)), - } - dataDisks[i].ManagedDisk = nil - } - } - profile.DataDisks = &dataDisks - return nil -} - -func (s *TemplateBuilder) SetCustomData(customData string) error { - resource, err := s.getResourceByType(resourceVirtualMachine) - if err != nil { - return err - } - - profile := resource.Properties.OsProfile - profile.CustomData = to.StringPtr(customData) - - return nil -} - -func (s *TemplateBuilder) SetVirtualNetwork(virtualNetworkResourceGroup, virtualNetworkName, subnetName string) error { - s.setVariable("virtualNetworkResourceGroup", virtualNetworkResourceGroup) - s.setVariable("virtualNetworkName", virtualNetworkName) - s.setVariable("subnetName", subnetName) - - s.deleteResourceByType(resourceVirtualNetworks) - s.deleteResourceByType(resourcePublicIPAddresses) - resource, err := s.getResourceByType(resourceNetworkInterfaces) - if err != nil { - return err - } - - s.deleteResourceDependency(resource, func(s string) bool { - return strings.Contains(s, "Microsoft.Network/virtualNetworks") || - strings.Contains(s, "Microsoft.Network/publicIPAddresses") - }) - - (*resource.Properties.IPConfigurations)[0].PublicIPAddress = nil - - return nil -} - -func (s *TemplateBuilder) SetPrivateVirtualNetworkWithPublicIp(virtualNetworkResourceGroup, virtualNetworkName, subnetName string) error { - s.setVariable("virtualNetworkResourceGroup", virtualNetworkResourceGroup) - s.setVariable("virtualNetworkName", virtualNetworkName) - s.setVariable("subnetName", subnetName) - - s.deleteResourceByType(resourceVirtualNetworks) - resource, err := s.getResourceByType(resourceNetworkInterfaces) - if err != nil { - return err - } - - s.deleteResourceDependency(resource, func(s string) bool { - return strings.Contains(s, "Microsoft.Network/virtualNetworks") - }) - - return nil -} - -func (s *TemplateBuilder) SetNetworkSecurityGroup(ipAddresses []string, port int) error { - nsgResource, dependency, resourceId := s.createNsgResource(ipAddresses, port) - if err := s.addResource(nsgResource); err != nil { - return err - } - - vnetResource, err := s.getResourceByType(resourceVirtualNetworks) - if err != nil { - return err - } - s.deleteResourceByType(resourceVirtualNetworks) - - s.addResourceDependency(vnetResource, dependency) - - if vnetResource.Properties == nil || vnetResource.Properties.Subnets == nil || len(*vnetResource.Properties.Subnets) != 1 { - return fmt.Errorf("template: could not find virtual network/subnet to add default network security group to") - } - subnet := ((*vnetResource.Properties.Subnets)[0]) - if subnet.SubnetPropertiesFormat == nil { - subnet.SubnetPropertiesFormat = &network.SubnetPropertiesFormat{} - } - if subnet.SubnetPropertiesFormat.NetworkSecurityGroup != nil { - return fmt.Errorf("template: subnet already has an associated network security group") - } - subnet.SubnetPropertiesFormat.NetworkSecurityGroup = &network.SecurityGroup{ - ID: to.StringPtr(resourceId), - } - - s.addResource(vnetResource) - - return nil -} - -func (s *TemplateBuilder) SetTags(tags *map[string]string) error { - if tags == nil || len(*tags) == 0 { - return nil - } - - for i := range s.template.Resources { - s.template.Resources[i].Tags = tags - } - return nil -} - -func (s *TemplateBuilder) SetBootDiagnostics(diagSTG string) error { - - resource, err := s.getResourceByType(resourceVirtualMachine) - if err != nil { - return err - } - - t := true - stg := fmt.Sprintf("https://%s.blob.core.windows.net", diagSTG) - - resource.Properties.DiagnosticsProfile.BootDiagnostics.Enabled = &t - resource.Properties.DiagnosticsProfile.BootDiagnostics.StorageURI = &stg - - return nil -} - -func (s *TemplateBuilder) ToJSON() (*string, error) { - bs, err := json.MarshalIndent(s.template, jsonPrefix, jsonIndent) - - if err != nil { - return nil, err - } - return to.StringPtr(string(bs)), err -} - -func (s *TemplateBuilder) getResourceByType(t string) (*Resource, error) { - for _, x := range s.template.Resources { - if strings.EqualFold(*x.Type, t) { - return x, nil - } - } - - return nil, fmt.Errorf("template: could not find a resource of type %s", t) -} - -func (s *TemplateBuilder) setVariable(name string, value string) { - (*s.template.Variables)[name] = value -} - -func (s *TemplateBuilder) toResourceID(id, name string) string { - return fmt.Sprintf("[resourceId(resourceGroup().name, '%s', '%s')]", id, name) -} - -func (s *TemplateBuilder) toVariable(name string) string { - return fmt.Sprintf("[variables('%s')]", name) -} - -func (s *TemplateBuilder) addResource(newResource *Resource) error { - for _, resource := range s.template.Resources { - if *resource.Type == *newResource.Type { - return fmt.Errorf("template: found an existing resource of type %s", *resource.Type) - } - } - - resources := append(s.template.Resources, newResource) - s.template.Resources = resources - return nil -} - -func (s *TemplateBuilder) deleteResourceByType(resourceType string) { - resources := make([]*Resource, 0) - - for _, resource := range s.template.Resources { - if *resource.Type == resourceType { - continue - } - resources = append(resources, resource) - } - - s.template.Resources = resources -} - -func (s *TemplateBuilder) addResourceDependency(resource *Resource, dep string) { - if resource.DependsOn != nil { - deps := append(*resource.DependsOn, dep) - resource.DependsOn = &deps - } else { - resource.DependsOn = &[]string{dep} - } -} - -func (s *TemplateBuilder) deleteResourceDependency(resource *Resource, predicate func(string) bool) { - deps := make([]string, 0) - - for _, dep := range *resource.DependsOn { - if !predicate(dep) { - deps = append(deps, dep) - } - } - - *resource.DependsOn = deps -} - -func (s *TemplateBuilder) createNsgResource(srcIpAddresses []string, port int) (*Resource, string, string) { - resource := &Resource{ - ApiVersion: to.StringPtr("[variables('networkSecurityGroupsApiVersion')]"), - Name: to.StringPtr("[parameters('nsgName')]"), - Type: to.StringPtr(resourceNetworkSecurityGroups), - Location: to.StringPtr("[variables('location')]"), - Properties: &Properties{ - SecurityRules: &[]network.SecurityRule{ - { - Name: to.StringPtr("AllowIPsToSshWinRMInbound"), - SecurityRulePropertiesFormat: &network.SecurityRulePropertiesFormat{ - Description: to.StringPtr("Allow inbound traffic from specified IP addresses"), - Protocol: network.SecurityRuleProtocolTCP, - Priority: to.Int32Ptr(100), - Access: network.SecurityRuleAccessAllow, - Direction: network.SecurityRuleDirectionInbound, - SourceAddressPrefixes: &srcIpAddresses, - SourcePortRange: to.StringPtr("*"), - DestinationAddressPrefix: to.StringPtr("VirtualNetwork"), - DestinationPortRange: to.StringPtr(strconv.Itoa(port)), - }, - }, - }, - }, - } - - dependency := fmt.Sprintf("[concat('%s/', parameters('nsgName'))]", resourceNetworkSecurityGroups) - resourceId := fmt.Sprintf("[resourceId('%s', parameters('nsgName'))]", resourceNetworkSecurityGroups) - - return resource, dependency, resourceId -} - -// See https://github.com/Azure/azure-quickstart-templates for a extensive list of templates. - -// Template to deploy a KeyVault. -// -// This template is still hard-coded unlike the ARM templates used for VMs for -// a couple of reasons. -// -// 1. The SDK defines no types for a Key Vault -// 2. The Key Vault template is relatively simple, and is static. -// -const KeyVault = `{ - "$schema": "http://schema.management.azure.com/schemas/2014-04-01-preview/deploymentTemplate.json", - "contentVersion": "1.0.0.0", - "parameters": { - "keyVaultName": { - "type": "string" - }, - "keyVaultSKU": { - "type": "string" - }, - "keyVaultSecretValue": { - "type": "securestring" - }, - "objectId": { - "type": "string" - }, - "tenantId": { - "type": "string" - } - }, - "variables": { - "apiVersion": "2015-06-01", - "location": "[resourceGroup().location]", - "keyVaultSecretName": "packerKeyVaultSecret" - }, - "resources": [ - { - "apiVersion": "[variables('apiVersion')]", - "type": "Microsoft.KeyVault/vaults", - "name": "[parameters('keyVaultName')]", - "location": "[variables('location')]", - "properties": { - "enabledForDeployment": "true", - "enabledForTemplateDeployment": "true", - "enableSoftDelete": "true", - "tenantId": "[parameters('tenantId')]", - "accessPolicies": [ - { - "tenantId": "[parameters('tenantId')]", - "objectId": "[parameters('objectId')]", - "permissions": { - "keys": [ "all" ], - "secrets": [ "all" ] - } - } - ], - "sku": { - "name": "[parameters('keyVaultSKU')]", - "family": "A" - } - }, - "resources": [ - { - "apiVersion": "[variables('apiVersion')]", - "type": "secrets", - "name": "[variables('keyVaultSecretName')]", - "dependsOn": [ - "[concat('Microsoft.KeyVault/vaults/', parameters('keyVaultName'))]" - ], - "properties": { - "value": "[parameters('keyVaultSecretValue')]" - } - } - ] - } - ] -}` - -const BasicTemplate = `{ - "$schema": "http://schema.management.azure.com/schemas/2014-04-01-preview/deploymentTemplate.json", - "contentVersion": "1.0.0.0", - "parameters": { - "adminUsername": { - "type": "string" - }, - "adminPassword": { - "type": "string" - }, - "dnsNameForPublicIP": { - "type": "string" - }, - "nicName": { - "type": "string" - }, - "osDiskName": { - "type": "string" - }, - "publicIPAddressName": { - "type": "string" - }, - "subnetName": { - "type": "string" - }, - "storageAccountBlobEndpoint": { - "type": "string" - }, - "virtualNetworkName": { - "type": "string" - }, - "nsgName": { - "type": "string" - }, - "vmSize": { - "type": "string" - }, - "vmName": { - "type": "string" - }, - "dataDiskName": { - "type": "string" - } - }, - "variables": { - "addressPrefix": "10.0.0.0/16", - "apiVersion": "2017-03-30", - "managedDiskApiVersion": "2017-03-30", - "networkInterfacesApiVersion": "2017-04-01", - "publicIPAddressApiVersion": "2017-04-01", - "virtualNetworksApiVersion": "2017-04-01", - "networkSecurityGroupsApiVersion": "2019-04-01", - "location": "[resourceGroup().location]", - "publicIPAddressType": "Dynamic", - "sshKeyPath": "[concat('/home/',parameters('adminUsername'),'/.ssh/authorized_keys')]", - "subnetName": "[parameters('subnetName')]", - "subnetAddressPrefix": "10.0.0.0/24", - "subnetRef": "[concat(variables('vnetID'),'/subnets/',variables('subnetName'))]", - "virtualNetworkName": "[parameters('virtualNetworkName')]", - "virtualNetworkResourceGroup": "[resourceGroup().name]", - "vmStorageAccountContainerName": "images", - "vnetID": "[resourceId(variables('virtualNetworkResourceGroup'), 'Microsoft.Network/virtualNetworks', variables('virtualNetworkName'))]" - }, - "resources": [ - { - "apiVersion": "[variables('publicIPAddressApiVersion')]", - "type": "Microsoft.Network/publicIPAddresses", - "name": "[parameters('publicIPAddressName')]", - "location": "[variables('location')]", - "properties": { - "publicIPAllocationMethod": "[variables('publicIPAddressType')]", - "dnsSettings": { - "domainNameLabel": "[parameters('dnsNameForPublicIP')]" - } - } - }, - { - "apiVersion": "[variables('virtualNetworksApiVersion')]", - "type": "Microsoft.Network/virtualNetworks", - "name": "[variables('virtualNetworkName')]", - "location": "[variables('location')]", - "properties": { - "addressSpace": { - "addressPrefixes": [ - "[variables('addressPrefix')]" - ] - }, - "subnets": [ - { - "name": "[variables('subnetName')]", - "properties": { - "addressPrefix": "[variables('subnetAddressPrefix')]" - } - } - ] - } - }, - { - "apiVersion": "[variables('networkInterfacesApiVersion')]", - "type": "Microsoft.Network/networkInterfaces", - "name": "[parameters('nicName')]", - "location": "[variables('location')]", - "dependsOn": [ - "[concat('Microsoft.Network/publicIPAddresses/', parameters('publicIPAddressName'))]", - "[concat('Microsoft.Network/virtualNetworks/', variables('virtualNetworkName'))]" - ], - "properties": { - "ipConfigurations": [ - { - "name": "ipconfig", - "properties": { - "privateIPAllocationMethod": "Dynamic", - "publicIPAddress": { - "id": "[resourceId('Microsoft.Network/publicIPAddresses', parameters('publicIPAddressName'))]" - }, - "subnet": { - "id": "[variables('subnetRef')]" - } - } - } - ] - } - }, - { - "apiVersion": "[variables('apiVersion')]", - "type": "Microsoft.Compute/virtualMachines", - "name": "[parameters('vmName')]", - "location": "[variables('location')]", - "dependsOn": [ - "[concat('Microsoft.Network/networkInterfaces/', parameters('nicName'))]" - ], - "properties": { - "hardwareProfile": { - "vmSize": "[parameters('vmSize')]" - }, - "osProfile": { - "computerName": "[parameters('vmName')]", - "adminUsername": "[parameters('adminUsername')]", - "adminPassword": "[parameters('adminPassword')]" - }, - "storageProfile": { - "osDisk": { - "name": "[parameters('osDiskName')]", - "vhd": { - "uri": "[concat(parameters('storageAccountBlobEndpoint'),variables('vmStorageAccountContainerName'),'/', parameters('osDiskName'),'.vhd')]" - }, - "caching": "ReadWrite", - "createOption": "FromImage" - } - }, - "networkProfile": { - "networkInterfaces": [ - { - "id": "[resourceId('Microsoft.Network/networkInterfaces', parameters('nicName'))]" - } - ] - }, - "diagnosticsProfile": { - "bootDiagnostics": { - "enabled": false - } - } - } - } - ] -}` diff --git a/builder/azure/common/template/template_builder_test.TestBuildLinux00.approved.json b/builder/azure/common/template/template_builder_test.TestBuildLinux00.approved.json deleted file mode 100644 index 403de815c..000000000 --- a/builder/azure/common/template/template_builder_test.TestBuildLinux00.approved.json +++ /dev/null @@ -1,182 +0,0 @@ -{ - "$schema": "http://schema.management.azure.com/schemas/2014-04-01-preview/deploymentTemplate.json", - "contentVersion": "1.0.0.0", - "parameters": { - "adminPassword": { - "type": "string" - }, - "adminUsername": { - "type": "string" - }, - "dataDiskName": { - "type": "string" - }, - "dnsNameForPublicIP": { - "type": "string" - }, - "nicName": { - "type": "string" - }, - "nsgName": { - "type": "string" - }, - "osDiskName": { - "type": "string" - }, - "publicIPAddressName": { - "type": "string" - }, - "storageAccountBlobEndpoint": { - "type": "string" - }, - "subnetName": { - "type": "string" - }, - "virtualNetworkName": { - "type": "string" - }, - "vmName": { - "type": "string" - }, - "vmSize": { - "type": "string" - } - }, - "resources": [ - { - "apiVersion": "[variables('publicIPAddressApiVersion')]", - "location": "[variables('location')]", - "name": "[parameters('publicIPAddressName')]", - "properties": { - "dnsSettings": { - "domainNameLabel": "[parameters('dnsNameForPublicIP')]" - }, - "publicIPAllocationMethod": "[variables('publicIPAddressType')]" - }, - "type": "Microsoft.Network/publicIPAddresses" - }, - { - "apiVersion": "[variables('virtualNetworksApiVersion')]", - "location": "[variables('location')]", - "name": "[variables('virtualNetworkName')]", - "properties": { - "addressSpace": { - "addressPrefixes": [ - "[variables('addressPrefix')]" - ] - }, - "subnets": [ - { - "name": "[variables('subnetName')]", - "properties": { - "addressPrefix": "[variables('subnetAddressPrefix')]" - } - } - ] - }, - "type": "Microsoft.Network/virtualNetworks" - }, - { - "apiVersion": "[variables('networkInterfacesApiVersion')]", - "dependsOn": [ - "[concat('Microsoft.Network/publicIPAddresses/', parameters('publicIPAddressName'))]", - "[concat('Microsoft.Network/virtualNetworks/', variables('virtualNetworkName'))]" - ], - "location": "[variables('location')]", - "name": "[parameters('nicName')]", - "properties": { - "ipConfigurations": [ - { - "name": "ipconfig", - "properties": { - "privateIPAllocationMethod": "Dynamic", - "publicIPAddress": { - "id": "[resourceId('Microsoft.Network/publicIPAddresses', parameters('publicIPAddressName'))]" - }, - "subnet": { - "id": "[variables('subnetRef')]" - } - } - } - ] - }, - "type": "Microsoft.Network/networkInterfaces" - }, - { - "apiVersion": "[variables('apiVersion')]", - "dependsOn": [ - "[concat('Microsoft.Network/networkInterfaces/', parameters('nicName'))]" - ], - "location": "[variables('location')]", - "name": "[parameters('vmName')]", - "properties": { - "diagnosticsProfile": { - "bootDiagnostics": { - "enabled": false - } - }, - "hardwareProfile": { - "vmSize": "[parameters('vmSize')]" - }, - "networkProfile": { - "networkInterfaces": [ - { - "id": "[resourceId('Microsoft.Network/networkInterfaces', parameters('nicName'))]" - } - ] - }, - "osProfile": { - "adminUsername": "[parameters('adminUsername')]", - "computerName": "[parameters('vmName')]", - "linuxConfiguration": { - "disablePasswordAuthentication": true, - "ssh": { - "publicKeys": [ - { - "keyData": "--test-ssh-authorized-key--", - "path": "[variables('sshKeyPath')]" - } - ] - } - } - }, - "storageProfile": { - "imageReference": { - "offer": "UbuntuServer", - "publisher": "Canonical", - "sku": "16.04", - "version": "latest" - }, - "osDisk": { - "caching": "ReadWrite", - "createOption": "FromImage", - "name": "[parameters('osDiskName')]", - "vhd": { - "uri": "[concat(parameters('storageAccountBlobEndpoint'),variables('vmStorageAccountContainerName'),'/', parameters('osDiskName'),'.vhd')]" - } - } - } - }, - "type": "Microsoft.Compute/virtualMachines" - } - ], - "variables": { - "addressPrefix": "10.0.0.0/16", - "apiVersion": "2017-03-30", - "location": "[resourceGroup().location]", - "managedDiskApiVersion": "2017-03-30", - "networkInterfacesApiVersion": "2017-04-01", - "networkSecurityGroupsApiVersion": "2019-04-01", - "publicIPAddressApiVersion": "2017-04-01", - "publicIPAddressType": "Dynamic", - "sshKeyPath": "[concat('/home/',parameters('adminUsername'),'/.ssh/authorized_keys')]", - "subnetAddressPrefix": "10.0.0.0/24", - "subnetName": "[parameters('subnetName')]", - "subnetRef": "[concat(variables('vnetID'),'/subnets/',variables('subnetName'))]", - "virtualNetworkName": "[parameters('virtualNetworkName')]", - "virtualNetworkResourceGroup": "[resourceGroup().name]", - "virtualNetworksApiVersion": "2017-04-01", - "vmStorageAccountContainerName": "images", - "vnetID": "[resourceId(variables('virtualNetworkResourceGroup'), 'Microsoft.Network/virtualNetworks', variables('virtualNetworkName'))]" - } -} \ No newline at end of file diff --git a/builder/azure/common/template/template_builder_test.TestBuildLinux01.approved.json b/builder/azure/common/template/template_builder_test.TestBuildLinux01.approved.json deleted file mode 100644 index 981354c91..000000000 --- a/builder/azure/common/template/template_builder_test.TestBuildLinux01.approved.json +++ /dev/null @@ -1,180 +0,0 @@ -{ - "$schema": "http://schema.management.azure.com/schemas/2014-04-01-preview/deploymentTemplate.json", - "contentVersion": "1.0.0.0", - "parameters": { - "adminPassword": { - "type": "string" - }, - "adminUsername": { - "type": "string" - }, - "dataDiskName": { - "type": "string" - }, - "dnsNameForPublicIP": { - "type": "string" - }, - "nicName": { - "type": "string" - }, - "nsgName": { - "type": "string" - }, - "osDiskName": { - "type": "string" - }, - "publicIPAddressName": { - "type": "string" - }, - "storageAccountBlobEndpoint": { - "type": "string" - }, - "subnetName": { - "type": "string" - }, - "virtualNetworkName": { - "type": "string" - }, - "vmName": { - "type": "string" - }, - "vmSize": { - "type": "string" - } - }, - "resources": [ - { - "apiVersion": "[variables('publicIPAddressApiVersion')]", - "location": "[variables('location')]", - "name": "[parameters('publicIPAddressName')]", - "properties": { - "dnsSettings": { - "domainNameLabel": "[parameters('dnsNameForPublicIP')]" - }, - "publicIPAllocationMethod": "[variables('publicIPAddressType')]" - }, - "type": "Microsoft.Network/publicIPAddresses" - }, - { - "apiVersion": "[variables('virtualNetworksApiVersion')]", - "location": "[variables('location')]", - "name": "[variables('virtualNetworkName')]", - "properties": { - "addressSpace": { - "addressPrefixes": [ - "[variables('addressPrefix')]" - ] - }, - "subnets": [ - { - "name": "[variables('subnetName')]", - "properties": { - "addressPrefix": "[variables('subnetAddressPrefix')]" - } - } - ] - }, - "type": "Microsoft.Network/virtualNetworks" - }, - { - "apiVersion": "[variables('networkInterfacesApiVersion')]", - "dependsOn": [ - "[concat('Microsoft.Network/publicIPAddresses/', parameters('publicIPAddressName'))]", - "[concat('Microsoft.Network/virtualNetworks/', variables('virtualNetworkName'))]" - ], - "location": "[variables('location')]", - "name": "[parameters('nicName')]", - "properties": { - "ipConfigurations": [ - { - "name": "ipconfig", - "properties": { - "privateIPAllocationMethod": "Dynamic", - "publicIPAddress": { - "id": "[resourceId('Microsoft.Network/publicIPAddresses', parameters('publicIPAddressName'))]" - }, - "subnet": { - "id": "[variables('subnetRef')]" - } - } - } - ] - }, - "type": "Microsoft.Network/networkInterfaces" - }, - { - "apiVersion": "[variables('apiVersion')]", - "dependsOn": [ - "[concat('Microsoft.Network/networkInterfaces/', parameters('nicName'))]" - ], - "location": "[variables('location')]", - "name": "[parameters('vmName')]", - "properties": { - "diagnosticsProfile": { - "bootDiagnostics": { - "enabled": false - } - }, - "hardwareProfile": { - "vmSize": "[parameters('vmSize')]" - }, - "networkProfile": { - "networkInterfaces": [ - { - "id": "[resourceId('Microsoft.Network/networkInterfaces', parameters('nicName'))]" - } - ] - }, - "osProfile": { - "adminPassword": "[parameters('adminPassword')]", - "adminUsername": "[parameters('adminUsername')]", - "computerName": "[parameters('vmName')]", - "linuxConfiguration": { - "ssh": { - "publicKeys": [ - { - "keyData": "--test-ssh-authorized-key--", - "path": "[variables('sshKeyPath')]" - } - ] - } - } - }, - "storageProfile": { - "osDisk": { - "caching": "ReadWrite", - "createOption": "FromImage", - "image": { - "uri": "http://azure/custom.vhd" - }, - "name": "[parameters('osDiskName')]", - "osType": "Linux", - "vhd": { - "uri": "[concat(parameters('storageAccountBlobEndpoint'),variables('vmStorageAccountContainerName'),'/', parameters('osDiskName'),'.vhd')]" - } - } - } - }, - "type": "Microsoft.Compute/virtualMachines" - } - ], - "variables": { - "addressPrefix": "10.0.0.0/16", - "apiVersion": "2017-03-30", - "location": "[resourceGroup().location]", - "managedDiskApiVersion": "2017-03-30", - "networkInterfacesApiVersion": "2017-04-01", - "networkSecurityGroupsApiVersion": "2019-04-01", - "publicIPAddressApiVersion": "2017-04-01", - "publicIPAddressType": "Dynamic", - "sshKeyPath": "[concat('/home/',parameters('adminUsername'),'/.ssh/authorized_keys')]", - "subnetAddressPrefix": "10.0.0.0/24", - "subnetName": "[parameters('subnetName')]", - "subnetRef": "[concat(variables('vnetID'),'/subnets/',variables('subnetName'))]", - "virtualNetworkName": "[parameters('virtualNetworkName')]", - "virtualNetworkResourceGroup": "[resourceGroup().name]", - "virtualNetworksApiVersion": "2017-04-01", - "vmStorageAccountContainerName": "images", - "vnetID": "[resourceId(variables('virtualNetworkResourceGroup'), 'Microsoft.Network/virtualNetworks', variables('virtualNetworkName'))]" - } -} \ No newline at end of file diff --git a/builder/azure/common/template/template_builder_test.TestBuildLinux02.approved.json b/builder/azure/common/template/template_builder_test.TestBuildLinux02.approved.json deleted file mode 100644 index fc1441816..000000000 --- a/builder/azure/common/template/template_builder_test.TestBuildLinux02.approved.json +++ /dev/null @@ -1,142 +0,0 @@ -{ - "$schema": "http://schema.management.azure.com/schemas/2014-04-01-preview/deploymentTemplate.json", - "contentVersion": "1.0.0.0", - "parameters": { - "adminPassword": { - "type": "string" - }, - "adminUsername": { - "type": "string" - }, - "dataDiskName": { - "type": "string" - }, - "dnsNameForPublicIP": { - "type": "string" - }, - "nicName": { - "type": "string" - }, - "nsgName": { - "type": "string" - }, - "osDiskName": { - "type": "string" - }, - "publicIPAddressName": { - "type": "string" - }, - "storageAccountBlobEndpoint": { - "type": "string" - }, - "subnetName": { - "type": "string" - }, - "virtualNetworkName": { - "type": "string" - }, - "vmName": { - "type": "string" - }, - "vmSize": { - "type": "string" - } - }, - "resources": [ - { - "apiVersion": "[variables('networkInterfacesApiVersion')]", - "dependsOn": [], - "location": "[variables('location')]", - "name": "[parameters('nicName')]", - "properties": { - "ipConfigurations": [ - { - "name": "ipconfig", - "properties": { - "privateIPAllocationMethod": "Dynamic", - "subnet": { - "id": "[variables('subnetRef')]" - } - } - } - ] - }, - "type": "Microsoft.Network/networkInterfaces" - }, - { - "apiVersion": "[variables('apiVersion')]", - "dependsOn": [ - "[concat('Microsoft.Network/networkInterfaces/', parameters('nicName'))]" - ], - "location": "[variables('location')]", - "name": "[parameters('vmName')]", - "properties": { - "diagnosticsProfile": { - "bootDiagnostics": { - "enabled": false - } - }, - "hardwareProfile": { - "vmSize": "[parameters('vmSize')]" - }, - "networkProfile": { - "networkInterfaces": [ - { - "id": "[resourceId('Microsoft.Network/networkInterfaces', parameters('nicName'))]" - } - ] - }, - "osProfile": { - "adminUsername": "[parameters('adminUsername')]", - "computerName": "[parameters('vmName')]", - "linuxConfiguration": { - "disablePasswordAuthentication": true, - "ssh": { - "publicKeys": [ - { - "keyData": "--test-ssh-authorized-key--", - "path": "[variables('sshKeyPath')]" - } - ] - } - } - }, - "storageProfile": { - "osDisk": { - "caching": "ReadWrite", - "createOption": "FromImage", - "diskSizeGB": 100, - "image": { - "uri": "http://azure/custom.vhd" - }, - "name": "[parameters('osDiskName')]", - "osType": "Linux", - "vhd": { - "uri": "[concat(parameters('storageAccountBlobEndpoint'),variables('vmStorageAccountContainerName'),'/', parameters('osDiskName'),'.vhd')]" - } - } - } - }, - "type": "Microsoft.Compute/virtualMachines" - } - ], - "variables": { - "addressPrefix": "10.0.0.0/16", - "apiVersion": "2017-03-30", - "location": "[resourceGroup().location]", - "managedDiskApiVersion": "2017-03-30", - "networkInterfacesApiVersion": "2017-04-01", - "networkSecurityGroupsApiVersion": "2019-04-01", - "publicIPAddressApiVersion": "2017-04-01", - "publicIPAddressType": "Dynamic", - "sshKeyPath": "[concat('/home/',parameters('adminUsername'),'/.ssh/authorized_keys')]", - "subnetAddressPrefix": "10.0.0.0/24", - "subnetName": "--subnet-name--", - "subnetRef": "[concat(variables('vnetID'),'/subnets/',variables('subnetName'))]", - "virtualNetworkName": "--virtual-network--", - "virtualNetworkResourceGroup": "--virtual-network-resource-group--", - "virtualNetworksApiVersion": "2017-04-01", - "vmStorageAccountContainerName": "images", - "vnetID": "[resourceId(variables('virtualNetworkResourceGroup'), 'Microsoft.Network/virtualNetworks', variables('virtualNetworkName'))]" - } -} \ No newline at end of file diff --git a/builder/azure/common/template/template_builder_test.TestBuildWindows00.approved.json b/builder/azure/common/template/template_builder_test.TestBuildWindows00.approved.json deleted file mode 100644 index 1c29ee885..000000000 --- a/builder/azure/common/template/template_builder_test.TestBuildWindows00.approved.json +++ /dev/null @@ -1,196 +0,0 @@ -{ - "$schema": "http://schema.management.azure.com/schemas/2014-04-01-preview/deploymentTemplate.json", - "contentVersion": "1.0.0.0", - "parameters": { - "adminPassword": { - "type": "string" - }, - "adminUsername": { - "type": "string" - }, - "dataDiskName": { - "type": "string" - }, - "dnsNameForPublicIP": { - "type": "string" - }, - "nicName": { - "type": "string" - }, - "nsgName": { - "type": "string" - }, - "osDiskName": { - "type": "string" - }, - "publicIPAddressName": { - "type": "string" - }, - "storageAccountBlobEndpoint": { - "type": "string" - }, - "subnetName": { - "type": "string" - }, - "virtualNetworkName": { - "type": "string" - }, - "vmName": { - "type": "string" - }, - "vmSize": { - "type": "string" - } - }, - "resources": [ - { - "apiVersion": "[variables('publicIPAddressApiVersion')]", - "location": "[variables('location')]", - "name": "[parameters('publicIPAddressName')]", - "properties": { - "dnsSettings": { - "domainNameLabel": "[parameters('dnsNameForPublicIP')]" - }, - "publicIPAllocationMethod": "[variables('publicIPAddressType')]" - }, - "type": "Microsoft.Network/publicIPAddresses" - }, - { - "apiVersion": "[variables('virtualNetworksApiVersion')]", - "location": "[variables('location')]", - "name": "[variables('virtualNetworkName')]", - "properties": { - "addressSpace": { - "addressPrefixes": [ - "[variables('addressPrefix')]" - ] - }, - "subnets": [ - { - "name": "[variables('subnetName')]", - "properties": { - "addressPrefix": "[variables('subnetAddressPrefix')]" - } - } - ] - }, - "type": "Microsoft.Network/virtualNetworks" - }, - { - "apiVersion": "[variables('networkInterfacesApiVersion')]", - "dependsOn": [ - "[concat('Microsoft.Network/publicIPAddresses/', parameters('publicIPAddressName'))]", - "[concat('Microsoft.Network/virtualNetworks/', variables('virtualNetworkName'))]" - ], - "location": "[variables('location')]", - "name": "[parameters('nicName')]", - "properties": { - "ipConfigurations": [ - { - "name": "ipconfig", - "properties": { - "privateIPAllocationMethod": "Dynamic", - "publicIPAddress": { - "id": "[resourceId('Microsoft.Network/publicIPAddresses', parameters('publicIPAddressName'))]" - }, - "subnet": { - "id": "[variables('subnetRef')]" - } - } - } - ] - }, - "type": "Microsoft.Network/networkInterfaces" - }, - { - "apiVersion": "[variables('apiVersion')]", - "dependsOn": [ - "[concat('Microsoft.Network/networkInterfaces/', parameters('nicName'))]" - ], - "location": "[variables('location')]", - "name": "[parameters('vmName')]", - "properties": { - "diagnosticsProfile": { - "bootDiagnostics": { - "enabled": false - } - }, - "hardwareProfile": { - "vmSize": "[parameters('vmSize')]" - }, - "networkProfile": { - "networkInterfaces": [ - { - "id": "[resourceId('Microsoft.Network/networkInterfaces', parameters('nicName'))]" - } - ] - }, - "osProfile": { - "adminPassword": "[parameters('adminPassword')]", - "adminUsername": "[parameters('adminUsername')]", - "computerName": "[parameters('vmName')]", - "secrets": [ - { - "sourceVault": { - "id": "[resourceId(resourceGroup().name, 'Microsoft.KeyVault/vaults', '--test-key-vault-name')]" - }, - "vaultCertificates": [ - { - "certificateStore": "My", - "certificateUrl": "--test-winrm-certificate-url--" - } - ] - } - ], - "windowsConfiguration": { - "provisionVMAgent": true, - "winRM": { - "listeners": [ - { - "certificateUrl": "--test-winrm-certificate-url--", - "protocol": "https" - } - ] - } - } - }, - "storageProfile": { - "imageReference": { - "offer": "WindowsServer", - "publisher": "MicrosoftWindowsServer", - "sku": "2012-R2-Datacenter", - "version": "latest" - }, - "osDisk": { - "caching": "ReadWrite", - "createOption": "FromImage", - "name": "[parameters('osDiskName')]", - "vhd": { - "uri": "[concat(parameters('storageAccountBlobEndpoint'),variables('vmStorageAccountContainerName'),'/', parameters('osDiskName'),'.vhd')]" - } - } - } - }, - "type": "Microsoft.Compute/virtualMachines" - } - ], - "variables": { - "addressPrefix": "10.0.0.0/16", - "apiVersion": "2017-03-30", - "location": "[resourceGroup().location]", - "managedDiskApiVersion": "2017-03-30", - "networkInterfacesApiVersion": "2017-04-01", - "networkSecurityGroupsApiVersion": "2019-04-01", - "publicIPAddressApiVersion": "2017-04-01", - "publicIPAddressType": "Dynamic", - "sshKeyPath": "[concat('/home/',parameters('adminUsername'),'/.ssh/authorized_keys')]", - "subnetAddressPrefix": "10.0.0.0/24", - "subnetName": "[parameters('subnetName')]", - "subnetRef": "[concat(variables('vnetID'),'/subnets/',variables('subnetName'))]", - "virtualNetworkName": "[parameters('virtualNetworkName')]", - "virtualNetworkResourceGroup": "[resourceGroup().name]", - "virtualNetworksApiVersion": "2017-04-01", - "vmStorageAccountContainerName": "images", - "vnetID": "[resourceId(variables('virtualNetworkResourceGroup'), 'Microsoft.Network/virtualNetworks', variables('virtualNetworkName'))]" - } -} \ No newline at end of file diff --git a/builder/azure/common/template/template_builder_test.TestBuildWindows01.approved.json b/builder/azure/common/template/template_builder_test.TestBuildWindows01.approved.json deleted file mode 100644 index 9c094ef04..000000000 --- a/builder/azure/common/template/template_builder_test.TestBuildWindows01.approved.json +++ /dev/null @@ -1,219 +0,0 @@ -{ - "$schema": "http://schema.management.azure.com/schemas/2014-04-01-preview/deploymentTemplate.json", - "contentVersion": "1.0.0.0", - "parameters": { - "adminPassword": { - "type": "string" - }, - "adminUsername": { - "type": "string" - }, - "dataDiskName": { - "type": "string" - }, - "dnsNameForPublicIP": { - "type": "string" - }, - "nicName": { - "type": "string" - }, - "nsgName": { - "type": "string" - }, - "osDiskName": { - "type": "string" - }, - "publicIPAddressName": { - "type": "string" - }, - "storageAccountBlobEndpoint": { - "type": "string" - }, - "subnetName": { - "type": "string" - }, - "virtualNetworkName": { - "type": "string" - }, - "vmName": { - "type": "string" - }, - "vmSize": { - "type": "string" - } - }, - "resources": [ - { - "apiVersion": "[variables('publicIPAddressApiVersion')]", - "location": "[variables('location')]", - "name": "[parameters('publicIPAddressName')]", - "properties": { - "dnsSettings": { - "domainNameLabel": "[parameters('dnsNameForPublicIP')]" - }, - "publicIPAllocationMethod": "[variables('publicIPAddressType')]" - }, - "type": "Microsoft.Network/publicIPAddresses" - }, - { - "apiVersion": "[variables('virtualNetworksApiVersion')]", - "location": "[variables('location')]", - "name": "[variables('virtualNetworkName')]", - "properties": { - "addressSpace": { - "addressPrefixes": [ - "[variables('addressPrefix')]" - ] - }, - "subnets": [ - { - "name": "[variables('subnetName')]", - "properties": { - "addressPrefix": "[variables('subnetAddressPrefix')]" - } - } - ] - }, - "type": "Microsoft.Network/virtualNetworks" - }, - { - "apiVersion": "[variables('networkInterfacesApiVersion')]", - "dependsOn": [ - "[concat('Microsoft.Network/publicIPAddresses/', parameters('publicIPAddressName'))]", - "[concat('Microsoft.Network/virtualNetworks/', variables('virtualNetworkName'))]" - ], - "location": "[variables('location')]", - "name": "[parameters('nicName')]", - "properties": { - "ipConfigurations": [ - { - "name": "ipconfig", - "properties": { - "privateIPAllocationMethod": "Dynamic", - "publicIPAddress": { - "id": "[resourceId('Microsoft.Network/publicIPAddresses', parameters('publicIPAddressName'))]" - }, - "subnet": { - "id": "[variables('subnetRef')]" - } - } - } - ] - }, - "type": "Microsoft.Network/networkInterfaces" - }, - { - "apiVersion": "[variables('apiVersion')]", - "dependsOn": [ - "[concat('Microsoft.Network/networkInterfaces/', parameters('nicName'))]" - ], - "location": "[variables('location')]", - "name": "[parameters('vmName')]", - "properties": { - "diagnosticsProfile": { - "bootDiagnostics": { - "enabled": false - } - }, - "hardwareProfile": { - "vmSize": "[parameters('vmSize')]" - }, - "networkProfile": { - "networkInterfaces": [ - { - "id": "[resourceId('Microsoft.Network/networkInterfaces', parameters('nicName'))]" - } - ] - }, - "osProfile": { - "adminPassword": "[parameters('adminPassword')]", - "adminUsername": "[parameters('adminUsername')]", - "computerName": "[parameters('vmName')]", - "secrets": [ - { - "sourceVault": { - "id": "[resourceId(resourceGroup().name, 'Microsoft.KeyVault/vaults', '--test-key-vault-name')]" - }, - "vaultCertificates": [ - { - "certificateStore": "My", - "certificateUrl": "--test-winrm-certificate-url--" - } - ] - } - ], - "windowsConfiguration": { - "provisionVMAgent": true, - "winRM": { - "listeners": [ - { - "certificateUrl": "--test-winrm-certificate-url--", - "protocol": "https" - } - ] - } - } - }, - "storageProfile": { - "dataDisks": [ - { - "caching": "ReadWrite", - "createOption": "Empty", - "diskSizeGB": 32, - "lun": 0, - "managedDisk": { - "storageAccountType": "Premium_LRS" - }, - "name": "[concat(parameters('dataDiskName'),'-1')]" - }, - { - "caching": "ReadWrite", - "createOption": "Empty", - "diskSizeGB": 64, - "lun": 1, - "managedDisk": { - "storageAccountType": "Premium_LRS" - }, - "name": "[concat(parameters('dataDiskName'),'-2')]" - } - ], - "imageReference": { - "offer": "2012-R2-Datacenter", - "publisher": "WindowsServer", - "sku": "latest", - "version": "2015-1" - }, - "osDisk": { - "caching": "ReadWrite", - "createOption": "FromImage", - "managedDisk": { - "storageAccountType": "Premium_LRS" - }, - "name": "[parameters('osDiskName')]", - "osType": "Windows" - } - } - }, - "type": "Microsoft.Compute/virtualMachines" - } - ], - "variables": { - "addressPrefix": "10.0.0.0/16", - "apiVersion": "2017-03-30", - "location": "[resourceGroup().location]", - "managedDiskApiVersion": "2017-03-30", - "networkInterfacesApiVersion": "2017-04-01", - "networkSecurityGroupsApiVersion": "2019-04-01", - "publicIPAddressApiVersion": "2017-04-01", - "publicIPAddressType": "Dynamic", - "sshKeyPath": "[concat('/home/',parameters('adminUsername'),'/.ssh/authorized_keys')]", - "subnetAddressPrefix": "10.0.0.0/24", - "subnetName": "[parameters('subnetName')]", - "subnetRef": "[concat(variables('vnetID'),'/subnets/',variables('subnetName'))]", - "virtualNetworkName": "[parameters('virtualNetworkName')]", - "virtualNetworkResourceGroup": "[resourceGroup().name]", - "virtualNetworksApiVersion": "2017-04-01", - "vmStorageAccountContainerName": "images", - "vnetID": "[resourceId(variables('virtualNetworkResourceGroup'), 'Microsoft.Network/virtualNetworks', variables('virtualNetworkName'))]" - } -} \ No newline at end of file diff --git a/builder/azure/common/template/template_builder_test.TestBuildWindows02.approved.json b/builder/azure/common/template/template_builder_test.TestBuildWindows02.approved.json deleted file mode 100644 index 281b8db83..000000000 --- a/builder/azure/common/template/template_builder_test.TestBuildWindows02.approved.json +++ /dev/null @@ -1,212 +0,0 @@ -{ - "$schema": "http://schema.management.azure.com/schemas/2014-04-01-preview/deploymentTemplate.json", - "contentVersion": "1.0.0.0", - "parameters": { - "adminPassword": { - "type": "string" - }, - "adminUsername": { - "type": "string" - }, - "dataDiskName": { - "type": "string" - }, - "dnsNameForPublicIP": { - "type": "string" - }, - "nicName": { - "type": "string" - }, - "nsgName": { - "type": "string" - }, - "osDiskName": { - "type": "string" - }, - "publicIPAddressName": { - "type": "string" - }, - "storageAccountBlobEndpoint": { - "type": "string" - }, - "subnetName": { - "type": "string" - }, - "virtualNetworkName": { - "type": "string" - }, - "vmName": { - "type": "string" - }, - "vmSize": { - "type": "string" - } - }, - "resources": [ - { - "apiVersion": "[variables('publicIPAddressApiVersion')]", - "location": "[variables('location')]", - "name": "[parameters('publicIPAddressName')]", - "properties": { - "dnsSettings": { - "domainNameLabel": "[parameters('dnsNameForPublicIP')]" - }, - "publicIPAllocationMethod": "[variables('publicIPAddressType')]" - }, - "type": "Microsoft.Network/publicIPAddresses" - }, - { - "apiVersion": "[variables('virtualNetworksApiVersion')]", - "location": "[variables('location')]", - "name": "[variables('virtualNetworkName')]", - "properties": { - "addressSpace": { - "addressPrefixes": [ - "[variables('addressPrefix')]" - ] - }, - "subnets": [ - { - "name": "[variables('subnetName')]", - "properties": { - "addressPrefix": "[variables('subnetAddressPrefix')]" - } - } - ] - }, - "type": "Microsoft.Network/virtualNetworks" - }, - { - "apiVersion": "[variables('networkInterfacesApiVersion')]", - "dependsOn": [ - "[concat('Microsoft.Network/publicIPAddresses/', parameters('publicIPAddressName'))]", - "[concat('Microsoft.Network/virtualNetworks/', variables('virtualNetworkName'))]" - ], - "location": "[variables('location')]", - "name": "[parameters('nicName')]", - "properties": { - "ipConfigurations": [ - { - "name": "ipconfig", - "properties": { - "privateIPAllocationMethod": "Dynamic", - "publicIPAddress": { - "id": "[resourceId('Microsoft.Network/publicIPAddresses', parameters('publicIPAddressName'))]" - }, - "subnet": { - "id": "[variables('subnetRef')]" - } - } - } - ] - }, - "type": "Microsoft.Network/networkInterfaces" - }, - { - "apiVersion": "[variables('apiVersion')]", - "dependsOn": [ - "[concat('Microsoft.Network/networkInterfaces/', parameters('nicName'))]" - ], - "location": "[variables('location')]", - "name": "[parameters('vmName')]", - "properties": { - "diagnosticsProfile": { - "bootDiagnostics": { - "enabled": false - } - }, - "hardwareProfile": { - "vmSize": "[parameters('vmSize')]" - }, - "networkProfile": { - "networkInterfaces": [ - { - "id": "[resourceId('Microsoft.Network/networkInterfaces', parameters('nicName'))]" - } - ] - }, - "osProfile": { - "adminPassword": "[parameters('adminPassword')]", - "adminUsername": "[parameters('adminUsername')]", - "computerName": "[parameters('vmName')]", - "secrets": [ - { - "sourceVault": { - "id": "[resourceId(resourceGroup().name, 'Microsoft.KeyVault/vaults', '--test-key-vault-name')]" - }, - "vaultCertificates": [ - { - "certificateStore": "My", - "certificateUrl": "--test-winrm-certificate-url--" - } - ] - } - ], - "windowsConfiguration": { - "provisionVMAgent": true, - "winRM": { - "listeners": [ - { - "certificateUrl": "--test-winrm-certificate-url--", - "protocol": "https" - } - ] - } - } - }, - "storageProfile": { - "dataDisks": [ - { - "caching": "ReadWrite", - "createOption": "Empty", - "diskSizeGB": 32, - "lun": 0, - "name": "[concat(parameters('dataDiskName'),'-1')]", - "vhd": { - "uri": "[concat(parameters('storageAccountBlobEndpoint'),variables('vmStorageAccountContainerName'),'/',parameters('dataDiskName'),'-1','.vhd')]" - } - }, - { - "caching": "ReadWrite", - "createOption": "Empty", - "diskSizeGB": 64, - "lun": 1, - "name": "[concat(parameters('dataDiskName'),'-2')]", - "vhd": { - "uri": "[concat(parameters('storageAccountBlobEndpoint'),variables('vmStorageAccountContainerName'),'/',parameters('dataDiskName'),'-2','.vhd')]" - } - } - ], - "osDisk": { - "caching": "ReadWrite", - "createOption": "FromImage", - "name": "[parameters('osDiskName')]", - "vhd": { - "uri": "[concat(parameters('storageAccountBlobEndpoint'),variables('vmStorageAccountContainerName'),'/', parameters('osDiskName'),'.vhd')]" - } - } - } - }, - "type": "Microsoft.Compute/virtualMachines" - } - ], - "variables": { - "addressPrefix": "10.0.0.0/16", - "apiVersion": "2017-03-30", - "location": "[resourceGroup().location]", - "managedDiskApiVersion": "2017-03-30", - "networkInterfacesApiVersion": "2017-04-01", - "networkSecurityGroupsApiVersion": "2019-04-01", - "publicIPAddressApiVersion": "2017-04-01", - "publicIPAddressType": "Dynamic", - "sshKeyPath": "[concat('/home/',parameters('adminUsername'),'/.ssh/authorized_keys')]", - "subnetAddressPrefix": "10.0.0.0/24", - "subnetName": "[parameters('subnetName')]", - "subnetRef": "[concat(variables('vnetID'),'/subnets/',variables('subnetName'))]", - "virtualNetworkName": "[parameters('virtualNetworkName')]", - "virtualNetworkResourceGroup": "[resourceGroup().name]", - "virtualNetworksApiVersion": "2017-04-01", - "vmStorageAccountContainerName": "images", - "vnetID": "[resourceId(variables('virtualNetworkResourceGroup'), 'Microsoft.Network/virtualNetworks', variables('virtualNetworkName'))]" - } -} \ No newline at end of file diff --git a/builder/azure/common/template/template_builder_test.TestNetworkSecurityGroup00.approved.json b/builder/azure/common/template/template_builder_test.TestNetworkSecurityGroup00.approved.json deleted file mode 100644 index 7415524d7..000000000 --- a/builder/azure/common/template/template_builder_test.TestNetworkSecurityGroup00.approved.json +++ /dev/null @@ -1,215 +0,0 @@ -{ - "$schema": "http://schema.management.azure.com/schemas/2014-04-01-preview/deploymentTemplate.json", - "contentVersion": "1.0.0.0", - "parameters": { - "adminPassword": { - "type": "string" - }, - "adminUsername": { - "type": "string" - }, - "dataDiskName": { - "type": "string" - }, - "dnsNameForPublicIP": { - "type": "string" - }, - "nicName": { - "type": "string" - }, - "nsgName": { - "type": "string" - }, - "osDiskName": { - "type": "string" - }, - "publicIPAddressName": { - "type": "string" - }, - "storageAccountBlobEndpoint": { - "type": "string" - }, - "subnetName": { - "type": "string" - }, - "virtualNetworkName": { - "type": "string" - }, - "vmName": { - "type": "string" - }, - "vmSize": { - "type": "string" - } - }, - "resources": [ - { - "apiVersion": "[variables('publicIPAddressApiVersion')]", - "location": "[variables('location')]", - "name": "[parameters('publicIPAddressName')]", - "properties": { - "dnsSettings": { - "domainNameLabel": "[parameters('dnsNameForPublicIP')]" - }, - "publicIPAllocationMethod": "[variables('publicIPAddressType')]" - }, - "type": "Microsoft.Network/publicIPAddresses" - }, - { - "apiVersion": "[variables('networkInterfacesApiVersion')]", - "dependsOn": [ - "[concat('Microsoft.Network/publicIPAddresses/', parameters('publicIPAddressName'))]", - "[concat('Microsoft.Network/virtualNetworks/', variables('virtualNetworkName'))]" - ], - "location": "[variables('location')]", - "name": "[parameters('nicName')]", - "properties": { - "ipConfigurations": [ - { - "name": "ipconfig", - "properties": { - "privateIPAllocationMethod": "Dynamic", - "publicIPAddress": { - "id": "[resourceId('Microsoft.Network/publicIPAddresses', parameters('publicIPAddressName'))]" - }, - "subnet": { - "id": "[variables('subnetRef')]" - } - } - } - ] - }, - "type": "Microsoft.Network/networkInterfaces" - }, - { - "apiVersion": "[variables('apiVersion')]", - "dependsOn": [ - "[concat('Microsoft.Network/networkInterfaces/', parameters('nicName'))]" - ], - "location": "[variables('location')]", - "name": "[parameters('vmName')]", - "properties": { - "diagnosticsProfile": { - "bootDiagnostics": { - "enabled": false - } - }, - "hardwareProfile": { - "vmSize": "[parameters('vmSize')]" - }, - "networkProfile": { - "networkInterfaces": [ - { - "id": "[resourceId('Microsoft.Network/networkInterfaces', parameters('nicName'))]" - } - ] - }, - "osProfile": { - "adminPassword": "[parameters('adminPassword')]", - "adminUsername": "[parameters('adminUsername')]", - "computerName": "[parameters('vmName')]", - "linuxConfiguration": { - "ssh": { - "publicKeys": [ - { - "keyData": "--test-ssh-authorized-key--", - "path": "[variables('sshKeyPath')]" - } - ] - } - } - }, - "storageProfile": { - "imageReference": { - "offer": "UbuntuServer", - "publisher": "Canonical", - "sku": "16.04", - "version": "latest" - }, - "osDisk": { - "caching": "ReadWrite", - "createOption": "FromImage", - "name": "[parameters('osDiskName')]", - "vhd": { - "uri": "[concat(parameters('storageAccountBlobEndpoint'),variables('vmStorageAccountContainerName'),'/', parameters('osDiskName'),'.vhd')]" - } - } - } - }, - "type": "Microsoft.Compute/virtualMachines" - }, - { - "apiVersion": "[variables('networkSecurityGroupsApiVersion')]", - "location": "[variables('location')]", - "name": "[parameters('nsgName')]", - "properties": { - "securityRules": [ - { - "name": "AllowIPsToSshWinRMInbound", - "properties": { - "access": "Allow", - "description": "Allow inbound traffic from specified IP addresses", - "destinationAddressPrefix": "VirtualNetwork", - "destinationPortRange": "123", - "direction": "Inbound", - "priority": 100, - "protocol": "Tcp", - "sourceAddressPrefixes": [ - "127.0.0.1", - "192.168.100.0/24" - ], - "sourcePortRange": "*" - } - } - ] - }, - "type": "Microsoft.Network/networkSecurityGroups" - }, - { - "apiVersion": "[variables('virtualNetworksApiVersion')]", - "dependsOn": [ - "[concat('Microsoft.Network/networkSecurityGroups/', parameters('nsgName'))]" - ], - "location": "[variables('location')]", - "name": "[variables('virtualNetworkName')]", - "properties": { - "addressSpace": { - "addressPrefixes": [ - "[variables('addressPrefix')]" - ] - }, - "subnets": [ - { - "name": "[variables('subnetName')]", - "properties": { - "addressPrefix": "[variables('subnetAddressPrefix')]", - "networkSecurityGroup": { - "id": "[resourceId('Microsoft.Network/networkSecurityGroups', parameters('nsgName'))]" - } - } - } - ] - }, - "type": "Microsoft.Network/virtualNetworks" - } - ], - "variables": { - "addressPrefix": "10.0.0.0/16", - "apiVersion": "2017-03-30", - "location": "[resourceGroup().location]", - "managedDiskApiVersion": "2017-03-30", - "networkInterfacesApiVersion": "2017-04-01", - "networkSecurityGroupsApiVersion": "2019-04-01", - "publicIPAddressApiVersion": "2017-04-01", - "publicIPAddressType": "Dynamic", - "sshKeyPath": "[concat('/home/',parameters('adminUsername'),'/.ssh/authorized_keys')]", - "subnetAddressPrefix": "10.0.0.0/24", - "subnetName": "[parameters('subnetName')]", - "subnetRef": "[concat(variables('vnetID'),'/subnets/',variables('subnetName'))]", - "virtualNetworkName": "[parameters('virtualNetworkName')]", - "virtualNetworkResourceGroup": "[resourceGroup().name]", - "virtualNetworksApiVersion": "2017-04-01", - "vmStorageAccountContainerName": "images", - "vnetID": "[resourceId(variables('virtualNetworkResourceGroup'), 'Microsoft.Network/virtualNetworks', variables('virtualNetworkName'))]" - } -} \ No newline at end of file diff --git a/builder/azure/common/template/template_builder_test.TestSetIdentity00.approved.json b/builder/azure/common/template/template_builder_test.TestSetIdentity00.approved.json deleted file mode 100644 index 606ebadba..000000000 --- a/builder/azure/common/template/template_builder_test.TestSetIdentity00.approved.json +++ /dev/null @@ -1,188 +0,0 @@ -{ - "$schema": "http://schema.management.azure.com/schemas/2014-04-01-preview/deploymentTemplate.json", - "contentVersion": "1.0.0.0", - "parameters": { - "adminPassword": { - "type": "string" - }, - "adminUsername": { - "type": "string" - }, - "dataDiskName": { - "type": "string" - }, - "dnsNameForPublicIP": { - "type": "string" - }, - "nicName": { - "type": "string" - }, - "nsgName": { - "type": "string" - }, - "osDiskName": { - "type": "string" - }, - "publicIPAddressName": { - "type": "string" - }, - "storageAccountBlobEndpoint": { - "type": "string" - }, - "subnetName": { - "type": "string" - }, - "virtualNetworkName": { - "type": "string" - }, - "vmName": { - "type": "string" - }, - "vmSize": { - "type": "string" - } - }, - "resources": [ - { - "apiVersion": "[variables('publicIPAddressApiVersion')]", - "location": "[variables('location')]", - "name": "[parameters('publicIPAddressName')]", - "properties": { - "dnsSettings": { - "domainNameLabel": "[parameters('dnsNameForPublicIP')]" - }, - "publicIPAllocationMethod": "[variables('publicIPAddressType')]" - }, - "type": "Microsoft.Network/publicIPAddresses" - }, - { - "apiVersion": "[variables('virtualNetworksApiVersion')]", - "location": "[variables('location')]", - "name": "[variables('virtualNetworkName')]", - "properties": { - "addressSpace": { - "addressPrefixes": [ - "[variables('addressPrefix')]" - ] - }, - "subnets": [ - { - "name": "[variables('subnetName')]", - "properties": { - "addressPrefix": "[variables('subnetAddressPrefix')]" - } - } - ] - }, - "type": "Microsoft.Network/virtualNetworks" - }, - { - "apiVersion": "[variables('networkInterfacesApiVersion')]", - "dependsOn": [ - "[concat('Microsoft.Network/publicIPAddresses/', parameters('publicIPAddressName'))]", - "[concat('Microsoft.Network/virtualNetworks/', variables('virtualNetworkName'))]" - ], - "location": "[variables('location')]", - "name": "[parameters('nicName')]", - "properties": { - "ipConfigurations": [ - { - "name": "ipconfig", - "properties": { - "privateIPAllocationMethod": "Dynamic", - "publicIPAddress": { - "id": "[resourceId('Microsoft.Network/publicIPAddresses', parameters('publicIPAddressName'))]" - }, - "subnet": { - "id": "[variables('subnetRef')]" - } - } - } - ] - }, - "type": "Microsoft.Network/networkInterfaces" - }, - { - "apiVersion": "[variables('apiVersion')]", - "dependsOn": [ - "[concat('Microsoft.Network/networkInterfaces/', parameters('nicName'))]" - ], - "identity": { - "type": "UserAssigned", - "userAssignedIdentities": { - "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/rg1/providers/Microsoft.ManagedIdentity/userAssignedIdentities/id": {} - } - }, - "location": "[variables('location')]", - "name": "[parameters('vmName')]", - "properties": { - "diagnosticsProfile": { - "bootDiagnostics": { - "enabled": false - } - }, - "hardwareProfile": { - "vmSize": "[parameters('vmSize')]" - }, - "networkProfile": { - "networkInterfaces": [ - { - "id": "[resourceId('Microsoft.Network/networkInterfaces', parameters('nicName'))]" - } - ] - }, - "osProfile": { - "adminUsername": "[parameters('adminUsername')]", - "computerName": "[parameters('vmName')]", - "linuxConfiguration": { - "disablePasswordAuthentication": true, - "ssh": { - "publicKeys": [ - { - "keyData": "--test-ssh-authorized-key--", - "path": "[variables('sshKeyPath')]" - } - ] - } - } - }, - "storageProfile": { - "imageReference": { - "offer": "UbuntuServer", - "publisher": "Canonical", - "sku": "16.04", - "version": "latest" - }, - "osDisk": { - "caching": "ReadWrite", - "createOption": "FromImage", - "name": "[parameters('osDiskName')]", - "vhd": { - "uri": "[concat(parameters('storageAccountBlobEndpoint'),variables('vmStorageAccountContainerName'),'/', parameters('osDiskName'),'.vhd')]" - } - } - } - }, - "type": "Microsoft.Compute/virtualMachines" - } - ], - "variables": { - "addressPrefix": "10.0.0.0/16", - "apiVersion": "2018-06-01", - "location": "[resourceGroup().location]", - "managedDiskApiVersion": "2017-03-30", - "networkInterfacesApiVersion": "2017-04-01", - "networkSecurityGroupsApiVersion": "2019-04-01", - "publicIPAddressApiVersion": "2017-04-01", - "publicIPAddressType": "Dynamic", - "sshKeyPath": "[concat('/home/',parameters('adminUsername'),'/.ssh/authorized_keys')]", - "subnetAddressPrefix": "10.0.0.0/24", - "subnetName": "[parameters('subnetName')]", - "subnetRef": "[concat(variables('vnetID'),'/subnets/',variables('subnetName'))]", - "virtualNetworkName": "[parameters('virtualNetworkName')]", - "virtualNetworkResourceGroup": "[resourceGroup().name]", - "virtualNetworksApiVersion": "2017-04-01", - "vmStorageAccountContainerName": "images", - "vnetID": "[resourceId(variables('virtualNetworkResourceGroup'), 'Microsoft.Network/virtualNetworks', variables('virtualNetworkName'))]" - } -} \ No newline at end of file diff --git a/builder/azure/common/template/template_builder_test.TestSharedImageGallery00.approved.json b/builder/azure/common/template/template_builder_test.TestSharedImageGallery00.approved.json deleted file mode 100644 index 98602fd16..000000000 --- a/builder/azure/common/template/template_builder_test.TestSharedImageGallery00.approved.json +++ /dev/null @@ -1,177 +0,0 @@ -{ - "$schema": "http://schema.management.azure.com/schemas/2014-04-01-preview/deploymentTemplate.json", - "contentVersion": "1.0.0.0", - "parameters": { - "adminPassword": { - "type": "string" - }, - "adminUsername": { - "type": "string" - }, - "dataDiskName": { - "type": "string" - }, - "dnsNameForPublicIP": { - "type": "string" - }, - "nicName": { - "type": "string" - }, - "nsgName": { - "type": "string" - }, - "osDiskName": { - "type": "string" - }, - "publicIPAddressName": { - "type": "string" - }, - "storageAccountBlobEndpoint": { - "type": "string" - }, - "subnetName": { - "type": "string" - }, - "virtualNetworkName": { - "type": "string" - }, - "vmName": { - "type": "string" - }, - "vmSize": { - "type": "string" - } - }, - "resources": [ - { - "apiVersion": "[variables('publicIPAddressApiVersion')]", - "location": "[variables('location')]", - "name": "[parameters('publicIPAddressName')]", - "properties": { - "dnsSettings": { - "domainNameLabel": "[parameters('dnsNameForPublicIP')]" - }, - "publicIPAllocationMethod": "[variables('publicIPAddressType')]" - }, - "type": "Microsoft.Network/publicIPAddresses" - }, - { - "apiVersion": "[variables('virtualNetworksApiVersion')]", - "location": "[variables('location')]", - "name": "[variables('virtualNetworkName')]", - "properties": { - "addressSpace": { - "addressPrefixes": [ - "[variables('addressPrefix')]" - ] - }, - "subnets": [ - { - "name": "[variables('subnetName')]", - "properties": { - "addressPrefix": "[variables('subnetAddressPrefix')]" - } - } - ] - }, - "type": "Microsoft.Network/virtualNetworks" - }, - { - "apiVersion": "[variables('networkInterfacesApiVersion')]", - "dependsOn": [ - "[concat('Microsoft.Network/publicIPAddresses/', parameters('publicIPAddressName'))]", - "[concat('Microsoft.Network/virtualNetworks/', variables('virtualNetworkName'))]" - ], - "location": "[variables('location')]", - "name": "[parameters('nicName')]", - "properties": { - "ipConfigurations": [ - { - "name": "ipconfig", - "properties": { - "privateIPAllocationMethod": "Dynamic", - "publicIPAddress": { - "id": "[resourceId('Microsoft.Network/publicIPAddresses', parameters('publicIPAddressName'))]" - }, - "subnet": { - "id": "[variables('subnetRef')]" - } - } - } - ] - }, - "type": "Microsoft.Network/networkInterfaces" - }, - { - "apiVersion": "[variables('apiVersion')]", - "dependsOn": [ - "[concat('Microsoft.Network/networkInterfaces/', parameters('nicName'))]" - ], - "location": "[variables('location')]", - "name": "[parameters('vmName')]", - "properties": { - "diagnosticsProfile": { - "bootDiagnostics": { - "enabled": false - } - }, - "hardwareProfile": { - "vmSize": "[parameters('vmSize')]" - }, - "networkProfile": { - "networkInterfaces": [ - { - "id": "[resourceId('Microsoft.Network/networkInterfaces', parameters('nicName'))]" - } - ] - }, - "osProfile": { - "adminPassword": "[parameters('adminPassword')]", - "adminUsername": "[parameters('adminUsername')]", - "computerName": "[parameters('vmName')]", - "linuxConfiguration": { - "ssh": { - "publicKeys": [ - { - "keyData": "--test-ssh-authorized-key--", - "path": "[variables('sshKeyPath')]" - } - ] - } - } - }, - "storageProfile": { - "imageReference": { - "id": "/subscriptions/ignore/resourceGroups/ignore/providers/Microsoft.Compute/galleries/ignore/images/ignore" - }, - "osDisk": { - "caching": "ReadOnly", - "createOption": "FromImage", - "name": "[parameters('osDiskName')]", - "osType": "Linux" - } - } - }, - "type": "Microsoft.Compute/virtualMachines" - } - ], - "variables": { - "addressPrefix": "10.0.0.0/16", - "apiVersion": "2018-06-01", - "location": "[resourceGroup().location]", - "managedDiskApiVersion": "2017-03-30", - "networkInterfacesApiVersion": "2017-04-01", - "networkSecurityGroupsApiVersion": "2019-04-01", - "publicIPAddressApiVersion": "2017-04-01", - "publicIPAddressType": "Dynamic", - "sshKeyPath": "[concat('/home/',parameters('adminUsername'),'/.ssh/authorized_keys')]", - "subnetAddressPrefix": "10.0.0.0/24", - "subnetName": "[parameters('subnetName')]", - "subnetRef": "[concat(variables('vnetID'),'/subnets/',variables('subnetName'))]", - "virtualNetworkName": "[parameters('virtualNetworkName')]", - "virtualNetworkResourceGroup": "[resourceGroup().name]", - "virtualNetworksApiVersion": "2017-04-01", - "vmStorageAccountContainerName": "images", - "vnetID": "[resourceId(variables('virtualNetworkResourceGroup'), 'Microsoft.Network/virtualNetworks', variables('virtualNetworkName'))]" - } -} \ No newline at end of file diff --git a/builder/azure/common/template/template_builder_test.go b/builder/azure/common/template/template_builder_test.go deleted file mode 100644 index 94a4b3673..000000000 --- a/builder/azure/common/template/template_builder_test.go +++ /dev/null @@ -1,283 +0,0 @@ -package template - -import ( - "testing" - - "github.com/Azure/azure-sdk-for-go/services/compute/mgmt/2018-04-01/compute" - approvaltests "github.com/approvals/go-approval-tests" -) - -// Ensure that a Linux template is configured as expected. -// * Include SSH configuration: authorized key, and key path. -func TestBuildLinux00(t *testing.T) { - testSubject, err := NewTemplateBuilder(BasicTemplate) - if err != nil { - t.Fatal(err) - } - - err = testSubject.BuildLinux("--test-ssh-authorized-key--", true) - if err != nil { - t.Fatal(err) - } - - err = testSubject.SetMarketPlaceImage("Canonical", "UbuntuServer", "16.04", "latest", compute.CachingTypesReadWrite) - if err != nil { - t.Fatal(err) - } - - doc, err := testSubject.ToJSON() - if err != nil { - t.Fatal(err) - } - - err = approvaltests.VerifyJSONBytes(t, []byte(*doc)) - if err != nil { - t.Fatal(err) - } -} - -// Ensure that a user can specify a custom VHD when building a Linux template. -func TestBuildLinux01(t *testing.T) { - testSubject, err := NewTemplateBuilder(BasicTemplate) - if err != nil { - t.Fatal(err) - } - - err = testSubject.BuildLinux("--test-ssh-authorized-key--", false) - if err != nil { - t.Fatal(err) - } - - err = testSubject.SetImageUrl("http://azure/custom.vhd", compute.Linux, compute.CachingTypesReadWrite) - if err != nil { - t.Fatal(err) - } - - doc, err := testSubject.ToJSON() - if err != nil { - t.Fatal(err) - } - - err = approvaltests.VerifyJSONBytes(t, []byte(*doc)) - if err != nil { - t.Fatal(err) - } -} - -// Ensure that a user can specify an existing Virtual Network -func TestBuildLinux02(t *testing.T) { - testSubject, err := NewTemplateBuilder(BasicTemplate) - if err != nil { - t.Fatal(err) - } - - err = testSubject.BuildLinux("--test-ssh-authorized-key--", true) - if err != nil { - t.Fatal(err) - } - err = testSubject.SetImageUrl("http://azure/custom.vhd", compute.Linux, compute.CachingTypesReadWrite) - if err != nil { - t.Fatal(err) - } - err = testSubject.SetOSDiskSizeGB(100) - if err != nil { - t.Fatal(err) - } - - err = testSubject.SetVirtualNetwork("--virtual-network-resource-group--", "--virtual-network--", "--subnet-name--") - if err != nil { - t.Fatal(err) - } - - doc, err := testSubject.ToJSON() - if err != nil { - t.Fatal(err) - } - - err = approvaltests.VerifyJSONBytes(t, []byte(*doc)) - if err != nil { - t.Fatal(err) - } -} - -// Ensure that a Windows template is configured as expected. -// * Include WinRM configuration. -// * Include KeyVault configuration, which is needed for WinRM. -func TestBuildWindows00(t *testing.T) { - testSubject, err := NewTemplateBuilder(BasicTemplate) - if err != nil { - t.Fatal(err) - } - - err = testSubject.BuildWindows("--test-key-vault-name", "--test-winrm-certificate-url--") - if err != nil { - t.Fatal(err) - } - - err = testSubject.SetMarketPlaceImage("MicrosoftWindowsServer", "WindowsServer", "2012-R2-Datacenter", "latest", compute.CachingTypesReadWrite) - if err != nil { - t.Fatal(err) - } - - doc, err := testSubject.ToJSON() - if err != nil { - t.Fatal(err) - } - - err = approvaltests.VerifyJSONBytes(t, []byte(*doc)) - if err != nil { - t.Fatal(err) - } -} - -// Windows build with additional disk for an managed build -func TestBuildWindows01(t *testing.T) { - testSubject, err := NewTemplateBuilder(BasicTemplate) - if err != nil { - t.Fatal(err) - } - - err = testSubject.BuildWindows("--test-key-vault-name", "--test-winrm-certificate-url--") - if err != nil { - t.Fatal(err) - } - - err = testSubject.SetManagedMarketplaceImage("MicrosoftWindowsServer", "WindowsServer", "2012-R2-Datacenter", "latest", "2015-1", "1", "Premium_LRS", compute.CachingTypesReadWrite) - if err != nil { - t.Fatal(err) - } - - err = testSubject.SetAdditionalDisks([]int32{32, 64}, "datadisk", true, compute.CachingTypesReadWrite) - if err != nil { - t.Fatal(err) - } - - doc, err := testSubject.ToJSON() - if err != nil { - t.Fatal(err) - } - - err = approvaltests.VerifyJSONBytes(t, []byte(*doc)) - if err != nil { - t.Fatal(err) - } -} - -// Windows build with additional disk for an unmanaged build -func TestBuildWindows02(t *testing.T) { - testSubject, err := NewTemplateBuilder(BasicTemplate) - if err != nil { - t.Fatal(err) - } - - err = testSubject.BuildWindows("--test-key-vault-name", "--test-winrm-certificate-url--") - if err != nil { - t.Fatal(err) - } - - err = testSubject.SetAdditionalDisks([]int32{32, 64}, "datadisk", false, compute.CachingTypesReadWrite) - if err != nil { - t.Fatal(err) - } - - doc, err := testSubject.ToJSON() - if err != nil { - t.Fatal(err) - } - - err = approvaltests.VerifyJSONBytes(t, []byte(*doc)) - if err != nil { - t.Fatal(err) - } -} - -// Shared Image Gallery Build -func TestSharedImageGallery00(t *testing.T) { - testSubject, err := NewTemplateBuilder(BasicTemplate) - if err != nil { - t.Fatal(err) - } - - err = testSubject.BuildLinux("--test-ssh-authorized-key--", false) - if err != nil { - t.Fatal(err) - } - - imageID := "/subscriptions/ignore/resourceGroups/ignore/providers/Microsoft.Compute/galleries/ignore/images/ignore" - err = testSubject.SetSharedGalleryImage("westcentralus", imageID, compute.CachingTypesReadOnly) - if err != nil { - t.Fatal(err) - } - - doc, err := testSubject.ToJSON() - if err != nil { - t.Fatal(err) - } - - err = approvaltests.VerifyJSONBytes(t, []byte(*doc)) - if err != nil { - t.Fatal(err) - } -} - -// Linux build with Network Security Group -func TestNetworkSecurityGroup00(t *testing.T) { - testSubject, err := NewTemplateBuilder(BasicTemplate) - if err != nil { - t.Fatal(err) - } - - err = testSubject.BuildLinux("--test-ssh-authorized-key--", false) - if err != nil { - t.Fatal(err) - } - - err = testSubject.SetMarketPlaceImage("Canonical", "UbuntuServer", "16.04", "latest", compute.CachingTypesReadWrite) - if err != nil { - t.Fatal(err) - } - - err = testSubject.SetNetworkSecurityGroup([]string{"127.0.0.1", "192.168.100.0/24"}, 123) - if err != nil { - t.Fatal(err) - } - - doc, err := testSubject.ToJSON() - if err != nil { - t.Fatal(err) - } - - err = approvaltests.VerifyJSONBytes(t, []byte(*doc)) - if err != nil { - t.Fatal(err) - } -} - -// Linux with user assigned managed identity configured -func TestSetIdentity00(t *testing.T) { - testSubject, err := NewTemplateBuilder(BasicTemplate) - if err != nil { - t.Fatal(err) - } - - if err = testSubject.BuildLinux("--test-ssh-authorized-key--", true); err != nil { - t.Fatal(err) - } - - if err = testSubject.SetMarketPlaceImage("Canonical", "UbuntuServer", "16.04", "latest", compute.CachingTypesReadWrite); err != nil { - t.Fatal(err) - } - - if err = testSubject.SetIdentity([]string{"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/rg1/providers/Microsoft.ManagedIdentity/userAssignedIdentities/id"}); err != nil { - t.Fatal(err) - } - - doc, err := testSubject.ToJSON() - if err != nil { - t.Fatal(err) - } - - if err = approvaltests.VerifyJSONBytes(t, []byte(*doc)); err != nil { - t.Fatal(err) - } -} diff --git a/builder/azure/common/template/template_parameters.go b/builder/azure/common/template/template_parameters.go deleted file mode 100644 index 262c85e56..000000000 --- a/builder/azure/common/template/template_parameters.go +++ /dev/null @@ -1,39 +0,0 @@ -package template - -// The intent of these types to facilitate interchange with Azure in the -// appropriate JSON format. A sample format is below. Each parameter listed -// below corresponds to a parameter defined in the template. -// -// { -// "storageAccountName": { -// "value" : "my_storage_account_name" -// }, -// "adminUserName" : { -// "value": "admin" -// } -// } - -type TemplateParameter struct { - Value string `json:"value"` -} - -type TemplateParameters struct { - AdminUsername *TemplateParameter `json:"adminUsername,omitempty"` - AdminPassword *TemplateParameter `json:"adminPassword,omitempty"` - DnsNameForPublicIP *TemplateParameter `json:"dnsNameForPublicIP,omitempty"` - KeyVaultName *TemplateParameter `json:"keyVaultName,omitempty"` - KeyVaultSKU *TemplateParameter `json:"keyVaultSKU,omitempty"` - KeyVaultSecretValue *TemplateParameter `json:"keyVaultSecretValue,omitempty"` - ObjectId *TemplateParameter `json:"objectId,omitempty"` - NicName *TemplateParameter `json:"nicName,omitempty"` - OSDiskName *TemplateParameter `json:"osDiskName,omitempty"` - DataDiskName *TemplateParameter `json:"dataDiskName,omitempty"` - PublicIPAddressName *TemplateParameter `json:"publicIPAddressName,omitempty"` - StorageAccountBlobEndpoint *TemplateParameter `json:"storageAccountBlobEndpoint,omitempty"` - SubnetName *TemplateParameter `json:"subnetName,omitempty"` - TenantId *TemplateParameter `json:"tenantId,omitempty"` - VirtualNetworkName *TemplateParameter `json:"virtualNetworkName,omitempty"` - NsgName *TemplateParameter `json:"nsgName,omitempty"` - VMSize *TemplateParameter `json:"vmSize,omitempty"` - VMName *TemplateParameter `json:"vmName,omitempty"` -} diff --git a/builder/azure/common/template/template_parameters_test.go b/builder/azure/common/template/template_parameters_test.go deleted file mode 100644 index 7a321128f..000000000 --- a/builder/azure/common/template/template_parameters_test.go +++ /dev/null @@ -1,112 +0,0 @@ -package template - -import ( - "encoding/json" - "fmt" - "strings" - "testing" -) - -func TestTemplateParametersShouldHaveExpectedKeys(t *testing.T) { - params := TemplateParameters{ - AdminUsername: &TemplateParameter{Value: "sentinel"}, - AdminPassword: &TemplateParameter{Value: "sentinel"}, - DnsNameForPublicIP: &TemplateParameter{Value: "sentinel"}, - OSDiskName: &TemplateParameter{Value: "sentinel"}, - StorageAccountBlobEndpoint: &TemplateParameter{Value: "sentinel"}, - VMName: &TemplateParameter{Value: "sentinel"}, - VMSize: &TemplateParameter{Value: "sentinel"}, - NsgName: &TemplateParameter{Value: "sentinel"}, - } - - bs, err := json.Marshal(params) - if err != nil { - t.Fail() - } - - var doc map[string]*json.RawMessage - err = json.Unmarshal(bs, &doc) - - if err != nil { - t.Fail() - } - - expectedKeys := []string{ - "adminUsername", - "adminPassword", - "dnsNameForPublicIP", - "osDiskName", - "storageAccountBlobEndpoint", - "vmSize", - "vmName", - "nsgName", - } - - for _, expectedKey := range expectedKeys { - _, containsKey := doc[expectedKey] - if containsKey == false { - t.Fatalf("Expected template parameters to contain the key value '%s', but it did not!", expectedKey) - } - } -} - -func TestParameterValuesShouldBeSet(t *testing.T) { - params := TemplateParameters{ - AdminUsername: &TemplateParameter{Value: "adminusername00"}, - AdminPassword: &TemplateParameter{Value: "adminpassword00"}, - DnsNameForPublicIP: &TemplateParameter{Value: "dnsnameforpublicip00"}, - OSDiskName: &TemplateParameter{Value: "osdiskname00"}, - StorageAccountBlobEndpoint: &TemplateParameter{Value: "storageaccountblobendpoint00"}, - VMName: &TemplateParameter{Value: "vmname00"}, - VMSize: &TemplateParameter{Value: "vmsize00"}, - NsgName: &TemplateParameter{Value: "nsgname00"}, - } - - bs, err := json.Marshal(params) - if err != nil { - t.Fail() - } - - var doc map[string]map[string]interface{} - err = json.Unmarshal(bs, &doc) - - if err != nil { - t.Fail() - } - - for k, v := range doc { - var expectedValue = fmt.Sprintf("%s00", strings.ToLower(k)) - var actualValue, exists = v["value"] - if exists != true { - t.Errorf("Expected to find a 'value' key under '%s', but it was missing!", k) - } - - if expectedValue != actualValue { - t.Errorf("Expected '%s', but actual was '%s'!", expectedValue, actualValue) - } - } -} - -func TestEmptyValuesShouldBeOmitted(t *testing.T) { - params := TemplateParameters{ - AdminUsername: &TemplateParameter{Value: "adminusername00"}, - } - - bs, err := json.Marshal(params) - if err != nil { - t.Fail() - } - - var doc map[string]map[string]interface{} - err = json.Unmarshal(bs, &doc) - - if err != nil { - t.Fail() - } - - if len(doc) != 1 { - t.Errorf("Failed to omit empty template parameters from the JSON document!") - t.Errorf("doc=%+v", doc) - t.Fail() - } -} diff --git a/builder/azure/common/template_funcs.go b/builder/azure/common/template_funcs.go deleted file mode 100644 index faccd4f07..000000000 --- a/builder/azure/common/template_funcs.go +++ /dev/null @@ -1,40 +0,0 @@ -package common - -import ( - "bytes" - "text/template" -) - -func isValidByteValue(b byte) bool { - if '0' <= b && b <= '9' { - return true - } - if 'a' <= b && b <= 'z' { - return true - } - if 'A' <= b && b <= 'Z' { - return true - } - return b == '.' || b == '_' || b == '-' -} - -// Clean up image name by replacing invalid characters with "-" -// Names are not allowed to end in '.', '-', or '_' and are trimmed. -func templateCleanImageName(s string) string { - b := []byte(s) - newb := make([]byte, len(b)) - for i := range newb { - if isValidByteValue(b[i]) { - newb[i] = b[i] - } else { - newb[i] = '-' - } - } - - newb = bytes.TrimRight(newb, "-_.") - return string(newb) -} - -var TemplateFuncs = template.FuncMap{ - "clean_resource_name": templateCleanImageName, -} diff --git a/builder/azure/common/template_funcs_test.go b/builder/azure/common/template_funcs_test.go deleted file mode 100644 index 1bdcf303f..000000000 --- a/builder/azure/common/template_funcs_test.go +++ /dev/null @@ -1,49 +0,0 @@ -package common - -import "testing" - -func TestTemplateCleanImageName(t *testing.T) { - vals := []struct { - origName string - expected string - }{ - // test that valid name is unchanged - { - origName: "abcde-012345xyz", - expected: "abcde-012345xyz", - }, - // test that colons are converted to hyphens - { - origName: "abcde-012345v1.0:0", - expected: "abcde-012345v1.0-0", - }, - // Name starting with number is not valid, but not in scope of this - // function to correct - { - origName: "012345v1.0:0", - expected: "012345v1.0-0", - }, - // Name over 80 chars is not valid, but not corrected by this function. - { - origName: "l012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789", - expected: "l012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789", - }, - // Name cannot end in a -Name over 80 chars is not valid, but not corrected by this function. - { - origName: "abcde-:_", - expected: "abcde", - }, - // Lost of special characters - { - origName: "My()./-_:&^ $%[]#'@name", - expected: "My--.--_-----------name", - }, - } - - for _, v := range vals { - name := templateCleanImageName(v.origName) - if name != v.expected { - t.Fatalf("template names do not match: expected %s got %s\n", v.expected, name) - } - } -} diff --git a/builder/azure/common/vault.go b/builder/azure/common/vault.go deleted file mode 100644 index a1732d8f5..000000000 --- a/builder/azure/common/vault.go +++ /dev/null @@ -1,138 +0,0 @@ -// NOTE: vault APIs do not yet exist in the SDK, but once they do this code -// should be removed. - -package common - -import ( - "fmt" - "net/http" - "net/url" - - "github.com/Azure/go-autorest/autorest" -) - -const ( - AzureVaultApiVersion = "2016-10-01" -) - -// Enables us to test steps that access this cli -type AZVaultClientIface interface { - GetSecret(string, string) (*Secret, error) - SetSecret(string, string, string) error -} - -type VaultClient struct { - autorest.Client - keyVaultEndpoint url.URL - SubscriptionID string - baseURI string -} - -func NewVaultClient(keyVaultEndpoint url.URL) VaultClient { - return VaultClient{ - keyVaultEndpoint: keyVaultEndpoint, - } -} - -func NewVaultClientWithBaseURI(baseURI, subscriptionID string) VaultClient { - return VaultClient{ - baseURI: baseURI, - SubscriptionID: subscriptionID, - } -} - -type Secret struct { - ID *string `json:"id,omitempty"` - Value string `json:"value"` -} - -func (client *VaultClient) GetSecret(vaultName, secretName string) (*Secret, error) { - p := map[string]interface{}{ - "secret-name": autorest.Encode("path", secretName), - } - q := map[string]interface{}{ - "api-version": AzureVaultApiVersion, - } - - req, err := autorest.Prepare( - &http.Request{}, - autorest.AsGet(), - autorest.WithBaseURL(client.getVaultUrl(vaultName)), - autorest.WithPathParameters("/secrets/{secret-name}", p), - autorest.WithQueryParameters(q), - ) - - if err != nil { - return nil, err - } - - resp, err := autorest.SendWithSender(client, req) - if err != nil { - return nil, err - } - - if resp.StatusCode != 200 { - return nil, fmt.Errorf( - "Failed to fetch secret from %s/%s, HTTP status code=%d (%s)", - vaultName, - secretName, - resp.StatusCode, - http.StatusText(resp.StatusCode)) - } - - var secret Secret - - err = autorest.Respond( - resp, - autorest.ByUnmarshallingJSON(&secret)) - if err != nil { - return nil, err - } - - return &secret, nil -} - -func (client *VaultClient) SetSecret(vaultName, secretName string, secretValue string) error { - p := map[string]interface{}{ - "secret-name": autorest.Encode("path", secretName), - } - q := map[string]interface{}{ - "api-version": AzureVaultApiVersion, - } - - jsonBody := fmt.Sprintf(`{"value": "%s"}`, secretValue) - - req, err := autorest.Prepare( - &http.Request{}, - autorest.AsPut(), - autorest.AsContentType("application/json; charset=utf-8"), - autorest.WithBaseURL(client.getVaultUrl(vaultName)), - autorest.WithPathParameters("/secrets/{secret-name}", p), - autorest.WithQueryParameters(q), - autorest.WithString(jsonBody), - ) - - if err != nil { - return err - } - - resp, err := autorest.SendWithSender(client, req) - if err != nil { - return err - } - - if resp.StatusCode != 200 { - return fmt.Errorf( - "Failed to set secret to %s/%s, HTTP status code=%d (%s)", - vaultName, - secretName, - resp.StatusCode, - http.StatusText(resp.StatusCode)) - } - - return nil -} - -func (client *VaultClient) getVaultUrl(vaultName string) string { - return fmt.Sprintf("%s://%s.%s/", client.keyVaultEndpoint.Scheme, vaultName, client.keyVaultEndpoint.Host) -} diff --git a/builder/azure/common/vault_client_mock.go b/builder/azure/common/vault_client_mock.go deleted file mode 100644 index 57bbd1c11..000000000 --- a/builder/azure/common/vault_client_mock.go +++ /dev/null @@ -1,56 +0,0 @@ -package common - -import ( - "fmt" - "net/http" - - "github.com/Azure/go-autorest/autorest" -) - -type MockAZVaultClient struct { - GetSecretCalled bool - SetSecretCalled bool - SetSecretVaultName string - SetSecretSecretName string - SetSecretCert string - DeleteResponderCalled bool - DeletePreparerCalled bool - DeleteSenderCalled bool - - IsError bool -} - -func (m *MockAZVaultClient) GetSecret(vaultName, secretName string) (*Secret, error) { - m.GetSecretCalled = true - var secret Secret - return &secret, nil -} - -func (m *MockAZVaultClient) SetSecret(vaultName, secretName string, secretValue string) error { - m.SetSecretCalled = true - m.SetSecretVaultName = vaultName - m.SetSecretSecretName = secretName - m.SetSecretCert = secretValue - - if m.IsError { - return fmt.Errorf("generic error!!") - } - - return nil -} - -func (m *MockAZVaultClient) DeletePreparer(resourceGroupName string, vaultName string) (*http.Request, error) { - m.DeletePreparerCalled = true - return nil, nil -} - -func (m *MockAZVaultClient) DeleteResponder(resp *http.Response) (autorest.Response, error) { - m.DeleteResponderCalled = true - var result autorest.Response - return result, nil -} - -func (m *MockAZVaultClient) DeleteSender(req *http.Request) (*http.Response, error) { - m.DeleteSenderCalled = true - return nil, nil -} diff --git a/builder/azure/common/vault_test.go b/builder/azure/common/vault_test.go deleted file mode 100644 index d1c94d76c..000000000 --- a/builder/azure/common/vault_test.go +++ /dev/null @@ -1,26 +0,0 @@ -package common - -import ( - "net/url" - "testing" -) - -func TestVaultClientKeyVaultEndpoint(t *testing.T) { - u, _ := url.Parse("https://vault.azure.net") - testSubject := NewVaultClient(*u) - - vaultUrl := testSubject.getVaultUrl("my") - if vaultUrl != "https://my.vault.azure.net/" { - t.Errorf("expected \"https://my.vault.azure.net/\", got %q", vaultUrl) - } -} - -func TestVaultClientKeyVaultEndpointPreserveScheme(t *testing.T) { - u, _ := url.Parse("http://vault.azure.net") - testSubject := NewVaultClient(*u) - - vaultUrl := testSubject.getVaultUrl("my") - if vaultUrl != "http://my.vault.azure.net/" { - t.Errorf("expected \"http://my.vault.azure.net/\", got %q", vaultUrl) - } -} diff --git a/builder/azure/dtl/TestVirtualMachineDeployment05.approved.txt b/builder/azure/dtl/TestVirtualMachineDeployment05.approved.txt deleted file mode 100644 index 31532ddbe..000000000 --- a/builder/azure/dtl/TestVirtualMachineDeployment05.approved.txt +++ /dev/null @@ -1,118 +0,0 @@ -{ - "$schema": "http://schema.management.azure.com/schemas/2014-04-01-preview/deploymentTemplate.json", - "contentVersion": "1.0.0.0", - "parameters": { - "adminPassword": { - "type": "string" - }, - "adminUsername": { - "type": "string" - }, - "dnsNameForPublicIP": { - "type": "string" - }, - "osDiskName": { - "type": "string" - }, - "storageAccountBlobEndpoint": { - "type": "string" - }, - "vmName": { - "type": "string" - }, - "vmSize": { - "type": "string" - } - }, - "resources": [ - { - "apiVersion": "[variables('apiVersion')]", - "dependsOn": [], - "location": "[variables('location')]", - "name": "[variables('nicName')]", - "properties": { - "ipConfigurations": [ - { - "name": "ipconfig", - "properties": { - "privateIPAllocationMethod": "Dynamic", - "subnet": { - "id": "[variables('subnetRef')]" - } - } - } - ] - }, - "type": "Microsoft.Network/networkInterfaces" - }, - { - "apiVersion": "[variables('apiVersion')]", - "dependsOn": [ - "[concat('Microsoft.Network/networkInterfaces/', variables('nicName'))]" - ], - "location": "[variables('location')]", - "name": "[parameters('vmName')]", - "properties": { - "diagnosticsProfile": { - "bootDiagnostics": { - "enabled": false - } - }, - "hardwareProfile": { - "vmSize": "[parameters('vmSize')]" - }, - "networkProfile": { - "networkInterfaces": [ - { - "id": "[resourceId('Microsoft.Network/networkInterfaces', variables('nicName'))]" - } - ] - }, - "osProfile": { - "adminPassword": "[parameters('adminPassword')]", - "adminUsername": "[parameters('adminUsername')]", - "computerName": "[parameters('vmName')]", - "linuxConfiguration": { - "ssh": { - "publicKeys": [ - { - "keyData": "", - "path": "[variables('sshKeyPath')]" - } - ] - } - } - }, - "storageProfile": { - "osDisk": { - "caching": "ReadWrite", - "createOption": "FromImage", - "image": { - "uri": "https://localhost/custom.vhd" - }, - "name": "[parameters('osDiskName')]", - "osType": "Linux", - "vhd": { - "uri": "[concat(parameters('storageAccountBlobEndpoint'),variables('vmStorageAccountContainerName'),'/', parameters('osDiskName'),'.vhd')]" - } - } - } - }, - "type": "Microsoft.Compute/virtualMachines" - } - ], - "variables": { - "addressPrefix": "10.0.0.0/16", - "apiVersion": "2015-06-15", - "location": "[resourceGroup().location]", - "publicIPAddressType": "Dynamic", - "sshKeyPath": "[concat('/home/',parameters('adminUsername'),'/.ssh/authorized_keys')]", - "subnetAddressPrefix": "10.0.0.0/24", - "subnetName": "ignore", - "subnetRef": "[concat(variables('vnetID'),'/subnets/',variables('subnetName'))]", - "virtualNetworkName": "ignore", - "virtualNetworkResourceGroup": "ignore", - "vmStorageAccountContainerName": "images", - "vnetID": "[resourceId(variables('virtualNetworkResourceGroup'), 'Microsoft.Network/virtualNetworks', variables('virtualNetworkName'))]" - } -} \ No newline at end of file diff --git a/builder/azure/dtl/WindowsMixAndMatch.json b/builder/azure/dtl/WindowsMixAndMatch.json deleted file mode 100644 index 1457d4a48..000000000 --- a/builder/azure/dtl/WindowsMixAndMatch.json +++ /dev/null @@ -1,65 +0,0 @@ -{ - "variables": { - "client_id": "{{env `client_id`}}", - "client_secret": "{{env `client_secret`}}", - "tenant_id": "{{env `tenant_id`}}", - "subscription_id": "{{env `subscription_id`}}", - "lab_name": "NewpackerRG", - "resource_group_name": "NewPackerRG", - "vm_name": "win21" - }, - "builders": [ - { - "type": "azure-dtl", - "client_id": "{{user `client_id`}}", - "client_secret": "{{user `client_secret`}}", - "tenant_id": "{{user `tenant_id`}}", - "subscription_id": "{{user `subscription_id`}}", - "managed_image_resource_group_name": "NewPackerRG", - "managed_image_name": "PackerImage2", - "os_type": "Windows", - "image_publisher": "MicrosoftWindowsDesktop", - "image_offer": "Windows-10", - "image_sku": "19h1-ent", - "azure_tags": { - "dept": "Engineering", - "task": "Image deployment" - }, - "dtl_artifacts": [ - { - "artifact_name": "windows-7zip" - }, - { - "artifact_name": "windows-mongodb" - } - ], - "lab_name": "{{user `lab_name`}}", - "vm_name": "{{user `vm_name`}}", - "lab_virtual_network_name": "dtlnewpackerrg", - "lab_resource_group_name": "{{user `resource_group_name`}}", - "lab_subnet_name": "dtlnewpackerrgSubnet", - "location": "Central US", - "vm_size": "Standard_DS2_v2" - } - ], - "provisioners": [ - { - "type": "azure-dtlartifact", - "client_id": "{{user `client_id`}}", - "client_secret": "{{user `client_secret`}}", - "tenant_id": "{{user `tenant_id`}}", - "subscription_id": "{{user `subscription_id`}}", - "lab_name": "{{user `lab_name`}}", - "resource_group_name": "{{user `resource_group_name`}}", - "vm_name": "{{user `vm_name`}}", - "dtl_artifacts": [ - { - "artifact_name": "windows-chrome" - }, - { - "artifact_name": "windows-azurepowershell" - } - ] - } - ] -} \ No newline at end of file diff --git a/builder/azure/dtl/WindowsSimple.json b/builder/azure/dtl/WindowsSimple.json deleted file mode 100644 index 446c41c33..000000000 --- a/builder/azure/dtl/WindowsSimple.json +++ /dev/null @@ -1,37 +0,0 @@ -{ - "variables": { - "client_id": "{{env `client_id`}}", - "client_secret": "{{env `client_secret`}}", - "tenant_id": "{{env `tenant_id`}}", - "subscription_id": "{{env `subscription_id`}}", - "lab_name": "NewpackerRG", - "resource_group_name": "NewPackerRG", - "vm_name": "win18" - }, - "builders": [ - { - "type": "azure-dtl", - "client_id": "{{user `client_id`}}", - "client_secret": "{{user `client_secret`}}", - "tenant_id": "{{user `tenant_id`}}", - "subscription_id": "{{user `subscription_id`}}", - "managed_image_resource_group_name": "NewPackerRG", - "managed_image_name": "PackerImage2", - "os_type": "Windows", - "image_publisher": "MicrosoftWindowsDesktop", - "image_offer": "Windows-10", - "image_sku": "19h1-ent", - "azure_tags": { - "dept": "Engineering", - "task": "Image deployment" - }, - "lab_name": "{{user `lab_name`}}", - "vm_name": "{{user `vm_name`}}", - "lab_virtual_network_name": "dtlnewpackerrg", - "lab_resource_group_name": "{{user `resource_group_name`}}", - "lab_subnet_name": "dtlnewpackerrgSubnet", - "location": "Central US", - "vm_size": "Standard_DS2_v2" - } - ] -} \ No newline at end of file diff --git a/builder/azure/dtl/acceptancetest.json b/builder/azure/dtl/acceptancetest.json deleted file mode 100644 index d1618e00d..000000000 --- a/builder/azure/dtl/acceptancetest.json +++ /dev/null @@ -1,72 +0,0 @@ -{ - "$schema": "http://schema.management.azure.com/schemas/2014-04-01-preview/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "parameters": { - "name": { - "type": "string", - "defaultValue": "packer-acceptance-test" - }, - "regionId": { - "type": "string", - "defaultValue": "southcentralus" - } - }, - "resources": [ - { - "apiVersion": "2018-10-15-preview", - "name": "[parameters('name')]", - "type": "Microsoft.DevTestLab/labs", - "location": "[parameters('regionId')]", - "tags": { - "env": "packer" - }, - "properties": { - "labStorageType": "Premium" - }, - "resources": [ - { - "apiVersion": "2018-10-15-preview", - "name": "LabVmsShutdown", - "location": "[parameters('regionId')]", - "type": "schedules", - "dependsOn": [ - "[resourceId('Microsoft.DevTestLab/labs', parameters('name'))]" - ], - "properties": { - "status": "Enabled", - "timeZoneId": "Pacific Standard Time", - "dailyRecurrence": { - "time": "1900" - }, - "taskType": "LabVmsShutdownTask", - "notificationSettings": { - "status": "Disabled", - "timeInMinutes": 30 - } - } - }, - { - "apiVersion": "2018-10-15-preview", - "name": "[concat('Dtl', parameters('name'))]", - "type": "virtualNetworks", - "location": "[parameters('regionId')]", - "dependsOn": [ - "[resourceId('Microsoft.DevTestLab/labs', parameters('name'))]" - ] - }, - { - "apiVersion": "2018-10-15-preview", - "name": "Public Environment Repo", - "type": "artifactSources", - "location": "[parameters('regionId')]", - "dependsOn": [ - "[resourceId('Microsoft.DevTestLab/labs', parameters('name'))]" - ], - "properties": { - "status": "Enabled" - } - } - ] - } - ] -} \ No newline at end of file diff --git a/builder/azure/dtl/artifact.go b/builder/azure/dtl/artifact.go deleted file mode 100644 index 0035e2d00..000000000 --- a/builder/azure/dtl/artifact.go +++ /dev/null @@ -1,199 +0,0 @@ -package dtl - -import ( - "bytes" - "fmt" - "net/url" - "path" - "strings" -) - -const ( - BuilderId = "Azure.ResourceManagement.VMImage" -) - -type AdditionalDiskArtifact struct { - AdditionalDiskUri string - AdditionalDiskUriReadOnlySas string -} - -type Artifact struct { - // OS type: Linux, Windows - OSType string - - // VHD - StorageAccountLocation string - OSDiskUri string - TemplateUri string - OSDiskUriReadOnlySas string - TemplateUriReadOnlySas string - - // Managed Image - ManagedImageResourceGroupName string - ManagedImageName string - ManagedImageLocation string - ManagedImageId string - ManagedImageOSDiskSnapshotName string - ManagedImageDataDiskSnapshotPrefix string - - // Additional Disks - AdditionalDisks *[]AdditionalDiskArtifact -} - -func NewManagedImageArtifact(osType, resourceGroup, name, location, id string) (*Artifact, error) { - return &Artifact{ - ManagedImageResourceGroupName: resourceGroup, - ManagedImageName: name, - ManagedImageLocation: location, - ManagedImageId: id, - OSType: osType, - }, nil -} - -func NewArtifact(template *CaptureTemplate, getSasUrl func(name string) string, osType string) (*Artifact, error) { - if template == nil { - return nil, fmt.Errorf("nil capture template") - } - - if len(template.Resources) != 1 { - return nil, fmt.Errorf("malformed capture template, expected one resource") - } - - vhdUri, err := url.Parse(template.Resources[0].Properties.StorageProfile.OSDisk.Image.Uri) - if err != nil { - return nil, err - } - - templateUri, err := storageUriToTemplateUri(vhdUri) - if err != nil { - return nil, err - } - - var additional_disks *[]AdditionalDiskArtifact - if template.Resources[0].Properties.StorageProfile.DataDisks != nil { - data_disks := make([]AdditionalDiskArtifact, len(template.Resources[0].Properties.StorageProfile.DataDisks)) - for i, additionaldisk := range template.Resources[0].Properties.StorageProfile.DataDisks { - additionalVhdUri, err := url.Parse(additionaldisk.Image.Uri) - if err != nil { - return nil, err - } - data_disks[i].AdditionalDiskUri = additionalVhdUri.String() - data_disks[i].AdditionalDiskUriReadOnlySas = getSasUrl(getStorageUrlPath(additionalVhdUri)) - } - additional_disks = &data_disks - } - - return &Artifact{ - OSType: osType, - OSDiskUri: vhdUri.String(), - OSDiskUriReadOnlySas: getSasUrl(getStorageUrlPath(vhdUri)), - TemplateUri: templateUri.String(), - TemplateUriReadOnlySas: getSasUrl(getStorageUrlPath(templateUri)), - - AdditionalDisks: additional_disks, - - StorageAccountLocation: template.Resources[0].Location, - }, nil -} - -func getStorageUrlPath(u *url.URL) string { - parts := strings.Split(u.Path, "/") - return strings.Join(parts[3:], "/") -} - -func storageUriToTemplateUri(su *url.URL) (*url.URL, error) { - // packer-osDisk.4085bb15-3644-4641-b9cd-f575918640b4.vhd -> 4085bb15-3644-4641-b9cd-f575918640b4 - filename := path.Base(su.Path) - parts := strings.Split(filename, ".") - - if len(parts) < 3 { - return nil, fmt.Errorf("malformed URL") - } - - // packer-osDisk.4085bb15-3644-4641-b9cd-f575918640b4.vhd -> packer - prefixParts := strings.Split(parts[0], "-") - prefix := strings.Join(prefixParts[:len(prefixParts)-1], "-") - - templateFilename := fmt.Sprintf("%s-vmTemplate.%s.json", prefix, parts[1]) - - // https://storage.blob.core.windows.net/system/Microsoft.Compute/Images/images/packer-osDisk.4085bb15-3644-4641-b9cd-f575918640b4.vhd" - // -> - // https://storage.blob.core.windows.net/system/Microsoft.Compute/Images/images/packer-vmTemplate.4085bb15-3644-4641-b9cd-f575918640b4.json" - return url.Parse(strings.Replace(su.String(), filename, templateFilename, 1)) -} - -func (a *Artifact) isManagedImage() bool { - return a.ManagedImageResourceGroupName != "" -} - -func (*Artifact) BuilderId() string { - return BuilderId -} - -func (*Artifact) Files() []string { - return []string{} -} - -func (a *Artifact) Id() string { - if a.OSDiskUri != "" { - return a.OSDiskUri - } - return a.ManagedImageId -} - -func (a *Artifact) State(name string) interface{} { - switch name { - case "atlas.artifact.metadata": - return a.stateAtlasMetadata() - default: - return nil - } -} - -func (a *Artifact) String() string { - var buf bytes.Buffer - - buf.WriteString(fmt.Sprintf("%s:\n\n", a.BuilderId())) - buf.WriteString(fmt.Sprintf("OSType: %s\n", a.OSType)) - if a.isManagedImage() { - buf.WriteString(fmt.Sprintf("ManagedImageResourceGroupName: %s\n", a.ManagedImageResourceGroupName)) - buf.WriteString(fmt.Sprintf("ManagedImageName: %s\n", a.ManagedImageName)) - buf.WriteString(fmt.Sprintf("ManagedImageId: %s\n", a.ManagedImageId)) - buf.WriteString(fmt.Sprintf("ManagedImageLocation: %s\n", a.ManagedImageLocation)) - if a.ManagedImageOSDiskSnapshotName != "" { - buf.WriteString(fmt.Sprintf("ManagedImageOSDiskSnapshotName: %s\n", a.ManagedImageOSDiskSnapshotName)) - } - if a.ManagedImageDataDiskSnapshotPrefix != "" { - buf.WriteString(fmt.Sprintf("ManagedImageDataDiskSnapshotPrefix: %s\n", a.ManagedImageDataDiskSnapshotPrefix)) - } - } 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)) - if a.AdditionalDisks != nil { - for i, additionaldisk := range *a.AdditionalDisks { - buf.WriteString(fmt.Sprintf("AdditionalDiskUri (datadisk-%d): %s\n", i+1, additionaldisk.AdditionalDiskUri)) - buf.WriteString(fmt.Sprintf("AdditionalDiskUriReadOnlySas (datadisk-%d): %s\n", i+1, additionaldisk.AdditionalDiskUriReadOnlySas)) - } - } - } - - return buf.String() -} - -func (*Artifact) Destroy() error { - return nil -} - -func (a *Artifact) stateAtlasMetadata() interface{} { - metadata := make(map[string]string) - metadata["StorageAccountLocation"] = a.StorageAccountLocation - metadata["OSDiskUri"] = a.OSDiskUri - metadata["OSDiskUriReadOnlySas"] = a.OSDiskUriReadOnlySas - metadata["TemplateUri"] = a.TemplateUri - metadata["TemplateUriReadOnlySas"] = a.TemplateUriReadOnlySas - - return metadata -} diff --git a/builder/azure/dtl/azure_client.go b/builder/azure/dtl/azure_client.go deleted file mode 100644 index 286eaa00e..000000000 --- a/builder/azure/dtl/azure_client.go +++ /dev/null @@ -1,211 +0,0 @@ -package dtl - -import ( - "encoding/json" - "fmt" - "math" - "net/http" - "os" - "strconv" - "time" - - "github.com/Azure/azure-sdk-for-go/services/compute/mgmt/2018-04-01/compute" - newCompute "github.com/Azure/azure-sdk-for-go/services/compute/mgmt/2019-03-01/compute" - dtl "github.com/Azure/azure-sdk-for-go/services/devtestlabs/mgmt/2018-09-15/dtl" - "github.com/Azure/azure-sdk-for-go/services/network/mgmt/2018-01-01/network" - "github.com/Azure/azure-sdk-for-go/services/resources/mgmt/2018-02-01/resources" - armStorage "github.com/Azure/azure-sdk-for-go/services/storage/mgmt/2017-10-01/storage" - "github.com/Azure/azure-sdk-for-go/storage" - "github.com/Azure/go-autorest/autorest" - "github.com/Azure/go-autorest/autorest/adal" - "github.com/Azure/go-autorest/autorest/azure" - "github.com/hashicorp/packer-plugin-sdk/useragent" - "github.com/hashicorp/packer/builder/azure/common" - "github.com/hashicorp/packer/builder/azure/version" -) - -const ( - EnvPackerLogAzureMaxLen = "PACKER_LOG_AZURE_MAXLEN" -) - -type AzureClient struct { - storage.BlobStorageClient - resources.DeploymentsClient - resources.DeploymentOperationsClient - resources.GroupsClient - network.PublicIPAddressesClient - network.InterfacesClient - network.SubnetsClient - network.VirtualNetworksClient - compute.ImagesClient - compute.VirtualMachinesClient - common.VaultClient - armStorage.AccountsClient - compute.DisksClient - compute.SnapshotsClient - newCompute.GalleryImageVersionsClient - newCompute.GalleryImagesClient - - InspectorMaxLength int - Template *CaptureTemplate - LastError azureErrorResponse - VaultClientDelete common.VaultClient - DtlLabsClient dtl.LabsClient - DtlVirtualMachineClient dtl.VirtualMachinesClient - DtlEnvironmentsClient dtl.EnvironmentsClient - DtlCustomImageClient dtl.CustomImagesClient - DtlVirtualNetworksClient dtl.VirtualNetworksClient -} - -func getCaptureResponse(body string) *CaptureTemplate { - var operation CaptureOperation - err := json.Unmarshal([]byte(body), &operation) - if err != nil { - return nil - } - - if operation.Properties != nil && operation.Properties.Output != nil { - return operation.Properties.Output - } - - return nil -} - -// HACK(chrboum): This method is a hack. It was written to work around this issue -// (https://github.com/Azure/azure-sdk-for-go/issues/307) and to an extent this -// issue (https://github.com/Azure/azure-rest-api-specs/issues/188). -// -// Capturing a VM is a long running operation that requires polling. There are -// couple different forms of polling, and the end result of a poll operation is -// discarded by the SDK. It is expected that any discarded data can be re-fetched, -// so discarding it has minimal impact. Unfortunately, there is no way to re-fetch -// the template returned by a capture call that I am aware of. -// -// If the second issue were fixed the VM ID would be included when GET'ing a VM. The -// VM ID could be used to locate the captured VHD, and captured template. -// Unfortunately, the VM ID is not included so this method cannot be used either. -// -// This code captures the template and saves it to the client (the AzureClient type). -// It expects that the capture API is called only once, or rather you only care that the -// last call's value is important because subsequent requests are not persisted. There -// is no care given to multiple threads writing this value because for our use case -// it does not matter. -func templateCapture(client *AzureClient) autorest.RespondDecorator { - return func(r autorest.Responder) autorest.Responder { - return autorest.ResponderFunc(func(resp *http.Response) error { - body, bodyString := handleBody(resp.Body, math.MaxInt64) - resp.Body = body - - captureTemplate := getCaptureResponse(bodyString) - if captureTemplate != nil { - client.Template = captureTemplate - } - - return r.Respond(resp) - }) - } -} - -func errorCapture(client *AzureClient) autorest.RespondDecorator { - return func(r autorest.Responder) autorest.Responder { - return autorest.ResponderFunc(func(resp *http.Response) error { - body, bodyString := handleBody(resp.Body, math.MaxInt64) - resp.Body = body - - errorResponse := newAzureErrorResponse(bodyString) - if errorResponse != nil { - client.LastError = *errorResponse - } - - return r.Respond(resp) - }) - } -} - -// WAITING(chrboum): I have logged https://github.com/Azure/azure-sdk-for-go/issues/311 to get this -// method included in the SDK. It has been accepted, and I'll cut over to the official way -// once it ships. -func byConcatDecorators(decorators ...autorest.RespondDecorator) autorest.RespondDecorator { - return func(r autorest.Responder) autorest.Responder { - return autorest.DecorateResponder(r, decorators...) - } -} - -func NewAzureClient(subscriptionID, resourceGroupName string, - cloud *azure.Environment, SharedGalleryTimeout time.Duration, PollingDuration time.Duration, - servicePrincipalToken *adal.ServicePrincipalToken) (*AzureClient, error) { - - var azureClient = &AzureClient{} - - maxlen := getInspectorMaxLength() - - azureClient.DtlVirtualMachineClient = dtl.NewVirtualMachinesClientWithBaseURI(cloud.ResourceManagerEndpoint, subscriptionID) - azureClient.DtlVirtualMachineClient.Authorizer = autorest.NewBearerAuthorizer(servicePrincipalToken) - azureClient.DtlVirtualMachineClient.RequestInspector = withInspection(maxlen) - azureClient.DtlVirtualMachineClient.ResponseInspector = byConcatDecorators(byInspecting(maxlen), templateCapture(azureClient), errorCapture(azureClient)) - azureClient.DtlVirtualMachineClient.UserAgent = fmt.Sprintf("%s %s", useragent.String(version.AzurePluginVersion.FormattedVersion()), azureClient.DtlVirtualMachineClient.UserAgent) - azureClient.DtlVirtualMachineClient.Client.PollingDuration = PollingDuration - - azureClient.DtlEnvironmentsClient = dtl.NewEnvironmentsClientWithBaseURI(cloud.ResourceManagerEndpoint, subscriptionID) - azureClient.DtlEnvironmentsClient.Authorizer = autorest.NewBearerAuthorizer(servicePrincipalToken) - azureClient.DtlEnvironmentsClient.RequestInspector = withInspection(maxlen) - azureClient.DtlEnvironmentsClient.ResponseInspector = byConcatDecorators(byInspecting(maxlen), templateCapture(azureClient), errorCapture(azureClient)) - azureClient.DtlEnvironmentsClient.UserAgent = fmt.Sprintf("%s %s", useragent.String(version.AzurePluginVersion.FormattedVersion()), azureClient.DtlEnvironmentsClient.UserAgent) - azureClient.DtlEnvironmentsClient.Client.PollingDuration = PollingDuration - - azureClient.DtlLabsClient = dtl.NewLabsClientWithBaseURI(cloud.ResourceManagerEndpoint, subscriptionID) - azureClient.DtlLabsClient.Authorizer = autorest.NewBearerAuthorizer(servicePrincipalToken) - azureClient.DtlLabsClient.RequestInspector = withInspection(maxlen) - azureClient.DtlLabsClient.ResponseInspector = byConcatDecorators(byInspecting(maxlen), templateCapture(azureClient), errorCapture(azureClient)) - azureClient.DtlLabsClient.UserAgent = fmt.Sprintf("%s %s", useragent.String(version.AzurePluginVersion.FormattedVersion()), azureClient.DtlLabsClient.UserAgent) - azureClient.DtlLabsClient.Client.PollingDuration = PollingDuration - - azureClient.DtlCustomImageClient = dtl.NewCustomImagesClientWithBaseURI(cloud.ResourceManagerEndpoint, subscriptionID) - azureClient.DtlCustomImageClient.Authorizer = autorest.NewBearerAuthorizer(servicePrincipalToken) - azureClient.DtlCustomImageClient.RequestInspector = withInspection(maxlen) - azureClient.DtlCustomImageClient.ResponseInspector = byConcatDecorators(byInspecting(maxlen), templateCapture(azureClient), errorCapture(azureClient)) - azureClient.DtlCustomImageClient.UserAgent = fmt.Sprintf("%s %s", useragent.String(version.AzurePluginVersion.FormattedVersion()), azureClient.DtlCustomImageClient.UserAgent) - azureClient.DtlCustomImageClient.PollingDuration = autorest.DefaultPollingDuration - azureClient.DtlCustomImageClient.Client.PollingDuration = PollingDuration - - azureClient.DtlVirtualNetworksClient = dtl.NewVirtualNetworksClientWithBaseURI(cloud.ResourceManagerEndpoint, subscriptionID) - azureClient.DtlVirtualNetworksClient.Authorizer = autorest.NewBearerAuthorizer(servicePrincipalToken) - azureClient.DtlVirtualNetworksClient.RequestInspector = withInspection(maxlen) - azureClient.DtlVirtualNetworksClient.ResponseInspector = byConcatDecorators(byInspecting(maxlen), templateCapture(azureClient), errorCapture(azureClient)) - azureClient.DtlVirtualNetworksClient.UserAgent = fmt.Sprintf("%s %s", useragent.String(version.AzurePluginVersion.FormattedVersion()), azureClient.DtlVirtualNetworksClient.UserAgent) - azureClient.DtlVirtualNetworksClient.Client.PollingDuration = PollingDuration - - azureClient.GalleryImageVersionsClient = newCompute.NewGalleryImageVersionsClientWithBaseURI(cloud.ResourceManagerEndpoint, subscriptionID) - azureClient.GalleryImageVersionsClient.Authorizer = autorest.NewBearerAuthorizer(servicePrincipalToken) - azureClient.GalleryImageVersionsClient.RequestInspector = withInspection(maxlen) - azureClient.GalleryImageVersionsClient.ResponseInspector = byConcatDecorators(byInspecting(maxlen), errorCapture(azureClient)) - azureClient.GalleryImageVersionsClient.UserAgent = fmt.Sprintf("%s %s", useragent.String(version.AzurePluginVersion.FormattedVersion()), azureClient.GalleryImageVersionsClient.UserAgent) - azureClient.GalleryImageVersionsClient.Client.PollingDuration = SharedGalleryTimeout - - azureClient.GalleryImagesClient = newCompute.NewGalleryImagesClientWithBaseURI(cloud.ResourceManagerEndpoint, subscriptionID) - azureClient.GalleryImagesClient.Authorizer = autorest.NewBearerAuthorizer(servicePrincipalToken) - azureClient.GalleryImagesClient.RequestInspector = withInspection(maxlen) - azureClient.GalleryImagesClient.ResponseInspector = byConcatDecorators(byInspecting(maxlen), errorCapture(azureClient)) - azureClient.GalleryImagesClient.UserAgent = fmt.Sprintf("%s %s", useragent.String(version.AzurePluginVersion.FormattedVersion()), azureClient.GalleryImagesClient.UserAgent) - azureClient.GalleryImagesClient.Client.PollingDuration = PollingDuration - - return azureClient, nil -} - -func getInspectorMaxLength() int64 { - value, ok := os.LookupEnv(EnvPackerLogAzureMaxLen) - if !ok { - return math.MaxInt64 - } - - i, err := strconv.ParseInt(value, 10, 64) - if err != nil { - return 0 - } - - if i < 0 { - return 0 - } - - return i -} diff --git a/builder/azure/dtl/azure_error_response.go b/builder/azure/dtl/azure_error_response.go deleted file mode 100644 index 2d92f101e..000000000 --- a/builder/azure/dtl/azure_error_response.go +++ /dev/null @@ -1,63 +0,0 @@ -package dtl - -import ( - "bytes" - "encoding/json" - "fmt" -) - -type azureErrorDetails struct { - Code string `json:"code"` - Message string `json:"message"` - Details []azureErrorDetails `json:"details"` -} - -type azureErrorResponse struct { - ErrorDetails azureErrorDetails `json:"error"` -} - -func newAzureErrorResponse(s string) *azureErrorResponse { - var errorResponse azureErrorResponse - err := json.Unmarshal([]byte(s), &errorResponse) - if err == nil { - return &errorResponse - } - - return nil -} - -func (e *azureErrorDetails) isEmpty() bool { - return e.Code == "" -} - -func (e *azureErrorResponse) Error() string { - var buf bytes.Buffer - //buf.WriteString("-=-=- ERROR -=-=-") - formatAzureErrorResponse(e.ErrorDetails, &buf, "") - //buf.WriteString("-=-=- ERROR -=-=-") - return buf.String() -} - -// format a Azure Error Response by recursing through the JSON structure. -// -// Errors may contain nested errors, which are JSON documents that have been -// serialized and escaped. Keep following this nesting all the way down... -func formatAzureErrorResponse(error azureErrorDetails, buf *bytes.Buffer, indent string) { - if error.isEmpty() { - return - } - - buf.WriteString(fmt.Sprintf("ERROR: %s-> %s : %s\n", indent, error.Code, error.Message)) - for _, x := range error.Details { - newIndent := fmt.Sprintf("%s ", indent) - - var aer azureErrorResponse - err := json.Unmarshal([]byte(x.Message), &aer) - if err == nil { - buf.WriteString(fmt.Sprintf("ERROR: %s-> %s\n", newIndent, x.Code)) - formatAzureErrorResponse(aer.ErrorDetails, buf, newIndent) - } else { - buf.WriteString(fmt.Sprintf("ERROR: %s-> %s : %s\n", newIndent, x.Code, x.Message)) - } - } -} diff --git a/builder/azure/dtl/azure_error_response_test.TestAzureErrorNestedShouldFormat.approved.txt b/builder/azure/dtl/azure_error_response_test.TestAzureErrorNestedShouldFormat.approved.txt deleted file mode 100644 index 39d4deeec..000000000 --- a/builder/azure/dtl/azure_error_response_test.TestAzureErrorNestedShouldFormat.approved.txt +++ /dev/null @@ -1,4 +0,0 @@ -ERROR: -> DeploymentFailed : At least one resource deployment operation failed. Please list deployment operations for details. Please see https://aka.ms/arm-debug for usage details. -ERROR: -> BadRequest -ERROR: -> InvalidRequestFormat : Cannot parse the request. -ERROR: -> InvalidJson : Error converting value "playground" to type 'Microsoft.WindowsAzure.Networking.Nrp.Frontend.Contract.Csm.Public.IpAllocationMethod'. Path 'properties.publicIPAllocationMethod', line 1, position 130. diff --git a/builder/azure/dtl/azure_error_response_test.TestAzureErrorSimpleShouldFormat.approved.txt b/builder/azure/dtl/azure_error_response_test.TestAzureErrorSimpleShouldFormat.approved.txt deleted file mode 100644 index 4b4834c62..000000000 --- a/builder/azure/dtl/azure_error_response_test.TestAzureErrorSimpleShouldFormat.approved.txt +++ /dev/null @@ -1 +0,0 @@ -ERROR: -> ResourceNotFound : The Resource 'Microsoft.Compute/images/PackerUbuntuImage' under resource group 'packer-test00' was not found. diff --git a/builder/azure/dtl/azure_error_response_test.go b/builder/azure/dtl/azure_error_response_test.go deleted file mode 100644 index fec3aa7f6..000000000 --- a/builder/azure/dtl/azure_error_response_test.go +++ /dev/null @@ -1,77 +0,0 @@ -package dtl - -import ( - "strings" - "testing" - - approvaltests "github.com/approvals/go-approval-tests" - "github.com/hashicorp/packer-plugin-sdk/json" -) - -const AzureErrorSimple = `{"error":{"code":"ResourceNotFound","message":"The Resource 'Microsoft.Compute/images/PackerUbuntuImage' under resource group 'packer-test00' was not found."}}` -const AzureErrorNested = `{"status":"Failed","error":{"code":"DeploymentFailed","message":"At least one resource deployment operation failed. Please list deployment operations for details. Please see https://aka.ms/arm-debug for usage details.","details":[{"code":"BadRequest","message":"{\r\n \"error\": {\r\n \"code\": \"InvalidRequestFormat\",\r\n \"message\": \"Cannot parse the request.\",\r\n \"details\": [\r\n {\r\n \"code\": \"InvalidJson\",\r\n \"message\": \"Error converting value \\\"playground\\\" to type 'Microsoft.WindowsAzure.Networking.Nrp.Frontend.Contract.Csm.Public.IpAllocationMethod'. Path 'properties.publicIPAllocationMethod', line 1, position 130.\"\r\n }\r\n ]\r\n }\r\n}"}]}}` - -func TestAzureErrorSimpleShouldUnmarshal(t *testing.T) { - var azureErrorResponse azureErrorResponse - err := json.Unmarshal([]byte(AzureErrorSimple), &azureErrorResponse) - if err != nil { - t.Fatal(err) - } - - if azureErrorResponse.ErrorDetails.Code != "ResourceNotFound" { - t.Errorf("Error.Code") - } - if azureErrorResponse.ErrorDetails.Message != "The Resource 'Microsoft.Compute/images/PackerUbuntuImage' under resource group 'packer-test00' was not found." { - t.Errorf("Error.Message") - } -} - -func TestAzureErrorNestedShouldUnmarshal(t *testing.T) { - var azureError azureErrorResponse - err := json.Unmarshal([]byte(AzureErrorNested), &azureError) - if err != nil { - t.Fatal(err) - } - - if azureError.ErrorDetails.Code != "DeploymentFailed" { - t.Errorf("Error.Code") - } - if !strings.HasPrefix(azureError.ErrorDetails.Message, "At least one resource deployment operation failed") { - t.Errorf("Error.Message") - } -} - -func TestAzureErrorEmptyShouldFormat(t *testing.T) { - var aer azureErrorResponse - s := aer.Error() - - if s != "" { - t.Fatalf("Expected \"\", but got %s", aer.Error()) - } -} - -func TestAzureErrorSimpleShouldFormat(t *testing.T) { - var azureErrorResponse azureErrorResponse - err := json.Unmarshal([]byte(AzureErrorSimple), &azureErrorResponse) - if err != nil { - t.Fatal(err) - } - - err = approvaltests.VerifyString(t, azureErrorResponse.Error()) - if err != nil { - t.Fatal(err) - } -} - -func TestAzureErrorNestedShouldFormat(t *testing.T) { - var azureErrorResponse azureErrorResponse - err := json.Unmarshal([]byte(AzureErrorNested), &azureErrorResponse) - if err != nil { - t.Fatal(err) - } - - err = approvaltests.VerifyString(t, azureErrorResponse.Error()) - if err != nil { - t.Fatal(err) - } -} diff --git a/builder/azure/dtl/builder.go b/builder/azure/dtl/builder.go deleted file mode 100644 index 05fd4102b..000000000 --- a/builder/azure/dtl/builder.go +++ /dev/null @@ -1,367 +0,0 @@ -package dtl - -import ( - "context" - "errors" - "fmt" - "log" - "os" - "runtime" - "strings" - - dtl "github.com/Azure/azure-sdk-for-go/services/devtestlabs/mgmt/2018-09-15/dtl" - - "github.com/Azure/go-autorest/autorest/adal" - "github.com/dgrijalva/jwt-go" - "github.com/hashicorp/hcl/v2/hcldec" - "github.com/hashicorp/packer-plugin-sdk/communicator" - "github.com/hashicorp/packer-plugin-sdk/multistep" - "github.com/hashicorp/packer-plugin-sdk/multistep/commonsteps" - packersdk "github.com/hashicorp/packer-plugin-sdk/packer" - packerAzureCommon "github.com/hashicorp/packer/builder/azure/common" - "github.com/hashicorp/packer/builder/azure/common/constants" - "github.com/hashicorp/packer/builder/azure/common/lin" -) - -type Builder struct { - config *Config - stateBag multistep.StateBag - runner multistep.Runner -} - -const ( - DefaultSasBlobContainer = "system/Microsoft.Compute" - DefaultSecretName = "packerKeyVaultSecret" -) - -func (b *Builder) ConfigSpec() hcldec.ObjectSpec { return b.config.FlatMapstructure().HCL2Spec() } - -func (b *Builder) Prepare(raws ...interface{}) ([]string, []string, error) { - c, warnings, errs := newConfig(raws...) - if errs != nil { - return nil, warnings, errs - } - - b.config = c - - b.stateBag = new(multistep.BasicStateBag) - b.configureStateBag(b.stateBag) - b.setTemplateParameters(b.stateBag) - - return nil, warnings, errs -} - -func (b *Builder) Run(ctx context.Context, ui packersdk.Ui, hook packersdk.Hook) (packersdk.Artifact, error) { - - ui.Say("Running builder ...") - - ctx, cancel := context.WithCancel(ctx) - defer cancel() - - // FillParameters function captures authType and sets defaults. - err := b.config.ClientConfig.FillParameters() - if err != nil { - return nil, err - } - - log.Print(":: Configuration") - packerAzureCommon.DumpConfig(b.config, func(s string) { log.Print(s) }) - - b.stateBag.Put("hook", hook) - b.stateBag.Put(constants.Ui, ui) - - spnCloud, err := b.getServicePrincipalToken(ui.Say) - if err != nil { - return nil, err - } - - ui.Message("Creating Azure Resource Manager (ARM) client ...") - azureClient, err := NewAzureClient( - b.config.ClientConfig.SubscriptionID, - b.config.LabResourceGroupName, - b.config.ClientConfig.CloudEnvironment(), - b.config.SharedGalleryTimeout, - b.config.PollingDurationTimeout, - spnCloud) - - if err != nil { - return nil, err - } - - resolver := newResourceResolver(azureClient) - if err := resolver.Resolve(b.config); err != nil { - return nil, err - } - if b.config.ClientConfig.ObjectID == "" { - b.config.ClientConfig.ObjectID = getObjectIdFromToken(ui, spnCloud) - } else { - ui.Message("You have provided Object_ID which is no longer needed, azure packer builder determines this dynamically from the authentication token") - } - - if b.config.ClientConfig.ObjectID == "" && b.config.OSType != constants.Target_Linux { - return nil, fmt.Errorf("could not determine the ObjectID for the user, which is required for Windows builds") - } - - if b.config.isManagedImage() { - // If a managed image already exists it cannot be overwritten. We need to delete it if the user has provided -force flag - _, err = azureClient.DtlCustomImageClient.Get(ctx, b.config.ManagedImageResourceGroupName, b.config.LabName, b.config.ManagedImageName, "") - - if err == nil { - if b.config.PackerForce { - ui.Say(fmt.Sprintf("the managed image named %s already exists, but deleting it due to -force flag", b.config.ManagedImageName)) - f, err := azureClient.DtlCustomImageClient.Delete(ctx, b.config.ManagedImageResourceGroupName, b.config.LabName, b.config.ManagedImageName) - if err == nil { - err = f.WaitForCompletionRef(ctx, azureClient.DtlCustomImageClient.Client) - } - if err != nil { - return nil, fmt.Errorf("failed to delete the managed image named %s : %s", b.config.ManagedImageName, azureClient.LastError.Error()) - } - } else { - return nil, fmt.Errorf("the managed image named %s already exists in the resource group %s, use the -force option to automatically delete it.", b.config.ManagedImageName, b.config.ManagedImageResourceGroupName) - } - } - - } else { - // User is not using Managed Images to build, warning message here that this path is being deprecated - ui.Error("Warning: You are using Azure Packer Builder to create VHDs which is being deprecated, consider using Managed Images. Learn more https://www.packer.io/docs/builders/azure/arm#azure-arm-builder-specific-options") - } - - b.config.validateLocationZoneResiliency(ui.Say) - - b.setRuntimeParameters(b.stateBag) - b.setTemplateParameters(b.stateBag) - var steps []multistep.Step - - deploymentName := b.stateBag.Get(constants.ArmDeploymentName).(string) - - // For Managed Images, validate that Shared Gallery Image exists before publishing to SIG - if b.config.isManagedImage() && b.config.SharedGalleryDestination.SigDestinationGalleryName != "" { - _, err = azureClient.GalleryImagesClient.Get(ctx, b.config.SharedGalleryDestination.SigDestinationResourceGroup, b.config.SharedGalleryDestination.SigDestinationGalleryName, b.config.SharedGalleryDestination.SigDestinationImageName) - if err != nil { - return nil, fmt.Errorf("The Shared Gallery Image to which to publish the managed image version to does not exist in the resource group %s", b.config.SharedGalleryDestination.SigDestinationResourceGroup) - } - // SIG requires that replication regions include the region in which the Managed Image resides - managedImageLocation := normalizeAzureRegion(b.stateBag.Get(constants.ArmLocation).(string)) - foundMandatoryReplicationRegion := false - var normalizedReplicationRegions []string - for _, region := range b.config.SharedGalleryDestination.SigDestinationReplicationRegions { - // change region to lower-case and strip spaces - normalizedRegion := normalizeAzureRegion(region) - normalizedReplicationRegions = append(normalizedReplicationRegions, normalizedRegion) - if strings.EqualFold(normalizedRegion, managedImageLocation) { - foundMandatoryReplicationRegion = true - continue - } - } - if foundMandatoryReplicationRegion == false { - b.config.SharedGalleryDestination.SigDestinationReplicationRegions = append(normalizedReplicationRegions, managedImageLocation) - } - b.stateBag.Put(constants.ArmManagedImageSharedGalleryReplicationRegions, b.config.SharedGalleryDestination.SigDestinationReplicationRegions) - } - - // Find the lab location - lab, err := azureClient.DtlLabsClient.Get(ctx, b.config.LabResourceGroupName, b.config.LabName, "") - if err != nil { - return nil, fmt.Errorf("Unable to fetch the Lab %s information in %s resource group", b.config.LabName, b.config.LabResourceGroupName) - } - - b.config.Location = *lab.Location - - if b.config.LabVirtualNetworkName == "" || b.config.LabSubnetName == "" { - virtualNetowrk, subnet, err := b.getSubnetInformation(ctx, ui, *azureClient) - - if err != nil { - return nil, err - } - b.config.LabVirtualNetworkName = *virtualNetowrk - b.config.LabSubnetName = *subnet - - ui.Message(fmt.Sprintf("No lab network information provided. Using %s Virtual network and %s subnet for Virtual Machine creation", b.config.LabVirtualNetworkName, b.config.LabSubnetName)) - } - - if b.config.OSType == constants.Target_Linux { - steps = []multistep.Step{ - NewStepDeployTemplate(azureClient, ui, b.config, deploymentName, GetVirtualMachineDeployment), - &communicator.StepConnectSSH{ - Config: &b.config.Comm, - Host: lin.SSHHost, - SSHConfig: b.config.Comm.SSHConfigFunc(), - }, - &commonsteps.StepProvision{}, - &commonsteps.StepCleanupTempKeys{ - Comm: &b.config.Comm, - }, - NewStepPowerOffCompute(azureClient, ui, b.config), - NewStepCaptureImage(azureClient, ui, b.config), - NewStepPublishToSharedImageGallery(azureClient, ui, b.config), - NewStepDeleteVirtualMachine(azureClient, ui, b.config), - } - } else if b.config.OSType == constants.Target_Windows { - steps = []multistep.Step{ - NewStepDeployTemplate(azureClient, ui, b.config, deploymentName, GetVirtualMachineDeployment), - &StepSaveWinRMPassword{ - Password: b.config.tmpAdminPassword, - BuildName: b.config.PackerBuildName, - }, - &communicator.StepConnectWinRM{ - Config: &b.config.Comm, - Host: func(stateBag multistep.StateBag) (string, error) { - return stateBag.Get(constants.SSHHost).(string), nil - }, - WinRMConfig: func(multistep.StateBag) (*communicator.WinRMConfig, error) { - return &communicator.WinRMConfig{ - Username: b.config.UserName, - Password: b.config.tmpAdminPassword, - }, nil - }, - }, - &commonsteps.StepProvision{}, - NewStepPowerOffCompute(azureClient, ui, b.config), - NewStepCaptureImage(azureClient, ui, b.config), - NewStepPublishToSharedImageGallery(azureClient, ui, b.config), - NewStepDeleteVirtualMachine(azureClient, ui, b.config), - } - } else { - return nil, fmt.Errorf("Builder does not support the os_type '%s'", b.config.OSType) - } - - if b.config.PackerDebug { - ui.Message(fmt.Sprintf("temp admin user: '%s'", b.config.UserName)) - ui.Message(fmt.Sprintf("temp admin password: '%s'", b.config.Password)) - - if len(b.config.Comm.SSHPrivateKey) != 0 { - debugKeyPath := fmt.Sprintf("%s-%s.pem", b.config.PackerBuildName, b.config.tmpComputeName) - ui.Message(fmt.Sprintf("temp ssh key: %s", debugKeyPath)) - - b.writeSSHPrivateKey(ui, debugKeyPath) - } - } - - b.runner = commonsteps.NewRunner(steps, b.config.PackerConfig, ui) - b.runner.Run(ctx, b.stateBag) - - // Report any errors. - if rawErr, ok := b.stateBag.GetOk(constants.Error); ok { - return nil, rawErr.(error) - } - - // If we were interrupted or cancelled, then just exit. - if _, ok := b.stateBag.GetOk(multistep.StateCancelled); ok { - return nil, errors.New("Build was cancelled.") - } - - if _, ok := b.stateBag.GetOk(multistep.StateHalted); ok { - return nil, errors.New("Build was halted.") - } - - if b.config.isManagedImage() { - managedImageID := fmt.Sprintf("/subscriptions/%s/resourceGroups/%s/providers/Microsoft.Compute/images/%s", b.config.ClientConfig.SubscriptionID, b.config.ManagedImageResourceGroupName, b.config.ManagedImageName) - return NewManagedImageArtifact(b.config.OSType, b.config.ManagedImageResourceGroupName, b.config.ManagedImageName, b.config.Location, managedImageID) - } - return &Artifact{}, nil -} - -func (b *Builder) writeSSHPrivateKey(ui packersdk.Ui, debugKeyPath string) { - f, err := os.Create(debugKeyPath) - if err != nil { - ui.Say(fmt.Sprintf("Error saving debug key: %s", err)) - } - defer f.Close() - - // Write the key out - if _, err := f.Write(b.config.Comm.SSHPrivateKey); err != nil { - ui.Say(fmt.Sprintf("Error saving debug key: %s", err)) - return - } - - // Chmod it so that it is SSH ready - if runtime.GOOS != "windows" { - if err := f.Chmod(0600); err != nil { - ui.Say(fmt.Sprintf("Error setting permissions of debug key: %s", err)) - } - } -} - -func (b *Builder) configureStateBag(stateBag multistep.StateBag) { - stateBag.Put(constants.AuthorizedKey, b.config.sshAuthorizedKey) - - stateBag.Put(constants.ArmTags, b.config.AzureTags) - stateBag.Put(constants.ArmComputeName, b.config.tmpComputeName) - stateBag.Put(constants.ArmDeploymentName, b.config.tmpDeploymentName) - stateBag.Put(constants.ArmKeyVaultName, b.config.tmpKeyVaultName) - stateBag.Put(constants.ArmNicName, b.config.tmpNicName) - stateBag.Put(constants.ArmPublicIPAddressName, b.config.tmpPublicIPAddressName) - if b.config.tmpResourceGroupName != "" { - stateBag.Put(constants.ArmResourceGroupName, b.config.tmpResourceGroupName) - stateBag.Put(constants.ArmIsExistingResourceGroup, false) - } else { - stateBag.Put(constants.ArmIsExistingResourceGroup, true) - } - - stateBag.Put(constants.ArmIsManagedImage, b.config.isManagedImage()) - stateBag.Put(constants.ArmManagedImageResourceGroupName, b.config.ManagedImageResourceGroupName) - stateBag.Put(constants.ArmManagedImageName, b.config.ManagedImageName) - if b.config.isManagedImage() && b.config.SharedGalleryDestination.SigDestinationGalleryName != "" { - stateBag.Put(constants.ArmManagedImageSigPublishResourceGroup, b.config.SharedGalleryDestination.SigDestinationResourceGroup) - stateBag.Put(constants.ArmManagedImageSharedGalleryName, b.config.SharedGalleryDestination.SigDestinationGalleryName) - stateBag.Put(constants.ArmManagedImageSharedGalleryImageName, b.config.SharedGalleryDestination.SigDestinationImageName) - stateBag.Put(constants.ArmManagedImageSharedGalleryImageVersion, b.config.SharedGalleryDestination.SigDestinationImageVersion) - stateBag.Put(constants.ArmManagedImageSubscription, b.config.ClientConfig.SubscriptionID) - } -} - -// Parameters that are only known at runtime after querying Azure. -func (b *Builder) setRuntimeParameters(stateBag multistep.StateBag) { - stateBag.Put(constants.ArmLocation, b.config.Location) -} - -func (b *Builder) setTemplateParameters(stateBag multistep.StateBag) { - stateBag.Put(constants.ArmVirtualMachineCaptureParameters, b.config.toVirtualMachineCaptureParameters()) -} - -func (b *Builder) getServicePrincipalToken(say func(string)) (*adal.ServicePrincipalToken, error) { - return b.config.ClientConfig.GetServicePrincipalToken(say, b.config.ClientConfig.CloudEnvironment().ResourceManagerEndpoint) -} - -func (b *Builder) getSubnetInformation(ctx context.Context, ui packersdk.Ui, azClient AzureClient) (*string, *string, error) { - num := int32(10) - virtualNetworkPage, err := azClient.DtlVirtualNetworksClient.List(ctx, b.config.LabResourceGroupName, b.config.LabName, "", "", &num, "") - - if err != nil { - return nil, nil, fmt.Errorf("Error retrieving Virtual networks in Resourcegroup %s", b.config.LabResourceGroupName) - } - - virtualNetworks := virtualNetworkPage.Values() - for _, virtualNetwork := range virtualNetworks { - for _, subnetOverride := range *virtualNetwork.SubnetOverrides { - // Check if the Subnet is allowed to create VMs having Public IP - if subnetOverride.UseInVMCreationPermission == dtl.Allow && subnetOverride.UsePublicIPAddressPermission == dtl.Allow { - // Return Virtual Network Name and Subnet Name - // Since we cannot query the Usage information from DTL network we cannot know the current remaining capacity. - // TODO (vaangadi) : Fix this to query the subnets that actually have space to create VM. - return virtualNetwork.Name, subnetOverride.LabSubnetName, nil - } - } - } - return nil, nil, fmt.Errorf("No available Subnet with available space in resource group %s", b.config.LabResourceGroupName) -} - -func getObjectIdFromToken(ui packersdk.Ui, token *adal.ServicePrincipalToken) string { - claims := jwt.MapClaims{} - var p jwt.Parser - - var err error - - _, _, err = p.ParseUnverified(token.OAuthToken(), claims) - - if err != nil { - ui.Error(fmt.Sprintf("Failed to parse the token,Error: %s", err.Error())) - return "" - } - return claims["oid"].(string) - -} - -func normalizeAzureRegion(name string) string { - return strings.ToLower(strings.Replace(name, " ", "", -1)) -} diff --git a/builder/azure/dtl/builder_acc_test.go b/builder/azure/dtl/builder_acc_test.go deleted file mode 100644 index bbea241f4..000000000 --- a/builder/azure/dtl/builder_acc_test.go +++ /dev/null @@ -1,142 +0,0 @@ -package dtl - -// these tests require the following variables to be set, -// although some test will only use a subset: -// -// * ARM_CLIENT_ID -// * ARM_CLIENT_SECRET -// * ARM_SUBSCRIPTION_ID -// * ARM_OBJECT_ID -// -// The subscription in question should have a resource group -// called "packer-acceptance-test" in "South Central US" region. -// This also requires a Devtest lab to be created with "packer-acceptance-test" -// name in "South Central US region. This can be achieved using the following -// az cli commands " -// az group create --name packer-acceptance-test --location "South Central US" -// az deployment group create \ -// --name ExampleDeployment \ -// --resource-group packer-acceptance-test \ -// --template-file acceptancetest.json \ - -// In addition, the PACKER_ACC variable should also be set to -// a non-empty value to enable Packer acceptance tests and the -// options "-v -timeout 90m" should be provided to the test -// command, e.g.: -// go test -v -timeout 90m -run TestBuilderAcc_.* - -import ( - "testing" - - builderT "github.com/hashicorp/packer/acctest" -) - -const DeviceLoginAcceptanceTest = "DEVICELOGIN_TEST" - -func TestBuilderAcc_ManagedDisk_Windows(t *testing.T) { - builderT.Test(t, builderT.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Builder: &Builder{}, - Template: testBuilderAccManagedDiskWindows, - }) -} -func TestBuilderAcc_ManagedDisk_Linux_Artifacts(t *testing.T) { - builderT.Test(t, builderT.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Builder: &Builder{}, - Template: testBuilderAccManagedDiskLinux, - }) -} - -func testAccPreCheck(*testing.T) {} - -const testBuilderAccManagedDiskWindows = ` -{ - "variables": { - "client_id": "{{env ` + "`ARM_CLIENT_ID`" + `}}", - "client_secret": "{{env ` + "`ARM_CLIENT_SECRET`" + `}}", - "subscription_id": "{{env ` + "`ARM_SUBSCRIPTION_ID`" + `}}", - "tenant_id": "{{env ` + "`ARM_TENANT_ID`" + `}}" - }, - "builders": [{ - "type": "test", - - "client_id": "{{user ` + "`client_id`" + `}}", - "client_secret": "{{user ` + "`client_secret`" + `}}", - "subscription_id": "{{user ` + "`subscription_id`" + `}}", - "tenant_id": "{{user ` + "`tenant_id`" + `}}", - - "lab_name": "packer-acceptance-test", - "lab_resource_group_name": "packer-acceptance-test", - "lab_virtual_network_name": "dtlpacker-acceptance-test", - - "managed_image_resource_group_name": "packer-acceptance-test", - "managed_image_name": "testBuilderAccManagedDiskWindows-{{timestamp}}", - - "os_type": "Windows", - "image_publisher": "MicrosoftWindowsServer", - "image_offer": "WindowsServer", - "image_sku": "2012-R2-Datacenter", - - "communicator": "winrm", - "winrm_use_ssl": "true", - "winrm_insecure": "true", - "winrm_timeout": "3m", - "winrm_username": "packer", - - "location": "South Central US", - "vm_size": "Standard_DS2_v2" - }] -} -` - -const testBuilderAccManagedDiskLinux = ` -{ - "variables": { - "client_id": "{{env ` + "`ARM_CLIENT_ID`" + `}}", - "client_secret": "{{env ` + "`ARM_CLIENT_SECRET`" + `}}", - "subscription_id": "{{env ` + "`ARM_SUBSCRIPTION_ID`" + `}}", - "tenant_id": "{{env ` + "`ARM_TENANT_ID`" + `}}" - }, - "builders": [{ - "type": "test", - - "client_id": "{{user ` + "`client_id`" + `}}", - "client_secret": "{{user ` + "`client_secret`" + `}}", - "subscription_id": "{{user ` + "`subscription_id`" + `}}", - - "lab_name": "packer-acceptance-test", - "lab_resource_group_name": "packer-acceptance-test", - "lab_virtual_network_name": "dtlpacker-acceptance-test", - - "managed_image_resource_group_name": "packer-acceptance-test", - "managed_image_name": "testBuilderAccManagedDiskLinux-{{timestamp}}", - - "os_type": "Linux", - "image_publisher": "Canonical", - "image_offer": "UbuntuServer", - "image_sku": "16.04-LTS", - - "location": "South Central US", - "vm_size": "Standard_DS2_v2", - - - "dtl_artifacts": [{ - "artifact_name": "linux-apt-package", - "parameters" : [{ - "name": "packages", - "value": "vim" - }, - { - "name":"update", - "value": "true" - }, - { - "name": "options", - "value": "--fix-broken" - }] - }] - - }] -} -` diff --git a/builder/azure/dtl/builder_test.go b/builder/azure/dtl/builder_test.go deleted file mode 100644 index 5120ebd40..000000000 --- a/builder/azure/dtl/builder_test.go +++ /dev/null @@ -1,33 +0,0 @@ -package dtl - -import ( - "testing" - - "github.com/hashicorp/packer/builder/azure/common/constants" -) - -func TestStateBagShouldBePopulatedExpectedValues(t *testing.T) { - var testSubject = &Builder{} - _, _, err := testSubject.Prepare(getDtlBuilderConfiguration(), getPackerConfiguration()) - if err != nil { - t.Fatalf("failed to prepare: %s", err) - } - - var expectedStateBagKeys = []string{ - constants.AuthorizedKey, - - constants.ArmTags, - constants.ArmComputeName, - constants.ArmDeploymentName, - constants.ArmNicName, - constants.ArmResourceGroupName, - constants.ArmVirtualMachineCaptureParameters, - constants.ArmPublicIPAddressName, - } - - for _, v := range expectedStateBagKeys { - if _, ok := testSubject.stateBag.GetOk(v); ok == false { - t.Errorf("Expected the builder's state bag to contain '%s', but it did not.", v) - } - } -} diff --git a/builder/azure/dtl/capture_template.go b/builder/azure/dtl/capture_template.go deleted file mode 100644 index 4f9cb7716..000000000 --- a/builder/azure/dtl/capture_template.go +++ /dev/null @@ -1,84 +0,0 @@ -package dtl - -type CaptureTemplateParameter struct { - Type string `json:"type"` - DefaultValue string `json:"defaultValue,omitempty"` -} - -type CaptureHardwareProfile struct { - VMSize string `json:"vmSize"` -} - -type CaptureUri struct { - Uri string `json:"uri"` -} - -type CaptureDisk struct { - OSType string `json:"osType"` - Name string `json:"name"` - Image CaptureUri `json:"image"` - Vhd CaptureUri `json:"vhd"` - CreateOption string `json:"createOption"` - Caching string `json:"caching"` -} - -type CaptureStorageProfile struct { - OSDisk CaptureDisk `json:"osDisk"` - DataDisks []CaptureDisk `json:"dataDisks"` -} - -type CaptureOSProfile struct { - ComputerName string `json:"computerName"` - AdminUsername string `json:"adminUsername"` - AdminPassword string `json:"adminPassword"` -} - -type CaptureNetworkInterface struct { - Id string `json:"id"` -} - -type CaptureNetworkProfile struct { - NetworkInterfaces []CaptureNetworkInterface `json:"networkInterfaces"` -} - -type CaptureBootDiagnostics struct { - Enabled bool `json:"enabled"` -} - -type CaptureDiagnosticProfile struct { - BootDiagnostics CaptureBootDiagnostics `json:"bootDiagnostics"` -} - -type CaptureProperties struct { - HardwareProfile CaptureHardwareProfile `json:"hardwareProfile"` - StorageProfile CaptureStorageProfile `json:"storageProfile"` - OSProfile CaptureOSProfile `json:"osProfile"` - NetworkProfile CaptureNetworkProfile `json:"networkProfile"` - DiagnosticsProfile CaptureDiagnosticProfile `json:"diagnosticsProfile"` - ProvisioningState int `json:"provisioningState"` -} - -type CaptureResources struct { - ApiVersion string `json:"apiVersion"` - Name string `json:"name"` - Type string `json:"type"` - Location string `json:"location"` - Properties CaptureProperties `json:"properties"` -} - -type CaptureTemplate struct { - Schema string `json:"$schema"` - ContentVersion string `json:"contentVersion"` - Parameters map[string]CaptureTemplateParameter `json:"parameters"` - Resources []CaptureResources `json:"resources"` -} - -type CaptureOperationProperties struct { - Output *CaptureTemplate `json:"output"` -} - -type CaptureOperation struct { - OperationId string `json:"operationId"` - Status string `json:"status"` - Properties *CaptureOperationProperties `json:"properties"` -} diff --git a/builder/azure/dtl/capture_template_test.go b/builder/azure/dtl/capture_template_test.go deleted file mode 100644 index 20e0d5ac9..000000000 --- a/builder/azure/dtl/capture_template_test.go +++ /dev/null @@ -1,272 +0,0 @@ -package dtl - -import ( - "encoding/json" - "testing" -) - -var captureTemplate01 = `{ - "operationId": "ac1c7c38-a591-41b3-89bd-ea39fceace1b", - "status": "Succeeded", - "startTime": "2016-04-04T21:07:25.2900874+00:00", - "endTime": "2016-04-04T21:07:26.4776321+00:00", - "properties": { - "output": { - "$schema": "http://schema.management.azure.com/schemas/2014-04-01-preview/VM_IP.json", - "contentVersion": "1.0.0.0", - "parameters": { - "vmName": { - "type": "string" - }, - "vmSize": { - "type": "string", - "defaultValue": "Standard_A2" - }, - "adminUserName": { - "type": "string" - }, - "adminPassword": { - "type": "securestring" - }, - "networkInterfaceId": { - "type": "string" - } - }, - "resources": [ - { - "apiVersion": "2015-06-15", - "properties": { - "hardwareProfile": { - "vmSize": "[parameters('vmSize')]" - }, - "storageProfile": { - "osDisk": { - "osType": "Linux", - "name": "packer-osDisk.32118633-6dc9-449f-83b6-a7d2983bec14.vhd", - "createOption": "FromImage", - "image": { - "uri": "http://storage.blob.core.windows.net/system/Microsoft.Compute/Images/images/packer-osDisk.32118633-6dc9-449f-83b6-a7d2983bec14.vhd" - }, - "vhd": { - "uri": "http://storage.blob.core.windows.net/vmcontainerce1a1b75-f480-47cb-8e6e-55142e4a5f68/osDisk.ce1a1b75-f480-47cb-8e6e-55142e4a5f68.vhd" - }, - "caching": "ReadWrite" - }, - "dataDisks": [ - { - "lun": 0, - "name": "packer-datadisk-0.32118633-6dc9-449f-83b6-a7d2983bec14.vhd", - "createOption": "Empty", - "image": { - "uri": "http://storage.blob.core.windows.net/system/Microsoft.Compute/Images/images/packer-datadisk-0.32118633-6dc9-449f-83b6-a7d2983bec14.vhd" - }, - "vhd": { - "uri": "http://storage.blob.core.windows.net/vmcontainerce1a1b75-f480-47cb-8e6e-55142e4a5f68/datadisk-0.ce1a1b75-f480-47cb-8e6e-55142e4a5f68.vhd" - }, - "caching": "ReadWrite" - }, - { - "lun": 1, - "name": "packer-datadisk-1.32118633-6dc9-449f-83b6-a7d2983bec14.vhd", - "createOption": "Empty", - "image": { - "uri": "http://storage.blob.core.windows.net/system/Microsoft.Compute/Images/images/packer-datadisk-1.32118633-6dc9-449f-83b6-a7d2983bec14.vhd" - }, - "vhd": { - "uri": "http://storage.blob.core.windows.net/vmcontainerce1a1b75-f480-47cb-8e6e-55142e4a5f68/datadisk-1.ce1a1b75-f480-47cb-8e6e-55142e4a5f68.vhd" - }, - "caching": "ReadWrite" - } - ] - }, - "osProfile": { - "computerName": "[parameters('vmName')]", - "adminUsername": "[parameters('adminUsername')]", - "adminPassword": "[parameters('adminPassword')]" - }, - "networkProfile": { - "networkInterfaces": [ - { - "id": "[parameters('networkInterfaceId')]" - } - ] - }, - "diagnosticsProfile": { - "bootDiagnostics": { - "enabled": false - } - }, - "provisioningState": 0 - }, - "name": "[parameters('vmName')]", - "type": "Microsoft.Compute/virtualMachines", - "location": "southcentralus" - } - ] - } - } -}` - -var captureTemplate02 = `{ - "operationId": "ac1c7c38-a591-41b3-89bd-ea39fceace1b", - "status": "Succeeded", - "startTime": "2016-04-04T21:07:25.2900874+00:00", - "endTime": "2016-04-04T21:07:26.4776321+00:00" -}` - -func TestCaptureParseJson(t *testing.T) { - var operation CaptureOperation - err := json.Unmarshal([]byte(captureTemplate01), &operation) - if err != nil { - t.Fatalf("failed to the sample capture operation: %s", err) - } - - testSubject := operation.Properties.Output - if testSubject.Schema != "http://schema.management.azure.com/schemas/2014-04-01-preview/VM_IP.json" { - t.Errorf("Schema's value was unexpected: %s", testSubject.Schema) - } - if testSubject.ContentVersion != "1.0.0.0" { - t.Errorf("ContentVersion's value was unexpected: %s", testSubject.ContentVersion) - } - - // == Parameters ==================================== - if len(testSubject.Parameters) != 5 { - t.Fatalf("expected parameters to have 5 keys, but got %d", len(testSubject.Parameters)) - } - if _, ok := testSubject.Parameters["vmName"]; !ok { - t.Errorf("Parameters['vmName'] was an expected parameters, but it did not exist") - } - if testSubject.Parameters["vmName"].Type != "string" { - t.Errorf("Parameters['vmName'].Type == 'string', but got '%s'", testSubject.Parameters["vmName"].Type) - } - if _, ok := testSubject.Parameters["vmSize"]; !ok { - t.Errorf("Parameters['vmSize'] was an expected parameters, but it did not exist") - } - if testSubject.Parameters["vmSize"].Type != "string" { - t.Errorf("Parameters['vmSize'].Type == 'string', but got '%s'", testSubject.Parameters["vmSize"]) - } - if testSubject.Parameters["vmSize"].DefaultValue != "Standard_A2" { - t.Errorf("Parameters['vmSize'].DefaultValue == 'string', but got '%s'", testSubject.Parameters["vmSize"].DefaultValue) - } - - // == Resources ===================================== - if len(testSubject.Resources) != 1 { - t.Fatalf("expected resources to have length 1, but got %d", len(testSubject.Resources)) - } - if testSubject.Resources[0].Name != "[parameters('vmName')]" { - t.Errorf("Resources[0].Name's value was unexpected: %s", testSubject.Resources[0].Name) - } - if testSubject.Resources[0].Type != "Microsoft.Compute/virtualMachines" { - t.Errorf("Resources[0].Type's value was unexpected: %s", testSubject.Resources[0].Type) - } - if testSubject.Resources[0].Location != "southcentralus" { - t.Errorf("Resources[0].Location's value was unexpected: %s", testSubject.Resources[0].Location) - } - - // == Resources/Properties ===================================== - if testSubject.Resources[0].Properties.ProvisioningState != 0 { - t.Errorf("Resources[0].Properties.ProvisioningState's value was unexpected: %d", testSubject.Resources[0].Properties.ProvisioningState) - } - - // == Resources/Properties/HardwareProfile ====================== - hardwareProfile := testSubject.Resources[0].Properties.HardwareProfile - if hardwareProfile.VMSize != "[parameters('vmSize')]" { - t.Errorf("Resources[0].Properties.HardwareProfile.VMSize's value was unexpected: %s", hardwareProfile.VMSize) - } - - // == Resources/Properties/StorageProfile/OSDisk ================ - osDisk := testSubject.Resources[0].Properties.StorageProfile.OSDisk - if osDisk.OSType != "Linux" { - t.Errorf("Resources[0].Properties.StorageProfile.OSDisk.OSDisk's value was unexpected: %s", osDisk.OSType) - } - if osDisk.Name != "packer-osDisk.32118633-6dc9-449f-83b6-a7d2983bec14.vhd" { - t.Errorf("Resources[0].Properties.StorageProfile.OSDisk.Name's value was unexpected: %s", osDisk.Name) - } - if osDisk.CreateOption != "FromImage" { - t.Errorf("Resources[0].Properties.StorageProfile.OSDisk.CreateOption's value was unexpected: %s", osDisk.CreateOption) - } - if osDisk.Image.Uri != "http://storage.blob.core.windows.net/system/Microsoft.Compute/Images/images/packer-osDisk.32118633-6dc9-449f-83b6-a7d2983bec14.vhd" { - t.Errorf("Resources[0].Properties.StorageProfile.OSDisk.Image.Uri's value was unexpected: %s", osDisk.Image.Uri) - } - if osDisk.Vhd.Uri != "http://storage.blob.core.windows.net/vmcontainerce1a1b75-f480-47cb-8e6e-55142e4a5f68/osDisk.ce1a1b75-f480-47cb-8e6e-55142e4a5f68.vhd" { - t.Errorf("Resources[0].Properties.StorageProfile.OSDisk.Vhd.Uri's value was unexpected: %s", osDisk.Vhd.Uri) - } - if osDisk.Caching != "ReadWrite" { - t.Errorf("Resources[0].Properties.StorageProfile.OSDisk.Caching's value was unexpected: %s", osDisk.Caching) - } - - // == Resources/Properties/StorageProfile/DataDisks ================ - dataDisks := testSubject.Resources[0].Properties.StorageProfile.DataDisks - if len(dataDisks) != 2 { - t.Errorf("Resources[0].Properties.StorageProfile.DataDisks, 2 disks expected but was: %d", len(dataDisks)) - } - if dataDisks[0].Name != "packer-datadisk-0.32118633-6dc9-449f-83b6-a7d2983bec14.vhd" { - t.Errorf("Resources[0].Properties.StorageProfile.dataDisks[0].Name's value was unexpected: %s", dataDisks[0].Name) - } - if dataDisks[0].CreateOption != "Empty" { - t.Errorf("Resources[0].Properties.StorageProfile.dataDisks[0].CreateOption's value was unexpected: %s", dataDisks[0].CreateOption) - } - if dataDisks[0].Image.Uri != "http://storage.blob.core.windows.net/system/Microsoft.Compute/Images/images/packer-datadisk-0.32118633-6dc9-449f-83b6-a7d2983bec14.vhd" { - t.Errorf("Resources[0].Properties.StorageProfile.dataDisks[0].Image.Uri's value was unexpected: %s", dataDisks[0].Image.Uri) - } - if dataDisks[0].Vhd.Uri != "http://storage.blob.core.windows.net/vmcontainerce1a1b75-f480-47cb-8e6e-55142e4a5f68/datadisk-0.ce1a1b75-f480-47cb-8e6e-55142e4a5f68.vhd" { - t.Errorf("Resources[0].Properties.StorageProfile.dataDisks[0].Vhd.Uri's value was unexpected: %s", dataDisks[0].Vhd.Uri) - } - if dataDisks[0].Caching != "ReadWrite" { - t.Errorf("Resources[0].Properties.StorageProfile.dataDisks[0].Caching's value was unexpected: %s", dataDisks[0].Caching) - } - if dataDisks[1].Name != "packer-datadisk-1.32118633-6dc9-449f-83b6-a7d2983bec14.vhd" { - t.Errorf("Resources[0].Properties.StorageProfile.dataDisks[1].Name's value was unexpected: %s", dataDisks[1].Name) - } - if dataDisks[1].CreateOption != "Empty" { - t.Errorf("Resources[0].Properties.StorageProfile.dataDisks[1].CreateOption's value was unexpected: %s", dataDisks[1].CreateOption) - } - if dataDisks[1].Image.Uri != "http://storage.blob.core.windows.net/system/Microsoft.Compute/Images/images/packer-datadisk-1.32118633-6dc9-449f-83b6-a7d2983bec14.vhd" { - t.Errorf("Resources[0].Properties.StorageProfile.dataDisks[1].Image.Uri's value was unexpected: %s", dataDisks[1].Image.Uri) - } - if dataDisks[1].Vhd.Uri != "http://storage.blob.core.windows.net/vmcontainerce1a1b75-f480-47cb-8e6e-55142e4a5f68/datadisk-1.ce1a1b75-f480-47cb-8e6e-55142e4a5f68.vhd" { - t.Errorf("Resources[0].Properties.StorageProfile.dataDisks[1].Vhd.Uri's value was unexpected: %s", dataDisks[1].Vhd.Uri) - } - if dataDisks[1].Caching != "ReadWrite" { - t.Errorf("Resources[0].Properties.StorageProfile.dataDisks[1].Caching's value was unexpected: %s", dataDisks[1].Caching) - } - - // == Resources/Properties/OSProfile ============================ - osProfile := testSubject.Resources[0].Properties.OSProfile - if osProfile.AdminPassword != "[parameters('adminPassword')]" { - t.Errorf("Resources[0].Properties.OSProfile.AdminPassword's value was unexpected: %s", osProfile.AdminPassword) - } - if osProfile.AdminUsername != "[parameters('adminUsername')]" { - t.Errorf("Resources[0].Properties.OSProfile.AdminUsername's value was unexpected: %s", osProfile.AdminUsername) - } - if osProfile.ComputerName != "[parameters('vmName')]" { - t.Errorf("Resources[0].Properties.OSProfile.ComputerName's value was unexpected: %s", osProfile.ComputerName) - } - - // == Resources/Properties/NetworkProfile ======================= - networkProfile := testSubject.Resources[0].Properties.NetworkProfile - if len(networkProfile.NetworkInterfaces) != 1 { - t.Errorf("Count of Resources[0].Properties.NetworkProfile.NetworkInterfaces was expected to be 1, but go %d", len(networkProfile.NetworkInterfaces)) - } - if networkProfile.NetworkInterfaces[0].Id != "[parameters('networkInterfaceId')]" { - t.Errorf("Resources[0].Properties.NetworkProfile.NetworkInterfaces[0].Id's value was unexpected: %s", networkProfile.NetworkInterfaces[0].Id) - } - - // == Resources/Properties/DiagnosticsProfile =================== - diagnosticsProfile := testSubject.Resources[0].Properties.DiagnosticsProfile - if diagnosticsProfile.BootDiagnostics.Enabled != false { - t.Errorf("Resources[0].Properties.DiagnosticsProfile.BootDiagnostics.Enabled's value was unexpected: %t", diagnosticsProfile.BootDiagnostics.Enabled) - } -} - -func TestCaptureEmptyOperationJson(t *testing.T) { - var operation CaptureOperation - err := json.Unmarshal([]byte(captureTemplate02), &operation) - if err != nil { - t.Fatalf("failed to the sample capture operation: %s", err) - } - - if operation.Properties != nil { - t.Errorf("JSON contained no properties, but value was not nil: %+v", operation.Properties) - } -} diff --git a/builder/azure/dtl/config.go b/builder/azure/dtl/config.go deleted file mode 100644 index da9214b1e..000000000 --- a/builder/azure/dtl/config.go +++ /dev/null @@ -1,767 +0,0 @@ -//go:generate packer-sdc struct-markdown -//go:generate packer-sdc mapstructure-to-hcl2 -type Config,SharedImageGallery,SharedImageGalleryDestination,DtlArtifact,ArtifactParameter - -package dtl - -import ( - "crypto/rand" - "crypto/rsa" - "crypto/x509" - "crypto/x509/pkix" - "encoding/base64" - "encoding/json" - "fmt" - "math/big" - "regexp" - "strings" - "time" - - "github.com/Azure/azure-sdk-for-go/services/compute/mgmt/2018-04-01/compute" - "github.com/Azure/go-autorest/autorest/to" - "github.com/masterzen/winrm" - - "github.com/hashicorp/packer/builder/azure/common/client" - "github.com/hashicorp/packer/builder/azure/common/constants" - - "github.com/hashicorp/packer-plugin-sdk/common" - "github.com/hashicorp/packer-plugin-sdk/communicator" - packersdk "github.com/hashicorp/packer-plugin-sdk/packer" - "github.com/hashicorp/packer-plugin-sdk/template/config" - "github.com/hashicorp/packer-plugin-sdk/template/interpolate" - "github.com/hashicorp/packer/builder/azure/pkcs12" - - "golang.org/x/crypto/ssh" -) - -const ( - DefaultImageVersion = "latest" - DefaultUserName = "packer" - DefaultPrivateVirtualNetworkWithPublicIp = false - DefaultVMSize = "Standard_A1" -) - -const ( - // https://docs.microsoft.com/en-us/azure/architecture/best-practices/naming-conventions#naming-rules-and-restrictions - // Regular expressions in Go are not expressive enough, such that the regular expression returned by Azure - // can be used (no backtracking). - // - // -> ^[^_\W][\w-._]{0,79}(? 0 { - return nil, nil, errs - } - - return &c, nil, nil -} - -func setSshValues(c *Config) error { - if c.Comm.SSHTimeout == 0 { - c.Comm.SSHTimeout = 20 * time.Minute - } - - if c.Comm.SSHPrivateKeyFile != "" { - privateKeyBytes, err := c.Comm.ReadSSHPrivateKeyFile() - if err != nil { - return err - } - signer, err := ssh.ParsePrivateKey(privateKeyBytes) - if err != nil { - return err - } - - publicKey := signer.PublicKey() - c.sshAuthorizedKey = fmt.Sprintf("%s %s packer Azure Deployment%s", - publicKey.Type(), - base64.StdEncoding.EncodeToString(publicKey.Marshal()), - time.Now().Format(time.RFC3339)) - c.Comm.SSHPrivateKey = privateKeyBytes - - } else { - sshKeyPair, err := NewOpenSshKeyPair() - if err != nil { - return err - } - - c.sshAuthorizedKey = sshKeyPair.AuthorizedKey() - c.Comm.SSHPrivateKey = sshKeyPair.PrivateKey() - } - - return nil -} - -func setWinRMCertificate(c *Config) error { - c.Comm.WinRMTransportDecorator = - func() winrm.Transporter { - return &winrm.ClientNTLM{} - } - - cert, password, err := c.createCertificate() - - c.winrmCertificate = cert - c.winrmPassword = password - - return err -} - -func setRuntimeValues(c *Config) { - var tempName = NewTempName(c) - - c.tmpAdminPassword = tempName.AdminPassword - packersdk.LogSecretFilter.Set(c.tmpAdminPassword) - - c.tmpCertificatePassword = tempName.CertificatePassword - c.tmpComputeName = tempName.ComputeName - - c.tmpDeploymentName = tempName.DeploymentName - if c.LabResourceGroupName == "" { - c.tmpResourceGroupName = tempName.ResourceGroupName - } else { - c.tmpResourceGroupName = c.LabResourceGroupName - } - c.tmpNicName = tempName.NicName - c.tmpPublicIPAddressName = tempName.PublicIPAddressName - c.tmpOSDiskName = tempName.OSDiskName - c.tmpSubnetName = tempName.SubnetName - c.tmpVirtualNetworkName = tempName.VirtualNetworkName - c.tmpKeyVaultName = tempName.KeyVaultName -} - -func setUserNamePassword(c *Config) { - if c.Comm.SSHUsername == "" { - c.Comm.SSHUsername = DefaultUserName - } - - c.UserName = c.Comm.SSHUsername - - if c.Comm.SSHPassword != "" { - c.Password = c.Comm.SSHPassword - } else { - c.Password = c.tmpAdminPassword - } -} - -func provideDefaultValues(c *Config) { - if c.VMSize == "" { - c.VMSize = DefaultVMSize - } - - if c.ManagedImageStorageAccountType == "" { - c.managedImageStorageAccountType = compute.StorageAccountTypesStandardLRS - } - - if c.DiskCachingType == "" { - c.diskCachingType = compute.CachingTypesReadWrite - } - - if c.ImagePublisher != "" && c.ImageVersion == "" { - c.ImageVersion = DefaultImageVersion - } -} - -func assertTagProperties(c *Config, errs *packersdk.MultiError) { - if len(c.AzureTags) > 15 { - errs = packersdk.MultiErrorAppend(errs, fmt.Errorf("a max of 15 tags are supported, but %d were provided", len(c.AzureTags))) - } - - for k, v := range c.AzureTags { - if len(k) > 512 { - errs = packersdk.MultiErrorAppend(errs, fmt.Errorf("the tag name %q exceeds (%d) the 512 character limit", k, len(k))) - } - if len(*v) > 256 { - errs = packersdk.MultiErrorAppend(errs, fmt.Errorf("the tag name %q exceeds (%d) the 256 character limit", *v, len(*v))) - } - } -} - -func assertRequiredParametersSet(c *Config, errs *packersdk.MultiError) { - c.ClientConfig.Validate(errs) - - ///////////////////////////////////////////// - // Capture - if c.CaptureContainerName == "" && c.ManagedImageName == "" { - errs = packersdk.MultiErrorAppend(errs, fmt.Errorf("A capture_container_name or managed_image_name must be specified")) - } - - if c.CaptureNamePrefix == "" && c.ManagedImageResourceGroupName == "" { - errs = packersdk.MultiErrorAppend(errs, fmt.Errorf("A capture_name_prefix or managed_image_resource_group_name must be specified")) - } - - if (c.CaptureNamePrefix != "" || c.CaptureContainerName != "") && (c.ManagedImageResourceGroupName != "" || c.ManagedImageName != "") { - errs = packersdk.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 c.CaptureContainerName != "" { - if !reCaptureContainerName.MatchString(c.CaptureContainerName) { - errs = packersdk.MultiErrorAppend(errs, fmt.Errorf("A capture_container_name must satisfy the regular expression %q.", reCaptureContainerName.String())) - } - - if strings.HasSuffix(c.CaptureContainerName, "-") { - errs = packersdk.MultiErrorAppend(errs, fmt.Errorf("A capture_container_name must not end with a hyphen, e.g. '-'.")) - } - - if strings.Contains(c.CaptureContainerName, "--") { - errs = packersdk.MultiErrorAppend(errs, fmt.Errorf("A capture_container_name must not contain consecutive hyphens, e.g. '--'.")) - } - - if c.CaptureNamePrefix == "" { - errs = packersdk.MultiErrorAppend(errs, fmt.Errorf("A capture_name_prefix must be specified")) - } - - if !reCaptureNamePrefix.MatchString(c.CaptureNamePrefix) { - errs = packersdk.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 = packersdk.MultiErrorAppend(errs, fmt.Errorf("A capture_name_prefix must not end with a hyphen or period.")) - } - } - - if c.LabResourceGroupName == "" { - errs = packersdk.MultiErrorAppend(errs, fmt.Errorf("The settings lab_resource_group_name needs to be defined.")) - } - - ///////////////////////////////////////////// - // Compute - toInt := func(b bool) int { - if b { - return 1 - } else { - return 0 - } - } - - isImageUrl := c.ImageUrl != "" - isCustomManagedImage := c.CustomManagedImageName != "" || c.CustomManagedImageResourceGroupName != "" - isSharedGallery := c.SharedGallery.GalleryName != "" - isPlatformImage := c.ImagePublisher != "" || c.ImageOffer != "" || c.ImageSku != "" - - countSourceInputs := toInt(isImageUrl) + toInt(isCustomManagedImage) + toInt(isPlatformImage) + toInt(isSharedGallery) - - if countSourceInputs > 1 { - errs = packersdk.MultiErrorAppend(errs, fmt.Errorf("Specify either a VHD (image_url), Image Reference (image_publisher, image_offer, image_sku), a Managed Disk (custom_managed_disk_image_name, custom_managed_disk_resource_group_name), or a Shared Gallery Image (shared_image_gallery)")) - } - - if isImageUrl && c.ManagedImageResourceGroupName != "" { - errs = packersdk.MultiErrorAppend(errs, fmt.Errorf("A managed image must be created from a managed image, it cannot be created from a VHD.")) - } - - if c.SharedGallery.GalleryName != "" { - if c.SharedGallery.Subscription == "" { - errs = packersdk.MultiErrorAppend(errs, fmt.Errorf("A shared_image_gallery.subscription must be specified")) - } - if c.SharedGallery.ResourceGroup == "" { - errs = packersdk.MultiErrorAppend(errs, fmt.Errorf("A shared_image_gallery.resource_group must be specified")) - } - if c.SharedGallery.ImageName == "" { - errs = packersdk.MultiErrorAppend(errs, fmt.Errorf("A shared_image_gallery.image_name must be specified")) - } - if c.CaptureContainerName != "" { - errs = packersdk.MultiErrorAppend(errs, fmt.Errorf("VHD Target [capture_container_name] is not supported when using Shared Image Gallery as source. Use managed_image_resource_group_name instead.")) - } - if c.CaptureNamePrefix != "" { - errs = packersdk.MultiErrorAppend(errs, fmt.Errorf("VHD Target [capture_name_prefix] is not supported when using Shared Image Gallery as source. Use managed_image_name instead.")) - } - } else if c.ImageUrl == "" && c.CustomManagedImageName == "" { - if c.ImagePublisher == "" { - errs = packersdk.MultiErrorAppend(errs, fmt.Errorf("An image_publisher must be specified")) - } - if c.ImageOffer == "" { - errs = packersdk.MultiErrorAppend(errs, fmt.Errorf("An image_offer must be specified")) - } - if c.ImageSku == "" { - errs = packersdk.MultiErrorAppend(errs, fmt.Errorf("An image_sku must be specified")) - } - } else if c.ImageUrl == "" && c.ImagePublisher == "" { - if c.CustomManagedImageResourceGroupName == "" { - errs = packersdk.MultiErrorAppend(errs, fmt.Errorf("An custom_managed_image_resource_group_name must be specified")) - } - if c.CustomManagedImageName == "" { - errs = packersdk.MultiErrorAppend(errs, fmt.Errorf("A custom_managed_image_name must be specified")) - } - if c.ManagedImageResourceGroupName == "" { - errs = packersdk.MultiErrorAppend(errs, fmt.Errorf("An managed_image_resource_group_name must be specified")) - } - if c.ManagedImageName == "" { - errs = packersdk.MultiErrorAppend(errs, fmt.Errorf("An managed_image_name must be specified")) - } - } else { - if c.ImagePublisher != "" || c.ImageOffer != "" || c.ImageSku != "" || c.ImageVersion != "" { - errs = packersdk.MultiErrorAppend(errs, fmt.Errorf("An image_url must not be specified if image_publisher, image_offer, image_sku, or image_version is specified")) - } - } - - if c.ManagedImageResourceGroupName != "" { - if ok, err := assertResourceGroupName(c.ManagedImageResourceGroupName, "managed_image_resource_group_name"); !ok { - errs = packersdk.MultiErrorAppend(errs, err) - } - } - - if c.ManagedImageName != "" { - if ok, err := assertManagedImageName(c.ManagedImageName, "managed_image_name"); !ok { - errs = packersdk.MultiErrorAppend(errs, err) - } - } - - if c.LabVirtualNetworkName == "" && c.LabResourceGroupName != "" { - errs = packersdk.MultiErrorAppend(errs, fmt.Errorf("If lab_resource_group_name is specified, so must lab_virtual_network_name")) - } - if c.LabVirtualNetworkName == "" && c.LabSubnetName != "" { - errs = packersdk.MultiErrorAppend(errs, fmt.Errorf("If virtual_network_subnet_name is specified, so must lab_virtual_network_name")) - } - - ///////////////////////////////////////////// - // Polling Duration Timeout - if c.PollingDurationTimeout == 0 { - // In the sdk, the default is 15 m. - c.PollingDurationTimeout = 15 * time.Minute - } - - ///////////////////////////////////////////// - // OS - if strings.EqualFold(c.OSType, constants.Target_Linux) { - c.OSType = constants.Target_Linux - } else if strings.EqualFold(c.OSType, constants.Target_Windows) { - c.OSType = constants.Target_Windows - } else if c.OSType == "" { - errs = packersdk.MultiErrorAppend(errs, fmt.Errorf("An os_type must be specified")) - } else { - errs = packersdk.MultiErrorAppend(errs, fmt.Errorf("The os_type %q is invalid", c.OSType)) - } - - switch c.ManagedImageStorageAccountType { - case "", string(compute.StorageAccountTypesStandardLRS): - c.managedImageStorageAccountType = compute.StorageAccountTypesStandardLRS - case string(compute.StorageAccountTypesPremiumLRS): - c.managedImageStorageAccountType = compute.StorageAccountTypesPremiumLRS - default: - errs = packersdk.MultiErrorAppend(errs, fmt.Errorf("The managed_image_storage_account_type %q is invalid", c.ManagedImageStorageAccountType)) - } - // Errs check to make the linter happy. - if errs != nil { - return - } -} - -func assertManagedImageName(name, setting string) (bool, error) { - if !isValidAzureName(reManagedDiskName, name) { - return false, fmt.Errorf("The setting %s must match the regular expression %q, and not end with a '-' or '.'.", setting, validManagedDiskName) - } - return true, nil -} - -func assertResourceGroupName(rgn, setting string) (bool, error) { - if !isValidAzureName(reResourceGroupName, rgn) { - return false, fmt.Errorf("The setting %s must match the regular expression %q, and not end with a '-' or '.'.", setting, validResourceGroupNameRe) - } - return true, nil -} - -func isValidAzureName(re *regexp.Regexp, rgn string) bool { - return re.Match([]byte(rgn)) && - !strings.HasSuffix(rgn, ".") && - !strings.HasSuffix(rgn, "-") -} - -func (c *Config) validateLocationZoneResiliency(say func(s string)) { - // Docs on regions that support Availibility Zones: - // https://docs.microsoft.com/en-us/azure/availability-zones/az-overview#regions-that-support-availability-zones - // Query technical names for locations: - // az account list-locations --query '[].name' -o tsv - - var zones = make(map[string]struct{}) - zones["westeurope"] = struct{}{} - zones["centralus"] = struct{}{} - zones["eastus2"] = struct{}{} - zones["francecentral"] = struct{}{} - zones["northeurope"] = struct{}{} - zones["southeastasia"] = struct{}{} - zones["westus2"] = struct{}{} - - if _, ok := zones[c.Location]; !ok { - say(fmt.Sprintf("WARNING: Zone resiliency may not be supported in %s, checkout the docs at https://docs.microsoft.com/en-us/azure/availability-zones/", c.Location)) - } -} diff --git a/builder/azure/dtl/config.hcl2spec.go b/builder/azure/dtl/config.hcl2spec.go deleted file mode 100644 index d0dd2c2d0..000000000 --- a/builder/azure/dtl/config.hcl2spec.go +++ /dev/null @@ -1,349 +0,0 @@ -// Code generated by "packer-sdc mapstructure-to-hcl2"; DO NOT EDIT. - -package dtl - -import ( - "github.com/hashicorp/hcl/v2/hcldec" - "github.com/zclconf/go-cty/cty" -) - -// FlatArtifactParameter is an auto-generated flat version of ArtifactParameter. -// Where the contents of a field with a `mapstructure:,squash` tag are bubbled up. -type FlatArtifactParameter struct { - Name *string `mapstructure:"name" cty:"name" hcl:"name"` - Value *string `mapstructure:"value" cty:"value" hcl:"value"` - Type *string `mapstructure:"type" cty:"type" hcl:"type"` -} - -// FlatMapstructure returns a new FlatArtifactParameter. -// FlatArtifactParameter is an auto-generated flat version of ArtifactParameter. -// Where the contents a fields with a `mapstructure:,squash` tag are bubbled up. -func (*ArtifactParameter) FlatMapstructure() interface{ HCL2Spec() map[string]hcldec.Spec } { - return new(FlatArtifactParameter) -} - -// HCL2Spec returns the hcl spec of a ArtifactParameter. -// This spec is used by HCL to read the fields of ArtifactParameter. -// The decoded values from this spec will then be applied to a FlatArtifactParameter. -func (*FlatArtifactParameter) HCL2Spec() map[string]hcldec.Spec { - s := map[string]hcldec.Spec{ - "name": &hcldec.AttrSpec{Name: "name", Type: cty.String, Required: false}, - "value": &hcldec.AttrSpec{Name: "value", Type: cty.String, Required: false}, - "type": &hcldec.AttrSpec{Name: "type", Type: cty.String, Required: false}, - } - return s -} - -// FlatConfig is an auto-generated flat version of Config. -// Where the contents of a field with a `mapstructure:,squash` tag are bubbled up. -type FlatConfig struct { - PackerBuildName *string `mapstructure:"packer_build_name" cty:"packer_build_name" hcl:"packer_build_name"` - PackerBuilderType *string `mapstructure:"packer_builder_type" cty:"packer_builder_type" hcl:"packer_builder_type"` - PackerCoreVersion *string `mapstructure:"packer_core_version" cty:"packer_core_version" hcl:"packer_core_version"` - PackerDebug *bool `mapstructure:"packer_debug" cty:"packer_debug" hcl:"packer_debug"` - PackerForce *bool `mapstructure:"packer_force" cty:"packer_force" hcl:"packer_force"` - PackerOnError *string `mapstructure:"packer_on_error" cty:"packer_on_error" hcl:"packer_on_error"` - PackerUserVars map[string]string `mapstructure:"packer_user_variables" cty:"packer_user_variables" hcl:"packer_user_variables"` - PackerSensitiveVars []string `mapstructure:"packer_sensitive_variables" cty:"packer_sensitive_variables" hcl:"packer_sensitive_variables"` - CloudEnvironmentName *string `mapstructure:"cloud_environment_name" required:"false" cty:"cloud_environment_name" hcl:"cloud_environment_name"` - ClientID *string `mapstructure:"client_id" cty:"client_id" hcl:"client_id"` - ClientSecret *string `mapstructure:"client_secret" cty:"client_secret" hcl:"client_secret"` - ClientCertPath *string `mapstructure:"client_cert_path" cty:"client_cert_path" hcl:"client_cert_path"` - ClientCertExpireTimeout *string `mapstructure:"client_cert_token_timeout" required:"false" cty:"client_cert_token_timeout" hcl:"client_cert_token_timeout"` - ClientJWT *string `mapstructure:"client_jwt" cty:"client_jwt" hcl:"client_jwt"` - ObjectID *string `mapstructure:"object_id" cty:"object_id" hcl:"object_id"` - TenantID *string `mapstructure:"tenant_id" required:"false" cty:"tenant_id" hcl:"tenant_id"` - SubscriptionID *string `mapstructure:"subscription_id" cty:"subscription_id" hcl:"subscription_id"` - UseAzureCLIAuth *bool `mapstructure:"use_azure_cli_auth" required:"false" cty:"use_azure_cli_auth" hcl:"use_azure_cli_auth"` - CaptureNamePrefix *string `mapstructure:"capture_name_prefix" cty:"capture_name_prefix" hcl:"capture_name_prefix"` - CaptureContainerName *string `mapstructure:"capture_container_name" cty:"capture_container_name" hcl:"capture_container_name"` - SharedGallery *FlatSharedImageGallery `mapstructure:"shared_image_gallery" cty:"shared_image_gallery" hcl:"shared_image_gallery"` - SharedGalleryDestination *FlatSharedImageGalleryDestination `mapstructure:"shared_image_gallery_destination" cty:"shared_image_gallery_destination" hcl:"shared_image_gallery_destination"` - SharedGalleryTimeout *string `mapstructure:"shared_image_gallery_timeout" cty:"shared_image_gallery_timeout" hcl:"shared_image_gallery_timeout"` - ImagePublisher *string `mapstructure:"image_publisher" cty:"image_publisher" hcl:"image_publisher"` - ImageOffer *string `mapstructure:"image_offer" cty:"image_offer" hcl:"image_offer"` - ImageSku *string `mapstructure:"image_sku" cty:"image_sku" hcl:"image_sku"` - ImageVersion *string `mapstructure:"image_version" cty:"image_version" hcl:"image_version"` - ImageUrl *string `mapstructure:"image_url" cty:"image_url" hcl:"image_url"` - CustomManagedImageResourceGroupName *string `mapstructure:"custom_managed_image_resource_group_name" cty:"custom_managed_image_resource_group_name" hcl:"custom_managed_image_resource_group_name"` - CustomManagedImageName *string `mapstructure:"custom_managed_image_name" cty:"custom_managed_image_name" hcl:"custom_managed_image_name"` - Location *string `mapstructure:"location" cty:"location" hcl:"location"` - VMSize *string `mapstructure:"vm_size" cty:"vm_size" hcl:"vm_size"` - ManagedImageResourceGroupName *string `mapstructure:"managed_image_resource_group_name" cty:"managed_image_resource_group_name" hcl:"managed_image_resource_group_name"` - ManagedImageName *string `mapstructure:"managed_image_name" cty:"managed_image_name" hcl:"managed_image_name"` - ManagedImageStorageAccountType *string `mapstructure:"managed_image_storage_account_type" required:"false" cty:"managed_image_storage_account_type" hcl:"managed_image_storage_account_type"` - AzureTags map[string]*string `mapstructure:"azure_tags" required:"false" cty:"azure_tags" hcl:"azure_tags"` - PlanID *string `mapstructure:"plan_id" required:"false" cty:"plan_id" hcl:"plan_id"` - PollingDurationTimeout *string `mapstructure:"polling_duration_timeout" required:"false" cty:"polling_duration_timeout" hcl:"polling_duration_timeout"` - OSType *string `mapstructure:"os_type" required:"false" cty:"os_type" hcl:"os_type"` - OSDiskSizeGB *int32 `mapstructure:"os_disk_size_gb" required:"false" cty:"os_disk_size_gb" hcl:"os_disk_size_gb"` - AdditionalDiskSize []int32 `mapstructure:"disk_additional_size" required:"false" cty:"disk_additional_size" hcl:"disk_additional_size"` - DiskCachingType *string `mapstructure:"disk_caching_type" required:"false" cty:"disk_caching_type" hcl:"disk_caching_type"` - StorageType *string `mapstructure:"storage_type" cty:"storage_type" hcl:"storage_type"` - LabVirtualNetworkName *string `mapstructure:"lab_virtual_network_name" cty:"lab_virtual_network_name" hcl:"lab_virtual_network_name"` - LabName *string `mapstructure:"lab_name" cty:"lab_name" hcl:"lab_name"` - LabSubnetName *string `mapstructure:"lab_subnet_name" cty:"lab_subnet_name" hcl:"lab_subnet_name"` - LabResourceGroupName *string `mapstructure:"lab_resource_group_name" cty:"lab_resource_group_name" hcl:"lab_resource_group_name"` - DtlArtifacts []FlatDtlArtifact `mapstructure:"dtl_artifacts" cty:"dtl_artifacts" hcl:"dtl_artifacts"` - VMName *string `mapstructure:"vm_name" cty:"vm_name" hcl:"vm_name"` - UserName *string `cty:"user_name" hcl:"user_name"` - Password *string `cty:"password" hcl:"password"` - VMCreationResourceGroup *string `cty:"vm_creation_resource_group" hcl:"vm_creation_resource_group"` - Type *string `mapstructure:"communicator" cty:"communicator" hcl:"communicator"` - PauseBeforeConnect *string `mapstructure:"pause_before_connecting" cty:"pause_before_connecting" hcl:"pause_before_connecting"` - SSHHost *string `mapstructure:"ssh_host" cty:"ssh_host" hcl:"ssh_host"` - SSHPort *int `mapstructure:"ssh_port" cty:"ssh_port" hcl:"ssh_port"` - SSHUsername *string `mapstructure:"ssh_username" cty:"ssh_username" hcl:"ssh_username"` - SSHPassword *string `mapstructure:"ssh_password" cty:"ssh_password" hcl:"ssh_password"` - SSHKeyPairName *string `mapstructure:"ssh_keypair_name" undocumented:"true" cty:"ssh_keypair_name" hcl:"ssh_keypair_name"` - SSHTemporaryKeyPairName *string `mapstructure:"temporary_key_pair_name" undocumented:"true" cty:"temporary_key_pair_name" hcl:"temporary_key_pair_name"` - SSHTemporaryKeyPairType *string `mapstructure:"temporary_key_pair_type" cty:"temporary_key_pair_type" hcl:"temporary_key_pair_type"` - SSHTemporaryKeyPairBits *int `mapstructure:"temporary_key_pair_bits" cty:"temporary_key_pair_bits" hcl:"temporary_key_pair_bits"` - SSHCiphers []string `mapstructure:"ssh_ciphers" cty:"ssh_ciphers" hcl:"ssh_ciphers"` - SSHClearAuthorizedKeys *bool `mapstructure:"ssh_clear_authorized_keys" cty:"ssh_clear_authorized_keys" hcl:"ssh_clear_authorized_keys"` - SSHKEXAlgos []string `mapstructure:"ssh_key_exchange_algorithms" cty:"ssh_key_exchange_algorithms" hcl:"ssh_key_exchange_algorithms"` - SSHPrivateKeyFile *string `mapstructure:"ssh_private_key_file" undocumented:"true" cty:"ssh_private_key_file" hcl:"ssh_private_key_file"` - SSHCertificateFile *string `mapstructure:"ssh_certificate_file" cty:"ssh_certificate_file" hcl:"ssh_certificate_file"` - SSHPty *bool `mapstructure:"ssh_pty" cty:"ssh_pty" hcl:"ssh_pty"` - SSHTimeout *string `mapstructure:"ssh_timeout" cty:"ssh_timeout" hcl:"ssh_timeout"` - SSHWaitTimeout *string `mapstructure:"ssh_wait_timeout" undocumented:"true" cty:"ssh_wait_timeout" hcl:"ssh_wait_timeout"` - SSHAgentAuth *bool `mapstructure:"ssh_agent_auth" undocumented:"true" cty:"ssh_agent_auth" hcl:"ssh_agent_auth"` - SSHDisableAgentForwarding *bool `mapstructure:"ssh_disable_agent_forwarding" cty:"ssh_disable_agent_forwarding" hcl:"ssh_disable_agent_forwarding"` - SSHHandshakeAttempts *int `mapstructure:"ssh_handshake_attempts" cty:"ssh_handshake_attempts" hcl:"ssh_handshake_attempts"` - SSHBastionHost *string `mapstructure:"ssh_bastion_host" cty:"ssh_bastion_host" hcl:"ssh_bastion_host"` - SSHBastionPort *int `mapstructure:"ssh_bastion_port" cty:"ssh_bastion_port" hcl:"ssh_bastion_port"` - SSHBastionAgentAuth *bool `mapstructure:"ssh_bastion_agent_auth" cty:"ssh_bastion_agent_auth" hcl:"ssh_bastion_agent_auth"` - SSHBastionUsername *string `mapstructure:"ssh_bastion_username" cty:"ssh_bastion_username" hcl:"ssh_bastion_username"` - SSHBastionPassword *string `mapstructure:"ssh_bastion_password" cty:"ssh_bastion_password" hcl:"ssh_bastion_password"` - SSHBastionInteractive *bool `mapstructure:"ssh_bastion_interactive" cty:"ssh_bastion_interactive" hcl:"ssh_bastion_interactive"` - SSHBastionPrivateKeyFile *string `mapstructure:"ssh_bastion_private_key_file" cty:"ssh_bastion_private_key_file" hcl:"ssh_bastion_private_key_file"` - SSHBastionCertificateFile *string `mapstructure:"ssh_bastion_certificate_file" cty:"ssh_bastion_certificate_file" hcl:"ssh_bastion_certificate_file"` - SSHFileTransferMethod *string `mapstructure:"ssh_file_transfer_method" cty:"ssh_file_transfer_method" hcl:"ssh_file_transfer_method"` - SSHProxyHost *string `mapstructure:"ssh_proxy_host" cty:"ssh_proxy_host" hcl:"ssh_proxy_host"` - SSHProxyPort *int `mapstructure:"ssh_proxy_port" cty:"ssh_proxy_port" hcl:"ssh_proxy_port"` - SSHProxyUsername *string `mapstructure:"ssh_proxy_username" cty:"ssh_proxy_username" hcl:"ssh_proxy_username"` - SSHProxyPassword *string `mapstructure:"ssh_proxy_password" cty:"ssh_proxy_password" hcl:"ssh_proxy_password"` - SSHKeepAliveInterval *string `mapstructure:"ssh_keep_alive_interval" cty:"ssh_keep_alive_interval" hcl:"ssh_keep_alive_interval"` - SSHReadWriteTimeout *string `mapstructure:"ssh_read_write_timeout" cty:"ssh_read_write_timeout" hcl:"ssh_read_write_timeout"` - SSHRemoteTunnels []string `mapstructure:"ssh_remote_tunnels" cty:"ssh_remote_tunnels" hcl:"ssh_remote_tunnels"` - SSHLocalTunnels []string `mapstructure:"ssh_local_tunnels" cty:"ssh_local_tunnels" hcl:"ssh_local_tunnels"` - SSHPublicKey []byte `mapstructure:"ssh_public_key" undocumented:"true" cty:"ssh_public_key" hcl:"ssh_public_key"` - SSHPrivateKey []byte `mapstructure:"ssh_private_key" undocumented:"true" cty:"ssh_private_key" hcl:"ssh_private_key"` - WinRMUser *string `mapstructure:"winrm_username" cty:"winrm_username" hcl:"winrm_username"` - WinRMPassword *string `mapstructure:"winrm_password" cty:"winrm_password" hcl:"winrm_password"` - WinRMHost *string `mapstructure:"winrm_host" cty:"winrm_host" hcl:"winrm_host"` - WinRMNoProxy *bool `mapstructure:"winrm_no_proxy" cty:"winrm_no_proxy" hcl:"winrm_no_proxy"` - WinRMPort *int `mapstructure:"winrm_port" cty:"winrm_port" hcl:"winrm_port"` - WinRMTimeout *string `mapstructure:"winrm_timeout" cty:"winrm_timeout" hcl:"winrm_timeout"` - WinRMUseSSL *bool `mapstructure:"winrm_use_ssl" cty:"winrm_use_ssl" hcl:"winrm_use_ssl"` - WinRMInsecure *bool `mapstructure:"winrm_insecure" cty:"winrm_insecure" hcl:"winrm_insecure"` - WinRMUseNTLM *bool `mapstructure:"winrm_use_ntlm" cty:"winrm_use_ntlm" hcl:"winrm_use_ntlm"` -} - -// FlatMapstructure returns a new FlatConfig. -// FlatConfig is an auto-generated flat version of Config. -// Where the contents a fields with a `mapstructure:,squash` tag are bubbled up. -func (*Config) FlatMapstructure() interface{ HCL2Spec() map[string]hcldec.Spec } { - return new(FlatConfig) -} - -// HCL2Spec returns the hcl spec of a Config. -// This spec is used by HCL to read the fields of Config. -// The decoded values from this spec will then be applied to a FlatConfig. -func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec { - s := map[string]hcldec.Spec{ - "packer_build_name": &hcldec.AttrSpec{Name: "packer_build_name", Type: cty.String, Required: false}, - "packer_builder_type": &hcldec.AttrSpec{Name: "packer_builder_type", Type: cty.String, Required: false}, - "packer_core_version": &hcldec.AttrSpec{Name: "packer_core_version", Type: cty.String, Required: false}, - "packer_debug": &hcldec.AttrSpec{Name: "packer_debug", Type: cty.Bool, Required: false}, - "packer_force": &hcldec.AttrSpec{Name: "packer_force", Type: cty.Bool, Required: false}, - "packer_on_error": &hcldec.AttrSpec{Name: "packer_on_error", Type: cty.String, Required: false}, - "packer_user_variables": &hcldec.AttrSpec{Name: "packer_user_variables", Type: cty.Map(cty.String), Required: false}, - "packer_sensitive_variables": &hcldec.AttrSpec{Name: "packer_sensitive_variables", Type: cty.List(cty.String), Required: false}, - "cloud_environment_name": &hcldec.AttrSpec{Name: "cloud_environment_name", Type: cty.String, Required: false}, - "client_id": &hcldec.AttrSpec{Name: "client_id", Type: cty.String, Required: false}, - "client_secret": &hcldec.AttrSpec{Name: "client_secret", Type: cty.String, Required: false}, - "client_cert_path": &hcldec.AttrSpec{Name: "client_cert_path", Type: cty.String, Required: false}, - "client_cert_token_timeout": &hcldec.AttrSpec{Name: "client_cert_token_timeout", Type: cty.String, Required: false}, - "client_jwt": &hcldec.AttrSpec{Name: "client_jwt", Type: cty.String, Required: false}, - "object_id": &hcldec.AttrSpec{Name: "object_id", Type: cty.String, Required: false}, - "tenant_id": &hcldec.AttrSpec{Name: "tenant_id", Type: cty.String, Required: false}, - "subscription_id": &hcldec.AttrSpec{Name: "subscription_id", Type: cty.String, Required: false}, - "use_azure_cli_auth": &hcldec.AttrSpec{Name: "use_azure_cli_auth", Type: cty.Bool, Required: false}, - "capture_name_prefix": &hcldec.AttrSpec{Name: "capture_name_prefix", Type: cty.String, Required: false}, - "capture_container_name": &hcldec.AttrSpec{Name: "capture_container_name", Type: cty.String, Required: false}, - "shared_image_gallery": &hcldec.BlockSpec{TypeName: "shared_image_gallery", Nested: hcldec.ObjectSpec((*FlatSharedImageGallery)(nil).HCL2Spec())}, - "shared_image_gallery_destination": &hcldec.BlockSpec{TypeName: "shared_image_gallery_destination", Nested: hcldec.ObjectSpec((*FlatSharedImageGalleryDestination)(nil).HCL2Spec())}, - "shared_image_gallery_timeout": &hcldec.AttrSpec{Name: "shared_image_gallery_timeout", Type: cty.String, Required: false}, - "image_publisher": &hcldec.AttrSpec{Name: "image_publisher", Type: cty.String, Required: false}, - "image_offer": &hcldec.AttrSpec{Name: "image_offer", Type: cty.String, Required: false}, - "image_sku": &hcldec.AttrSpec{Name: "image_sku", Type: cty.String, Required: false}, - "image_version": &hcldec.AttrSpec{Name: "image_version", Type: cty.String, Required: false}, - "image_url": &hcldec.AttrSpec{Name: "image_url", Type: cty.String, Required: false}, - "custom_managed_image_resource_group_name": &hcldec.AttrSpec{Name: "custom_managed_image_resource_group_name", Type: cty.String, Required: false}, - "custom_managed_image_name": &hcldec.AttrSpec{Name: "custom_managed_image_name", Type: cty.String, Required: false}, - "location": &hcldec.AttrSpec{Name: "location", Type: cty.String, Required: false}, - "vm_size": &hcldec.AttrSpec{Name: "vm_size", Type: cty.String, Required: false}, - "managed_image_resource_group_name": &hcldec.AttrSpec{Name: "managed_image_resource_group_name", Type: cty.String, Required: false}, - "managed_image_name": &hcldec.AttrSpec{Name: "managed_image_name", Type: cty.String, Required: false}, - "managed_image_storage_account_type": &hcldec.AttrSpec{Name: "managed_image_storage_account_type", Type: cty.String, Required: false}, - "azure_tags": &hcldec.AttrSpec{Name: "azure_tags", Type: cty.Map(cty.String), Required: false}, - "plan_id": &hcldec.AttrSpec{Name: "plan_id", Type: cty.String, Required: false}, - "polling_duration_timeout": &hcldec.AttrSpec{Name: "polling_duration_timeout", Type: cty.String, Required: false}, - "os_type": &hcldec.AttrSpec{Name: "os_type", Type: cty.String, Required: false}, - "os_disk_size_gb": &hcldec.AttrSpec{Name: "os_disk_size_gb", Type: cty.Number, Required: false}, - "disk_additional_size": &hcldec.AttrSpec{Name: "disk_additional_size", Type: cty.List(cty.Number), Required: false}, - "disk_caching_type": &hcldec.AttrSpec{Name: "disk_caching_type", Type: cty.String, Required: false}, - "storage_type": &hcldec.AttrSpec{Name: "storage_type", Type: cty.String, Required: false}, - "lab_virtual_network_name": &hcldec.AttrSpec{Name: "lab_virtual_network_name", Type: cty.String, Required: false}, - "lab_name": &hcldec.AttrSpec{Name: "lab_name", Type: cty.String, Required: false}, - "lab_subnet_name": &hcldec.AttrSpec{Name: "lab_subnet_name", Type: cty.String, Required: false}, - "lab_resource_group_name": &hcldec.AttrSpec{Name: "lab_resource_group_name", Type: cty.String, Required: false}, - "dtl_artifacts": &hcldec.BlockListSpec{TypeName: "dtl_artifacts", Nested: hcldec.ObjectSpec((*FlatDtlArtifact)(nil).HCL2Spec())}, - "vm_name": &hcldec.AttrSpec{Name: "vm_name", Type: cty.String, Required: false}, - "user_name": &hcldec.AttrSpec{Name: "user_name", Type: cty.String, Required: false}, - "password": &hcldec.AttrSpec{Name: "password", Type: cty.String, Required: false}, - "vm_creation_resource_group": &hcldec.AttrSpec{Name: "vm_creation_resource_group", Type: cty.String, Required: false}, - "communicator": &hcldec.AttrSpec{Name: "communicator", Type: cty.String, Required: false}, - "pause_before_connecting": &hcldec.AttrSpec{Name: "pause_before_connecting", Type: cty.String, Required: false}, - "ssh_host": &hcldec.AttrSpec{Name: "ssh_host", Type: cty.String, Required: false}, - "ssh_port": &hcldec.AttrSpec{Name: "ssh_port", Type: cty.Number, Required: false}, - "ssh_username": &hcldec.AttrSpec{Name: "ssh_username", Type: cty.String, Required: false}, - "ssh_password": &hcldec.AttrSpec{Name: "ssh_password", Type: cty.String, Required: false}, - "ssh_keypair_name": &hcldec.AttrSpec{Name: "ssh_keypair_name", Type: cty.String, Required: false}, - "temporary_key_pair_name": &hcldec.AttrSpec{Name: "temporary_key_pair_name", Type: cty.String, Required: false}, - "temporary_key_pair_type": &hcldec.AttrSpec{Name: "temporary_key_pair_type", Type: cty.String, Required: false}, - "temporary_key_pair_bits": &hcldec.AttrSpec{Name: "temporary_key_pair_bits", Type: cty.Number, Required: false}, - "ssh_ciphers": &hcldec.AttrSpec{Name: "ssh_ciphers", Type: cty.List(cty.String), Required: false}, - "ssh_clear_authorized_keys": &hcldec.AttrSpec{Name: "ssh_clear_authorized_keys", Type: cty.Bool, Required: false}, - "ssh_key_exchange_algorithms": &hcldec.AttrSpec{Name: "ssh_key_exchange_algorithms", Type: cty.List(cty.String), Required: false}, - "ssh_private_key_file": &hcldec.AttrSpec{Name: "ssh_private_key_file", Type: cty.String, Required: false}, - "ssh_certificate_file": &hcldec.AttrSpec{Name: "ssh_certificate_file", Type: cty.String, Required: false}, - "ssh_pty": &hcldec.AttrSpec{Name: "ssh_pty", Type: cty.Bool, Required: false}, - "ssh_timeout": &hcldec.AttrSpec{Name: "ssh_timeout", Type: cty.String, Required: false}, - "ssh_wait_timeout": &hcldec.AttrSpec{Name: "ssh_wait_timeout", Type: cty.String, Required: false}, - "ssh_agent_auth": &hcldec.AttrSpec{Name: "ssh_agent_auth", Type: cty.Bool, Required: false}, - "ssh_disable_agent_forwarding": &hcldec.AttrSpec{Name: "ssh_disable_agent_forwarding", Type: cty.Bool, Required: false}, - "ssh_handshake_attempts": &hcldec.AttrSpec{Name: "ssh_handshake_attempts", Type: cty.Number, Required: false}, - "ssh_bastion_host": &hcldec.AttrSpec{Name: "ssh_bastion_host", Type: cty.String, Required: false}, - "ssh_bastion_port": &hcldec.AttrSpec{Name: "ssh_bastion_port", Type: cty.Number, Required: false}, - "ssh_bastion_agent_auth": &hcldec.AttrSpec{Name: "ssh_bastion_agent_auth", Type: cty.Bool, Required: false}, - "ssh_bastion_username": &hcldec.AttrSpec{Name: "ssh_bastion_username", Type: cty.String, Required: false}, - "ssh_bastion_password": &hcldec.AttrSpec{Name: "ssh_bastion_password", Type: cty.String, Required: false}, - "ssh_bastion_interactive": &hcldec.AttrSpec{Name: "ssh_bastion_interactive", Type: cty.Bool, Required: false}, - "ssh_bastion_private_key_file": &hcldec.AttrSpec{Name: "ssh_bastion_private_key_file", Type: cty.String, Required: false}, - "ssh_bastion_certificate_file": &hcldec.AttrSpec{Name: "ssh_bastion_certificate_file", Type: cty.String, Required: false}, - "ssh_file_transfer_method": &hcldec.AttrSpec{Name: "ssh_file_transfer_method", Type: cty.String, Required: false}, - "ssh_proxy_host": &hcldec.AttrSpec{Name: "ssh_proxy_host", Type: cty.String, Required: false}, - "ssh_proxy_port": &hcldec.AttrSpec{Name: "ssh_proxy_port", Type: cty.Number, Required: false}, - "ssh_proxy_username": &hcldec.AttrSpec{Name: "ssh_proxy_username", Type: cty.String, Required: false}, - "ssh_proxy_password": &hcldec.AttrSpec{Name: "ssh_proxy_password", Type: cty.String, Required: false}, - "ssh_keep_alive_interval": &hcldec.AttrSpec{Name: "ssh_keep_alive_interval", Type: cty.String, Required: false}, - "ssh_read_write_timeout": &hcldec.AttrSpec{Name: "ssh_read_write_timeout", Type: cty.String, Required: false}, - "ssh_remote_tunnels": &hcldec.AttrSpec{Name: "ssh_remote_tunnels", Type: cty.List(cty.String), Required: false}, - "ssh_local_tunnels": &hcldec.AttrSpec{Name: "ssh_local_tunnels", Type: cty.List(cty.String), Required: false}, - "ssh_public_key": &hcldec.AttrSpec{Name: "ssh_public_key", Type: cty.List(cty.Number), Required: false}, - "ssh_private_key": &hcldec.AttrSpec{Name: "ssh_private_key", Type: cty.List(cty.Number), Required: false}, - "winrm_username": &hcldec.AttrSpec{Name: "winrm_username", Type: cty.String, Required: false}, - "winrm_password": &hcldec.AttrSpec{Name: "winrm_password", Type: cty.String, Required: false}, - "winrm_host": &hcldec.AttrSpec{Name: "winrm_host", Type: cty.String, Required: false}, - "winrm_no_proxy": &hcldec.AttrSpec{Name: "winrm_no_proxy", Type: cty.Bool, Required: false}, - "winrm_port": &hcldec.AttrSpec{Name: "winrm_port", Type: cty.Number, Required: false}, - "winrm_timeout": &hcldec.AttrSpec{Name: "winrm_timeout", Type: cty.String, Required: false}, - "winrm_use_ssl": &hcldec.AttrSpec{Name: "winrm_use_ssl", Type: cty.Bool, Required: false}, - "winrm_insecure": &hcldec.AttrSpec{Name: "winrm_insecure", Type: cty.Bool, Required: false}, - "winrm_use_ntlm": &hcldec.AttrSpec{Name: "winrm_use_ntlm", Type: cty.Bool, Required: false}, - } - return s -} - -// FlatDtlArtifact is an auto-generated flat version of DtlArtifact. -// Where the contents of a field with a `mapstructure:,squash` tag are bubbled up. -type FlatDtlArtifact struct { - ArtifactName *string `mapstructure:"artifact_name" cty:"artifact_name" hcl:"artifact_name"` - RepositoryName *string `mapstructure:"repository_name" cty:"repository_name" hcl:"repository_name"` - ArtifactId *string `mapstructure:"artifact_id" cty:"artifact_id" hcl:"artifact_id"` - Parameters []FlatArtifactParameter `mapstructure:"parameters" cty:"parameters" hcl:"parameters"` -} - -// FlatMapstructure returns a new FlatDtlArtifact. -// FlatDtlArtifact is an auto-generated flat version of DtlArtifact. -// Where the contents a fields with a `mapstructure:,squash` tag are bubbled up. -func (*DtlArtifact) FlatMapstructure() interface{ HCL2Spec() map[string]hcldec.Spec } { - return new(FlatDtlArtifact) -} - -// HCL2Spec returns the hcl spec of a DtlArtifact. -// This spec is used by HCL to read the fields of DtlArtifact. -// The decoded values from this spec will then be applied to a FlatDtlArtifact. -func (*FlatDtlArtifact) HCL2Spec() map[string]hcldec.Spec { - s := map[string]hcldec.Spec{ - "artifact_name": &hcldec.AttrSpec{Name: "artifact_name", Type: cty.String, Required: false}, - "repository_name": &hcldec.AttrSpec{Name: "repository_name", Type: cty.String, Required: false}, - "artifact_id": &hcldec.AttrSpec{Name: "artifact_id", Type: cty.String, Required: false}, - "parameters": &hcldec.BlockListSpec{TypeName: "parameters", Nested: hcldec.ObjectSpec((*FlatArtifactParameter)(nil).HCL2Spec())}, - } - return s -} - -// FlatSharedImageGallery is an auto-generated flat version of SharedImageGallery. -// Where the contents of a field with a `mapstructure:,squash` tag are bubbled up. -type FlatSharedImageGallery struct { - Subscription *string `mapstructure:"subscription" cty:"subscription" hcl:"subscription"` - ResourceGroup *string `mapstructure:"resource_group" cty:"resource_group" hcl:"resource_group"` - GalleryName *string `mapstructure:"gallery_name" cty:"gallery_name" hcl:"gallery_name"` - ImageName *string `mapstructure:"image_name" cty:"image_name" hcl:"image_name"` - ImageVersion *string `mapstructure:"image_version" cty:"image_version" hcl:"image_version"` -} - -// FlatMapstructure returns a new FlatSharedImageGallery. -// FlatSharedImageGallery is an auto-generated flat version of SharedImageGallery. -// Where the contents a fields with a `mapstructure:,squash` tag are bubbled up. -func (*SharedImageGallery) FlatMapstructure() interface{ HCL2Spec() map[string]hcldec.Spec } { - return new(FlatSharedImageGallery) -} - -// HCL2Spec returns the hcl spec of a SharedImageGallery. -// This spec is used by HCL to read the fields of SharedImageGallery. -// The decoded values from this spec will then be applied to a FlatSharedImageGallery. -func (*FlatSharedImageGallery) HCL2Spec() map[string]hcldec.Spec { - s := map[string]hcldec.Spec{ - "subscription": &hcldec.AttrSpec{Name: "subscription", Type: cty.String, Required: false}, - "resource_group": &hcldec.AttrSpec{Name: "resource_group", Type: cty.String, Required: false}, - "gallery_name": &hcldec.AttrSpec{Name: "gallery_name", Type: cty.String, Required: false}, - "image_name": &hcldec.AttrSpec{Name: "image_name", Type: cty.String, Required: false}, - "image_version": &hcldec.AttrSpec{Name: "image_version", Type: cty.String, Required: false}, - } - return s -} - -// FlatSharedImageGalleryDestination is an auto-generated flat version of SharedImageGalleryDestination. -// Where the contents of a field with a `mapstructure:,squash` tag are bubbled up. -type FlatSharedImageGalleryDestination struct { - SigDestinationResourceGroup *string `mapstructure:"resource_group" cty:"resource_group" hcl:"resource_group"` - SigDestinationGalleryName *string `mapstructure:"gallery_name" cty:"gallery_name" hcl:"gallery_name"` - SigDestinationImageName *string `mapstructure:"image_name" cty:"image_name" hcl:"image_name"` - SigDestinationImageVersion *string `mapstructure:"image_version" cty:"image_version" hcl:"image_version"` - SigDestinationReplicationRegions []string `mapstructure:"replication_regions" cty:"replication_regions" hcl:"replication_regions"` -} - -// FlatMapstructure returns a new FlatSharedImageGalleryDestination. -// FlatSharedImageGalleryDestination is an auto-generated flat version of SharedImageGalleryDestination. -// Where the contents a fields with a `mapstructure:,squash` tag are bubbled up. -func (*SharedImageGalleryDestination) FlatMapstructure() interface{ HCL2Spec() map[string]hcldec.Spec } { - return new(FlatSharedImageGalleryDestination) -} - -// HCL2Spec returns the hcl spec of a SharedImageGalleryDestination. -// This spec is used by HCL to read the fields of SharedImageGalleryDestination. -// The decoded values from this spec will then be applied to a FlatSharedImageGalleryDestination. -func (*FlatSharedImageGalleryDestination) HCL2Spec() map[string]hcldec.Spec { - s := map[string]hcldec.Spec{ - "resource_group": &hcldec.AttrSpec{Name: "resource_group", Type: cty.String, Required: false}, - "gallery_name": &hcldec.AttrSpec{Name: "gallery_name", Type: cty.String, Required: false}, - "image_name": &hcldec.AttrSpec{Name: "image_name", Type: cty.String, Required: false}, - "image_version": &hcldec.AttrSpec{Name: "image_version", Type: cty.String, Required: false}, - "replication_regions": &hcldec.AttrSpec{Name: "replication_regions", Type: cty.List(cty.String), Required: false}, - } - return s -} diff --git a/builder/azure/dtl/config_test.go b/builder/azure/dtl/config_test.go deleted file mode 100644 index 5690ffe68..000000000 --- a/builder/azure/dtl/config_test.go +++ /dev/null @@ -1,543 +0,0 @@ -package dtl - -import ( - "fmt" - "testing" - "time" - - "github.com/hashicorp/packer/builder/azure/common/constants" -) - -// List of configuration parameters that are required by the DTL builder. -var requiredConfigValues = []string{ - "capture_name_prefix", - "capture_container_name", - "client_id", - "client_secret", - "image_offer", - "image_publisher", - "image_sku", - "location", - "os_type", - "subscription_id", - "lab_resource_group_name", - "lab_virtual_network_name", -} - -func TestConfigShouldProvideReasonableDefaultValues(t *testing.T) { - c, _, err := newConfig(getDtlBuilderConfiguration(), getPackerConfiguration()) - - if err != nil { - t.Error("Expected configuration creation to succeed, but it failed!\n") - t.Fatalf(" errors: %s\n", err) - } - - if c.UserName == "" { - t.Error("Expected 'UserName' to be populated, but it was empty!") - } - - if c.VMSize == "" { - t.Error("Expected 'VMSize' to be populated, but it was empty!") - } - - if c.ClientConfig.ObjectID != "" { - t.Errorf("Expected 'ObjectID' to be nil, but it was '%s'!", c.ClientConfig.ObjectID) - } - - if c.managedImageStorageAccountType == "" { - t.Errorf("Expected 'managedImageStorageAccountType' to be populated, but it was empty!") - } - - if c.diskCachingType == "" { - t.Errorf("Expected 'diskCachingType' to be populated, but it was empty!") - } -} - -func TestConfigShouldDefaultVMSizeToStandardA1(t *testing.T) { - c, _, _ := newConfig(getDtlBuilderConfiguration(), getPackerConfiguration()) - - if c.VMSize != "Standard_A1" { - t.Errorf("Expected 'VMSize' to default to 'Standard_A1', but got '%s'.", c.VMSize) - } -} - -func TestConfigShouldDefaultImageVersionToLatest(t *testing.T) { - c, _, _ := newConfig(getDtlBuilderConfiguration(), getPackerConfiguration()) - - if c.ImageVersion != "latest" { - t.Errorf("Expected 'ImageVersion' to default to 'latest', but got '%s'.", c.ImageVersion) - } -} - -// The user can pass the value virtual_network_resource_group_name to avoid the lookup of -// a virtual network's resource group, or to help with disambiguation. The value should -// only be set if virtual_network_name was set. -func TestConfigVirtualNetworkResourceGroupNameMustBeSetWithVirtualNetworkName(t *testing.T) { - config := map[string]string{ - "capture_name_prefix": "ignore", - "capture_container_name": "ignore", - "location": "ignore", - "image_url": "ignore", - "subscription_id": "ignore", - "os_type": constants.Target_Linux, - "communicator": "none", - "virtual_network_resource_group_name": "MyVirtualNetworkRG", - } - - _, _, err := newConfig(config, getPackerConfiguration()) - if err == nil { - t.Error("Expected Config to reject virtual_network_resource_group_name, if virtual_network_name is not set.") - } -} - -// The user can pass the value virtual_network_subnet_name to avoid the lookup of -// a virtual network subnet's name, or to help with disambiguation. The value should -// only be set if virtual_network_name was set. -func TestConfigVirtualNetworkSubnetNameMustBeSetWithVirtualNetworkName(t *testing.T) { - config := map[string]string{ - "capture_name_prefix": "ignore", - "capture_container_name": "ignore", - "location": "ignore", - "image_url": "ignore", - "subscription_id": "ignore", - "os_type": constants.Target_Linux, - "communicator": "none", - "virtual_network_subnet_name": "MyVirtualNetworkRG", - } - - _, _, err := newConfig(config, getPackerConfiguration()) - if err == nil { - t.Error("Expected Config to reject virtual_network_subnet_name, if virtual_network_name is not set.") - } -} - -func TestSystemShouldDefineRuntimeValues(t *testing.T) { - c, _, _ := newConfig(getDtlBuilderConfiguration(), getPackerConfiguration()) - - if c.Password == "" { - t.Errorf("Expected Password to not be empty, but it was '%s'!", c.Password) - } - - if c.tmpComputeName == "" { - t.Errorf("Expected tmpComputeName to not be empty, but it was '%s'!", c.tmpComputeName) - } - - if c.tmpDeploymentName == "" { - t.Errorf("Expected tmpDeploymentName to not be empty, but it was '%s'!", c.tmpDeploymentName) - } - - if c.tmpResourceGroupName == "" { - t.Errorf("Expected tmpResourceGroupName to not be empty, but it was '%s'!", c.tmpResourceGroupName) - } - - if c.tmpOSDiskName == "" { - t.Errorf("Expected tmpOSDiskName to not be empty, but it was '%s'!", c.tmpOSDiskName) - } -} - -func TestConfigShouldTransformToVirtualMachineCaptureParameters(t *testing.T) { - c, _, _ := newConfig(getDtlBuilderConfiguration(), getPackerConfiguration()) - parameters := c.toVirtualMachineCaptureParameters() - - if *parameters.DestinationContainerName != c.CaptureContainerName { - t.Errorf("Expected DestinationContainerName to be equal to config's CaptureContainerName, but they were '%s' and '%s' respectively.", *parameters.DestinationContainerName, c.CaptureContainerName) - } - - if *parameters.VhdPrefix != c.CaptureNamePrefix { - t.Errorf("Expected DestinationContainerName to be equal to config's CaptureContainerName, but they were '%s' and '%s' respectively.", *parameters.VhdPrefix, c.CaptureNamePrefix) - } - - if *parameters.OverwriteVhds != false { - t.Error("Expected OverwriteVhds to be false, but it was not.") - } -} - -func TestConfigShouldSupportPackersConfigElements(t *testing.T) { - c, _, err := newConfig( - getDtlBuilderConfiguration(), - getPackerConfiguration(), - getPackerCommunicatorConfiguration()) - - if err != nil { - t.Fatal(err) - } - - if c.Comm.SSHTimeout != 1*time.Hour { - t.Errorf("Expected Comm.SSHTimeout to be a duration of an hour, but got '%s' instead.", c.Comm.SSHTimeout) - } - - if c.Comm.WinRMTimeout != 2*time.Hour { - t.Errorf("Expected Comm.WinRMTimeout to be a durationof two hours, but got '%s' instead.", c.Comm.WinRMTimeout) - } -} - -func TestWinRMConfigShouldSetRoundTripDecorator(t *testing.T) { - config := getDtlBuilderConfiguration() - config["communicator"] = "winrm" - config["winrm_username"] = "username" - config["winrm_password"] = "password" - - c, _, err := newConfig(config, getPackerConfiguration()) - if err != nil { - t.Fatal(err) - } - - if c.Comm.WinRMTransportDecorator == nil { - t.Error("Expected WinRMTransportDecorator to be set, but it was nil") - } -} - -func TestUserDeviceLoginIsEnabledForLinux(t *testing.T) { - config := map[string]string{ - "capture_name_prefix": "ignore", - "capture_container_name": "ignore", - "image_offer": "ignore", - "image_publisher": "ignore", - "image_sku": "ignore", - "location": "ignore", - "subscription_id": "ignore", - "os_type": constants.Target_Linux, - "communicator": "none", - "lab_resource_group_name": "ignore", - "lab_virtual_network_name": "ignore", - } - - _, _, err := newConfig(config, getPackerConfiguration()) - if err != nil { - t.Fatalf("failed to use device login for Linux: %s", err) - } -} - -func TestConfigShouldAcceptTags(t *testing.T) { - config := map[string]interface{}{ - "capture_name_prefix": "ignore", - "capture_container_name": "ignore", - "image_offer": "ignore", - "image_publisher": "ignore", - "image_sku": "ignore", - "location": "ignore", - "subscription_id": "ignore", - "communicator": "none", - "lab_resource_group_name": "ignore", - "lab_virtual_network_name": "ignore", - // Does not matter for this test case, just pick one. - "os_type": constants.Target_Linux, - "azure_tags": map[string]string{ - "tag01": "value01", - "tag02": "value02", - }, - } - - c, _, err := newConfig(config, getPackerConfiguration()) - - if err != nil { - t.Fatal(err) - } - - if len(c.AzureTags) != 2 { - t.Fatalf("expected to find 2 tags, but got %d", len(c.AzureTags)) - } - - if _, ok := c.AzureTags["tag01"]; !ok { - t.Error("expected to find key=\"tag01\", but did not") - } - if _, ok := c.AzureTags["tag02"]; !ok { - t.Error("expected to find key=\"tag02\", but did not") - } - - value := c.AzureTags["tag01"] - if *value != "value01" { - t.Errorf("expected AzureTags[\"tag01\"] to have value \"value01\", but got %q", *value) - } - - value = c.AzureTags["tag02"] - if *value != "value02" { - t.Errorf("expected AzureTags[\"tag02\"] to have value \"value02\", but got %q", *value) - } -} - -func TestConfigShouldRejectTagsInExcessOf15AcceptTags(t *testing.T) { - tooManyTags := map[string]string{} - for i := 0; i < 16; i++ { - tooManyTags[fmt.Sprintf("tag%.2d", i)] = "ignored" - } - - config := map[string]interface{}{ - "capture_name_prefix": "ignore", - "capture_container_name": "ignore", - "image_offer": "ignore", - "image_publisher": "ignore", - "image_sku": "ignore", - "location": "ignore", - "subscription_id": "ignore", - "communicator": "none", - "lab_resource_group_name": "ignore", - "lab_virtual_network_name": "ignore", - // Does not matter for this test case, just pick one. - "os_type": constants.Target_Linux, - "azure_tags": tooManyTags, - } - - _, _, err := newConfig(config, getPackerConfiguration()) - - if err == nil { - t.Fatal("expected config to reject based on an excessive amount of tags (> 15)") - } -} - -func TestConfigShouldRejectExcessiveTagNameLength(t *testing.T) { - nameTooLong := make([]byte, 513) - for i := range nameTooLong { - nameTooLong[i] = 'a' - } - - tags := map[string]string{} - tags[string(nameTooLong)] = "ignored" - - config := map[string]interface{}{ - "capture_name_prefix": "ignore", - "capture_container_name": "ignore", - "image_offer": "ignore", - "image_publisher": "ignore", - "image_sku": "ignore", - "location": "ignore", - "subscription_id": "ignore", - "communicator": "none", - "lab_resource_group_name": "ignore", - "lab_virtual_network_name": "ignore", - // Does not matter for this test case, just pick one. - "os_type": constants.Target_Linux, - "azure_tags": tags, - } - - _, _, err := newConfig(config, getPackerConfiguration()) - if err == nil { - t.Fatal("expected config to reject tag name based on length (> 512)") - } -} - -func TestConfigShouldRejectExcessiveTagValueLength(t *testing.T) { - valueTooLong := make([]byte, 257) - for i := range valueTooLong { - valueTooLong[i] = 'a' - } - - tags := map[string]string{} - tags["tag01"] = string(valueTooLong) - - config := map[string]interface{}{ - "capture_name_prefix": "ignore", - "capture_container_name": "ignore", - "image_offer": "ignore", - "image_publisher": "ignore", - "image_sku": "ignore", - "location": "ignore", - "subscription_id": "ignore", - "communicator": "none", - "lab_resource_group_name": "ignore", - "lab_virtual_network_name": "ignore", - // Does not matter for this test case, just pick one. - "os_type": constants.Target_Linux, - "azure_tags": tags, - } - - _, _, err := newConfig(config, getPackerConfiguration()) - if err == nil { - t.Fatal("expected config to reject tag value based on length (> 256)") - } -} - -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", - "lab_resource_group_name": "ignore", - "lab_virtual_network_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") - } -} - -func TestConfigShouldAcceptManagedImageStorageAccountTypes(t *testing.T) { - config := map[string]interface{}{ - "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", - "lab_resource_group_name": "ignore", - "lab_virtual_network_name": "ignore", - - // Does not matter for this test case, just pick one. - "os_type": constants.Target_Linux, - } - - storage_account_types := []string{"Premium_LRS", "Standard_LRS"} - - for _, x := range storage_account_types { - config["managed_image_storage_account_type"] = x - _, _, err := newConfig(config, getPackerConfiguration()) - if err != nil { - t.Fatalf("expected config to accept a managed_image_storage_account_type of %q", x) - } - } -} - -func TestConfigShouldAcceptDiskCachingTypes(t *testing.T) { - config := map[string]interface{}{ - "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", - "lab_resource_group_name": "ignore", - "lab_virtual_network_name": "ignore", - - // Does not matter for this test case, just pick one. - "os_type": constants.Target_Linux, - } - - storage_account_types := []string{"None", "ReadOnly", "ReadWrite"} - - for _, x := range storage_account_types { - config["disk_caching_type"] = x - _, _, err := newConfig(config, getPackerConfiguration()) - if err != nil { - t.Fatalf("expected config to accept a disk_caching_type of %q", x) - } - } -} - -func TestConfigAdditionalDiskDefaultIsNil(t *testing.T) { - c, _, _ := newConfig(getDtlBuilderConfiguration(), getPackerConfiguration()) - if c.AdditionalDiskSize != nil { - t.Errorf("Expected Config to not have a set of additional disks, but got a non nil value") - } -} - -func TestConfigAdditionalDiskOverrideDefault(t *testing.T) { - config := map[string]string{ - "capture_name_prefix": "ignore", - "capture_container_name": "ignore", - "location": "ignore", - "image_url": "ignore", - "subscription_id": "ignore", - "os_type": constants.Target_Linux, - "communicator": "none", - "lab_resource_group_name": "ignore", - "lab_virtual_network_name": "ignore", - } - - diskconfig := map[string][]int32{ - "disk_additional_size": {32, 64}, - } - - c, _, _ := newConfig(config, diskconfig, getPackerConfiguration()) - if c.AdditionalDiskSize == nil { - t.Errorf("Expected Config to have a set of additional disks, but got nil") - } - if len(c.AdditionalDiskSize) != 2 { - t.Errorf("Expected Config to have a 2 additional disks, but got %d additional disks", len(c.AdditionalDiskSize)) - } - if c.AdditionalDiskSize[0] != 32 { - t.Errorf("Expected Config to have the first additional disks of size 32Gb, but got %dGb", c.AdditionalDiskSize[0]) - } - if c.AdditionalDiskSize[1] != 64 { - t.Errorf("Expected Config to have the second additional disks of size 64Gb, but got %dGb", c.AdditionalDiskSize[1]) - } -} - -func TestConfigShouldAllowSharedImageGalleryOptions(t *testing.T) { - config := map[string]interface{}{ - "location": "ignore", - "subscription_id": "ignore", - "os_type": "linux", - "lab_resource_group_name": "ignore", - "lab_virtual_network_name": "ignore", - "shared_image_gallery": map[string]string{ - "subscription": "ignore", - "resource_group": "ignore", - "gallery_name": "ignore", - "image_name": "ignore", - "image_version": "ignore", - }, - } - - _, _, err := newConfig(config, getPackerConfiguration()) - if err == nil { - t.Log("expected config to accept Shared Image Gallery options", err) - } - -} - -func TestConfigShouldRejectSharedImageGalleryWithVhdTarget(t *testing.T) { - config := map[string]interface{}{ - "location": "ignore", - "subscription_id": "ignore", - "os_type": "linux", - "shared_image_gallery": map[string]string{ - "subscription": "ignore", - "resource_group": "ignore", - "gallery_name": "ignore", - "image_name": "ignore", - "image_version": "ignore", - }, - "capture_container_name": "ignore", - "capture_name_prefix": "ignore", - "lab_resource_group_name": "ignore", - "lab_virtual_network_name": "ignore", - } - - _, _, err := newConfig(config, getPackerConfiguration()) - if err != nil { - t.Log("expected an error if Shared Image Gallery source is used with VHD target", err) - } -} - -func getDtlBuilderConfiguration() map[string]string { - m := make(map[string]string) - for _, v := range requiredConfigValues { - m[v] = "ignored00" - } - - m["communicator"] = "none" - m["os_type"] = constants.Target_Linux - return m -} - -func getPackerConfiguration() interface{} { - config := map[string]interface{}{ - "packer_build_name": "azure-arm-vm", - "packer_builder_type": "azure-arm-vm", - "packer_debug": "false", - "packer_force": "false", - "packer_template_path": "/home/jenkins/azure-arm-vm/template.json", - } - - return config -} - -func getPackerCommunicatorConfiguration() map[string]string { - config := map[string]string{ - "ssh_timeout": "1h", - "winrm_timeout": "2h", - } - - return config -} diff --git a/builder/azure/dtl/inspector.go b/builder/azure/dtl/inspector.go deleted file mode 100644 index 824963f75..000000000 --- a/builder/azure/dtl/inspector.go +++ /dev/null @@ -1,71 +0,0 @@ -package dtl - -import ( - "bytes" - "io/ioutil" - "log" - "net/http" - - "io" - - "github.com/Azure/go-autorest/autorest" - "github.com/Azure/go-autorest/autorest/azure" - "github.com/hashicorp/packer/builder/azure/common/logutil" -) - -func chop(data []byte, maxlen int64) string { - s := string(data) - if int64(len(s)) > maxlen { - s = s[:maxlen] + "..." - } - return s -} - -func handleBody(body io.ReadCloser, maxlen int64) (io.ReadCloser, string) { - if body == nil { - return nil, "" - } - - defer body.Close() - - b, err := ioutil.ReadAll(body) - if err != nil { - return nil, "" - } - - return ioutil.NopCloser(bytes.NewReader(b)), chop(b, maxlen) -} - -func withInspection(maxlen int64) autorest.PrepareDecorator { - return func(p autorest.Preparer) autorest.Preparer { - return autorest.PreparerFunc(func(r *http.Request) (*http.Request, error) { - body, bodyString := handleBody(r.Body, maxlen) - r.Body = body - - log.Print("Azure request", logutil.Fields{ - "method": r.Method, - "request": r.URL.String(), - "body": bodyString, - }) - return p.Prepare(r) - }) - } -} - -func byInspecting(maxlen int64) autorest.RespondDecorator { - return func(r autorest.Responder) autorest.Responder { - return autorest.ResponderFunc(func(resp *http.Response) error { - body, bodyString := handleBody(resp.Body, maxlen) - resp.Body = body - - log.Print("Azure response", logutil.Fields{ - "status": resp.Status, - "method": resp.Request.Method, - "request": resp.Request.URL.String(), - "x-ms-request-id": azure.ExtractRequestID(resp), - "body": bodyString, - }) - return r.Respond(resp) - }) - } -} diff --git a/builder/azure/dtl/openssh_key_pair.go b/builder/azure/dtl/openssh_key_pair.go deleted file mode 100644 index 3e2f5a371..000000000 --- a/builder/azure/dtl/openssh_key_pair.go +++ /dev/null @@ -1,59 +0,0 @@ -package dtl - -import ( - "crypto/rand" - "crypto/rsa" - "crypto/x509" - "encoding/base64" - "encoding/pem" - "fmt" - "time" - - "golang.org/x/crypto/ssh" -) - -const ( - KeySize = 2048 -) - -type OpenSshKeyPair struct { - privateKey *rsa.PrivateKey - publicKey ssh.PublicKey -} - -func NewOpenSshKeyPair() (*OpenSshKeyPair, error) { - return NewOpenSshKeyPairWithSize(KeySize) -} - -func NewOpenSshKeyPairWithSize(keySize int) (*OpenSshKeyPair, error) { - privateKey, err := rsa.GenerateKey(rand.Reader, keySize) - if err != nil { - return nil, err - } - - publicKey, err := ssh.NewPublicKey(&privateKey.PublicKey) - if err != nil { - return nil, err - } - - return &OpenSshKeyPair{ - privateKey: privateKey, - publicKey: publicKey, - }, nil -} - -func (s *OpenSshKeyPair) AuthorizedKey() string { - return fmt.Sprintf("%s %s packer Azure Deployment%s", - s.publicKey.Type(), - base64.StdEncoding.EncodeToString(s.publicKey.Marshal()), - time.Now().Format(time.RFC3339)) -} - -func (s *OpenSshKeyPair) PrivateKey() []byte { - privateKey := pem.EncodeToMemory(&pem.Block{ - Type: "RSA PRIVATE KEY", - Bytes: x509.MarshalPKCS1PrivateKey(s.privateKey), - }) - - return privateKey -} diff --git a/builder/azure/dtl/openssh_key_pair_test.go b/builder/azure/dtl/openssh_key_pair_test.go deleted file mode 100644 index d4aa6e94d..000000000 --- a/builder/azure/dtl/openssh_key_pair_test.go +++ /dev/null @@ -1,37 +0,0 @@ -package dtl - -import ( - "testing" - - "golang.org/x/crypto/ssh" -) - -func TestFart(t *testing.T) { - -} - -func TestAuthorizedKeyShouldParse(t *testing.T) { - testSubject, err := NewOpenSshKeyPairWithSize(512) - if err != nil { - t.Fatalf("Failed to create a new OpenSSH key pair, err=%s.", err) - } - - authorizedKey := testSubject.AuthorizedKey() - - _, _, _, _, err = ssh.ParseAuthorizedKey([]byte(authorizedKey)) - if err != nil { - t.Fatalf("Failed to parse the authorized key, err=%s", err) - } -} - -func TestPrivateKeyShouldParse(t *testing.T) { - testSubject, err := NewOpenSshKeyPairWithSize(512) - if err != nil { - t.Fatalf("Failed to create a new OpenSSH key pair, err=%s.", err) - } - - _, err = ssh.ParsePrivateKey(testSubject.PrivateKey()) - if err != nil { - t.Fatalf("Failed to parse the private key, err=%s\n", err) - } -} diff --git a/builder/azure/dtl/resource_resolver.go b/builder/azure/dtl/resource_resolver.go deleted file mode 100644 index d5c486fd8..000000000 --- a/builder/azure/dtl/resource_resolver.go +++ /dev/null @@ -1,141 +0,0 @@ -package dtl - -// Code to resolve resources that are required by the API. These resources -// can most likely be resolved without asking the user, thereby reducing the -// amount of configuration they need to provide. -// -// Resource resolver differs from config retriever because resource resolver -// requires a client to communicate with the Azure API. A config retriever is -// used to determine values without use of a client. - -import ( - "context" - "fmt" - "strings" - - "github.com/Azure/azure-sdk-for-go/services/compute/mgmt/2018-04-01/compute" -) - -type resourceResolver struct { - client *AzureClient - findVirtualNetworkResourceGroup func(*AzureClient, string) (string, error) - findVirtualNetworkSubnet func(*AzureClient, string, string) (string, error) -} - -func newResourceResolver(client *AzureClient) *resourceResolver { - return &resourceResolver{ - client: client, - findVirtualNetworkResourceGroup: findVirtualNetworkResourceGroup, - findVirtualNetworkSubnet: findVirtualNetworkSubnet, - } -} - -func (s *resourceResolver) Resolve(c *Config) error { - // if s.shouldResolveResourceGroup(c) { - // resourceGroupName, err := s.findVirtualNetworkResourceGroup(s.client, c.VirtualNetworkName) - // if err != nil { - // return err - // } - - // subnetName, err := s.findVirtualNetworkSubnet(s.client, resourceGroupName, c.VirtualNetworkName) - // if err != nil { - // return err - // } - - // c.VirtualNetworkResourceGroupName = resourceGroupName - // c.VirtualNetworkSubnetName = subnetName - // } - - if s.shouldResolveManagedImageName(c) { - image, err := findManagedImageByName(s.client, c.CustomManagedImageName, c.CustomManagedImageResourceGroupName) - if err != nil { - return err - } - - c.customManagedImageID = *image.ID - } - - return nil -} - -// func (s *resourceResolver) shouldResolveResourceGroup(c *Config) bool { -// return c.VirtualNetworkName != "" && c.VirtualNetworkResourceGroupName == "" -// } - -func (s *resourceResolver) shouldResolveManagedImageName(c *Config) bool { - return c.CustomManagedImageName != "" -} - -func getResourceGroupNameFromId(id string) string { - // "/subscriptions/3f499422-dd76-4114-8859-86d526c9deb6/resourceGroups/packer-Resource-Group-yylnwsl30j/providers/... - xs := strings.Split(id, "/") - return xs[4] -} - -func findManagedImageByName(client *AzureClient, name, resourceGroupName string) (*compute.Image, error) { - images, err := client.ImagesClient.ListByResourceGroupComplete(context.TODO(), resourceGroupName) - if err != nil { - return nil, err - } - - for images.NotDone() { - image := images.Value() - if strings.EqualFold(name, *image.Name) { - return &image, nil - } - if err = images.Next(); err != nil { - return nil, err - } - } - - return nil, fmt.Errorf("Cannot find an image named '%s' in the resource group '%s'", name, resourceGroupName) -} - -func findVirtualNetworkResourceGroup(client *AzureClient, name string) (string, error) { - virtualNetworks, err := client.VirtualNetworksClient.ListAllComplete(context.TODO()) - if err != nil { - return "", err - } - - resourceGroupNames := make([]string, 0) - for virtualNetworks.NotDone() { - virtualNetwork := virtualNetworks.Value() - if strings.EqualFold(name, *virtualNetwork.Name) { - rgn := getResourceGroupNameFromId(*virtualNetwork.ID) - resourceGroupNames = append(resourceGroupNames, rgn) - } - if err = virtualNetworks.Next(); err != nil { - return "", err - } - } - - if len(resourceGroupNames) == 0 { - return "", fmt.Errorf("Cannot find a resource group with a virtual network called %q", name) - } - - if len(resourceGroupNames) > 1 { - return "", fmt.Errorf("Found multiple resource groups with a virtual network called %q, please use virtual_network_subnet_name and virtual_network_resource_group_name to disambiguate", name) - } - - return resourceGroupNames[0], nil -} - -func findVirtualNetworkSubnet(client *AzureClient, resourceGroupName string, name string) (string, error) { - subnets, err := client.SubnetsClient.List(context.TODO(), resourceGroupName, name) - if err != nil { - return "", err - } - - subnetList := subnets.Values() // only first page of subnets, but only interested in ==0 or >1 - - if len(subnetList) == 0 { - return "", fmt.Errorf("Cannot find a subnet in the resource group %q associated with the virtual network called %q", resourceGroupName, name) - } - - if len(subnetList) > 1 { - return "", fmt.Errorf("Found multiple subnets in the resource group %q associated with the virtual network called %q, please use virtual_network_subnet_name and virtual_network_resource_group_name to disambiguate", resourceGroupName, name) - } - - subnet := subnetList[0] - return *subnet.Name, nil -} diff --git a/builder/azure/dtl/step.go b/builder/azure/dtl/step.go deleted file mode 100644 index b5de4cb95..000000000 --- a/builder/azure/dtl/step.go +++ /dev/null @@ -1,20 +0,0 @@ -package dtl - -import ( - "github.com/hashicorp/packer-plugin-sdk/multistep" - "github.com/hashicorp/packer/builder/azure/common/constants" -) - -func processStepResult( - err error, sayError func(error), state multistep.StateBag) multistep.StepAction { - - if err != nil { - state.Put(constants.Error, err) - sayError(err) - - return multistep.ActionHalt - } - - return multistep.ActionContinue - -} diff --git a/builder/azure/dtl/step_capture_image.go b/builder/azure/dtl/step_capture_image.go deleted file mode 100644 index a16315977..000000000 --- a/builder/azure/dtl/step_capture_image.go +++ /dev/null @@ -1,125 +0,0 @@ -package dtl - -import ( - "context" - "fmt" - - "github.com/Azure/azure-sdk-for-go/services/devtestlabs/mgmt/2018-09-15/dtl" - - "github.com/hashicorp/packer-plugin-sdk/multistep" - packersdk "github.com/hashicorp/packer-plugin-sdk/packer" - "github.com/hashicorp/packer/builder/azure/common/constants" -) - -type StepCaptureImage struct { - client *AzureClient - captureManagedImage func(ctx context.Context) error - get func(client *AzureClient) *CaptureTemplate - config *Config - say func(message string) - error func(e error) -} - -func NewStepCaptureImage(client *AzureClient, ui packersdk.Ui, config *Config) *StepCaptureImage { - var step = &StepCaptureImage{ - client: client, - get: func(client *AzureClient) *CaptureTemplate { - return client.Template - }, - config: config, - say: func(message string) { - ui.Say(message) - }, - error: func(e error) { - ui.Error(e.Error()) - }, - } - - // step.captureVhd = step.captureImage - step.captureManagedImage = step.captureImageFromVM - - return step -} - -func (s *StepCaptureImage) captureImageFromVM(ctx context.Context) error { - imageID := fmt.Sprintf("/subscriptions/%s/resourceGroups/%s/providers/Microsoft.DevTestLab/labs/%s/virtualMachines/%s", - s.config.ClientConfig.SubscriptionID, - s.config.tmpResourceGroupName, - s.config.LabName, - s.config.tmpComputeName) - - customImageProperties := dtl.CustomImageProperties{} - - if s.config.OSType == constants.Target_Linux { - customImageProperties = dtl.CustomImageProperties{ - VM: &dtl.CustomImagePropertiesFromVM{ - LinuxOsInfo: &dtl.LinuxOsInfo{ - LinuxOsState: dtl.DeprovisionRequested, - }, - SourceVMID: &imageID, - }, - } - } else if s.config.OSType == constants.Target_Windows { - customImageProperties = dtl.CustomImageProperties{ - VM: &dtl.CustomImagePropertiesFromVM{ - WindowsOsInfo: &dtl.WindowsOsInfo{ - WindowsOsState: dtl.SysprepRequested, - }, - SourceVMID: &imageID, - }, - } - } - - customImage := &dtl.CustomImage{ - Name: &s.config.ManagedImageName, - CustomImageProperties: &customImageProperties, - } - - f, err := s.client.DtlCustomImageClient.CreateOrUpdate(ctx, s.config.LabResourceGroupName, s.config.LabName, s.config.ManagedImageName, *customImage) - if err == nil { - err = f.WaitForCompletionRef(ctx, s.client.DtlCustomImageClient.Client) - } - if err != nil { - s.say("Error from Capture Image") - s.say(s.client.LastError.Error()) - } - - return err -} - -func (s *StepCaptureImage) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction { - s.say("Capturing image ...") - - var computeName = state.Get(constants.ArmComputeName).(string) - var location = state.Get(constants.ArmLocation).(string) - var resourceGroupName = state.Get(constants.ArmResourceGroupName).(string) - - s.say(fmt.Sprintf(" -> Compute ResourceGroupName : '%s'", resourceGroupName)) - s.say(fmt.Sprintf(" -> Compute Name : '%s'", computeName)) - s.say(fmt.Sprintf(" -> Compute Location : '%s'", location)) - - err := s.captureImageFromVM(ctx) - - if err != nil { - s.error(err) - state.Put(constants.Error, err) - - return multistep.ActionHalt - } - - // HACK(chrboum): I do not like this. The capture method should be returning this value - // instead having to pass in another lambda. - // - // Having to resort to capturing the template via an inspector is hack, and once I can - // resolve that I can cleanup this code too. See the comments in azure_client.go for more - // details. - // [paulmey]: autorest.Future now has access to the last http.Response, but I'm not sure if - // the body is still accessible. - template := s.get(s.client) - state.Put(constants.ArmCaptureTemplate, template) - - return multistep.ActionContinue -} - -func (*StepCaptureImage) Cleanup(multistep.StateBag) { -} diff --git a/builder/azure/dtl/step_delete_virtual_machine.go b/builder/azure/dtl/step_delete_virtual_machine.go deleted file mode 100644 index ae21a6ed1..000000000 --- a/builder/azure/dtl/step_delete_virtual_machine.go +++ /dev/null @@ -1,61 +0,0 @@ -package dtl - -import ( - "context" - "fmt" - - "github.com/hashicorp/packer-plugin-sdk/multistep" - packersdk "github.com/hashicorp/packer-plugin-sdk/packer" - "github.com/hashicorp/packer/builder/azure/common/constants" -) - -type StepDeleteVirtualMachine struct { - client *AzureClient - config *Config - delete func(ctx context.Context, resourceGroupName string, computeName string, state multistep.StateBag) error - say func(message string) - error func(e error) -} - -func NewStepDeleteVirtualMachine(client *AzureClient, ui packersdk.Ui, config *Config) *StepDeleteVirtualMachine { - var step = &StepDeleteVirtualMachine{ - client: client, - config: config, - say: func(message string) { ui.Say(message) }, - error: func(e error) { ui.Error(e.Error()) }, - } - - step.delete = step.deleteVirtualMachine - return step -} - -func (s *StepDeleteVirtualMachine) deleteVirtualMachine(ctx context.Context, resourceGroupName string, vmName string, state multistep.StateBag) error { - f, err := s.client.DtlVirtualMachineClient.Delete(ctx, resourceGroupName, s.config.LabName, vmName) - if err == nil { - err = f.WaitForCompletionRef(ctx, s.client.DtlVirtualMachineClient.Client) - } - if err != nil { - s.say("Error from delete VM") - s.say(s.client.LastError.Error()) - } - - return err -} - -func (s *StepDeleteVirtualMachine) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction { - s.say("Deleting the virtual machine ...") - - var resourceGroupName = state.Get(constants.ArmResourceGroupName).(string) - var computeName = state.Get(constants.ArmComputeName).(string) - - s.say(fmt.Sprintf(" -> ResourceGroupName : '%s'", resourceGroupName)) - s.say(fmt.Sprintf(" -> ComputeName : '%s'", computeName)) - - err := s.deleteVirtualMachine(ctx, resourceGroupName, computeName, state) - - s.say("Deleting virtual machine ...Complete") - return processStepResult(err, s.error, state) -} - -func (*StepDeleteVirtualMachine) Cleanup(multistep.StateBag) { -} diff --git a/builder/azure/dtl/step_deploy_template.go b/builder/azure/dtl/step_deploy_template.go deleted file mode 100644 index b6dd83589..000000000 --- a/builder/azure/dtl/step_deploy_template.go +++ /dev/null @@ -1,192 +0,0 @@ -package dtl - -import ( - "context" - "errors" - "fmt" - "net/url" - "strings" - - "github.com/hashicorp/packer-plugin-sdk/multistep" - packersdk "github.com/hashicorp/packer-plugin-sdk/packer" - "github.com/hashicorp/packer/builder/azure/common/constants" -) - -type StepDeployTemplate struct { - client *AzureClient - deploy func(ctx context.Context, resourceGroupName string, deploymentName string, state multistep.StateBag) error - delete func(ctx context.Context, client *AzureClient, resourceType string, resourceName string, resourceGroupName string) error - disk func(ctx context.Context, resourceGroupName string, computeName string) (string, string, error) - deleteDisk func(ctx context.Context, imageType string, imageName string, resourceGroupName string) error - say func(message string) - error func(e error) - config *Config - factory templateFactoryFuncDtl - name string -} - -func NewStepDeployTemplate(client *AzureClient, ui packersdk.Ui, config *Config, deploymentName string, factory templateFactoryFuncDtl) *StepDeployTemplate { - var step = &StepDeployTemplate{ - client: client, - say: func(message string) { ui.Say(message) }, - error: func(e error) { ui.Error(e.Error()) }, - config: config, - factory: factory, - name: deploymentName, - } - - step.deploy = step.deployTemplate - step.delete = deleteResource - step.disk = step.getImageDetails - step.deleteDisk = step.deleteImage - return step -} - -func (s *StepDeployTemplate) deployTemplate(ctx context.Context, resourceGroupName string, deploymentName string, state multistep.StateBag) error { - - vmlistPage, err := s.client.DtlVirtualMachineClient.List(ctx, s.config.tmpResourceGroupName, s.config.LabName, "", "", nil, "") - - if err != nil { - s.say(s.client.LastError.Error()) - return err - } - - vmList := vmlistPage.Values() - for i := range vmList { - if *vmList[i].Name == s.config.tmpComputeName { - return fmt.Errorf("Error: Virtual Machine %s already exists. Please use another name", s.config.tmpComputeName) - } - } - - s.say(fmt.Sprintf("Creating Virtual Machine %s", s.config.tmpComputeName)) - labMachine, err := s.factory(s.config) - if err != nil { - return err - } - - f, err := s.client.DtlLabsClient.CreateEnvironment(ctx, s.config.tmpResourceGroupName, s.config.LabName, *labMachine) - - if err == nil { - err = f.WaitForCompletionRef(ctx, s.client.DtlLabsClient.Client) - } - if err != nil { - s.say(s.client.LastError.Error()) - return err - } - expand := "Properties($expand=ComputeVm,Artifacts,NetworkInterface)" - - vm, err := s.client.DtlVirtualMachineClient.Get(ctx, s.config.tmpResourceGroupName, s.config.LabName, s.config.tmpComputeName, expand) - if err != nil { - s.say(s.client.LastError.Error()) - } - xs := strings.Split(*vm.LabVirtualMachineProperties.ComputeID, "/") - s.config.VMCreationResourceGroup = xs[4] - - s.say(fmt.Sprintf(" -> VM FQDN : '%s'", *vm.Fqdn)) - - state.Put(constants.SSHHost, *vm.Fqdn) - s.config.tmpFQDN = *vm.Fqdn - - // Resuing the Resource group name from common constants as all steps depend on it. - state.Put(constants.ArmResourceGroupName, s.config.VMCreationResourceGroup) - - s.say(fmt.Sprintf(" -> VM ResourceGroupName : '%s'", s.config.VMCreationResourceGroup)) - - return err -} - -func (s *StepDeployTemplate) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction { - s.say("Deploying deployment template ...") - - var resourceGroupName = state.Get(constants.ArmResourceGroupName).(string) - - s.say(fmt.Sprintf(" -> Lab ResourceGroupName : '%s'", resourceGroupName)) - - return processStepResult( - s.deploy(ctx, resourceGroupName, s.name, state), - s.error, state) -} - -func (s *StepDeployTemplate) getImageDetails(ctx context.Context, resourceGroupName string, computeName string) (string, string, error) { - //We can't depend on constants.ArmOSDiskVhd being set - var imageName string - var imageType string - vm, err := s.client.VirtualMachinesClient.Get(ctx, resourceGroupName, computeName, "") - if err != nil { - return imageName, imageType, err - } else { - if vm.StorageProfile.OsDisk.Vhd != nil { - imageType = "image" - imageName = *vm.StorageProfile.OsDisk.Vhd.URI - } else { - imageType = "Microsoft.Compute/disks" - imageName = *vm.StorageProfile.OsDisk.ManagedDisk.ID - } - } - return imageType, imageName, nil -} - -//TODO(paulmey): move to helpers file -func deleteResource(ctx context.Context, client *AzureClient, resourceType string, resourceName string, resourceGroupName string) error { - switch resourceType { - case "Microsoft.Compute/virtualMachines": - f, err := client.VirtualMachinesClient.Delete(ctx, resourceGroupName, resourceName) - if err == nil { - err = f.WaitForCompletionRef(ctx, client.VirtualMachinesClient.Client) - } - return err - case "Microsoft.Network/networkInterfaces": - f, err := client.InterfacesClient.Delete(ctx, resourceGroupName, resourceName) - if err == nil { - err = f.WaitForCompletionRef(ctx, client.InterfacesClient.Client) - } - return err - case "Microsoft.Network/virtualNetworks": - f, err := client.VirtualNetworksClient.Delete(ctx, resourceGroupName, resourceName) - if err == nil { - err = f.WaitForCompletionRef(ctx, client.VirtualNetworksClient.Client) - } - return err - case "Microsoft.Network/publicIPAddresses": - f, err := client.PublicIPAddressesClient.Delete(ctx, resourceGroupName, resourceName) - if err == nil { - err = f.WaitForCompletionRef(ctx, client.PublicIPAddressesClient.Client) - } - return err - } - return nil -} - -func (s *StepDeployTemplate) deleteImage(ctx context.Context, imageType string, imageName string, resourceGroupName string) error { - // Managed disk - if imageType == "Microsoft.Compute/disks" { - xs := strings.Split(imageName, "/") - diskName := xs[len(xs)-1] - f, err := s.client.DisksClient.Delete(ctx, resourceGroupName, diskName) - if err == nil { - err = f.WaitForCompletionRef(ctx, s.client.DisksClient.Client) - } - return err - } - // VHD image - u, err := url.Parse(imageName) - if err != nil { - return err - } - xs := strings.Split(u.Path, "/") - if len(xs) < 3 { - return errors.New("Unable to parse path of image " + imageName) - } - var storageAccountName = xs[1] - var blobName = strings.Join(xs[2:], "/") - - blob := s.client.BlobStorageClient.GetContainerReference(storageAccountName).GetBlobReference(blobName) - err = blob.Delete(nil) - return err -} - -func (s *StepDeployTemplate) Cleanup(state multistep.StateBag) { - //Only clean up if this was an existing resource group and the resource group - //is marked as created - // Just return now -} diff --git a/builder/azure/dtl/step_power_off_compute.go b/builder/azure/dtl/step_power_off_compute.go deleted file mode 100644 index f0eed13d8..000000000 --- a/builder/azure/dtl/step_power_off_compute.go +++ /dev/null @@ -1,61 +0,0 @@ -package dtl - -import ( - "context" - "fmt" - - "github.com/hashicorp/packer-plugin-sdk/multistep" - packersdk "github.com/hashicorp/packer-plugin-sdk/packer" - "github.com/hashicorp/packer/builder/azure/common/constants" -) - -type StepPowerOffCompute struct { - client *AzureClient - config *Config - powerOff func(ctx context.Context, resourceGroupName string, labName, computeName string) error - say func(message string) - error func(e error) -} - -func NewStepPowerOffCompute(client *AzureClient, ui packersdk.Ui, config *Config) *StepPowerOffCompute { - - var step = &StepPowerOffCompute{ - client: client, - config: config, - say: func(message string) { ui.Say(message) }, - error: func(e error) { ui.Error(e.Error()) }, - } - - step.powerOff = step.powerOffCompute - return step -} - -func (s *StepPowerOffCompute) powerOffCompute(ctx context.Context, resourceGroupName string, labName, computeName string) error { - //f, err := s.client.VirtualMachinesClient.Deallocate(ctx, resourceGroupName, computeName) - f, err := s.client.DtlVirtualMachineClient.Stop(ctx, resourceGroupName, labName, computeName) - if err == nil { - err = f.WaitForCompletionRef(ctx, s.client.DtlVirtualMachineClient.Client) - } - if err != nil { - s.say(s.client.LastError.Error()) - } - return err -} - -func (s *StepPowerOffCompute) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction { - s.say("Powering off machine ...") - - var resourceGroupName = state.Get(constants.ArmResourceGroupName).(string) - var computeName = state.Get(constants.ArmComputeName).(string) - - s.say(fmt.Sprintf(" -> ResourceGroupName : '%s'", resourceGroupName)) - s.say(fmt.Sprintf(" -> ComputeName : '%s'", computeName)) - - err := s.powerOff(ctx, s.config.LabResourceGroupName, s.config.LabName, computeName) - - s.say("Powering off machine ...Complete") - return processStepResult(err, s.error, state) -} - -func (*StepPowerOffCompute) Cleanup(multistep.StateBag) { -} diff --git a/builder/azure/dtl/step_publish_to_shared_image_gallery.go b/builder/azure/dtl/step_publish_to_shared_image_gallery.go deleted file mode 100644 index f080a0dde..000000000 --- a/builder/azure/dtl/step_publish_to_shared_image_gallery.go +++ /dev/null @@ -1,126 +0,0 @@ -package dtl - -import ( - "context" - "fmt" - - "github.com/Azure/azure-sdk-for-go/services/compute/mgmt/2019-03-01/compute" - "github.com/hashicorp/packer-plugin-sdk/multistep" - packersdk "github.com/hashicorp/packer-plugin-sdk/packer" - "github.com/hashicorp/packer/builder/azure/common/constants" -) - -type StepPublishToSharedImageGallery struct { - client *AzureClient - publish func(ctx context.Context, mdiID, miSigPubRg, miSIGalleryName, miSGImageName, miSGImageVersion string, miSigReplicationRegions []string, location string, tags map[string]*string) (string, error) - say func(message string) - error func(e error) - toSIG func() bool -} - -func NewStepPublishToSharedImageGallery(client *AzureClient, ui packersdk.Ui, config *Config) *StepPublishToSharedImageGallery { - var step = &StepPublishToSharedImageGallery{ - client: client, - say: func(message string) { - ui.Say(message) - }, - error: func(e error) { - ui.Error(e.Error()) - }, - toSIG: func() bool { - return config.isManagedImage() && config.SharedGalleryDestination.SigDestinationGalleryName != "" - }, - } - - step.publish = step.publishToSig - return step -} - -func (s *StepPublishToSharedImageGallery) publishToSig(ctx context.Context, mdiID string, miSigPubRg string, miSIGalleryName string, miSGImageName string, miSGImageVersion string, miSigReplicationRegions []string, location string, tags map[string]*string) (string, error) { - - replicationRegions := make([]compute.TargetRegion, len(miSigReplicationRegions)) - for i, v := range miSigReplicationRegions { - regionName := v - replicationRegions[i] = compute.TargetRegion{Name: ®ionName} - } - - galleryImageVersion := compute.GalleryImageVersion{ - Location: &location, - Tags: tags, - GalleryImageVersionProperties: &compute.GalleryImageVersionProperties{ - PublishingProfile: &compute.GalleryImageVersionPublishingProfile{ - Source: &compute.GalleryArtifactSource{ - ManagedImage: &compute.ManagedArtifact{ - ID: &mdiID, - }, - }, - TargetRegions: &replicationRegions, - }, - }, - } - - f, err := s.client.GalleryImageVersionsClient.CreateOrUpdate(ctx, miSigPubRg, miSIGalleryName, miSGImageName, miSGImageVersion, galleryImageVersion) - - if err != nil { - s.say(s.client.LastError.Error()) - return "", err - } - - err = f.WaitForCompletionRef(ctx, s.client.GalleryImageVersionsClient.Client) - - if err != nil { - s.say(s.client.LastError.Error()) - return "", err - } - - createdSGImageVersion, err := f.Result(s.client.GalleryImageVersionsClient) - - if err != nil { - s.say(s.client.LastError.Error()) - return "", err - } - - s.say(fmt.Sprintf(" -> Shared Gallery Image Version ID : '%s'", *(createdSGImageVersion.ID))) - return *(createdSGImageVersion.ID), nil -} - -func (s *StepPublishToSharedImageGallery) Run(ctx context.Context, stateBag multistep.StateBag) multistep.StepAction { - if !s.toSIG() { - return multistep.ActionContinue - } - - s.say("Publishing to Shared Image Gallery ...") - - var miSigPubRg = stateBag.Get(constants.ArmManagedImageSigPublishResourceGroup).(string) - var miSIGalleryName = stateBag.Get(constants.ArmManagedImageSharedGalleryName).(string) - var miSGImageName = stateBag.Get(constants.ArmManagedImageSharedGalleryImageName).(string) - var miSGImageVersion = stateBag.Get(constants.ArmManagedImageSharedGalleryImageVersion).(string) - var location = stateBag.Get(constants.ArmLocation).(string) - var tags = stateBag.Get(constants.ArmTags).(map[string]*string) - var miSigReplicationRegions = stateBag.Get(constants.ArmManagedImageSharedGalleryReplicationRegions).([]string) - var targetManagedImageResourceGroupName = stateBag.Get(constants.ArmManagedImageResourceGroupName).(string) - var targetManagedImageName = stateBag.Get(constants.ArmManagedImageName).(string) - var managedImageSubscription = stateBag.Get(constants.ArmManagedImageSubscription).(string) - var mdiID = fmt.Sprintf("/subscriptions/%s/resourceGroups/%s/providers/Microsoft.Compute/images/%s", managedImageSubscription, targetManagedImageResourceGroupName, targetManagedImageName) - - s.say(fmt.Sprintf(" -> MDI ID used for SIG publish : '%s'", mdiID)) - s.say(fmt.Sprintf(" -> SIG publish resource group : '%s'", miSigPubRg)) - s.say(fmt.Sprintf(" -> SIG gallery name : '%s'", miSIGalleryName)) - s.say(fmt.Sprintf(" -> SIG image name : '%s'", miSGImageName)) - s.say(fmt.Sprintf(" -> SIG image version : '%s'", miSGImageVersion)) - s.say(fmt.Sprintf(" -> SIG replication regions : '%v'", miSigReplicationRegions)) - createdGalleryImageVersionID, err := s.publish(ctx, mdiID, miSigPubRg, miSIGalleryName, miSGImageName, miSGImageVersion, miSigReplicationRegions, location, tags) - - if err != nil { - stateBag.Put(constants.Error, err) - s.error(err) - - return multistep.ActionHalt - } - - stateBag.Put(constants.ArmManagedImageSharedGalleryId, createdGalleryImageVersionID) - return multistep.ActionContinue -} - -func (*StepPublishToSharedImageGallery) Cleanup(multistep.StateBag) { -} diff --git a/builder/azure/dtl/step_save_winrm_password.go b/builder/azure/dtl/step_save_winrm_password.go deleted file mode 100644 index 975a9ff39..000000000 --- a/builder/azure/dtl/step_save_winrm_password.go +++ /dev/null @@ -1,22 +0,0 @@ -package dtl - -import ( - "context" - - "github.com/hashicorp/packer-plugin-sdk/multistep" - packersdk "github.com/hashicorp/packer-plugin-sdk/packer" -) - -type StepSaveWinRMPassword struct { - Password string - BuildName string -} - -func (s *StepSaveWinRMPassword) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction { - // store so that we can access this later during provisioning - state.Put("winrm_password", s.Password) - packersdk.LogSecretFilter.Set(s.Password) - return multistep.ActionContinue -} - -func (s *StepSaveWinRMPassword) Cleanup(multistep.StateBag) {} diff --git a/builder/azure/dtl/step_test.go b/builder/azure/dtl/step_test.go deleted file mode 100644 index d337a5e49..000000000 --- a/builder/azure/dtl/step_test.go +++ /dev/null @@ -1,40 +0,0 @@ -package dtl - -import ( - "fmt" - "testing" - - "github.com/hashicorp/packer-plugin-sdk/multistep" - "github.com/hashicorp/packer/builder/azure/common/constants" -) - -func TestProcessStepResultShouldContinueForNonErrors(t *testing.T) { - stateBag := new(multistep.BasicStateBag) - - code := processStepResult(nil, func(error) { t.Fatal("Should not be called!") }, stateBag) - if _, ok := stateBag.GetOk(constants.Error); ok { - t.Errorf("Error was nil, but was still in the state bag.") - } - - if code != multistep.ActionContinue { - t.Errorf("Expected ActionContinue(%d), but got=%d", multistep.ActionContinue, code) - } -} - -func TestProcessStepResultShouldHaltOnError(t *testing.T) { - stateBag := new(multistep.BasicStateBag) - isSaidError := false - - code := processStepResult(fmt.Errorf("boom"), func(error) { isSaidError = true }, stateBag) - if _, ok := stateBag.GetOk(constants.Error); !ok { - t.Errorf("Error was non nil, but was not in the state bag.") - } - - if !isSaidError { - t.Errorf("Expected error to be said, but it was not.") - } - - if code != multistep.ActionHalt { - t.Errorf("Expected ActionHalt(%d), but got=%d", multistep.ActionHalt, code) - } -} diff --git a/builder/azure/dtl/template_factory.go b/builder/azure/dtl/template_factory.go deleted file mode 100644 index 821d43a03..000000000 --- a/builder/azure/dtl/template_factory.go +++ /dev/null @@ -1,136 +0,0 @@ -package dtl - -import ( - "fmt" - "strings" - - "github.com/Azure/azure-sdk-for-go/services/devtestlabs/mgmt/2018-09-15/dtl" -) - -type templateFactoryFuncDtl func(*Config) (*dtl.LabVirtualMachineCreationParameter, error) - -func newBool(val bool) *bool { - b := true - if val == b { - return &b - } else { - b = false - return &b - } -} - -func getCustomImageId(config *Config) *string { - if config.CustomManagedImageName != "" && config.CustomManagedImageResourceGroupName != "" { - customManagedImageID := fmt.Sprintf("/subscriptions/%s/resourceGroups/%s/providers/Microsoft.Compute/images/%s", - config.ClientConfig.SubscriptionID, - config.CustomManagedImageResourceGroupName, - config.CustomManagedImageName) - return &customManagedImageID - } - return nil -} - -func GetVirtualMachineDeployment(config *Config) (*dtl.LabVirtualMachineCreationParameter, error) { - - galleryImageRef := dtl.GalleryImageReference{ - Offer: &config.ImageOffer, - Publisher: &config.ImagePublisher, - Sku: &config.ImageSku, - OsType: &config.OSType, - Version: &config.ImageVersion, - } - - labVirtualNetworkID := fmt.Sprintf("/subscriptions/%s/resourceGroups/%s/providers/Microsoft.DevTestLab/labs/%s/virtualnetworks/%s", - config.ClientConfig.SubscriptionID, - config.tmpResourceGroupName, - config.LabName, - config.LabVirtualNetworkName) - - dtlArtifacts := []dtl.ArtifactInstallProperties{} - - if config.DtlArtifacts != nil { - for i := range config.DtlArtifacts { - if config.DtlArtifacts[i].RepositoryName == "" { - config.DtlArtifacts[i].RepositoryName = "public repo" - } - config.DtlArtifacts[i].ArtifactId = fmt.Sprintf("/subscriptions/%s/resourceGroups/%s/providers/Microsoft.DevTestLab/labs/%s/artifactSources/%s/artifacts/%s", - config.ClientConfig.SubscriptionID, - config.tmpResourceGroupName, - config.LabName, - config.DtlArtifacts[i].RepositoryName, - config.DtlArtifacts[i].ArtifactName) - - dparams := []dtl.ArtifactParameterProperties{} - for j := range config.DtlArtifacts[i].Parameters { - - dp := &dtl.ArtifactParameterProperties{} - dp.Name = &config.DtlArtifacts[i].Parameters[j].Name - dp.Value = &config.DtlArtifacts[i].Parameters[j].Value - - dparams = append(dparams, *dp) - } - dtlArtifact := &dtl.ArtifactInstallProperties{ - ArtifactTitle: &config.DtlArtifacts[i].ArtifactName, - ArtifactID: &config.DtlArtifacts[i].ArtifactId, - Parameters: &dparams, - } - dtlArtifacts = append(dtlArtifacts, *dtlArtifact) - } - } - - if strings.ToLower(config.OSType) == "windows" { - // Add mandatory Artifact - var winrma = "windows-winrm" - var artifactid = fmt.Sprintf("/subscriptions/%s/resourceGroups/%s/providers/Microsoft.DevTestLab/labs/%s/artifactSources/public repo/artifacts/%s", - config.ClientConfig.SubscriptionID, - config.tmpResourceGroupName, - config.LabName, - winrma) - - var hostname = "hostName" - //var hostNameValue = fmt.Sprintf("%s.%s.cloudapp.azure.com", config.VMName, config.Location) - dparams := []dtl.ArtifactParameterProperties{} - dp := &dtl.ArtifactParameterProperties{} - dp.Name = &hostname - dp.Value = &config.tmpFQDN - dparams = append(dparams, *dp) - - winrmArtifact := &dtl.ArtifactInstallProperties{ - ArtifactTitle: &winrma, - ArtifactID: &artifactid, - Parameters: &dparams, - } - dtlArtifacts = append(dtlArtifacts, *winrmArtifact) - } - - labMachineProps := &dtl.LabVirtualMachineCreationParameterProperties{ - CreatedByUserID: &config.ClientConfig.ClientID, - OwnerObjectID: &config.ClientConfig.ObjectID, - OsType: &config.OSType, - Size: &config.VMSize, - UserName: &config.UserName, - Password: &config.Password, - SSHKey: &config.sshAuthorizedKey, - IsAuthenticationWithSSHKey: newBool(true), - LabSubnetName: &config.LabSubnetName, - LabVirtualNetworkID: &labVirtualNetworkID, - DisallowPublicIPAddress: newBool(false), - GalleryImageReference: &galleryImageRef, - CustomImageID: getCustomImageId(config), - PlanID: &config.PlanID, - - AllowClaim: newBool(false), - StorageType: &config.StorageType, - VirtualMachineCreationSource: dtl.FromGalleryImage, - Artifacts: &dtlArtifacts, - } - - labMachine := &dtl.LabVirtualMachineCreationParameter{ - Name: &config.tmpComputeName, - Location: &config.Location, - Tags: config.AzureTags, - LabVirtualMachineCreationParameterProperties: labMachineProps, - } - - return labMachine, nil -} diff --git a/builder/azure/dtl/template_funcs.go b/builder/azure/dtl/template_funcs.go deleted file mode 100644 index d34952e1c..000000000 --- a/builder/azure/dtl/template_funcs.go +++ /dev/null @@ -1,46 +0,0 @@ -package dtl - -import ( - "bytes" - "text/template" - - packertpl "github.com/hashicorp/packer-plugin-sdk/template" -) - -func isValidByteValue(b byte) bool { - if '0' <= b && b <= '9' { - return true - } - if 'a' <= b && b <= 'z' { - return true - } - if 'A' <= b && b <= 'Z' { - return true - } - return b == '.' || b == '_' || b == '-' -} - -// Clean up image name by replacing invalid characters with "-" -// Names are not allowed to end in '.', '-', or '_' and are trimmed. -func templateCleanImageName(s string) string { - if ok, _ := assertManagedImageName(s, ""); ok { - return s - } - b := []byte(s) - newb := make([]byte, len(b)) - for i := range newb { - if isValidByteValue(b[i]) { - newb[i] = b[i] - } else { - newb[i] = '-' - } - } - - newb = bytes.TrimRight(newb, "-_.") - return string(newb) -} - -var TemplateFuncs = template.FuncMap{ - "clean_resource_name": templateCleanImageName, - "clean_image_name": packertpl.DeprecatedTemplateFunc("clean_image_name", "clean_resource_name", templateCleanImageName), -} diff --git a/builder/azure/dtl/template_funcs_test.go b/builder/azure/dtl/template_funcs_test.go deleted file mode 100644 index 13c8e25ce..000000000 --- a/builder/azure/dtl/template_funcs_test.go +++ /dev/null @@ -1,49 +0,0 @@ -package dtl - -import "testing" - -func TestTemplateCleanImageName(t *testing.T) { - vals := []struct { - origName string - expected string - }{ - // test that valid name is unchanged - { - origName: "abcde-012345xyz", - expected: "abcde-012345xyz", - }, - // test that colons are converted to hyphens - { - origName: "abcde-012345v1.0:0", - expected: "abcde-012345v1.0-0", - }, - // Name starting with number is not valid, but not in scope of this - // function to correct - { - origName: "012345v1.0:0", - expected: "012345v1.0-0", - }, - // Name over 80 chars is not valid, but not corrected by this function. - { - origName: "l012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789", - expected: "l012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789", - }, - // Name cannot end in a -Name over 80 chars is not valid, but not corrected by this function. - { - origName: "abcde-:_", - expected: "abcde", - }, - // Lost of special characters - { - origName: "My()./-_:&^ $%[]#'@name", - expected: "My--.--_-----------name", - }, - } - - for _, v := range vals { - name := templateCleanImageName(v.origName) - if name != v.expected { - t.Fatalf("template names do not match: expected %s got %s\n", v.expected, name) - } - } -} diff --git a/builder/azure/dtl/tempname.go b/builder/azure/dtl/tempname.go deleted file mode 100644 index 38a138c39..000000000 --- a/builder/azure/dtl/tempname.go +++ /dev/null @@ -1,74 +0,0 @@ -package dtl - -import ( - "fmt" - "strings" - - "github.com/hashicorp/packer-plugin-sdk/random" -) - -type TempName struct { - AdminPassword string - CertificatePassword string - ComputeName string - DeploymentName string - KeyVaultName string - ResourceGroupName string - OSDiskName string - NicName string - SubnetName string - PublicIPAddressName string - VirtualNetworkName string -} - -func NewTempName(c *Config) *TempName { - tempName := &TempName{} - suffix := random.AlphaNumLower(10) - - if c.VMName != "" { - suffix = c.VMName - } - - tempName.ComputeName = suffix - tempName.DeploymentName = fmt.Sprintf("pkrdp%s", suffix) - tempName.KeyVaultName = fmt.Sprintf("pkrkv%s", suffix) - tempName.OSDiskName = fmt.Sprintf("pkros%s", suffix) - tempName.NicName = tempName.ComputeName - tempName.PublicIPAddressName = tempName.ComputeName - tempName.SubnetName = fmt.Sprintf("pkrsn%s", suffix) - tempName.VirtualNetworkName = fmt.Sprintf("pkrvn%s", suffix) - tempName.ResourceGroupName = fmt.Sprintf("packer-Resource-Group-%s", suffix) - - tempName.AdminPassword = generatePassword() - tempName.CertificatePassword = random.AlphaNum(32) - return tempName -} - -// generate a password that is acceptable to Azure -// Three of the four items must be met. -// 1. Contains an uppercase character -// 2. Contains a lowercase character -// 3. Contains a numeric digit -// 4. Contains a special character -func generatePassword() string { - var s string - for i := 0; i < 100; i++ { - s := random.AlphaNum(32) - if !strings.ContainsAny(s, random.PossibleNumbers) { - continue - } - - if !strings.ContainsAny(s, random.PossibleLowerCase) { - continue - } - - if !strings.ContainsAny(s, random.PossibleUpperCase) { - continue - } - - return s - } - - // if an acceptable password cannot be generated in 100 tries, give up - return s -} diff --git a/builder/azure/examples/centos.json b/builder/azure/examples/centos.json deleted file mode 100644 index 9570ce7e9..000000000 --- a/builder/azure/examples/centos.json +++ /dev/null @@ -1,44 +0,0 @@ -{ - "variables": { - "client_id": "{{env `ARM_CLIENT_ID`}}", - "client_secret": "{{env `ARM_CLIENT_SECRET`}}", - "subscription_id": "{{env `ARM_SUBSCRIPTION_ID`}}", - "tenant_id": "{{env `ARM_TENANT_ID`}}", - "ssh_user": "centos", - "ssh_pass": "{{env `ARM_SSH_PASS`}}" - }, - "builders": [{ - "type": "azure-arm", - - "client_id": "{{user `client_id`}}", - "client_secret": "{{user `client_secret`}}", - "subscription_id": "{{user `subscription_id`}}", - "tenant_id": "{{user `tenant_id`}}", - - "managed_image_resource_group_name": "packertest", - "managed_image_name": "MyCentOSImage", - - "ssh_username": "{{user `ssh_user`}}", - "ssh_password": "{{user `ssh_pass`}}", - - "os_type": "Linux", - "image_publisher": "OpenLogic", - "image_offer": "CentOS", - "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/builder/azure/examples/debian-chroot.json b/builder/azure/examples/debian-chroot.json deleted file mode 100644 index 00909a55f..000000000 --- a/builder/azure/examples/debian-chroot.json +++ /dev/null @@ -1,27 +0,0 @@ -{ - "variables": { - "client_id": "{{env `ARM_CLIENT_ID`}}", - "client_secret": "{{env `ARM_CLIENT_SECRET`}}", - "subscription_id": "{{env `ARM_SUBSCRIPTION_ID`}}", - "resource_group": "{{env `ARM_IMAGE_RESOURCEGROUP_ID`}}" - }, - "builders": [{ - "type": "azure-chroot", - - "client_id": "{{user `client_id`}}", - "client_secret": "{{user `client_secret`}}", - "subscription_id": "{{user `subscription_id`}}", - - "image_resource_id": "/subscriptions/{{user `subscription_id`}}/resourceGroups/{{user `resource_group`}}/providers/Microsoft.Compute/images/MyDebianOSImage-{{timestamp}}", - - "source": "credativ:Debian:9:latest" - }], - "provisioners": [{ - "inline": [ - "apt-get update", - "apt-get upgrade -y" - ], - "inline_shebang": "/bin/sh -x", - "type": "shell" - }] -} \ No newline at end of file diff --git a/builder/azure/examples/debian.json b/builder/azure/examples/debian.json deleted file mode 100644 index f1d97daad..000000000 --- a/builder/azure/examples/debian.json +++ /dev/null @@ -1,45 +0,0 @@ -{ - "variables": { - "client_id": "{{env `ARM_CLIENT_ID`}}", - "client_secret": "{{env `ARM_CLIENT_SECRET`}}", - "subscription_id": "{{env `ARM_SUBSCRIPTION_ID`}}", - "ssh_user": "packer", - "ssh_pass": "{{env `ARM_SSH_PASS`}}" - }, - "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`}}", - - "managed_image_resource_group_name": "packertest", - "managed_image_name": "MyDebianOSImage", - - "ssh_username": "{{user `ssh_user`}}", - "ssh_password": "{{user `ssh_pass`}}", - - "os_type": "Linux", - "image_publisher": "credativ", - "image_offer": "Debian", - "image_sku": "9", - "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": [ - "apt-get update", - "apt-get upgrade -y", - - "/usr/sbin/waagent -force -deprovision+user && export HISTSIZE=0 && sync" - ], - "inline_shebang": "/bin/sh -x", - "skip_clean": true, - "type": "shell" - }] -} diff --git a/builder/azure/examples/freebsd-chroot.json b/builder/azure/examples/freebsd-chroot.json deleted file mode 100644 index 8b8d42825..000000000 --- a/builder/azure/examples/freebsd-chroot.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "variables": {}, - "builders": [ - { - "type": "azure-chroot", - "source": "thefreebsdfoundation:freebsd-12_1:12_1-release:latest", - "image_resource_id": "/subscriptions/{{vm `subscription_id`}}/resourceGroups/{{vm `resource_group`}}/providers/Microsoft.Compute/images/freebsd-{{timestamp}}", - "os_disk_size_gb": 64, - "os_disk_storage_account_type": "Premium_LRS", - "mount_partition": 2, - "chroot_mounts": [ - ["devfs", "devfs", "/dev"], - ["procfs", "procfs", "/proc"] - ] - } - ], - "provisioners": [ - { - "inline": [ - "env ASSUME_ALWAYS_YES=YES pkg bootstrap" - ], - "inline_shebang": "/bin/sh -x", - "type": "shell" - } - ] -} diff --git a/builder/azure/examples/freebsd.json b/builder/azure/examples/freebsd.json deleted file mode 100644 index eedad52ea..000000000 --- a/builder/azure/examples/freebsd.json +++ /dev/null @@ -1,43 +0,0 @@ -{ - "variables": { - "client_id": "{{env `ARM_CLIENT_ID`}}", - "client_secret": "{{env `ARM_CLIENT_SECRET`}}", - "subscription_id": "{{env `ARM_SUBSCRIPTION_ID`}}", - "ssh_user": "packer", - "ssh_pass": "{{env `ARM_SSH_PASS`}}" - }, - "builders": [{ - "type": "azure-arm", - - "client_id": "{{user `client_id`}}", - "client_secret": "{{user `client_secret`}}", - "subscription_id": "{{user `subscription_id`}}", - - "managed_image_resource_group_name": "packertest", - "managed_image_name": "MyFreeBsdOSImage", - - "ssh_username": "{{user `ssh_user`}}", - "ssh_password": "{{user `ssh_pass`}}", - - "os_type": "Linux", - "image_publisher": "MicrosoftOSTC", - "image_offer": "FreeBSD", - "image_sku": "11.1", - "image_version": "latest", - - "location": "West US 2", - "vm_size": "Standard_DS2_v2" - }], - "provisioners": [{ - "execute_command": "chmod +x {{ .Path }}; {{ .Vars }} sudo -E sh '{{ .Path }}'", - "inline": [ - "env ASSUME_ALWAYS_YES=YES pkg bootstrap", - "/usr/sbin/waagent -force -deprovision+user && export HISTSIZE=0 && sync" - ], - "inline_shebang": "/bin/sh -x", - "type": "shell", - "skip_clean": "true", - "expect_disconnect": "true" - }] - -} diff --git a/builder/azure/examples/linux_custom_image.json b/builder/azure/examples/linux_custom_image.json deleted file mode 100644 index 91bbf0a39..000000000 --- a/builder/azure/examples/linux_custom_image.json +++ /dev/null @@ -1,44 +0,0 @@ -{ - "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": [ - { - "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`}}", - - "capture_container_name": "images", - "capture_name_prefix": "packer", - - "os_type": "Linux", - "image_url": "https://my-storage-account.blob.core.windows.net/path/to/your/custom/image.vhd", - - "azure_tags": { - "dept": "engineering", - "task": "image deployment" - }, - - "location": "West US", - "vm_size": "Standard_DS2_v2" - } - ], - "provisioners": [{ - "execute_command": "chmod +x {{ .Path }}; {{ .Vars }} sudo -E sh '{{ .Path }}'", - "inline": [ - "apt-get update", - "apt-get upgrade -y", - "/usr/sbin/waagent -force -deprovision+user && export HISTSIZE=0 && sync" - ], - "inline_shebang": "/bin/sh -x", - "type": "shell" - }] -} diff --git a/builder/azure/examples/linux_custom_managed_image.json b/builder/azure/examples/linux_custom_managed_image.json deleted file mode 100644 index 7863e30c6..000000000 --- a/builder/azure/examples/linux_custom_managed_image.json +++ /dev/null @@ -1,40 +0,0 @@ -{ - "variables": { - "client_id": "{{env `ARM_CLIENT_ID`}}", - "client_secret": "{{env `ARM_CLIENT_SECRET`}}", - "subscription_id": "{{env `ARM_SUBSCRIPTION_ID`}}" - }, - "builders": [ - { - "type": "azure-arm", - - "client_id": "{{user `client_id`}}", - "client_secret": "{{user `client_secret`}}", - "subscription_id": "{{user `subscription_id`}}", - - "os_type": "Linux", - "custom_managed_image_resource_group_name": "MyResourceGroup", - "custom_managed_image_name": "MyImage", - "managed_image_resource_group_name": "PackerImages", - "managed_image_name": "MyImage", - - "azure_tags": { - "dept": "engineering", - "task": "image deployment" - }, - - "location": "West US", - "vm_size": "Standard_DS2_v2" - } - ], - "provisioners": [{ - "execute_command": "chmod +x {{ .Path }}; {{ .Vars }} sudo -E sh '{{ .Path }}'", - "inline": [ - "apt-get update", - "apt-get upgrade -y", - "/usr/sbin/waagent -force -deprovision+user && export HISTSIZE=0 && sync" - ], - "inline_shebang": "/bin/sh -x", - "type": "shell" - }] -} diff --git a/builder/azure/examples/marketplace_plan_info.json b/builder/azure/examples/marketplace_plan_info.json deleted file mode 100644 index 5cf58e280..000000000 --- a/builder/azure/examples/marketplace_plan_info.json +++ /dev/null @@ -1,47 +0,0 @@ -{ - "variables": { - "client_id": "{{env `ARM_CLIENT_ID`}}", - "client_secret": "{{env `ARM_CLIENT_SECRET`}}", - "subscription_id": "{{env `ARM_SUBSCRIPTION_ID`}}" - }, - "builders": [{ - "type": "azure-arm", - - "client_id": "{{user `client_id`}}", - "client_secret": "{{user `client_secret`}}", - "subscription_id": "{{user `subscription_id`}}", - - "managed_image_resource_group_name": "packertest", - "managed_image_name": "MyMarketplaceOSImage", - - "os_type": "Linux", - "image_publisher": "bitnami", - "image_offer": "rabbitmq", - "image_sku": "rabbitmq", - - "azure_tags": { - "dept": "engineering", - "task": "image deployment" - }, - - "plan_info": { - "plan_name": "rabbitmq", - "plan_product": "rabbitmq", - "plan_publisher": "bitnami" - }, - - "location": "West US", - "vm_size": "Standard_DS2_v2" - }], - "provisioners": [{ - "execute_command": "chmod +x {{ .Path }}; {{ .Vars }} sudo -E sh '{{ .Path }}'", - "inline": [ - "apt-get update", - "apt-get upgrade -y", - - "/usr/sbin/waagent -force -deprovision+user && export HISTSIZE=0 && sync" - ], - "inline_shebang": "/bin/sh -x", - "type": "shell" - }] -} diff --git a/builder/azure/examples/rhel.json b/builder/azure/examples/rhel.json deleted file mode 100644 index 895d4079b..000000000 --- a/builder/azure/examples/rhel.json +++ /dev/null @@ -1,45 +0,0 @@ -{ - "variables": { - "client_id": "{{env `ARM_CLIENT_ID`}}", - "client_secret": "{{env `ARM_CLIENT_SECRET`}}", - "subscription_id": "{{env `ARM_SUBSCRIPTION_ID`}}", - "tenant_id": "{{env `ARM_TENANT_ID`}}", - "ssh_user": "centos", - "ssh_pass": "{{env `ARM_SSH_PASS`}}" - }, - "builders": [{ - "type": "azure-arm", - - "client_id": "{{user `client_id`}}", - "client_secret": "{{user `client_secret`}}", - "subscription_id": "{{user `subscription_id`}}", - "tenant_id": "{{user `tenant_id`}}", - - "managed_image_resource_group_name": "packertest", - "managed_image_name": "MyRedHatOSImage", - - - "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/builder/azure/examples/suse.json b/builder/azure/examples/suse.json deleted file mode 100644 index 4c6ff8e9e..000000000 --- a/builder/azure/examples/suse.json +++ /dev/null @@ -1,42 +0,0 @@ -{ - "variables": { - "client_id": "{{env `ARM_CLIENT_ID`}}", - "client_secret": "{{env `ARM_CLIENT_SECRET`}}", - "subscription_id": "{{env `ARM_SUBSCRIPTION_ID`}}", - "ssh_user": "packer", - "ssh_pass": "{{env `ARM_SSH_PASS`}}" - }, - "builders": [{ - "type": "azure-arm", - - "client_id": "{{user `client_id`}}", - "client_secret": "{{user `client_secret`}}", - "subscription_id": "{{user `subscription_id`}}", - - "managed_image_resource_group_name": "packertest", - "managed_image_name": "MySuseOSImage", - - "ssh_username": "{{user `ssh_user`}}", - "ssh_password": "{{user `ssh_pass`}}", - - "os_type": "Linux", - "image_publisher": "SUSE", - "image_offer": "SLES", - "image_sku": "12-SP3", - "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": [ - "zypper update -y", - - "/usr/sbin/waagent -force -deprovision+user && export HISTSIZE=0 && sync" - ], - "inline_shebang": "/bin/sh -x", - "skip_clean": true, - "type": "shell" - }] -} diff --git a/builder/azure/examples/ubuntu-chroot.json b/builder/azure/examples/ubuntu-chroot.json deleted file mode 100644 index e7cd330f7..000000000 --- a/builder/azure/examples/ubuntu-chroot.json +++ /dev/null @@ -1,41 +0,0 @@ -{ - "variables": { - "client_id": "{{env `ARM_CLIENT_ID`}}", - "client_secret": "{{env `ARM_CLIENT_SECRET`}}", - "subscription_id": "{{env `ARM_SUBSCRIPTION_ID`}}", - "resource_group": "{{env `ARM_IMAGE_RESOURCEGROUP_ID`}}", - "gallery_name": "{{env `ARM_GALLERY_NAME`}}" - }, - "builders": [{ - "type": "azure-chroot", - - "client_id": "{{user `client_id`}}", - "client_secret": "{{user `client_secret`}}", - "subscription_id": "{{user `subscription_id`}}", - - "source": "Canonical:UbuntuServer:20.04-LTS:latest", - - "shared_image_destination": { - "resource_group": "{{user `resource_group`}}", - "gallery_name": "{{user `gallery_name`}}", - "image_name": "MyUbuntuOSImage", - "image_version": "1.0.0", - "exclude_from_latest": false, - "target_regions": [ - { - "name": "eastus", - "replicas": "1", - "storage_account_type": "standard_zrs" - } - ] - } - }], - "provisioners": [{ - "inline": [ - "apt update", - "apt upgrade -y" - ], - "inline_shebang": "/bin/sh -x", - "type": "shell" - }] -} diff --git a/builder/azure/examples/ubuntu.json b/builder/azure/examples/ubuntu.json deleted file mode 100644 index eefe62299..000000000 --- a/builder/azure/examples/ubuntu.json +++ /dev/null @@ -1,41 +0,0 @@ -{ - "variables": { - "client_id": "{{env `ARM_CLIENT_ID`}}", - "client_secret": "{{env `ARM_CLIENT_SECRET`}}", - "subscription_id": "{{env `ARM_SUBSCRIPTION_ID`}}" - }, - "builders": [{ - "type": "azure-arm", - - "client_id": "{{user `client_id`}}", - "client_secret": "{{user `client_secret`}}", - "subscription_id": "{{user `subscription_id`}}", - - "os_type": "Linux", - "image_publisher": "Canonical", - "image_offer": "UbuntuServer", - "image_sku": "16.04-LTS", - - "managed_image_resource_group_name": "packertest", - "managed_image_name": "MyUbuntuImage", - - "azure_tags": { - "dept": "engineering", - "task": "image deployment" - }, - - "location": "South Central US", - "vm_size": "Standard_DS2_v2" - }], - "provisioners": [{ - "execute_command": "chmod +x {{ .Path }}; {{ .Vars }} sudo -E sh '{{ .Path }}'", - "inline": [ - "apt-get update", - "apt-get upgrade -y", - - "/usr/sbin/waagent -force -deprovision+user && export HISTSIZE=0 && sync" - ], - "inline_shebang": "/bin/sh -x", - "type": "shell" - }] -} diff --git a/builder/azure/examples/ubuntu_managed_image_sig.json b/builder/azure/examples/ubuntu_managed_image_sig.json deleted file mode 100644 index 4789ad891..000000000 --- a/builder/azure/examples/ubuntu_managed_image_sig.json +++ /dev/null @@ -1,46 +0,0 @@ -{ - "variables": { - "client_id": "{{env `ARM_CLIENT_ID`}}", - "client_secret": "{{env `ARM_CLIENT_SECRET`}}", - "subscription_id": "{{env `ARM_SUBSCRIPTION_ID`}}", - "tenant_id": "{{env `ARM_TENANT_ID`}}" - }, - "builders": [{ - "type": "azure-arm", - - "client_id": "{{user `client_id`}}", - "client_secret": "{{user `client_secret`}}", - "tenant_id": "{{user `tenant_id`}}", - "subscription_id": "{{user `subscription_id`}}", - - "os_type": "Linux", - "image_publisher": "Canonical", - "image_offer": "UbuntuServer", - "image_sku": "16.04-LTS", - - "location": "West Central US", - "vm_size": "Standard_DS2_v2", - - "managed_image_resource_group_name": "PackerSigRGManagedImageRG", - "managed_image_name": "demo-image-sig-packer", - "shared_image_gallery_destination": { - "resource_group": "PackerSigPublishRG", - "gallery_name": "PackerSigGallery", - "image_name": "PackerSigImageDefinition", - "image_version": "1.0.0", - "replication_regions": ["South Central US"] - } - }], - "provisioners": [{ - "execute_command": "chmod +x {{ .Path }}; {{ .Vars }} sudo -E sh '{{ .Path }}'", - "inline": [ - "apt-get update", - "apt-get upgrade -y", - - "/usr/sbin/waagent -force -deprovision+user && export HISTSIZE=0 && sync" - ], - "inline_shebang": "/bin/sh -x", - "type": "shell" - }] -} - diff --git a/builder/azure/examples/ubuntu_quickstart.json b/builder/azure/examples/ubuntu_quickstart.json deleted file mode 100644 index e405d9eb9..000000000 --- a/builder/azure/examples/ubuntu_quickstart.json +++ /dev/null @@ -1,35 +0,0 @@ -{ - "variables": { - "resource_group": "{{env `ARM_RESOURCE_GROUP`}}", - "storage_account": "{{env `ARM_STORAGE_ACCOUNT`}}", - "subscription_id": "{{env `ARM_SUBSCRIPTION_ID`}}" - }, - "builders": [{ - "type": "azure-arm", - - "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", - "image_sku": "16.04-LTS", - - "location": "West US", - "vm_size": "Standard_DS2_v2" - }], - "provisioners": [{ - "execute_command": "chmod +x {{ .Path }}; {{ .Vars }} sudo -E sh '{{ .Path }}'", - "inline": [ - "apt-get update", - "apt-get upgrade -y", - "/usr/sbin/waagent -force -deprovision+user && export HISTSIZE=0 && sync" - ], - "inline_shebang": "/bin/sh -x", - "type": "shell" - }] -} diff --git a/builder/azure/examples/windows.json b/builder/azure/examples/windows.json deleted file mode 100644 index c1ee94d3d..000000000 --- a/builder/azure/examples/windows.json +++ /dev/null @@ -1,45 +0,0 @@ -{ - "variables": { - "client_id": "{{env `ARM_CLIENT_ID`}}", - "client_secret": "{{env `ARM_CLIENT_SECRET`}}", - "subscription_id": "{{env `ARM_SUBSCRIPTION_ID`}}" - }, - "builders": [{ - "type": "azure-arm", - - "client_id": "{{user `client_id`}}", - "client_secret": "{{user `client_secret`}}", - "subscription_id": "{{user `subscription_id`}}", - - "managed_image_resource_group_name": "packertest", - "managed_image_name": "MyWindowsOSImage", - - "os_type": "Windows", - "image_publisher": "MicrosoftWindowsServer", - "image_offer": "WindowsServer", - "image_sku": "2012-R2-Datacenter", - - "communicator": "winrm", - "winrm_use_ssl": "true", - "winrm_insecure": "true", - "winrm_timeout": "3m", - "winrm_username": "packer", - - "location": "South Central US", - "vm_size": "Standard_DS2_v2" - }], - "provisioners": [{ - "type": "powershell", - "inline": [ - " # NOTE: the following *3* lines are only needed if the you have installed the Guest Agent.", - " while ((Get-Service RdAgent).Status -ne 'Running') { Start-Sleep -s 5 }", - " while ((Get-Service WindowsAzureTelemetryService).Status -ne 'Running') { Start-Sleep -s 5 }", - " while ((Get-Service WindowsAzureGuestAgent).Status -ne 'Running') { Start-Sleep -s 5 }", - - "if( Test-Path $Env:SystemRoot\\windows\\system32\\Sysprep\\unattend.xml ){ rm $Env:SystemRoot\\windows\\system32\\Sysprep\\unattend.xml -Force}", - "& $env:SystemRoot\\System32\\Sysprep\\Sysprep.exe /oobe /generalize /quiet /quit /mode:vm", - "while($true) { $imageState = Get-ItemProperty HKLM:\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Setup\\State | Select ImageState; Write-Output $imageState.ImageState; if($imageState.ImageState -ne 'IMAGE_STATE_GENERALIZE_RESEAL_TO_OOBE') { Start-Sleep -s 10 } else { break } }" - ] - }] -} - diff --git a/builder/azure/examples/windows_custom_image.json b/builder/azure/examples/windows_custom_image.json deleted file mode 100644 index a6e3d0057..000000000 --- a/builder/azure/examples/windows_custom_image.json +++ /dev/null @@ -1,49 +0,0 @@ -{ - "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`}}", - "object_id": "{{env `ARM_OBJECT_ID`}}" - }, - "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`}}", - "object_id": "{{user `object_id`}}", - - "capture_container_name": "images", - "capture_name_prefix": "packer", - - "os_type": "Windows", - "image_url": "https://my-storage-account.blob.core.windows.net/path/to/your/custom/image.vhd", - - "azure_tags": { - "dept": "engineering", - "task": "image deployment" - }, - - "location": "West US", - "vm_size": "Standard_DS2_v2" - } - ], - "provisioners": [{ - "type": "powershell", - "inline": [ - " # NOTE: the following *3* lines are only needed if the you have installed the Guest Agent.", - " while ((Get-Service RdAgent).Status -ne 'Running') { Start-Sleep -s 5 }", - " while ((Get-Service WindowsAzureTelemetryService).Status -ne 'Running') { Start-Sleep -s 5 }", - " while ((Get-Service WindowsAzureGuestAgent).Status -ne 'Running') { Start-Sleep -s 5 }", - - "if( Test-Path $Env:SystemRoot\\windows\\system32\\Sysprep\\unattend.xml ){ rm $Env:SystemRoot\\windows\\system32\\Sysprep\\unattend.xml -Force}", - "& $env:SystemRoot\\System32\\Sysprep\\Sysprep.exe /oobe /generalize /quiet /quit /mode:vm", - "while($true) { $imageState = Get-ItemProperty HKLM:\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Setup\\State | Select ImageState; if($imageState.ImageState -ne 'IMAGE_STATE_GENERALIZE_RESEAL_TO_OOBE') { Write-Output $imageState.ImageState; Start-Sleep -s 10 } else { break } }" - ] - }] -} diff --git a/builder/azure/examples/windows_quickstart.json b/builder/azure/examples/windows_quickstart.json deleted file mode 100644 index 6d4fffb57..000000000 --- a/builder/azure/examples/windows_quickstart.json +++ /dev/null @@ -1,41 +0,0 @@ -{ - "variables": { - "subscription_id": "{{env `ARM_SUBSCRIPTION_ID`}}" - }, - "builders": [{ - "type": "azure-arm", - - "subscription_id": "{{user `subscription_id`}}", - - "managed_image_resource_group_name": "packertest", - "managed_image_name": "MyWindowsOSImage", - - "os_type": "Windows", - "image_publisher": "MicrosoftWindowsServer", - "image_offer": "WindowsServer", - "image_sku": "2012-R2-Datacenter", - - "communicator": "winrm", - "winrm_use_ssl": "true", - "winrm_insecure": "true", - "winrm_timeout": "3m", - "winrm_username": "packer", - - "location": "South Central US", - "vm_size": "Standard_DS2_v2" - }], - "provisioners": [{ - "type": "powershell", - "inline": [ - " # NOTE: the following *3* lines are only needed if the you have installed the Guest Agent.", - " while ((Get-Service RdAgent).Status -ne 'Running') { Start-Sleep -s 5 }", - " while ((Get-Service WindowsAzureTelemetryService).Status -ne 'Running') { Start-Sleep -s 5 }", - " while ((Get-Service WindowsAzureGuestAgent).Status -ne 'Running') { Start-Sleep -s 5 }", - - "if( Test-Path $Env:SystemRoot\\windows\\system32\\Sysprep\\unattend.xml ){ rm $Env:SystemRoot\\windows\\system32\\Sysprep\\unattend.xml -Force}", - "& $env:SystemRoot\\System32\\Sysprep\\Sysprep.exe /oobe /generalize /quiet /quit /mode:vm", - "while($true) { $imageState = Get-ItemProperty HKLM:\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Setup\\State | Select ImageState; if($imageState.ImageState -ne 'IMAGE_STATE_GENERALIZE_RESEAL_TO_OOBE') { Write-Output $imageState.ImageState; Start-Sleep -s 10 } else { break } }" - ] - }] -} - diff --git a/builder/azure/pkcs12/LICENSE b/builder/azure/pkcs12/LICENSE deleted file mode 100644 index 6a66aea5e..000000000 --- a/builder/azure/pkcs12/LICENSE +++ /dev/null @@ -1,27 +0,0 @@ -Copyright (c) 2009 The Go Authors. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - * Redistributions of source code must retain the above copyright -notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above -copyright notice, this list of conditions and the following disclaimer -in the documentation and/or other materials provided with the -distribution. - * Neither the name of Google Inc. nor the names of its -contributors may be used to endorse or promote products derived from -this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/builder/azure/pkcs12/bmp-string.go b/builder/azure/pkcs12/bmp-string.go deleted file mode 100644 index 284d2a68f..000000000 --- a/builder/azure/pkcs12/bmp-string.go +++ /dev/null @@ -1,50 +0,0 @@ -// Copyright 2015 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package pkcs12 - -import ( - "errors" - "unicode/utf16" -) - -// bmpString returns s encoded in UCS-2 with a zero terminator. -func bmpString(s string) ([]byte, error) { - // References: - // https://tools.ietf.org/html/rfc7292#appendix-B.1 - // http://en.wikipedia.org/wiki/Plane_(Unicode)#Basic_Multilingual_Plane - // - non-BMP characters are encoded in UTF 16 by using a surrogate pair of 16-bit codes - // EncodeRune returns 0xfffd if the rune does not need special encoding - // - the above RFC provides the info that BMPStrings are NULL terminated. - - ret := make([]byte, 0, 2*len(s)+2) - - for _, r := range s { - if t, _ := utf16.EncodeRune(r); t != 0xfffd { - return nil, errors.New("pkcs12: string contains characters that cannot be encoded in UCS-2") - } - ret = append(ret, byte(r/256), byte(r%256)) - } - - return append(ret, 0, 0), nil -} - -func decodeBMPString(bmpString []byte) (string, error) { - if len(bmpString)%2 != 0 { - return "", errors.New("pkcs12: odd-length BMP string") - } - - // strip terminator if present - if l := len(bmpString); l >= 2 && bmpString[l-1] == 0 && bmpString[l-2] == 0 { - bmpString = bmpString[:l-2] - } - - s := make([]uint16, 0, len(bmpString)/2) - for len(bmpString) > 0 { - s = append(s, uint16(bmpString[0])<<8+uint16(bmpString[1])) - bmpString = bmpString[2:] - } - - return string(utf16.Decode(s)), nil -} diff --git a/builder/azure/pkcs12/bmp-string_test.go b/builder/azure/pkcs12/bmp-string_test.go deleted file mode 100644 index 711528b81..000000000 --- a/builder/azure/pkcs12/bmp-string_test.go +++ /dev/null @@ -1,69 +0,0 @@ -// Copyright 2015 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package pkcs12 - -import ( - "bytes" - "encoding/hex" - "testing" -) - -var bmpStringTests = []struct { - in string - expectedHex string - shouldFail bool -}{ - {"", "0000", false}, - // Example from https://tools.ietf.org/html/rfc7292#appendix-B. - {"Beavis", "0042006500610076006900730000", false}, - // Some characters from the "Letterlike Symbols Unicode block". - {"\u2115 - Double-struck N", "21150020002d00200044006f00750062006c0065002d00730074007200750063006b0020004e0000", false}, - // any character outside the BMP should trigger an error. - {"\U0001f000 East wind (Mahjong)", "", true}, -} - -func TestBMPStringDecode(t *testing.T) { - if _, err := decodeBMPString([]byte("a")); err == nil { - t.Fatalf("expected decode to fail, but it succeeded") - } -} - -func TestBMPString(t *testing.T) { - for i, test := range bmpStringTests { - expected, err := hex.DecodeString(test.expectedHex) - if err != nil { - t.Fatalf("#%d: failed to decode expectation", i) - } - - out, err := bmpString(test.in) - if err == nil && test.shouldFail { - t.Errorf("#%d: expected to fail, but produced %x", i, out) - continue - } - - if err != nil && !test.shouldFail { - t.Errorf("#%d: failed unexpectedly: %s", i, err) - continue - } - - if !test.shouldFail { - if !bytes.Equal(out, expected) { - t.Errorf("#%d: expected %s, got %x", i, test.expectedHex, out) - continue - } - - roundTrip, err := decodeBMPString(out) - if err != nil { - t.Errorf("#%d: decoding output gave an error: %s", i, err) - continue - } - - if roundTrip != test.in { - t.Errorf("#%d: decoding output resulted in %q, but it should have been %q", i, roundTrip, test.in) - continue - } - } - } -} diff --git a/builder/azure/pkcs12/crypto.go b/builder/azure/pkcs12/crypto.go deleted file mode 100644 index 6c81eb774..000000000 --- a/builder/azure/pkcs12/crypto.go +++ /dev/null @@ -1,167 +0,0 @@ -// Copyright 2015 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package pkcs12 - -import ( - "bytes" - "crypto/cipher" - "crypto/des" - "crypto/rand" - "crypto/x509/pkix" - "encoding/asn1" - "errors" - "io" - - "github.com/hashicorp/packer/builder/azure/pkcs12/rc2" -) - -const ( - pbeIterationCount = 2048 - pbeSaltSizeBytes = 8 -) - -var ( - oidPBEWithSHAAnd3KeyTripleDESCBC = asn1.ObjectIdentifier([]int{1, 2, 840, 113549, 1, 12, 1, 3}) - oidPBEWithSHAAnd40BitRC2CBC = asn1.ObjectIdentifier([]int{1, 2, 840, 113549, 1, 12, 1, 6}) -) - -// pbeCipher is an abstraction of a PKCS#12 cipher. -type pbeCipher interface { - // create returns a cipher.Block given a key. - create(key []byte) (cipher.Block, error) - // deriveKey returns a key derived from the given password and salt. - deriveKey(salt, password []byte, iterations int) []byte - // deriveKey returns an IV derived from the given password and salt. - deriveIV(salt, password []byte, iterations int) []byte -} - -type shaWithTripleDESCBC struct{} - -func (shaWithTripleDESCBC) create(key []byte) (cipher.Block, error) { - return des.NewTripleDESCipher(key) -} - -func (shaWithTripleDESCBC) deriveKey(salt, password []byte, iterations int) []byte { - return pbkdf(sha1Sum, 20, 64, salt, password, iterations, 1, 24) -} - -func (shaWithTripleDESCBC) deriveIV(salt, password []byte, iterations int) []byte { - return pbkdf(sha1Sum, 20, 64, salt, password, iterations, 2, 8) -} - -type shaWith40BitRC2CBC struct{} - -func (shaWith40BitRC2CBC) create(key []byte) (cipher.Block, error) { - return rc2.New(key, len(key)*8) -} - -func (shaWith40BitRC2CBC) deriveKey(salt, password []byte, iterations int) []byte { - return pbkdf(sha1Sum, 20, 64, salt, password, iterations, 1, 5) -} - -func (shaWith40BitRC2CBC) deriveIV(salt, password []byte, iterations int) []byte { - return pbkdf(sha1Sum, 20, 64, salt, password, iterations, 2, 8) -} - -type pbeParams struct { - Salt []byte - Iterations int -} - -func pbDecrypterFor(algorithm pkix.AlgorithmIdentifier, password []byte) (cipher.BlockMode, int, error) { - var cipherType pbeCipher - - switch { - case algorithm.Algorithm.Equal(oidPBEWithSHAAnd3KeyTripleDESCBC): - cipherType = shaWithTripleDESCBC{} - case algorithm.Algorithm.Equal(oidPBEWithSHAAnd40BitRC2CBC): - cipherType = shaWith40BitRC2CBC{} - default: - return nil, 0, NotImplementedError("algorithm " + algorithm.Algorithm.String() + " is not supported") - } - - var params pbeParams - if err := unmarshal(algorithm.Parameters.FullBytes, ¶ms); err != nil { - return nil, 0, err - } - - key := cipherType.deriveKey(params.Salt, password, params.Iterations) - iv := cipherType.deriveIV(params.Salt, password, params.Iterations) - - block, err := cipherType.create(key) - if err != nil { - return nil, 0, err - } - - return cipher.NewCBCDecrypter(block, iv), block.BlockSize(), nil -} - -func pbDecrypt(info decryptable, password []byte) (decrypted []byte, err error) { - cbc, blockSize, err := pbDecrypterFor(info.Algorithm(), password) - if err != nil { - return nil, err - } - - encrypted := info.Data() - if len(encrypted) == 0 { - return nil, errors.New("pkcs12: empty encrypted data") - } - if len(encrypted)%blockSize != 0 { - return nil, errors.New("pkcs12: input is not a multiple of the block size") - } - decrypted = make([]byte, len(encrypted)) - cbc.CryptBlocks(decrypted, encrypted) - - psLen := int(decrypted[len(decrypted)-1]) - if psLen == 0 || psLen > blockSize { - return nil, ErrDecryption - } - - if len(decrypted) < psLen { - return nil, ErrDecryption - } - ps := decrypted[len(decrypted)-psLen:] - decrypted = decrypted[:len(decrypted)-psLen] - if bytes.Compare(ps, bytes.Repeat([]byte{byte(psLen)}, psLen)) != 0 { - return nil, ErrDecryption - } - - return -} - -func pad(src []byte, blockSize int) []byte { - paddingLength := blockSize - len(src)%blockSize - paddingText := bytes.Repeat([]byte{byte(paddingLength)}, paddingLength) - return append(src, paddingText...) -} - -func pbEncrypt(plainText, salt, password []byte, iterations int) (cipherText []byte, err error) { - if _, err := io.ReadFull(rand.Reader, salt); err != nil { - return nil, errors.New("pkcs12: failed to create a random salt value: " + err.Error()) - } - - cipherType := shaWithTripleDESCBC{} - key := cipherType.deriveKey(salt, password, iterations) - iv := cipherType.deriveIV(salt, password, iterations) - - block, err := cipherType.create(key) - if err != nil { - return nil, errors.New("pkcs12: failed to create a block cipher: " + err.Error()) - } - - paddedPlainText := pad(plainText, block.BlockSize()) - - encrypter := cipher.NewCBCEncrypter(block, iv) - cipherText = make([]byte, len(paddedPlainText)) - encrypter.CryptBlocks(cipherText, paddedPlainText) - - return cipherText, nil -} - -// decryptable abstracts a object that contains ciphertext. -type decryptable interface { - Algorithm() pkix.AlgorithmIdentifier - Data() []byte -} diff --git a/builder/azure/pkcs12/crypto_test.go b/builder/azure/pkcs12/crypto_test.go deleted file mode 100644 index efcd90820..000000000 --- a/builder/azure/pkcs12/crypto_test.go +++ /dev/null @@ -1,168 +0,0 @@ -// Copyright 2015 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package pkcs12 - -import ( - "bytes" - "crypto/rand" - "crypto/x509/pkix" - "encoding/asn1" - "io" - "testing" -) - -var sha1WithTripleDES = asn1.ObjectIdentifier([]int{1, 2, 840, 113549, 1, 12, 1, 3}) - -func TestPbDecrypterFor(t *testing.T) { - params, _ := asn1.Marshal(pbeParams{ - Salt: []byte{1, 2, 3, 4, 5, 6, 7, 8}, - Iterations: 2048, - }) - alg := pkix.AlgorithmIdentifier{ - Algorithm: asn1.ObjectIdentifier([]int{1, 2, 3}), - Parameters: asn1.RawValue{ - FullBytes: params, - }, - } - - pass, _ := bmpString("Sesame open") - - _, _, err := pbDecrypterFor(alg, pass) - if _, ok := err.(NotImplementedError); !ok { - t.Errorf("expected not implemented error, got: %T %s", err, err) - } - - alg.Algorithm = sha1WithTripleDES - cbc, blockSize, err := pbDecrypterFor(alg, pass) - if err != nil { - t.Errorf("unexpected error from pbDecrypterFor %v", err) - } - if blockSize != 8 { - t.Errorf("unexpected block size %d, wanted 8", blockSize) - } - - plaintext := []byte{1, 2, 3, 4, 5, 6, 7, 8} - expectedCiphertext := []byte{185, 73, 135, 249, 137, 1, 122, 247} - ciphertext := make([]byte, len(plaintext)) - cbc.CryptBlocks(ciphertext, plaintext) - - if bytes.Compare(ciphertext, expectedCiphertext) != 0 { - t.Errorf("bad ciphertext, got %x but wanted %x", ciphertext, expectedCiphertext) - } -} - -var pbDecryptTests = []struct { - in []byte - expected []byte - expectedError error -}{ - { - []byte("\x33\x73\xf3\x9f\xda\x49\xae\xfc\xa0\x9a\xdf\x5a\x58\xa0\xea\x46"), // 7 padding bytes - []byte("A secret!"), - nil, - }, - { - []byte("\x33\x73\xf3\x9f\xda\x49\xae\xfc\x96\x24\x2f\x71\x7e\x32\x3f\xe7"), // 8 padding bytes - []byte("A secret"), - nil, - }, - { - []byte("\x35\x0c\xc0\x8d\xab\xa9\x5d\x30\x7f\x9a\xec\x6a\xd8\x9b\x9c\xd9"), // 9 padding bytes, incorrect - nil, - ErrDecryption, - }, - { - []byte("\xb2\xf9\x6e\x06\x60\xae\x20\xcf\x08\xa0\x7b\xd9\x6b\x20\xef\x41"), // incorrect padding bytes: [ ... 0x04 0x02 ] - nil, - ErrDecryption, - }, -} - -func TestPbDecrypt(t *testing.T) { - salt := []byte("\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8") - - for i, test := range pbDecryptTests { - decryptable := makeTestDecryptable(test.in, salt) - password, _ := bmpString("sesame") - - plaintext, err := pbDecrypt(decryptable, password) - if err != test.expectedError { - t.Errorf("#%d: got error %q, but wanted %q", i, err, test.expectedError) - continue - } - - if !bytes.Equal(plaintext, test.expected) { - t.Errorf("#%d: got %x, but wanted %x", i, plaintext, test.expected) - } - } -} - -func TestRoundTripPkc12EncryptDecrypt(t *testing.T) { - salt := []byte{0xfe, 0xee, 0xfa, 0xce} - password := salt - - // Sweep the possible padding lengths - for i := 0; i < 9; i++ { - bs := make([]byte, i) - _, err := io.ReadFull(rand.Reader, bs) - if err != nil { - t.Fatalf("failed to read: %s", err) - } - - cipherText, err := pbEncrypt(bs, salt, password, 4096) - if err != nil { - t.Fatalf("failed to encrypt: %s\n", err) - } - - if len(cipherText)%8 != 0 { - t.Fatalf("plain text was not padded as expected") - } - - decryptable := makeTestDecryptable(cipherText, salt) - plainText, err := pbDecrypt(decryptable, password) - if err != nil { - t.Fatalf("failed to decrypt: %s\n", err) - } - - if !bytes.Equal(bs, plainText) { - t.Fatalf("got %x, but wanted %x", bs, plainText) - } - } -} - -func makeTestDecryptable(bytes, salt []byte) testDecryptable { - decryptable := testDecryptable{ - data: bytes, - algorithm: pkix.AlgorithmIdentifier{ - Algorithm: sha1WithTripleDES, - Parameters: pbeParams{ - Salt: salt, - Iterations: 4096, - }.RawASN1(), - }, - } - - return decryptable -} - -type testDecryptable struct { - data []byte - algorithm pkix.AlgorithmIdentifier -} - -func (d testDecryptable) Algorithm() pkix.AlgorithmIdentifier { return d.algorithm } -func (d testDecryptable) Data() []byte { return d.data } - -func (params pbeParams) RawASN1() (raw asn1.RawValue) { - asn1Bytes, err := asn1.Marshal(params) - if err != nil { - panic(err) - } - _, err = asn1.Unmarshal(asn1Bytes, &raw) - if err != nil { - panic(err) - } - return -} diff --git a/builder/azure/pkcs12/errors.go b/builder/azure/pkcs12/errors.go deleted file mode 100644 index 36ad6e957..000000000 --- a/builder/azure/pkcs12/errors.go +++ /dev/null @@ -1,28 +0,0 @@ -// Copyright 2015 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package pkcs12 - -import "errors" - -var ( - // ErrDecryption represents a failure to decrypt the input. - ErrDecryption = errors.New("pkcs12: decryption error, incorrect padding") - - // ErrIncorrectPassword is returned when an incorrect password is detected. - // Usually, P12/PFX data is signed to be able to verify the password. - ErrIncorrectPassword = errors.New("pkcs12: decryption password incorrect") -) - -// NotImplementedError indicates that the input is not currently supported. -type NotImplementedError string -type EncodeError string - -func (e NotImplementedError) Error() string { - return "pkcs12: " + string(e) -} - -func (e EncodeError) Error() string { - return "pkcs12: encode error: " + string(e) -} diff --git a/builder/azure/pkcs12/mac.go b/builder/azure/pkcs12/mac.go deleted file mode 100644 index 76ad0cdc5..000000000 --- a/builder/azure/pkcs12/mac.go +++ /dev/null @@ -1,50 +0,0 @@ -// Copyright 2015 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package pkcs12 - -import ( - "crypto/hmac" - "crypto/sha1" - "crypto/x509/pkix" - "encoding/asn1" -) - -type macData struct { - Mac digestInfo - MacSalt []byte - Iterations int `asn1:"optional,default:1"` -} - -// from PKCS#7: -type digestInfo struct { - Algorithm pkix.AlgorithmIdentifier - Digest []byte -} - -var ( - oidSHA1 = asn1.ObjectIdentifier([]int{1, 3, 14, 3, 2, 26}) -) - -func verifyMac(macData *macData, message, password []byte) error { - if !macData.Mac.Algorithm.Algorithm.Equal(oidSHA1) { - return NotImplementedError("unknown digest algorithm: " + macData.Mac.Algorithm.Algorithm.String()) - } - - expectedMAC := computeMac(message, macData.Iterations, macData.MacSalt, password) - - if !hmac.Equal(macData.Mac.Digest, expectedMAC) { - return ErrIncorrectPassword - } - return nil -} - -func computeMac(message []byte, iterations int, salt, password []byte) []byte { - key := pbkdf(sha1Sum, 20, 64, salt, password, iterations, 3, 20) - - mac := hmac.New(sha1.New, key) - mac.Write(message) - - return mac.Sum(nil) -} diff --git a/builder/azure/pkcs12/mac_test.go b/builder/azure/pkcs12/mac_test.go deleted file mode 100644 index 1ed4ff21e..000000000 --- a/builder/azure/pkcs12/mac_test.go +++ /dev/null @@ -1,42 +0,0 @@ -// Copyright 2015 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package pkcs12 - -import ( - "encoding/asn1" - "testing" -) - -func TestVerifyMac(t *testing.T) { - td := macData{ - Mac: digestInfo{ - Digest: []byte{0x18, 0x20, 0x3d, 0xff, 0x1e, 0x16, 0xf4, 0x92, 0xf2, 0xaf, 0xc8, 0x91, 0xa9, 0xba, 0xd6, 0xca, 0x9d, 0xee, 0x51, 0x93}, - }, - MacSalt: []byte{1, 2, 3, 4, 5, 6, 7, 8}, - Iterations: 2048, - } - - message := []byte{11, 12, 13, 14, 15} - password, _ := bmpString("") - - td.Mac.Algorithm.Algorithm = asn1.ObjectIdentifier([]int{1, 2, 3}) - err := verifyMac(&td, message, password) - if _, ok := err.(NotImplementedError); !ok { - t.Errorf("err: %v", err) - } - - td.Mac.Algorithm.Algorithm = asn1.ObjectIdentifier([]int{1, 3, 14, 3, 2, 26}) - err = verifyMac(&td, message, password) - if err != ErrIncorrectPassword { - t.Errorf("Expected incorrect password, got err: %v", err) - } - - password, _ = bmpString("Sesame open") - err = verifyMac(&td, message, password) - if err != nil { - t.Errorf("err: %v", err) - } - -} diff --git a/builder/azure/pkcs12/pbkdf.go b/builder/azure/pkcs12/pbkdf.go deleted file mode 100644 index 5c419d41e..000000000 --- a/builder/azure/pkcs12/pbkdf.go +++ /dev/null @@ -1,170 +0,0 @@ -// Copyright 2015 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package pkcs12 - -import ( - "bytes" - "crypto/sha1" - "math/big" -) - -var ( - one = big.NewInt(1) -) - -// sha1Sum returns the SHA-1 hash of in. -func sha1Sum(in []byte) []byte { - sum := sha1.Sum(in) - return sum[:] -} - -// fillWithRepeats returns v*ceiling(len(pattern) / v) bytes consisting of -// repeats of pattern. -func fillWithRepeats(pattern []byte, v int) []byte { - if len(pattern) == 0 { - return nil - } - outputLen := v * ((len(pattern) + v - 1) / v) - return bytes.Repeat(pattern, (outputLen+len(pattern)-1)/len(pattern))[:outputLen] -} - -func pbkdf(hash func([]byte) []byte, u, v int, salt, password []byte, r int, ID byte, size int) (key []byte) { - // implementation of https://tools.ietf.org/html/rfc7292#appendix-B.2 , RFC text verbatim in comments - - // Let H be a hash function built around a compression function f: - - // Z_2^u x Z_2^v -> Z_2^u - - // (that is, H has a chaining variable and output of length u bits, and - // the message input to the compression function of H is v bits). The - // values for u and v are as follows: - - // HASH FUNCTION VALUE u VALUE v - // MD2, MD5 128 512 - // SHA-1 160 512 - // SHA-224 224 512 - // SHA-256 256 512 - // SHA-384 384 1024 - // SHA-512 512 1024 - // SHA-512/224 224 1024 - // SHA-512/256 256 1024 - - // Furthermore, let r be the iteration count. - - // We assume here that u and v are both multiples of 8, as are the - // lengths of the password and salt strings (which we denote by p and s, - // respectively) and the number n of pseudorandom bits required. In - // addition, u and v are of course non-zero. - - // For information on security considerations for MD5 [19], see [25] and - // [1], and on those for MD2, see [18]. - - // The following procedure can be used to produce pseudorandom bits for - // a particular "purpose" that is identified by a byte called "ID". - // This standard specifies 3 different values for the ID byte: - - // 1. If ID=1, then the pseudorandom bits being produced are to be used - // as key material for performing encryption or decryption. - - // 2. If ID=2, then the pseudorandom bits being produced are to be used - // as an IV (Initial Value) for encryption or decryption. - - // 3. If ID=3, then the pseudorandom bits being produced are to be used - // as an integrity key for MACing. - - // 1. Construct a string, D (the "diversifier"), by concatenating v/8 - // copies of ID. - var D []byte - for i := 0; i < v; i++ { - D = append(D, ID) - } - - // 2. Concatenate copies of the salt together to create a string S of - // length v(ceiling(s/v)) bits (the final copy of the salt may be - // truncated to create S). Note that if the salt is the empty - // string, then so is S. - - S := fillWithRepeats(salt, v) - - // 3. Concatenate copies of the password together to create a string P - // of length v(ceiling(p/v)) bits (the final copy of the password - // may be truncated to create P). Note that if the password is the - // empty string, then so is P. - - P := fillWithRepeats(password, v) - - // 4. Set I=S||P to be the concatenation of S and P. - I := append(S, P...) - - // 5. Set c=ceiling(n/u). - c := (size + u - 1) / u - - // 6. For i=1, 2, ..., c, do the following: - A := make([]byte, c*20) - var IjBuf []byte - for i := 0; i < c; i++ { - // A. Set A2=H^r(D||I). (i.e., the r-th hash of D||1, - // H(H(H(... H(D||I)))) - Ai := hash(append(D, I...)) - for j := 1; j < r; j++ { - Ai = hash(Ai) - } - copy(A[i*20:], Ai[:]) - - if i < c-1 { // skip on last iteration - // B. Concatenate copies of Ai to create a string B of length v - // bits (the final copy of Ai may be truncated to create B). - var B []byte - for len(B) < v { - B = append(B, Ai[:]...) - } - B = B[:v] - - // C. Treating I as a concatenation I_0, I_1, ..., I_(k-1) of v-bit - // blocks, where k=ceiling(s/v)+ceiling(p/v), modify I by - // setting I_j=(I_j+B+1) mod 2^v for each j. - { - Bbi := new(big.Int).SetBytes(B) - Ij := new(big.Int) - - for j := 0; j < len(I)/v; j++ { - Ij.SetBytes(I[j*v : (j+1)*v]) - Ij.Add(Ij, Bbi) - Ij.Add(Ij, one) - Ijb := Ij.Bytes() - // We expect Ijb to be exactly v bytes, - // if it is longer or shorter we must - // adjust it accordingly. - if len(Ijb) > v { - Ijb = Ijb[len(Ijb)-v:] - } - if len(Ijb) < v { - if IjBuf == nil { - IjBuf = make([]byte, v) - } - bytesShort := v - len(Ijb) - for i := 0; i < bytesShort; i++ { - IjBuf[i] = 0 - } - copy(IjBuf[bytesShort:], Ijb) - Ijb = IjBuf - } - copy(I[j*v:(j+1)*v], Ijb) - } - } - } - } - // 7. Concatenate A_1, A_2, ..., A_c together to form a pseudorandom - // bit string, A. - - // 8. Use the first n bits of A as the output of this entire process. - return A[:size] - - // If the above process is being used to generate a DES key, the process - // should be used to create 64 random bits, and the key's parity bits - // should be set after the 64 bits have been produced. Similar concerns - // hold for 2-key and 3-key triple-DES keys, for CDMF keys, and for any - // similar keys with parity bits "built into them". -} diff --git a/builder/azure/pkcs12/pbkdf_test.go b/builder/azure/pkcs12/pbkdf_test.go deleted file mode 100644 index 262037d7e..000000000 --- a/builder/azure/pkcs12/pbkdf_test.go +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright 2015 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package pkcs12 - -import ( - "bytes" - "testing" -) - -func TestThatPBKDFWorksCorrectlyForLongKeys(t *testing.T) { - cipherInfo := shaWithTripleDESCBC{} - - salt := []byte("\xff\xff\xff\xff\xff\xff\xff\xff") - password, _ := bmpString("sesame") - key := cipherInfo.deriveKey(salt, password, 2048) - - if expected := []byte("\x7c\xd9\xfd\x3e\x2b\x3b\xe7\x69\x1a\x44\xe3\xbe\xf0\xf9\xea\x0f\xb9\xb8\x97\xd4\xe3\x25\xd9\xd1"); bytes.Compare(key, expected) != 0 { - t.Fatalf("expected key '%x', but found '%x'", expected, key) - } -} - -func TestThatPBKDFHandlesLeadingZeros(t *testing.T) { - // This test triggers a case where I_j (in step 6C) ends up with leading zero - // byte, meaning that len(Ijb) < v (leading zeros get stripped by big.Int). - // This was previously causing bug whereby certain inputs would break the - // derivation and produce the wrong output. - key := pbkdf(sha1Sum, 20, 64, []byte("\xf3\x7e\x05\xb5\x18\x32\x4b\x4b"), []byte("\x00\x00"), 2048, 1, 24) - expected := []byte("\x00\xf7\x59\xff\x47\xd1\x4d\xd0\x36\x65\xd5\x94\x3c\xb3\xc4\xa3\x9a\x25\x55\xc0\x2a\xed\x66\xe1") - if bytes.Compare(key, expected) != 0 { - t.Fatalf("expected key '%x', but found '%x'", expected, key) - } -} diff --git a/builder/azure/pkcs12/pkcs12.go b/builder/azure/pkcs12/pkcs12.go deleted file mode 100644 index c5ce90f0d..000000000 --- a/builder/azure/pkcs12/pkcs12.go +++ /dev/null @@ -1,530 +0,0 @@ -// Copyright 2015 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Package pkcs12 implements some of PKCS#12. -// -// This implementation is distilled from https://tools.ietf.org/html/rfc7292 -// and referenced documents. It is intended for decoding P12/PFX-stored -// certificates and keys for use with the crypto/tls package. -package pkcs12 - -import ( - "crypto/ecdsa" - "crypto/rand" - "crypto/rsa" - "crypto/x509" - "crypto/x509/pkix" - "encoding/asn1" - "encoding/hex" - "encoding/pem" - "errors" - "io" -) - -var ( - oidDataContentType = asn1.ObjectIdentifier([]int{1, 2, 840, 113549, 1, 7, 1}) - oidEncryptedDataContentType = asn1.ObjectIdentifier([]int{1, 2, 840, 113549, 1, 7, 6}) - - oidFriendlyName = asn1.ObjectIdentifier([]int{1, 2, 840, 113549, 1, 9, 20}) - oidLocalKeyID = asn1.ObjectIdentifier([]int{1, 2, 840, 113549, 1, 9, 21}) - oidMicrosoftCSPName = asn1.ObjectIdentifier([]int{1, 3, 6, 1, 4, 1, 311, 17, 1}) - - localKeyId = []byte{0x01, 0x00, 0x00, 0x00} -) - -type pfxPdu struct { - Version int - AuthSafe contentInfo - MacData macData `asn1:"optional"` -} - -type contentInfo struct { - ContentType asn1.ObjectIdentifier - Content asn1.RawValue `asn1:"tag:0,explicit,optional"` -} - -type encryptedData struct { - Version int - EncryptedContentInfo encryptedContentInfo -} - -type encryptedContentInfo struct { - ContentType asn1.ObjectIdentifier - ContentEncryptionAlgorithm pkix.AlgorithmIdentifier - EncryptedContent []byte `asn1:"tag:0,optional"` -} - -func (i encryptedContentInfo) Algorithm() pkix.AlgorithmIdentifier { - return i.ContentEncryptionAlgorithm -} - -func (i encryptedContentInfo) Data() []byte { return i.EncryptedContent } - -type safeBag struct { - Id asn1.ObjectIdentifier - Value asn1.RawValue `asn1:"tag:0,explicit"` - Attributes []pkcs12Attribute `asn1:"set,optional"` -} - -type pkcs12Attribute struct { - Id asn1.ObjectIdentifier - Value asn1.RawValue `asn1:"set"` -} - -type encryptedPrivateKeyInfo struct { - AlgorithmIdentifier pkix.AlgorithmIdentifier - EncryptedData []byte -} - -func (i encryptedPrivateKeyInfo) Algorithm() pkix.AlgorithmIdentifier { - return i.AlgorithmIdentifier -} - -func (i encryptedPrivateKeyInfo) Data() []byte { - return i.EncryptedData -} - -// PEM block types -const ( - certificateType = "CERTIFICATE" - privateKeyType = "PRIVATE KEY" -) - -// unmarshal calls asn1.Unmarshal, but also returns an error if there is any -// trailing data after unmarshalling. -func unmarshal(in []byte, out interface{}) error { - trailing, err := asn1.Unmarshal(in, out) - if err != nil { - return err - } - if len(trailing) != 0 { - return errors.New("pkcs12: trailing data found") - } - return nil -} - -// ConvertToPEM converts all "safe bags" contained in pfxData to PEM blocks. -func ToPEM(pfxData []byte, password string) ([]*pem.Block, error) { - encodedPassword, err := bmpString(password) - if err != nil { - return nil, ErrIncorrectPassword - } - - bags, encodedPassword, err := getSafeContents(pfxData, encodedPassword) - - blocks := make([]*pem.Block, 0, len(bags)) - for _, bag := range bags { - block, err := convertBag(&bag, encodedPassword) - if err != nil { - return nil, err - } - blocks = append(blocks, block) - } - - return blocks, nil -} - -func convertBag(bag *safeBag, password []byte) (*pem.Block, error) { - block := &pem.Block{ - Headers: make(map[string]string), - } - - for _, attribute := range bag.Attributes { - k, v, err := convertAttribute(&attribute) - if err != nil { - return nil, err - } - block.Headers[k] = v - } - - switch { - case bag.Id.Equal(oidCertBag): - block.Type = certificateType - certsData, err := decodeCertBag(bag.Value.Bytes) - if err != nil { - return nil, err - } - block.Bytes = certsData - case bag.Id.Equal(oidPKCS8ShroudedKeyBag): - block.Type = privateKeyType - - key, err := decodePkcs8ShroudedKeyBag(bag.Value.Bytes, password) - if err != nil { - return nil, err - } - - switch key := key.(type) { - case *rsa.PrivateKey: - block.Bytes = x509.MarshalPKCS1PrivateKey(key) - case *ecdsa.PrivateKey: - block.Bytes, err = x509.MarshalECPrivateKey(key) - if err != nil { - return nil, err - } - default: - return nil, errors.New("found unknown private key type in PKCS#8 wrapping") - } - default: - return nil, errors.New("don't know how to convert a safe bag of type " + bag.Id.String()) - } - return block, nil -} - -func convertAttribute(attribute *pkcs12Attribute) (key, value string, err error) { - isString := false - - switch { - case attribute.Id.Equal(oidFriendlyName): - key = "friendlyName" - isString = true - case attribute.Id.Equal(oidLocalKeyID): - key = "localKeyId" - case attribute.Id.Equal(oidMicrosoftCSPName): - // This key is chosen to match OpenSSL. - key = "Microsoft CSP Name" - isString = true - default: - return "", "", errors.New("pkcs12: unknown attribute with OID " + attribute.Id.String()) - } - - if isString { - if err := unmarshal(attribute.Value.Bytes, &attribute.Value); err != nil { - return "", "", err - } - if value, err = decodeBMPString(attribute.Value.Bytes); err != nil { - return "", "", err - } - } else { - var id []byte - if err := unmarshal(attribute.Value.Bytes, &id); err != nil { - return "", "", err - } - value = hex.EncodeToString(id) - } - - return key, value, nil -} - -// Decode extracts a certificate and private key from pfxData. This function -// assumes that there is only one certificate and only one private key in the -// pfxData. -func Decode(pfxData []byte, password string) (privateKey interface{}, certificate *x509.Certificate, err error) { - encodedPassword, err := bmpString(password) - if err != nil { - return nil, nil, err - } - - bags, encodedPassword, err := getSafeContents(pfxData, encodedPassword) - if err != nil { - return nil, nil, err - } - - if len(bags) != 2 { - err = errors.New("pkcs12: expected exactly two safe bags in the PFX PDU") - return - } - - for _, bag := range bags { - switch { - case bag.Id.Equal(oidCertBag): - if certificate != nil { - err = errors.New("pkcs12: expected exactly one certificate bag") - } - - certsData, err := decodeCertBag(bag.Value.Bytes) - if err != nil { - return nil, nil, err - } - certs, err := x509.ParseCertificates(certsData) - if err != nil { - return nil, nil, err - } - if len(certs) != 1 { - err = errors.New("pkcs12: expected exactly one certificate in the certBag") - return nil, nil, err - } - certificate = certs[0] - - case bag.Id.Equal(oidPKCS8ShroudedKeyBag): - if privateKey != nil { - err = errors.New("pkcs12: expected exactly one key bag") - } - if privateKey, err = decodePkcs8ShroudedKeyBag(bag.Value.Bytes, encodedPassword); err != nil { - return nil, nil, err - } - } - } - - if certificate == nil { - return nil, nil, errors.New("pkcs12: certificate missing") - } - if privateKey == nil { - return nil, nil, errors.New("pkcs12: private key missing") - } - - return -} - -func getLocalKeyId(id []byte) (attribute pkcs12Attribute, err error) { - octetString := asn1.RawValue{Tag: 4, Class: 0, IsCompound: false, Bytes: id} - bytes, err := asn1.Marshal(octetString) - if err != nil { - return - } - - attribute = pkcs12Attribute{ - Id: oidLocalKeyID, - Value: asn1.RawValue{Tag: 17, Class: 0, IsCompound: true, Bytes: bytes}, - } - - return attribute, nil -} - -func convertToRawVal(val interface{}) (raw asn1.RawValue, err error) { - bytes, err := asn1.Marshal(val) - if err != nil { - return - } - - _, err = asn1.Unmarshal(bytes, &raw) - return raw, nil -} - -func makeSafeBags(oid asn1.ObjectIdentifier, value []byte) ([]safeBag, error) { - attribute, err := getLocalKeyId(localKeyId) - - if err != nil { - return nil, EncodeError("local key id: " + err.Error()) - } - - bag := make([]safeBag, 1) - bag[0] = safeBag{ - Id: oid, - Value: asn1.RawValue{Tag: 0, Class: 2, IsCompound: true, Bytes: value}, - Attributes: []pkcs12Attribute{attribute}, - } - - return bag, nil -} - -func makeCertBagContentInfo(derBytes []byte) (*contentInfo, error) { - certBag1 := certBag{ - Id: oidCertTypeX509Certificate, - Data: derBytes, - } - - bytes, err := asn1.Marshal(certBag1) - if err != nil { - return nil, EncodeError("encoding cert bag: " + err.Error()) - } - - certSafeBags, err := makeSafeBags(oidCertBag, bytes) - if err != nil { - return nil, EncodeError("safe bags: " + err.Error()) - } - - return makeContentInfo(certSafeBags) -} - -func makeShroudedKeyBagContentInfo(privateKey interface{}, password []byte) (*contentInfo, error) { - shroudedKeyBagBytes, err := encodePkcs8ShroudedKeyBag(privateKey, password) - if err != nil { - return nil, EncodeError("encode PKCS#8 shrouded key bag: " + err.Error()) - } - - safeBags, err := makeSafeBags(oidPKCS8ShroudedKeyBag, shroudedKeyBagBytes) - if err != nil { - return nil, EncodeError("safe bags: " + err.Error()) - } - - return makeContentInfo(safeBags) -} - -func makeContentInfo(val interface{}) (*contentInfo, error) { - fullBytes, err := asn1.Marshal(val) - if err != nil { - return nil, EncodeError("contentInfo raw value marshal: " + err.Error()) - } - - octetStringVal := asn1.RawValue{Tag: 4, Class: 0, IsCompound: false, Bytes: fullBytes} - octetStringFullBytes, err := asn1.Marshal(octetStringVal) - if err != nil { - return nil, EncodeError("raw contentInfo to octet string: " + err.Error()) - } - - contentInfo := contentInfo{ContentType: oidDataContentType} - contentInfo.Content = asn1.RawValue{Tag: 0, Class: 2, IsCompound: true, Bytes: octetStringFullBytes} - - return &contentInfo, nil -} - -func makeContentInfos(derBytes []byte, privateKey interface{}, password []byte) ([]contentInfo, error) { - shroudedKeyContentInfo, err := makeShroudedKeyBagContentInfo(privateKey, password) - if err != nil { - return nil, EncodeError("shrouded key content info: " + err.Error()) - } - - certBagContentInfo, err := makeCertBagContentInfo(derBytes) - if err != nil { - return nil, EncodeError("cert bag content info: " + err.Error()) - } - - contentInfos := make([]contentInfo, 2) - contentInfos[0] = *shroudedKeyContentInfo - contentInfos[1] = *certBagContentInfo - - return contentInfos, nil -} - -func makeSalt(saltByteCount int) ([]byte, error) { - salt := make([]byte, saltByteCount) - _, err := io.ReadFull(rand.Reader, salt) - return salt, err -} - -// Encode converts a certificate and a private key to the PKCS#12 byte stream format. -// -// derBytes is a DER encoded certificate. -// privateKey is an RSA -func Encode(derBytes []byte, privateKey interface{}, password string) (pfxBytes []byte, err error) { - secret, err := bmpString(password) - if err != nil { - return nil, ErrIncorrectPassword - } - - contentInfos, err := makeContentInfos(derBytes, privateKey, secret) - if err != nil { - return nil, err - } - - // Marshal []contentInfo so we can re-constitute the byte stream that will - // be suitable for computing the MAC - bytes, err := asn1.Marshal(contentInfos) - if err != nil { - return nil, err - } - - // Unmarshal as an asn1.RawValue so, we can compute the MAC against the .Bytes - var contentInfosRaw asn1.RawValue - err = unmarshal(bytes, &contentInfosRaw) - if err != nil { - return nil, err - } - - authSafeContentInfo, err := makeContentInfo(contentInfosRaw) - if err != nil { - return nil, EncodeError("authSafe content info: " + err.Error()) - } - - salt, err := makeSalt(pbeSaltSizeBytes) - if err != nil { - return nil, EncodeError("salt value: " + err.Error()) - } - - // Compute the MAC for marshaled bytes of contentInfos, which includes the - // cert bag, and the shrouded key bag. - digest := computeMac(contentInfosRaw.FullBytes, pbeIterationCount, salt, secret) - - pfx := pfxPdu{ - Version: 3, - AuthSafe: *authSafeContentInfo, - MacData: macData{ - Iterations: pbeIterationCount, - MacSalt: salt, - Mac: digestInfo{ - Algorithm: pkix.AlgorithmIdentifier{ - Algorithm: oidSHA1, - }, - Digest: digest, - }, - }, - } - - bytes, err = asn1.Marshal(pfx) - if err != nil { - return nil, EncodeError("marshal PFX PDU: " + err.Error()) - } - - return bytes, err -} - -func getSafeContents(p12Data, password []byte) (bags []safeBag, updatedPassword []byte, err error) { - pfx := new(pfxPdu) - - if err := unmarshal(p12Data, pfx); err != nil { - return nil, nil, errors.New("pkcs12: error reading P12 data: " + err.Error()) - } - - if pfx.Version != 3 { - return nil, nil, NotImplementedError("can only decode v3 PFX PDU's") - } - - if !pfx.AuthSafe.ContentType.Equal(oidDataContentType) { - return nil, nil, NotImplementedError("only password-protected PFX is implemented") - } - - // unmarshal the explicit bytes in the content for type 'data' - if err := unmarshal(pfx.AuthSafe.Content.Bytes, &pfx.AuthSafe.Content); err != nil { - return nil, nil, err - } - - if len(pfx.MacData.Mac.Algorithm.Algorithm) == 0 { - return nil, nil, errors.New("pkcs12: no MAC in data") - } - - if err := verifyMac(&pfx.MacData, pfx.AuthSafe.Content.Bytes, password); err != nil { - if err == ErrIncorrectPassword && len(password) == 2 && password[0] == 0 && password[1] == 0 { - // some implementations use an empty byte array - // for the empty string password try one more - // time with empty-empty password - password = nil - err = verifyMac(&pfx.MacData, pfx.AuthSafe.Content.Bytes, password) - } - if err != nil { - return nil, nil, err - } - } - - var authenticatedSafe []contentInfo - if err := unmarshal(pfx.AuthSafe.Content.Bytes, &authenticatedSafe); err != nil { - return nil, nil, err - } - - if len(authenticatedSafe) != 2 { - return nil, nil, NotImplementedError("expected exactly two items in the authenticated safe") - } - - for _, ci := range authenticatedSafe { - var data []byte - - switch { - case ci.ContentType.Equal(oidDataContentType): - if err := unmarshal(ci.Content.Bytes, &data); err != nil { - return nil, nil, err - } - case ci.ContentType.Equal(oidEncryptedDataContentType): - var encryptedData encryptedData - if err := unmarshal(ci.Content.Bytes, &encryptedData); err != nil { - return nil, nil, err - } - if encryptedData.Version != 0 { - return nil, nil, NotImplementedError("only version 0 of EncryptedData is supported") - } - if data, err = pbDecrypt(encryptedData.EncryptedContentInfo, password); err != nil { - return nil, nil, err - } - default: - return nil, nil, NotImplementedError("only data and encryptedData content types are supported in authenticated safe") - } - - var safeContents []safeBag - if err := unmarshal(data, &safeContents); err != nil { - return nil, nil, err - } - - bags = append(bags, safeContents...) - } - - return bags, password, nil -} diff --git a/builder/azure/pkcs12/pkcs12_test.go b/builder/azure/pkcs12/pkcs12_test.go deleted file mode 100644 index 2ac382a0b..000000000 --- a/builder/azure/pkcs12/pkcs12_test.go +++ /dev/null @@ -1,247 +0,0 @@ -// Copyright 2015 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package pkcs12 - -import ( - "crypto/ecdsa" - "crypto/elliptic" - "crypto/rand" - "crypto/rsa" - "crypto/tls" - "crypto/x509" - "crypto/x509/pkix" - "encoding/base64" - "encoding/pem" - "fmt" - "math/big" - "testing" - "time" -) - -func TestPfx(t *testing.T) { - for commonName, base64P12 := range testdata { - p12, _ := base64.StdEncoding.DecodeString(base64P12) - - priv, cert, err := Decode(p12, "") - if err != nil { - t.Fatal(err) - } - - if err := priv.(*rsa.PrivateKey).Validate(); err != nil { - t.Errorf("error while validating private key: %v", err) - } - - if cert.Subject.CommonName != commonName { - t.Errorf("expected common name to be %q, but found %q", commonName, cert.Subject.CommonName) - } - } -} - -func TestPfxRoundTriRsa(t *testing.T) { - privateKey, err := rsa.GenerateKey(rand.Reader, 512) - if err != nil { - t.Fatal(err.Error()) - } - - key := testPfxRoundTrip(t, privateKey) - - actualPrivateKey, ok := key.(*rsa.PrivateKey) - if !ok { - t.Fatalf("failed to decode private key") - } - - if privateKey.D.Cmp(actualPrivateKey.D) != 0 { - t.Errorf("priv.D") - } -} - -func TestPfxRoundTriEcdsa(t *testing.T) { - privateKey, err := ecdsa.GenerateKey(elliptic.P224(), rand.Reader) - if err != nil { - t.Fatal(err.Error()) - } - - key := testPfxRoundTrip(t, privateKey) - - actualPrivateKey, ok := key.(*ecdsa.PrivateKey) - if !ok { - t.Fatalf("failed to decode private key") - } - - if privateKey.D.Cmp(actualPrivateKey.D) != 0 { - t.Errorf("priv.D") - } -} - -func testPfxRoundTrip(t *testing.T, privateKey interface{}) interface{} { - certificateBytes, err := newCertificate("hostname", privateKey) - if err != nil { - t.Fatal(err.Error()) - } - - bytes, err := Encode(certificateBytes, privateKey, "sesame") - if err != nil { - t.Fatal(err.Error()) - } - - key, _, err := Decode(bytes, "sesame") - if err != nil { - t.Fatalf(err.Error()) - } - - return key -} - -func TestPEM(t *testing.T) { - for commonName, base64P12 := range testdata { - p12, _ := base64.StdEncoding.DecodeString(base64P12) - - blocks, err := ToPEM(p12, "") - if err != nil { - t.Fatalf("error while converting to PEM: %s", err) - } - - var pemData []byte - for _, b := range blocks { - pemData = append(pemData, pem.EncodeToMemory(b)...) - } - - cert, err := tls.X509KeyPair(pemData, pemData) - if err != nil { - t.Errorf("err while converting to key pair: %v", err) - } - config := tls.Config{ - Certificates: []tls.Certificate{cert}, - } - config.BuildNameToCertificate() - - if _, exists := config.NameToCertificate[commonName]; !exists { - t.Errorf("did not find our cert in PEM?: %v", config.NameToCertificate) - } - } -} - -func ExampleToPEM() { - p12, _ := base64.StdEncoding.DecodeString(`MIIJzgIBAzCCCZQGCS ... CA+gwggPk==`) - - blocks, err := ToPEM(p12, "password") - if err != nil { - panic(err) - } - - var pemData []byte - for _, b := range blocks { - pemData = append(pemData, pem.EncodeToMemory(b)...) - } - - // then use PEM data for tls to construct tls certificate: - cert, err := tls.X509KeyPair(pemData, pemData) - if err != nil { - panic(err) - } - - config := &tls.Config{ - Certificates: []tls.Certificate{cert}, - } - - _ = config -} - -func newCertificate(hostname string, privateKey interface{}) ([]byte, error) { - t, _ := time.Parse("2006-01-02", "2016-01-01") - notBefore := t - notAfter := notBefore.Add(365 * 24 * time.Hour) - - serialNumber, err := rand.Int(rand.Reader, new(big.Int).Lsh(big.NewInt(1), 128)) - if err != nil { - err := fmt.Errorf("Failed to Generate Serial Number: %v", err) - return nil, err - } - - template := x509.Certificate{ - SerialNumber: serialNumber, - Issuer: pkix.Name{ - CommonName: hostname, - }, - Subject: pkix.Name{ - CommonName: hostname, - }, - - NotBefore: notBefore, - NotAfter: notAfter, - - KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature, - ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth}, - BasicConstraintsValid: true, - } - - var publicKey interface{} - switch key := privateKey.(type) { - case *rsa.PrivateKey: - publicKey = key.Public() - case *ecdsa.PrivateKey: - publicKey = key.Public() - default: - panic(fmt.Sprintf("unsupported private key type: %T", privateKey)) - } - - derBytes, err := x509.CreateCertificate(rand.Reader, &template, &template, publicKey, privateKey) - if err != nil { - return nil, fmt.Errorf("Failed to Generate derBytes: " + err.Error()) - } - - return derBytes, nil -} - -var testdata = map[string]string{ - // 'null' password test case - "Windows Azure Tools": `MIIKDAIBAzCCCcwGCSqGSIb3DQEHAaCCCb0Eggm5MIIJtTCCBe4GCSqGSIb3DQEHAaCCBd8EggXbMIIF1zCCBdMGCyqGSIb3DQEMCgECoIIE7jCCBOowHAYKKoZIhvcNAQwBAzAOBAhStUNnlTGV+gICB9AEggTIJ81JIossF6boFWpPtkiQRPtI6DW6e9QD4/WvHAVrM2bKdpMzSMsCML5NyuddANTKHBVq00Jc9keqGNAqJPKkjhSUebzQFyhe0E1oI9T4zY5UKr/I8JclOeccH4QQnsySzYUG2SnniXnQ+JrG3juetli7EKth9h6jLc6xbubPadY5HMB3wL/eG/kJymiXwU2KQ9Mgd4X6jbcV+NNCE/8jbZHvSTCPeYTJIjxfeX61Sj5kFKUCzERbsnpyevhY3X0eYtEDezZQarvGmXtMMdzf8HJHkWRdk9VLDLgjk8uiJif/+X4FohZ37ig0CpgC2+dP4DGugaZZ51hb8tN9GeCKIsrmWogMXDIVd0OACBp/EjJVmFB6y0kUCXxUE0TZt0XA1tjAGJcjDUpBvTntZjPsnH/4ZySy+s2d9OOhJ6pzRQBRm360TzkFdSwk9DLiLdGfv4pwMMu/vNGBlqjP/1sQtj+jprJiD1sDbCl4AdQZVoMBQHadF2uSD4/o17XG/Ci0r2h6Htc2yvZMAbEY4zMjjIn2a+vqIxD6onexaek1R3zbkS9j19D6EN9EWn8xgz80YRCyW65znZk8xaIhhvlU/mg7sTxeyuqroBZNcq6uDaQTehDpyH7bY2l4zWRpoj10a6JfH2q5shYz8Y6UZC/kOTfuGqbZDNZWro/9pYquvNNW0M847E5t9bsf9VkAAMHRGBbWoVoU9VpI0UnoXSfvpOo+aXa2DSq5sHHUTVY7A9eov3z5IqT+pligx11xcs+YhDWcU8di3BTJisohKvv5Y8WSkm/rloiZd4ig269k0jTRk1olP/vCksPli4wKG2wdsd5o42nX1yL7mFfXocOANZbB+5qMkiwdyoQSk+Vq+C8nAZx2bbKhUq2MbrORGMzOe0Hh0x2a0PeObycN1Bpyv7Mp3ZI9h5hBnONKCnqMhtyQHUj/nNvbJUnDVYNfoOEqDiEqqEwB7YqWzAKz8KW0OIqdlM8uiQ4JqZZlFllnWJUfaiDrdFM3lYSnFQBkzeVlts6GpDOOBjCYd7dcCNS6kq6pZC6p6HN60Twu0JnurZD6RT7rrPkIGE8vAenFt4iGe/yF52fahCSY8Ws4K0UTwN7bAS+4xRHVCWvE8sMRZsRCHizb5laYsVrPZJhE6+hux6OBb6w8kwPYXc+ud5v6UxawUWgt6uPwl8mlAtU9Z7Miw4Nn/wtBkiLL/ke1UI1gqJtcQXgHxx6mzsjh41+nAgTvdbsSEyU6vfOmxGj3Rwc1eOrIhJUqn5YjOWfzzsz/D5DzWKmwXIwdspt1p+u+kol1N3f2wT9fKPnd/RGCb4g/1hc3Aju4DQYgGY782l89CEEdalpQ/35bQczMFk6Fje12HykakWEXd/bGm9Unh82gH84USiRpeOfQvBDYoqEyrY3zkFZzBjhDqa+jEcAj41tcGx47oSfDq3iVYCdL7HSIjtnyEktVXd7mISZLoMt20JACFcMw+mrbjlug+eU7o2GR7T+LwtOp/p4LZqyLa7oQJDwde1BNZtm3TCK2P1mW94QDL0nDUps5KLtr1DaZXEkRbjSJub2ZE9WqDHyU3KA8G84Tq/rN1IoNu/if45jacyPje1Npj9IftUZSP22nV7HMwZtwQ4P4MYHRMBMGCSqGSIb3DQEJFTEGBAQBAAAAMFsGCSqGSIb3DQEJFDFOHkwAewBCADQAQQA0AEYARQBCADAALQBBADEAOABBAC0ANAA0AEIAQgAtAEIANQBGADIALQA0ADkAMQBFAEYAMQA1ADIAQgBBADEANgB9MF0GCSsGAQQBgjcRATFQHk4ATQBpAGMAcgBvAHMAbwBmAHQAIABTAG8AZgB0AHcAYQByAGUAIABLAGUAeQAgAFMAdABvAHIAYQBnAGUAIABQAHIAbwB2AGkAZABlAHIwggO/BgkqhkiG9w0BBwagggOwMIIDrAIBADCCA6UGCSqGSIb3DQEHATAcBgoqhkiG9w0BDAEGMA4ECEBk5ZAYpu0WAgIH0ICCA3hik4mQFGpw9Ha8TQPtk+j2jwWdxfF0+sTk6S8PTsEfIhB7wPltjiCK92Uv2tCBQnodBUmatIfkpnRDEySmgmdglmOCzj204lWAMRs94PoALGn3JVBXbO1vIDCbAPOZ7Z0Hd0/1t2hmk8v3//QJGUg+qr59/4y/MuVfIg4qfkPcC2QSvYWcK3oTf6SFi5rv9B1IOWFgN5D0+C+x/9Lb/myPYX+rbOHrwtJ4W1fWKoz9g7wwmGFA9IJ2DYGuH8ifVFbDFT1Vcgsvs8arSX7oBsJVW0qrP7XkuDRe3EqCmKW7rBEwYrFznhxZcRDEpMwbFoSvgSIZ4XhFY9VKYglT+JpNH5iDceYEBOQL4vBLpxNUk3l5jKaBNxVa14AIBxq18bVHJ+STInhLhad4u10v/Xbx7wIL3f9DX1yLAkPrpBYbNHS2/ew6H/ySDJnoIDxkw2zZ4qJ+qUJZ1S0lbZVG+VT0OP5uF6tyOSpbMlcGkdl3z254n6MlCrTifcwkzscysDsgKXaYQw06rzrPW6RDub+t+hXzGny799fS9jhQMLDmOggaQ7+LA4oEZsfT89HLMWxJYDqjo3gIfjciV2mV54R684qLDS+AO09U49e6yEbwGlq8lpmO/pbXCbpGbB1b3EomcQbxdWxW2WEkkEd/VBn81K4M3obmywwXJkw+tPXDXfBmzzaqqCR+onMQ5ME1nMkY8ybnfoCc1bDIupjVWsEL2Wvq752RgI6KqzVNr1ew1IdqV5AWN2fOfek+0vi3Jd9FHF3hx8JMwjJL9dZsETV5kHtYJtE7wJ23J68BnCt2eI0GEuwXcCf5EdSKN/xXCTlIokc4Qk/gzRdIZsvcEJ6B1lGovKG54X4IohikqTjiepjbsMWj38yxDmK3mtENZ9ci8FPfbbvIEcOCZIinuY3qFUlRSbx7VUerEoV1IP3clUwexVQo4lHFee2jd7ocWsdSqSapW7OWUupBtDzRkqVhE7tGria+i1W2d6YLlJ21QTjyapWJehAMO637OdbJCCzDs1cXbodRRE7bsP492ocJy8OX66rKdhYbg8srSFNKdb3pF3UDNbN9jhI/t8iagRhNBhlQtTr1me2E/c86Q18qcRXl4bcXTt6acgCeffK6Y26LcVlrgjlD33AEYRRUeyC+rpxbT0aMjdFderlndKRIyG23mSp0HaUwNzAfMAcGBSsOAwIaBBRlviCbIyRrhIysg2dc/KbLFTc2vQQUg4rfwHMM4IKYRD/fsd1x6dda+wQ=`, - // empty string password test case - "testing@example.com": `MIIJzgIBAzCCCZQGCSqGSIb3DQEHAaCCCYUEggmBMIIJfTCCA/cGCSqGSIb3DQEHBqCCA+gwggPk -AgEAMIID3QYJKoZIhvcNAQcBMBwGCiqGSIb3DQEMAQYwDgQIIszfRGqcmPcCAggAgIIDsOZ9Eg1L -s5Wx8JhYoV3HAL4aRnkAWvTYB5NISZOgSgIQTssmt/3A7134dibTmaT/93LikkL3cTKLnQzJ4wDf -YZ1bprpVJvUqz+HFT79m27bP9zYXFrvxWBJbxjYKTSjQMgz+h8LAEpXXGajCmxMJ1oCOtdXkhhzc -LdZN6SAYgtmtyFnCdMEDskSggGuLb3fw84QEJ/Sj6FAULXunW/CPaS7Ce0TMsKmNU/jfFWj3yXXw -ro0kwjKiVLpVFlnBlHo2OoVU7hmkm59YpGhLgS7nxLD3n7nBroQ0ID1+8R01NnV9XLGoGzxMm1te -6UyTCkr5mj+kEQ8EP1Ys7g/TC411uhVWySMt/rcpkx7Vz1r9kYEAzJpONAfr6cuEVkPKrxpq4Fh0 -2fzlKBky0i/hrfIEUmngh+ERHUb/Mtv/fkv1j5w9suESbhsMLLiCXAlsP1UWMX+3bNizi3WVMEts -FM2k9byn+p8IUD/A8ULlE4kEaWeoc+2idkCNQkLGuIdGUXUFVm58se0auUkVRoRJx8x4CkMesT8j -b1H831W66YRWoEwwDQp2kK1lA2vQXxdVHWlFevMNxJeromLzj3ayiaFrfByeUXhR2S+Hpm+c0yNR -4UVU9WED2kacsZcpRm9nlEa5sr28mri5JdBrNa/K02OOhvKCxr5ZGmbOVzUQKla2z4w+Ku9k8POm -dfDNU/fGx1b5hcFWtghXe3msWVsSJrQihnN6q1ughzNiYZlJUGcHdZDRtiWwCFI0bR8h/Dmg9uO9 -4rawQQrjIRT7B8yF3UbkZyAqs8Ppb1TsMeNPHh1rxEfGVQknh/48ouJYsmtbnzugTUt3mJCXXiL+ -XcPMV6bBVAUu4aaVKSmg9+yJtY4/VKv10iw88ktv29fViIdBe3t6l/oPuvQgbQ8dqf4T8w0l/uKZ -9lS1Na9jfT1vCoS7F5TRi+tmyj1vL5kr/amEIW6xKEP6oeAMvCMtbPAzVEj38zdJ1R22FfuIBxkh -f0Zl7pdVbmzRxl/SBx9iIBJSqAvcXItiT0FIj8HxQ+0iZKqMQMiBuNWJf5pYOLWGrIyntCWwHuaQ -wrx0sTGuEL9YXLEAsBDrsvzLkx/56E4INGZFrH8G7HBdW6iGqb22IMI4GHltYSyBRKbB0gadYTyv -abPEoqww8o7/85aPSzOTJ/53ozD438Q+d0u9SyDuOb60SzCD/zPuCEd78YgtXJwBYTuUNRT27FaM -3LGMX8Hz+6yPNRnmnA2XKPn7dx/IlaqAjIs8MIIFfgYJKoZIhvcNAQcBoIIFbwSCBWswggVnMIIF -YwYLKoZIhvcNAQwKAQKgggTuMIIE6jAcBgoqhkiG9w0BDAEDMA4ECJr0cClYqOlcAgIIAASCBMhe -OQSiP2s0/46ONXcNeVAkz2ksW3u/+qorhSiskGZ0b3dFa1hhgBU2Q7JVIkc4Hf7OXaT1eVQ8oqND -uhqsNz83/kqYo70+LS8Hocj49jFgWAKrf/yQkdyP1daHa2yzlEw4mkpqOfnIORQHvYCa8nEApspZ -wVu8y6WVuLHKU67mel7db2xwstQp7PRuSAYqGjTfAylElog8ASdaqqYbYIrCXucF8iF9oVgmb/Qo -xrXshJ9aSLO4MuXlTPELmWgj07AXKSb90FKNihE+y0bWb9LPVFY1Sly3AX9PfrtkSXIZwqW3phpv -MxGxQl/R6mr1z+hlTfY9Wdpb5vlKXPKA0L0Rt8d2pOesylFi6esJoS01QgP1kJILjbrV731kvDc0 -Jsd+Oxv4BMwA7ClG8w1EAOInc/GrV1MWFGw/HeEqj3CZ/l/0jv9bwkbVeVCiIhoL6P6lVx9pXq4t -KZ0uKg/tk5TVJmG2vLcMLvezD0Yk3G2ZOMrywtmskrwoF7oAUpO9e87szoH6fEvUZlkDkPVW1NV4 -cZk3DBSQiuA3VOOg8qbo/tx/EE3H59P0axZWno2GSB0wFPWd1aj+b//tJEJHaaNR6qPRj4IWj9ru -Qbc8eRAcVWleHg8uAehSvUXlFpyMQREyrnpvMGddpiTC8N4UMrrBRhV7+UbCOWhxPCbItnInBqgl -1JpSZIP7iUtsIMdu3fEC2cdbXMTRul+4rdzUR7F9OaezV3jjvcAbDvgbK1CpyC+MJ1Mxm/iTgk9V -iUArydhlR8OniN84GyGYoYCW9O/KUwb6ASmeFOu/msx8x6kAsSQHIkKqMKv0TUR3kZnkxUvdpBGP -KTl4YCTvNGX4dYALBqrAETRDhua2KVBD/kEttDHwBNVbN2xi81+Mc7ml461aADfk0c66R/m2sjHB -2tN9+wG12OIWFQjL6wF/UfJMYamxx2zOOExiId29Opt57uYiNVLOO4ourPewHPeH0u8Gz35aero7 -lkt7cZAe1Q0038JUuE/QGlnK4lESK9UkSIQAjSaAlTsrcfwtQxB2EjoOoLhwH5mvxUEmcNGNnXUc -9xj3M5BD3zBz3Ft7G3YMMDwB1+zC2l+0UG0MGVjMVaeoy32VVNvxgX7jk22OXG1iaOB+PY9kdk+O -X+52BGSf/rD6X0EnqY7XuRPkMGgjtpZeAYxRQnFtCZgDY4wYheuxqSSpdF49yNczSPLkgB3CeCfS -+9NTKN7aC6hBbmW/8yYh6OvSiCEwY0lFS/T+7iaVxr1loE4zI1y/FFp4Pe1qfLlLttVlkygga2UU -SCunTQ8UB/M5IXWKkhMOO11dP4niWwb39Y7pCWpau7mwbXOKfRPX96cgHnQJK5uG+BesDD1oYnX0 -6frN7FOnTSHKruRIwuI8KnOQ/I+owmyz71wiv5LMQt+yM47UrEjB/EZa5X8dpEwOZvkdqL7utcyo -l0XH5kWMXdW856LL/FYftAqJIDAmtX1TXF/rbP6mPyN/IlDC0gjP84Uzd/a2UyTIWr+wk49Ek3vQ -/uDamq6QrwAxVmNh5Tset5Vhpc1e1kb7mRMZIzxSP8JcTuYd45oFKi98I8YjvueHVZce1g7OudQP -SbFQoJvdT46iBg1TTatlltpOiH2mFaxWVS0xYjAjBgkqhkiG9w0BCRUxFgQUdA9eVqvETX4an/c8 -p8SsTugkit8wOwYJKoZIhvcNAQkUMS4eLABGAHIAaQBlAG4AZABsAHkAIABuAGEAbQBlACAAZgBv -AHIAIABjAGUAcgB0MDEwITAJBgUrDgMCGgUABBRFsNz3Zd1O1GI8GTuFwCWuDOjEEwQIuBEfIcAy -HQ8CAggA`, -} diff --git a/builder/azure/pkcs12/pkcs8.go b/builder/azure/pkcs12/pkcs8.go deleted file mode 100644 index 22ab14d25..000000000 --- a/builder/azure/pkcs12/pkcs8.go +++ /dev/null @@ -1,67 +0,0 @@ -// Copyright 2016 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. -package pkcs12 - -import ( - "crypto/ecdsa" - "crypto/rsa" - "crypto/x509" - "crypto/x509/pkix" - "encoding/asn1" - "errors" -) - -// pkcs8 reflects an ASN.1, PKCS#8 PrivateKey. See -// ftp://ftp.rsasecurity.com/pub/pkcs/pkcs-8/pkcs-8v1_2.asn -// and RFC5208. -type pkcs8 struct { - Version int - Algo pkix.AlgorithmIdentifier - PrivateKey []byte - // optional attributes omitted. -} - -var ( - oidPublicKeyRSA = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 1} - oidPublicKeyECDSA = asn1.ObjectIdentifier{1, 2, 840, 10045, 2, 1} - - nullAsn = asn1.RawValue{Tag: 5} -) - -// marshalPKCS8PrivateKey converts a private key to PKCS#8 encoded form. -// See http://www.rsa.com/rsalabs/node.asp?id=2130 and RFC5208. -func marshalPKCS8PrivateKey(key interface{}) (der []byte, err error) { - pkcs := pkcs8{ - Version: 0, - } - - switch key := key.(type) { - case *rsa.PrivateKey: - pkcs.Algo = pkix.AlgorithmIdentifier{ - Algorithm: oidPublicKeyRSA, - Parameters: nullAsn, - } - pkcs.PrivateKey = x509.MarshalPKCS1PrivateKey(key) - case *ecdsa.PrivateKey: - bytes, err := x509.MarshalECPrivateKey(key) - if err != nil { - return nil, errors.New("x509: failed to marshal to PKCS#8: " + err.Error()) - } - - pkcs.Algo = pkix.AlgorithmIdentifier{ - Algorithm: oidPublicKeyECDSA, - Parameters: nullAsn, - } - pkcs.PrivateKey = bytes - default: - return nil, errors.New("x509: PKCS#8 only RSA and ECDSA private keys supported") - } - - bytes, err := asn1.Marshal(pkcs) - if err != nil { - return nil, errors.New("x509: failed to marshal to PKCS#8: " + err.Error()) - } - - return bytes, nil -} diff --git a/builder/azure/pkcs12/pkcs8_test.go b/builder/azure/pkcs12/pkcs8_test.go deleted file mode 100644 index 7d12119f5..000000000 --- a/builder/azure/pkcs12/pkcs8_test.go +++ /dev/null @@ -1,141 +0,0 @@ -// Copyright 2016 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. -package pkcs12 - -import ( - "crypto/ecdsa" - "crypto/elliptic" - "crypto/rand" - "crypto/rsa" - "crypto/x509" - "encoding/asn1" - "testing" -) - -func TestRoundTripPkcs8Rsa(t *testing.T) { - privateKey, err := rsa.GenerateKey(rand.Reader, 512) - if err != nil { - t.Fatalf("failed to generate a private key: %s", err) - } - - bytes, err := marshalPKCS8PrivateKey(privateKey) - if err != nil { - t.Fatalf("failed to marshal private key: %s", err) - } - - key, err := x509.ParsePKCS8PrivateKey(bytes) - if err != nil { - t.Fatalf("failed to parse private key: %s", err) - } - - actualPrivateKey, ok := key.(*rsa.PrivateKey) - if !ok { - t.Fatalf("expected key to be of type *rsa.PrivateKey, but actual was %T", key) - } - - if actualPrivateKey.Validate() != nil { - t.Fatalf("private key did not validate") - } - - if actualPrivateKey.N.Cmp(privateKey.N) != 0 { - t.Errorf("private key's N did not round trip") - } - if actualPrivateKey.D.Cmp(privateKey.D) != 0 { - t.Errorf("private key's D did not round trip") - } - if actualPrivateKey.E != privateKey.E { - t.Errorf("private key's E did not round trip") - } - if actualPrivateKey.Primes[0].Cmp(privateKey.Primes[0]) != 0 { - t.Errorf("private key's P did not round trip") - } - if actualPrivateKey.Primes[1].Cmp(privateKey.Primes[1]) != 0 { - t.Errorf("private key's Q did not round trip") - } -} - -func TestRoundTripPkcs8Ecdsa(t *testing.T) { - privateKey, err := ecdsa.GenerateKey(elliptic.P224(), rand.Reader) - if err != nil { - t.Fatalf("failed to generate a private key: %s", err) - } - - bytes, err := marshalPKCS8PrivateKey(privateKey) - if err != nil { - t.Fatalf("failed to marshal private key: %s", err) - } - - key, err := x509.ParsePKCS8PrivateKey(bytes) - if err != nil { - t.Fatalf("failed to parse private key: %s", err) - } - - actualPrivateKey, ok := key.(*ecdsa.PrivateKey) - if !ok { - t.Fatalf("expected key to be of type *ecdsa.PrivateKey, but actual was %T", key) - } - - // sanity check, not exhaustive - if actualPrivateKey.D.Cmp(privateKey.D) != 0 { - t.Errorf("private key's D did not round trip") - } - if actualPrivateKey.X.Cmp(privateKey.X) != 0 { - t.Errorf("private key's X did not round trip") - } - if actualPrivateKey.Y.Cmp(privateKey.Y) != 0 { - t.Errorf("private key's Y did not round trip") - } - if actualPrivateKey.Curve.Params().B.Cmp(privateKey.Curve.Params().B) != 0 { - t.Errorf("private key's Curve.B did not round trip") - } -} - -func TestNullParametersPkcs8Rsa(t *testing.T) { - privateKey, err := rsa.GenerateKey(rand.Reader, 512) - if err != nil { - t.Fatalf("failed to generate a private key: %s", err) - } - - checkNullParameter(t, privateKey) -} - -func TestNullParametersPkcs8Ecdsa(t *testing.T) { - privateKey, err := ecdsa.GenerateKey(elliptic.P224(), rand.Reader) - if err != nil { - t.Fatalf("failed to generate a private key: %s", err) - } - - checkNullParameter(t, privateKey) -} - -func checkNullParameter(t *testing.T, privateKey interface{}) { - bytes, err := marshalPKCS8PrivateKey(privateKey) - if err != nil { - t.Fatalf("failed to marshal private key: %s", err) - } - - var pkcs pkcs8 - rest, err := asn1.Unmarshal(bytes, &pkcs) - if err != nil { - t.Fatalf("failed to unmarshal PKCS#8: %s", err) - } - - if len(rest) != 0 { - t.Fatalf("unexpected trailing bytes of len=%d, bytes=%x", len(rest), rest) - } - - // Only version == 0 is known and valid - if pkcs.Version != 0 { - t.Errorf("expected version=0, but actual=%d", pkcs.Version) - } - - // ensure a NULL parameter is inserted - if pkcs.Algo.Parameters.Tag != 5 { - t.Errorf("expected parameters to be NULL, but actual tag=%d, class=%d, isCompound=%t, bytes=%x", - pkcs.Algo.Parameters.Tag, - pkcs.Algo.Parameters.Class, - pkcs.Algo.Parameters.IsCompound, - pkcs.Algo.Parameters.Bytes) - } -} diff --git a/builder/azure/pkcs12/rc2/bench_test.go b/builder/azure/pkcs12/rc2/bench_test.go deleted file mode 100644 index 3347f338c..000000000 --- a/builder/azure/pkcs12/rc2/bench_test.go +++ /dev/null @@ -1,27 +0,0 @@ -// Copyright 2015 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package rc2 - -import ( - "testing" -) - -func BenchmarkEncrypt(b *testing.B) { - r, _ := New([]byte{0, 0, 0, 0, 0, 0, 0, 0}, 64) - b.ResetTimer() - var src [8]byte - for i := 0; i < b.N; i++ { - r.Encrypt(src[:], src[:]) - } -} - -func BenchmarkDecrypt(b *testing.B) { - r, _ := New([]byte{0, 0, 0, 0, 0, 0, 0, 0}, 64) - b.ResetTimer() - var src [8]byte - for i := 0; i < b.N; i++ { - r.Decrypt(src[:], src[:]) - } -} diff --git a/builder/azure/pkcs12/rc2/rc2.go b/builder/azure/pkcs12/rc2/rc2.go deleted file mode 100644 index 8c7090258..000000000 --- a/builder/azure/pkcs12/rc2/rc2.go +++ /dev/null @@ -1,274 +0,0 @@ -// Copyright 2015 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Package rc2 implements the RC2 cipher -/* -https://www.ietf.org/rfc/rfc2268.txt -http://people.csail.mit.edu/rivest/pubs/KRRR98.pdf - -This code is licensed under the MIT license. -*/ -package rc2 - -import ( - "crypto/cipher" - "encoding/binary" -) - -// The rc2 block size in bytes -const BlockSize = 8 - -type rc2Cipher struct { - k [64]uint16 -} - -// New returns a new rc2 cipher with the given key and effective key length t1 -func New(key []byte, t1 int) (cipher.Block, error) { - // TODO(dgryski): error checking for key length - return &rc2Cipher{ - k: expandKey(key, t1), - }, nil -} - -func (*rc2Cipher) BlockSize() int { return BlockSize } - -var piTable = [256]byte{ - 0xd9, 0x78, 0xf9, 0xc4, 0x19, 0xdd, 0xb5, 0xed, 0x28, 0xe9, 0xfd, 0x79, 0x4a, 0xa0, 0xd8, 0x9d, - 0xc6, 0x7e, 0x37, 0x83, 0x2b, 0x76, 0x53, 0x8e, 0x62, 0x4c, 0x64, 0x88, 0x44, 0x8b, 0xfb, 0xa2, - 0x17, 0x9a, 0x59, 0xf5, 0x87, 0xb3, 0x4f, 0x13, 0x61, 0x45, 0x6d, 0x8d, 0x09, 0x81, 0x7d, 0x32, - 0xbd, 0x8f, 0x40, 0xeb, 0x86, 0xb7, 0x7b, 0x0b, 0xf0, 0x95, 0x21, 0x22, 0x5c, 0x6b, 0x4e, 0x82, - 0x54, 0xd6, 0x65, 0x93, 0xce, 0x60, 0xb2, 0x1c, 0x73, 0x56, 0xc0, 0x14, 0xa7, 0x8c, 0xf1, 0xdc, - 0x12, 0x75, 0xca, 0x1f, 0x3b, 0xbe, 0xe4, 0xd1, 0x42, 0x3d, 0xd4, 0x30, 0xa3, 0x3c, 0xb6, 0x26, - 0x6f, 0xbf, 0x0e, 0xda, 0x46, 0x69, 0x07, 0x57, 0x27, 0xf2, 0x1d, 0x9b, 0xbc, 0x94, 0x43, 0x03, - 0xf8, 0x11, 0xc7, 0xf6, 0x90, 0xef, 0x3e, 0xe7, 0x06, 0xc3, 0xd5, 0x2f, 0xc8, 0x66, 0x1e, 0xd7, - 0x08, 0xe8, 0xea, 0xde, 0x80, 0x52, 0xee, 0xf7, 0x84, 0xaa, 0x72, 0xac, 0x35, 0x4d, 0x6a, 0x2a, - 0x96, 0x1a, 0xd2, 0x71, 0x5a, 0x15, 0x49, 0x74, 0x4b, 0x9f, 0xd0, 0x5e, 0x04, 0x18, 0xa4, 0xec, - 0xc2, 0xe0, 0x41, 0x6e, 0x0f, 0x51, 0xcb, 0xcc, 0x24, 0x91, 0xaf, 0x50, 0xa1, 0xf4, 0x70, 0x39, - 0x99, 0x7c, 0x3a, 0x85, 0x23, 0xb8, 0xb4, 0x7a, 0xfc, 0x02, 0x36, 0x5b, 0x25, 0x55, 0x97, 0x31, - 0x2d, 0x5d, 0xfa, 0x98, 0xe3, 0x8a, 0x92, 0xae, 0x05, 0xdf, 0x29, 0x10, 0x67, 0x6c, 0xba, 0xc9, - 0xd3, 0x00, 0xe6, 0xcf, 0xe1, 0x9e, 0xa8, 0x2c, 0x63, 0x16, 0x01, 0x3f, 0x58, 0xe2, 0x89, 0xa9, - 0x0d, 0x38, 0x34, 0x1b, 0xab, 0x33, 0xff, 0xb0, 0xbb, 0x48, 0x0c, 0x5f, 0xb9, 0xb1, 0xcd, 0x2e, - 0xc5, 0xf3, 0xdb, 0x47, 0xe5, 0xa5, 0x9c, 0x77, 0x0a, 0xa6, 0x20, 0x68, 0xfe, 0x7f, 0xc1, 0xad, -} - -func expandKey(key []byte, t1 int) [64]uint16 { - - l := make([]byte, 128) - copy(l, key) - - var t = len(key) - var t8 = (t1 + 7) / 8 - var tm = byte(255 % uint(1<<(8+uint(t1)-8*uint(t8)))) - - for i := len(key); i < 128; i++ { - l[i] = piTable[l[i-1]+l[uint8(i-t)]] - } - - l[128-t8] = piTable[l[128-t8]&tm] - - for i := 127 - t8; i >= 0; i-- { - l[i] = piTable[l[i+1]^l[i+t8]] - } - - var k [64]uint16 - - for i := range k { - k[i] = uint16(l[2*i]) + uint16(l[2*i+1])*256 - } - - return k -} - -func rotl16(x uint16, b uint) uint16 { - return (x >> (16 - b)) | (x << b) -} - -func (c *rc2Cipher) Encrypt(dst, src []byte) { - - r0 := binary.LittleEndian.Uint16(src[0:]) - r1 := binary.LittleEndian.Uint16(src[2:]) - r2 := binary.LittleEndian.Uint16(src[4:]) - r3 := binary.LittleEndian.Uint16(src[6:]) - - var j int - - for j <= 16 { - // mix r0 - r0 = r0 + c.k[j] + (r3 & r2) + ((^r3) & r1) - r0 = rotl16(r0, 1) - j++ - - // mix r1 - r1 = r1 + c.k[j] + (r0 & r3) + ((^r0) & r2) - r1 = rotl16(r1, 2) - j++ - - // mix r2 - r2 = r2 + c.k[j] + (r1 & r0) + ((^r1) & r3) - r2 = rotl16(r2, 3) - j++ - - // mix r3 - r3 = r3 + c.k[j] + (r2 & r1) + ((^r2) & r0) - r3 = rotl16(r3, 5) - j++ - - } - - r0 = r0 + c.k[r3&63] - r1 = r1 + c.k[r0&63] - r2 = r2 + c.k[r1&63] - r3 = r3 + c.k[r2&63] - - for j <= 40 { - - // mix r0 - r0 = r0 + c.k[j] + (r3 & r2) + ((^r3) & r1) - r0 = rotl16(r0, 1) - j++ - - // mix r1 - r1 = r1 + c.k[j] + (r0 & r3) + ((^r0) & r2) - r1 = rotl16(r1, 2) - j++ - - // mix r2 - r2 = r2 + c.k[j] + (r1 & r0) + ((^r1) & r3) - r2 = rotl16(r2, 3) - j++ - - // mix r3 - r3 = r3 + c.k[j] + (r2 & r1) + ((^r2) & r0) - r3 = rotl16(r3, 5) - j++ - - } - - r0 = r0 + c.k[r3&63] - r1 = r1 + c.k[r0&63] - r2 = r2 + c.k[r1&63] - r3 = r3 + c.k[r2&63] - - for j <= 60 { - - // mix r0 - r0 = r0 + c.k[j] + (r3 & r2) + ((^r3) & r1) - r0 = rotl16(r0, 1) - j++ - - // mix r1 - r1 = r1 + c.k[j] + (r0 & r3) + ((^r0) & r2) - r1 = rotl16(r1, 2) - j++ - - // mix r2 - r2 = r2 + c.k[j] + (r1 & r0) + ((^r1) & r3) - r2 = rotl16(r2, 3) - j++ - - // mix r3 - r3 = r3 + c.k[j] + (r2 & r1) + ((^r2) & r0) - r3 = rotl16(r3, 5) - j++ - } - - binary.LittleEndian.PutUint16(dst[0:], r0) - binary.LittleEndian.PutUint16(dst[2:], r1) - binary.LittleEndian.PutUint16(dst[4:], r2) - binary.LittleEndian.PutUint16(dst[6:], r3) -} - -func (c *rc2Cipher) Decrypt(dst, src []byte) { - - r0 := binary.LittleEndian.Uint16(src[0:]) - r1 := binary.LittleEndian.Uint16(src[2:]) - r2 := binary.LittleEndian.Uint16(src[4:]) - r3 := binary.LittleEndian.Uint16(src[6:]) - - j := 63 - - for j >= 44 { - // unmix r3 - r3 = rotl16(r3, 16-5) - r3 = r3 - c.k[j] - (r2 & r1) - ((^r2) & r0) - j-- - - // unmix r2 - r2 = rotl16(r2, 16-3) - r2 = r2 - c.k[j] - (r1 & r0) - ((^r1) & r3) - j-- - - // unmix r1 - r1 = rotl16(r1, 16-2) - r1 = r1 - c.k[j] - (r0 & r3) - ((^r0) & r2) - j-- - - // unmix r0 - r0 = rotl16(r0, 16-1) - r0 = r0 - c.k[j] - (r3 & r2) - ((^r3) & r1) - j-- - } - - r3 = r3 - c.k[r2&63] - r2 = r2 - c.k[r1&63] - r1 = r1 - c.k[r0&63] - r0 = r0 - c.k[r3&63] - - for j >= 20 { - // unmix r3 - r3 = rotl16(r3, 16-5) - r3 = r3 - c.k[j] - (r2 & r1) - ((^r2) & r0) - j-- - - // unmix r2 - r2 = rotl16(r2, 16-3) - r2 = r2 - c.k[j] - (r1 & r0) - ((^r1) & r3) - j-- - - // unmix r1 - r1 = rotl16(r1, 16-2) - r1 = r1 - c.k[j] - (r0 & r3) - ((^r0) & r2) - j-- - - // unmix r0 - r0 = rotl16(r0, 16-1) - r0 = r0 - c.k[j] - (r3 & r2) - ((^r3) & r1) - j-- - - } - - r3 = r3 - c.k[r2&63] - r2 = r2 - c.k[r1&63] - r1 = r1 - c.k[r0&63] - r0 = r0 - c.k[r3&63] - - for j >= 0 { - - // unmix r3 - r3 = rotl16(r3, 16-5) - r3 = r3 - c.k[j] - (r2 & r1) - ((^r2) & r0) - j-- - - // unmix r2 - r2 = rotl16(r2, 16-3) - r2 = r2 - c.k[j] - (r1 & r0) - ((^r1) & r3) - j-- - - // unmix r1 - r1 = rotl16(r1, 16-2) - r1 = r1 - c.k[j] - (r0 & r3) - ((^r0) & r2) - j-- - - // unmix r0 - r0 = rotl16(r0, 16-1) - r0 = r0 - c.k[j] - (r3 & r2) - ((^r3) & r1) - j-- - - } - - binary.LittleEndian.PutUint16(dst[0:], r0) - binary.LittleEndian.PutUint16(dst[2:], r1) - binary.LittleEndian.PutUint16(dst[4:], r2) - binary.LittleEndian.PutUint16(dst[6:], r3) -} diff --git a/builder/azure/pkcs12/rc2/rc2_test.go b/builder/azure/pkcs12/rc2/rc2_test.go deleted file mode 100644 index 8a49dfaf3..000000000 --- a/builder/azure/pkcs12/rc2/rc2_test.go +++ /dev/null @@ -1,93 +0,0 @@ -// Copyright 2015 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package rc2 - -import ( - "bytes" - "encoding/hex" - "testing" -) - -func TestEncryptDecrypt(t *testing.T) { - - // TODO(dgryski): add the rest of the test vectors from the RFC - var tests = []struct { - key string - plain string - cipher string - t1 int - }{ - { - "0000000000000000", - "0000000000000000", - "ebb773f993278eff", - 63, - }, - { - "ffffffffffffffff", - "ffffffffffffffff", - "278b27e42e2f0d49", - 64, - }, - { - "3000000000000000", - "1000000000000001", - "30649edf9be7d2c2", - 64, - }, - { - "88", - "0000000000000000", - "61a8a244adacccf0", - 64, - }, - { - "88bca90e90875a", - "0000000000000000", - "6ccf4308974c267f", - 64, - }, - { - "88bca90e90875a7f0f79c384627bafb2", - "0000000000000000", - "1a807d272bbe5db1", - 64, - }, - { - "88bca90e90875a7f0f79c384627bafb2", - "0000000000000000", - "2269552ab0f85ca6", - 128, - }, - { - "88bca90e90875a7f0f79c384627bafb216f80a6f85920584c42fceb0be255daf1e", - "0000000000000000", - "5b78d3a43dfff1f1", - 129, - }, - } - - for _, tt := range tests { - k, _ := hex.DecodeString(tt.key) - p, _ := hex.DecodeString(tt.plain) - c, _ := hex.DecodeString(tt.cipher) - - b, _ := New(k, tt.t1) - - var dst [8]byte - - b.Encrypt(dst[:], p) - - if !bytes.Equal(dst[:], c) { - t.Errorf("encrypt failed: got % 2x wanted % 2x\n", dst, c) - } - - b.Decrypt(dst[:], c) - - if !bytes.Equal(dst[:], p) { - t.Errorf("decrypt failed: got % 2x wanted % 2x\n", dst, p) - } - } -} diff --git a/builder/azure/pkcs12/safebags.go b/builder/azure/pkcs12/safebags.go deleted file mode 100644 index 836236da3..000000000 --- a/builder/azure/pkcs12/safebags.go +++ /dev/null @@ -1,105 +0,0 @@ -// Copyright 2015 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package pkcs12 - -import ( - "crypto/x509" - "crypto/x509/pkix" - "encoding/asn1" - "errors" -) - -var ( - // see https://tools.ietf.org/html/rfc7292#appendix-D - oidCertTypeX509Certificate = asn1.ObjectIdentifier([]int{1, 2, 840, 113549, 1, 9, 22, 1}) - oidPKCS8ShroudedKeyBag = asn1.ObjectIdentifier([]int{1, 2, 840, 113549, 1, 12, 10, 1, 2}) - oidCertBag = asn1.ObjectIdentifier([]int{1, 2, 840, 113549, 1, 12, 10, 1, 3}) -) - -type certBag struct { - Id asn1.ObjectIdentifier - Data []byte `asn1:"tag:0,explicit"` -} - -func getAlgorithmParams(salt []byte, iterations int) (asn1.RawValue, error) { - params := pbeParams{ - Salt: salt, - Iterations: iterations, - } - - return convertToRawVal(params) -} - -func encodePkcs8ShroudedKeyBag(privateKey interface{}, password []byte) (bytes []byte, err error) { - privateKeyBytes, err := marshalPKCS8PrivateKey(privateKey) - - if err != nil { - return nil, errors.New("pkcs12: error encoding PKCS#8 private key: " + err.Error()) - } - - salt, err := makeSalt(pbeSaltSizeBytes) - if err != nil { - return nil, errors.New("pkcs12: error creating PKCS#8 salt: " + err.Error()) - } - - pkData, err := pbEncrypt(privateKeyBytes, salt, password, pbeIterationCount) - if err != nil { - return nil, errors.New("pkcs12: error encoding PKCS#8 shrouded key bag when encrypting cert bag: " + err.Error()) - } - - params, err := getAlgorithmParams(salt, pbeIterationCount) - if err != nil { - return nil, errors.New("pkcs12: error encoding PKCS#8 shrouded key bag algorithm's parameters: " + err.Error()) - } - - pkinfo := encryptedPrivateKeyInfo{ - AlgorithmIdentifier: pkix.AlgorithmIdentifier{ - Algorithm: oidPBEWithSHAAnd3KeyTripleDESCBC, - Parameters: params, - }, - EncryptedData: pkData, - } - - bytes, err = asn1.Marshal(pkinfo) - if err != nil { - return nil, errors.New("pkcs12: error encoding PKCS#8 shrouded key bag: " + err.Error()) - } - - return bytes, err -} - -func decodePkcs8ShroudedKeyBag(asn1Data, password []byte) (privateKey interface{}, err error) { - pkinfo := new(encryptedPrivateKeyInfo) - if err = unmarshal(asn1Data, pkinfo); err != nil { - return nil, errors.New("pkcs12: error decoding PKCS#8 shrouded key bag: " + err.Error()) - } - - pkData, err := pbDecrypt(pkinfo, password) - if err != nil { - return nil, errors.New("pkcs12: error decrypting PKCS#8 shrouded key bag: " + err.Error()) - } - - ret := new(asn1.RawValue) - if err = unmarshal(pkData, ret); err != nil { - return nil, errors.New("pkcs12: error unmarshalling decrypted private key: " + err.Error()) - } - - if privateKey, err = x509.ParsePKCS8PrivateKey(pkData); err != nil { - return nil, errors.New("pkcs12: error parsing PKCS#8 private key: " + err.Error()) - } - - return privateKey, nil -} - -func decodeCertBag(asn1Data []byte) (x509Certificates []byte, err error) { - bag := new(certBag) - if err := unmarshal(asn1Data, bag); err != nil { - return nil, errors.New("pkcs12: error decoding cert bag: " + err.Error()) - } - if !bag.Id.Equal(oidCertTypeX509Certificate) { - return nil, NotImplementedError("only X509 certificates are supported") - } - return bag.Data, nil -} diff --git a/builder/azure/pkcs12/safebags_test.go b/builder/azure/pkcs12/safebags_test.go deleted file mode 100644 index f21a83c68..000000000 --- a/builder/azure/pkcs12/safebags_test.go +++ /dev/null @@ -1,78 +0,0 @@ -// Copyright 2016 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. -package pkcs12 - -import ( - "crypto/rand" - "crypto/rsa" - "encoding/asn1" - "testing" -) - -// Assert the default algorithm parameters are in the correct order, -// and default to the correct value. Defaults are based on OpenSSL. -// 1. IterationCount, defaults to 2,048 long. -// 2. Salt, is 8 bytes long. -func TestDefaultAlgorithmParametersPkcs8ShroudedKeyBag(t *testing.T) { - privateKey, err := rsa.GenerateKey(rand.Reader, 512) - if err != nil { - t.Fatalf("failed to generate a private key: %s", err) - } - - password := []byte("sesame") - bytes, err := encodePkcs8ShroudedKeyBag(privateKey, password) - if err != nil { - t.Fatalf("failed to encode PKCS#8 shrouded key bag: %s", err) - } - - var pkinfo encryptedPrivateKeyInfo - rest, err := asn1.Unmarshal(bytes, &pkinfo) - if err != nil { - t.Fatalf("failed to unmarshal encryptedPrivateKeyInfo %s", err) - } - - if len(rest) != 0 { - t.Fatalf("unexpected trailing bytes of len=%d, bytes=%x", len(rest), rest) - } - - var params pbeParams - rest, err = asn1.Unmarshal(pkinfo.Algorithm().Parameters.FullBytes, ¶ms) - if err != nil { - t.Fatalf("failed to unmarshal encryptedPrivateKeyInfo %s", err) - } - - if len(rest) != 0 { - t.Fatalf("unexpected trailing bytes of len=%d, bytes=%x", len(rest), rest) - } - - if params.Iterations != pbeIterationCount { - t.Errorf("expected iteration count to be %d, but actual=%d", pbeIterationCount, params.Iterations) - } - if len(params.Salt) != pbeSaltSizeBytes { - t.Errorf("expected the number of salt bytes to be %d, but actual=%d", pbeSaltSizeBytes, len(params.Salt)) - } -} - -func TestRoundTripPkcs8ShroudedKeyBag(t *testing.T) { - privateKey, err := rsa.GenerateKey(rand.Reader, 512) - if err != nil { - t.Fatalf("failed to generate a private key: %s", err) - } - - password := []byte("sesame") - bytes, err := encodePkcs8ShroudedKeyBag(privateKey, password) - if err != nil { - t.Fatalf("failed to encode PKCS#8 shrouded key bag: %s", err) - } - - key, err := decodePkcs8ShroudedKeyBag(bytes, password) - if err != nil { - t.Fatalf("failed to decode PKCS#8 shrouded key bag: %s", err) - } - - actualPrivateKey := key.(*rsa.PrivateKey) - if actualPrivateKey.D.Cmp(privateKey.D) != 0 { - t.Fatalf("failed to round-trip rsa.PrivateKey.D") - } -} diff --git a/builder/azure/version/version.go b/builder/azure/version/version.go deleted file mode 100644 index 7e0d2c0f4..000000000 --- a/builder/azure/version/version.go +++ /dev/null @@ -1,13 +0,0 @@ -package version - -import ( - "github.com/hashicorp/packer-plugin-sdk/version" - packerVersion "github.com/hashicorp/packer/version" -) - -var AzurePluginVersion *version.PluginVersion - -func init() { - AzurePluginVersion = version.InitializePluginVersion( - packerVersion.Version, packerVersion.VersionPrerelease) -} diff --git a/command/plugin.go b/command/plugin.go index 5e007a0c2..58f718f84 100644 --- a/command/plugin.go +++ b/command/plugin.go @@ -13,9 +13,6 @@ import ( packersdk "github.com/hashicorp/packer-plugin-sdk/packer" "github.com/hashicorp/packer-plugin-sdk/plugin" - azurearmbuilder "github.com/hashicorp/packer/builder/azure/arm" - azurechrootbuilder "github.com/hashicorp/packer/builder/azure/chroot" - azuredtlbuilder "github.com/hashicorp/packer/builder/azure/dtl" filebuilder "github.com/hashicorp/packer/builder/file" nullbuilder "github.com/hashicorp/packer/builder/null" oneandonebuilder "github.com/hashicorp/packer/builder/oneandone" @@ -25,7 +22,6 @@ import ( compresspostprocessor "github.com/hashicorp/packer/post-processor/compress" manifestpostprocessor "github.com/hashicorp/packer/post-processor/manifest" shelllocalpostprocessor "github.com/hashicorp/packer/post-processor/shell-local" - azuredtlartifactprovisioner "github.com/hashicorp/packer/provisioner/azure-dtlartifact" breakpointprovisioner "github.com/hashicorp/packer/provisioner/breakpoint" fileprovisioner "github.com/hashicorp/packer/provisioner/file" inspecprovisioner "github.com/hashicorp/packer/provisioner/inspec" @@ -43,9 +39,6 @@ type PluginCommand struct { } var Builders = map[string]packersdk.Builder{ - "azure-arm": new(azurearmbuilder.Builder), - "azure-chroot": new(azurechrootbuilder.Builder), - "azure-dtl": new(azuredtlbuilder.Builder), "file": new(filebuilder.Builder), "null": new(nullbuilder.Builder), "oneandone": new(oneandonebuilder.Builder), @@ -53,17 +46,16 @@ var Builders = map[string]packersdk.Builder{ } var Provisioners = map[string]packersdk.Provisioner{ - "azure-dtlartifact": new(azuredtlartifactprovisioner.Provisioner), - "breakpoint": new(breakpointprovisioner.Provisioner), - "file": new(fileprovisioner.Provisioner), - "inspec": new(inspecprovisioner.Provisioner), - "powershell": new(powershellprovisioner.Provisioner), - "salt-masterless": new(saltmasterlessprovisioner.Provisioner), - "shell": new(shellprovisioner.Provisioner), - "shell-local": new(shelllocalprovisioner.Provisioner), - "sleep": new(sleepprovisioner.Provisioner), - "windows-restart": new(windowsrestartprovisioner.Provisioner), - "windows-shell": new(windowsshellprovisioner.Provisioner), + "breakpoint": new(breakpointprovisioner.Provisioner), + "file": new(fileprovisioner.Provisioner), + "inspec": new(inspecprovisioner.Provisioner), + "powershell": new(powershellprovisioner.Provisioner), + "salt-masterless": new(saltmasterlessprovisioner.Provisioner), + "shell": new(shellprovisioner.Provisioner), + "shell-local": new(shelllocalprovisioner.Provisioner), + "sleep": new(sleepprovisioner.Provisioner), + "windows-restart": new(windowsrestartprovisioner.Provisioner), + "windows-shell": new(windowsshellprovisioner.Provisioner), } var PostProcessors = map[string]packersdk.PostProcessor{ diff --git a/command/vendored_plugins.go b/command/vendored_plugins.go index b2ec67897..146b4452b 100644 --- a/command/vendored_plugins.go +++ b/command/vendored_plugins.go @@ -19,6 +19,10 @@ import ( anazibimportpostprocessor "github.com/hashicorp/packer-plugin-amazon/post-processor/import" ansibleprovisioner "github.com/hashicorp/packer-plugin-ansible/provisioner/ansible" ansiblelocalprovisioner "github.com/hashicorp/packer-plugin-ansible/provisioner/ansible-local" + azurearmbuilder "github.com/hashicorp/packer-plugin-azure/builder/azure/arm" + azurechrootbuilder "github.com/hashicorp/packer-plugin-azure/builder/azure/chroot" + azuredtlbuilder "github.com/hashicorp/packer-plugin-azure/builder/azure/dtl" + azuredtlartifactprovisioner "github.com/hashicorp/packer-plugin-azure/provisioner/azure-dtlartifact" chefclientprovisioner "github.com/hashicorp/packer-plugin-chef/provisioner/chef-client" chefsoloprovisioner "github.com/hashicorp/packer-plugin-chef/provisioner/chef-solo" cloudstackbuilder "github.com/hashicorp/packer-plugin-cloudstack/builder/cloudstack" @@ -94,6 +98,9 @@ var VendoredBuilders = map[string]packersdk.Builder{ "amazon-ebssurrogate": new(amazonebssurrogatebuilder.Builder), "amazon-ebsvolume": new(amazonebsvolumebuilder.Builder), "amazon-instance": new(amazoninstancebuilder.Builder), + "azure-arm": new(azurearmbuilder.Builder), + "azure-chroot": new(azurechrootbuilder.Builder), + "azure-dtl": new(azuredtlbuilder.Builder), "cloudstack": new(cloudstackbuilder.Builder), "digitalocean": new(digitaloceanbuilder.Builder), "docker": new(dockerbuilder.Builder), @@ -138,6 +145,7 @@ var VendoredBuilders = map[string]packersdk.Builder{ // VendoredProvisioners are provisioner components that were once bundled with the // Packer core, but are now being imported from their counterpart plugin repos var VendoredProvisioners = map[string]packersdk.Provisioner{ + "azure-dtlartifact": new(azuredtlartifactprovisioner.Provisioner), "ansible": new(ansibleprovisioner.Provisioner), "ansible-local": new(ansiblelocalprovisioner.Provisioner), "chef-client": new(chefclientprovisioner.Provisioner), diff --git a/contrib/azure-setup.sh b/contrib/azure-setup.sh deleted file mode 100755 index 7b7eac7c6..000000000 --- a/contrib/azure-setup.sh +++ /dev/null @@ -1,268 +0,0 @@ -#!/usr/bin/env bash -set -e - -meta_name= -azure_client_id= # Derived from application after creation -azure_client_name= # Application name -azure_client_secret= # Application password -azure_group_name= -azure_storage_name= -azure_subscription_id= # Derived from the account after login -azure_tenant_id= # Derived from the account after login -location= -azure_object_id= -azureversion= -create_sleep=10 - -showhelp() { - echo "azure-setup" - echo "" - echo " azure-setup helps you generate packer credentials for azure" - echo "" - echo " The script creates a resource group, storage account, application" - echo " (client), service principal, and permissions and displays a snippet" - echo " for use in your packer templates." - echo "" - echo " For simplicity we make a lot of assumptions and choose reasonable" - echo " defaults. If you want more control over what happens, please use" - echo " the azure-cli directly." - echo "" - echo " Note that you must already have an Azure account, username," - echo " password, and subscription. You can create those here:" - echo "" - echo " - https://azure.microsoft.com/en-us/account/" - echo "" - echo "REQUIREMENTS" - echo "" - echo " - azure-cli" - echo " - jq" - echo "" - echo " Use the requirements command (below) for more info." - echo "" - echo "USAGE" - echo "" - echo " ./azure-setup.sh requirements" - echo " ./azure-setup.sh setup" - echo "" -} - -requirements() { - found=0 - - azureversion=$(az --version) - if [ $? -eq 0 ]; then - found=$((found + 1)) - echo "Found azure-cli version: $azureversion" - else - echo "azure-cli is missing. Please install azure-cli from" - echo "https://docs.microsoft.com/en-us/cli/azure/install-azure-cli?view=azure-cli-latest" - echo "Alternatively, you can use the Cloud Shell https://docs.microsoft.com/en-us/azure/cloud-shell/overview right from the Azure Portal or even VS Code." - fi - - jqversion=$(jq --version) - if [ $? -eq 0 ]; then - found=$((found + 1)) - echo "Found jq version: $jqversion" - else - echo "jq is missing. Please install jq from" - echo "https://stedolan.github.io/jq/" - fi - - if [ $found -lt 2 ]; then - exit 1 - fi -} - -askSubscription() { - az account list -otable - echo "" - echo "Please enter the Id of the account you wish to use. If you do not see" - echo "a valid account in the list press Ctrl+C to abort and create one." - echo "If you leave this blank we will use the Current account." - echo -n "> " - read azure_subscription_id - - if [ "$azure_subscription_id" != "" ]; then - az account set --subscription $azure_subscription_id - else - azure_subscription_id=$(az account list --output json | jq -r '.[] | select(.isDefault==true) | .id') - fi - azure_tenant_id=$(az account list --output json | jq -r '.[] | select(.id=="'$azure_subscription_id'") | .tenantId') - echo "Using subscription_id: $azure_subscription_id" - echo "Using tenant_id: $azure_tenant_id" -} - -askName() { - echo "" - echo "Choose a name for your resource group, storage account and client" - echo "client. This is arbitrary, but it must not already be in use by" - echo "any of those resources. ALPHANUMERIC ONLY. Ex: mypackerbuild" - echo -n "> " - read meta_name -} - -askSecret() { - echo "" - echo "Enter a secret for your application. We recommend generating one with" - echo "openssl rand -base64 24. If you leave this blank we will attempt to" - echo "generate one for you using openssl. THIS WILL BE SHOWN IN PLAINTEXT." - echo "Ex: mypackersecret8734" - echo -n "> " - read azure_client_secret - if [ "$azure_client_secret" = "" ]; then - azure_client_secret=$(openssl rand -base64 24) - if [ $? -ne 0 ]; then - echo "Error generating secret" - exit 1 - fi - echo "Generated client_secret: $azure_client_secret" - fi -} - -askLocation() { - az account list-locations -otable - echo "" - echo "Choose which region your resource group and storage account will be created. example: westus" - echo -n "> " - read location -} - -createResourceGroup() { - echo "==> Creating resource group" - az group create -n $meta_name -l $location - if [ $? -eq 0 ]; then - azure_group_name=$meta_name - else - echo "Error creating resource group: $meta_name" - return 1 - fi -} - -createStorageAccount() { - echo "==> Creating storage account" - az storage account create --name $meta_name --resource-group $meta_name --location $location --kind Storage --sku Standard_LRS - if [ $? -eq 0 ]; then - azure_storage_name=$meta_name - else - echo "Error creating storage account: $meta_name" - return 1 - fi -} - -createApplication() { - echo "==> Creating application" - echo "==> Does application exist?" - azure_client_id=$(az ad app list --output json | jq -r '.[] | select(.displayName | contains("'$meta_name'")) ') - - if [ "$azure_client_id" != "" ]; then - echo "==> application already exist, grab appId" - azure_client_id=$(az ad app list --output json | jq -r '.[] | select(.displayName | contains("'$meta_name'")) .appId') - else - echo "==> application does not exist" - azure_client_id=$(az ad app create --display-name $meta_name --identifier-uris http://$meta_name --homepage http://$meta_name --password $azure_client_secret --output json | jq -r .appId) - fi - - if [ $? -ne 0 ]; then - echo "Error creating application: $meta_name @ http://$meta_name" - return 1 - fi -} - -createServicePrincipal() { - echo "==> Creating service principal" - azure_object_id=$(az ad sp create --id $azure_client_id --output json | jq -r .objectId) - echo $azure_object_id "was selected." - - if [ $? -ne 0 ]; then - echo "Error creating service principal: $azure_client_id" - return 1 - fi -} - -createPermissions() { - echo "==> Creating permissions" - az role assignment create --assignee $azure_object_id --role "Owner" --scope /subscriptions/$azure_subscription_id - # If the user wants to use a more conservative scope, she can. She must - # configure the Azure builder to use build_resource_group_name. The - # easiest solution is subscription wide permission. - # az role assignment create --spn http://$meta_name -g $azure_group_name -o "API Management Service Contributor" - if [ $? -ne 0 ]; then - echo "Error creating permissions for: http://$meta_name" - return 1 - fi -} - -showConfigs() { - echo "" - echo "Use the following configuration for your packer template:" - echo "" - echo "{" - echo " \"client_id\": \"$azure_client_id\"," - echo " \"client_secret\": \"$azure_client_secret\"," - echo " \"object_id\": \"$azure_object_id\"," - echo " \"subscription_id\": \"$azure_subscription_id\"," - echo " \"tenant_id\": \"$azure_tenant_id\"," - echo " \"resource_group_name\": \"$azure_group_name\"," - echo " \"storage_account\": \"$azure_storage_name\"," - echo "}" - echo "" -} - -doSleep() { - local sleep_time=${PACKER_SLEEP_TIME-$create_sleep} - echo "" - echo "Sleeping for ${sleep_time} seconds to wait for resources to be " - echo "created. If you get an error about a resource not existing, you can " - echo "try increasing the amount of time we wait after creating resources " - echo "by setting PACKER_SLEEP_TIME to something higher than the default." - echo "" - sleep $sleep_time -} - -retryable() { - n=0 - until [ $n -ge $1 ] - do - $2 && return 0 - echo "$2 failed. Retrying..." - n=$[$n+1] - doSleep - done - echo "$2 failed after $1 tries. Exiting." - exit 1 -} - - -setup() { - requirements - - az login - - askSubscription - askName - askSecret - askLocation - - # Some of the resources take a while to converge in the API. To make the - # script more reliable we'll add a sleep after we create each resource. - - retryable 3 createResourceGroup - retryable 3 createStorageAccount - retryable 3 createApplication - retryable 3 createServicePrincipal - retryable 3 createPermissions - - showConfigs -} - -case "$1" in - requirements) - requirements - ;; - setup) - setup - ;; - *) - showhelp - ;; -esac diff --git a/go.mod b/go.mod index f0d964e8e..38d0955de 100644 --- a/go.mod +++ b/go.mod @@ -2,18 +2,9 @@ module github.com/hashicorp/packer require ( github.com/1and1/oneandone-cloudserver-sdk-go v1.0.1 - github.com/Azure/azure-sdk-for-go v40.5.0+incompatible - github.com/Azure/go-autorest/autorest v0.10.0 - github.com/Azure/go-autorest/autorest/adal v0.8.2 - github.com/Azure/go-autorest/autorest/azure/auth v0.4.2 - github.com/Azure/go-autorest/autorest/azure/cli v0.3.1 - github.com/Azure/go-autorest/autorest/date v0.2.0 - github.com/Azure/go-autorest/autorest/to v0.3.0 - github.com/approvals/go-approval-tests v0.0.0-20160714161514-ad96e53bea43 github.com/biogo/hts v0.0.0-20160420073057-50da7d4131a3 github.com/cheggaaa/pb v1.0.27 github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e - github.com/dgrijalva/jwt-go v3.2.0+incompatible github.com/dsnet/compress v0.0.1 github.com/exoscale/packer-plugin-exoscale v0.1.1 github.com/gobwas/glob v0.2.3 @@ -22,15 +13,16 @@ require ( github.com/hako/durafmt v0.0.0-20200710122514-c0fb7b4da026 github.com/hashicorp/go-checkpoint v0.0.0-20171009173528-1545e56e46de github.com/hashicorp/go-cty-funcs v0.0.0-20200930094925-2721b1e36840 - github.com/hashicorp/go-getter/v2 v2.0.0-20200604122502-a6995fa1edad + github.com/hashicorp/go-getter/v2 v2.0.0 github.com/hashicorp/go-multierror v1.1.1 github.com/hashicorp/go-uuid v1.0.2 github.com/hashicorp/go-version v1.3.0 github.com/hashicorp/hcl/v2 v2.10.0 github.com/hashicorp/packer-plugin-alicloud v0.0.2 github.com/hashicorp/packer-plugin-amazon v0.0.1 - github.com/hashicorp/packer-plugin-ansible v0.0.2 - github.com/hashicorp/packer-plugin-chef v0.0.1 + github.com/hashicorp/packer-plugin-ansible v0.0.3 + github.com/hashicorp/packer-plugin-azure v0.0.2 + github.com/hashicorp/packer-plugin-chef v0.0.2 github.com/hashicorp/packer-plugin-cloudstack v0.0.1 github.com/hashicorp/packer-plugin-converge v0.0.1 github.com/hashicorp/packer-plugin-digitalocean v0.0.1 @@ -49,10 +41,10 @@ require ( github.com/hashicorp/packer-plugin-outscale v0.0.1 github.com/hashicorp/packer-plugin-parallels v0.0.1 github.com/hashicorp/packer-plugin-proxmox v0.0.2 - github.com/hashicorp/packer-plugin-puppet v0.0.1 + github.com/hashicorp/packer-plugin-puppet v0.0.2 github.com/hashicorp/packer-plugin-qemu v0.0.1 github.com/hashicorp/packer-plugin-scaleway v0.0.1 - github.com/hashicorp/packer-plugin-sdk v0.2.0 + github.com/hashicorp/packer-plugin-sdk v0.2.1 github.com/hashicorp/packer-plugin-tencentcloud v0.0.1 github.com/hashicorp/packer-plugin-triton v0.0.0-20210421085122-768dd7c764d9 github.com/hashicorp/packer-plugin-ucloud v0.0.1 @@ -69,14 +61,13 @@ require ( github.com/mitchellh/mapstructure v1.4.1 github.com/mitchellh/panicwrap v1.0.0 github.com/mitchellh/prefixedio v0.0.0-20151214002211-6e6954073784 - github.com/mitchellh/reflectwalk v1.0.0 github.com/pierrec/lz4 v2.0.5+incompatible github.com/posener/complete v1.2.3 github.com/profitbricks/profitbricks-sdk-go v4.0.2+incompatible github.com/shirou/gopsutil v3.21.1+incompatible github.com/stretchr/testify v1.7.0 - github.com/ulikunitz/xz v0.5.6 - github.com/zclconf/go-cty v1.8.2 + github.com/ulikunitz/xz v0.5.8 + github.com/zclconf/go-cty v1.8.3 github.com/zclconf/go-cty-yaml v1.0.1 golang.org/x/crypto v0.0.0-20210415154028-4f45737414dc golang.org/x/mod v0.4.1 diff --git a/go.sum b/go.sum index 5d34e64cf..39f323b5d 100644 --- a/go.sum +++ b/go.sum @@ -41,39 +41,49 @@ cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9 dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= github.com/1and1/oneandone-cloudserver-sdk-go v1.0.1 h1:RMTyvS5bjvSWiUcfqfr/E2pxHEMrALvU+E12n6biymg= github.com/1and1/oneandone-cloudserver-sdk-go v1.0.1/go.mod h1:61apmbkVJH4kg+38ftT+/l0XxdUCVnHggqcOTqZRSEE= -github.com/Azure/azure-sdk-for-go v40.5.0+incompatible h1:CVQNKuUepSFBo6BW6gM1J9slPHLRcjn6vaw+j+causw= github.com/Azure/azure-sdk-for-go v40.5.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= +github.com/Azure/azure-sdk-for-go v51.2.0+incompatible h1:qQNk//OOHK0GZcgMMgdJ4tZuuh0zcOeUkpTxjvKFpSQ= +github.com/Azure/azure-sdk-for-go v51.2.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= github.com/Azure/go-autorest v14.2.0+incompatible h1:V5VMDjClD3GiElqLWO7mz2MxNAK/vTfRHdAubSIPRgs= github.com/Azure/go-autorest v14.2.0+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24= github.com/Azure/go-autorest/autorest v0.9.0/go.mod h1:xyHB1BMZT0cuDHU7I0+g046+BFDTQ8rEZB0s4Yfa6bI= github.com/Azure/go-autorest/autorest v0.9.3/go.mod h1:GsRuLYvwzLjjjRoWEIyMUaYq8GNUx2nRB378IPt/1p0= -github.com/Azure/go-autorest/autorest v0.10.0 h1:mvdtztBqcL8se7MdrUweNieTNi4kfNG6GOJuurQJpuY= github.com/Azure/go-autorest/autorest v0.10.0/go.mod h1:/FALq9T/kS7b5J5qsQ+RSTUdAmGFqi0vUdVNNx8q630= +github.com/Azure/go-autorest/autorest v0.11.18 h1:90Y4srNYrwOtAgVo3ndrQkTYn6kf1Eg/AjTFJ8Is2aM= +github.com/Azure/go-autorest/autorest v0.11.18/go.mod h1:dSiJPy22c3u0OtOKDNttNgqpNFY/GeWa7GH/Pz56QRA= github.com/Azure/go-autorest/autorest/adal v0.5.0/go.mod h1:8Z9fGy2MpX0PvDjB1pEgQTmVqjGhiHBW7RJJEciWzS0= github.com/Azure/go-autorest/autorest/adal v0.8.0/go.mod h1:Z6vX6WXXuyieHAXwMj0S6HY6e6wcHn37qQMBQlvY3lc= github.com/Azure/go-autorest/autorest/adal v0.8.1/go.mod h1:ZjhuQClTqx435SRJ2iMlOxPYt3d2C/T/7TiQCVZSn3Q= -github.com/Azure/go-autorest/autorest/adal v0.8.2 h1:O1X4oexUxnZCaEUGsvMnr8ZGj8HI37tNezwY4npRqA0= github.com/Azure/go-autorest/autorest/adal v0.8.2/go.mod h1:ZjhuQClTqx435SRJ2iMlOxPYt3d2C/T/7TiQCVZSn3Q= +github.com/Azure/go-autorest/autorest/adal v0.9.5/go.mod h1:B7KF7jKIeC9Mct5spmyCB/A8CG/sEz1vwIRGv/bbw7A= +github.com/Azure/go-autorest/autorest/adal v0.9.13 h1:Mp5hbtOePIzM8pJVRa3YLrWWmZtoxRXqUEzCfJt3+/Q= +github.com/Azure/go-autorest/autorest/adal v0.9.13/go.mod h1:W/MM4U6nLxnIskrw4UwWzlHfGjwUS50aOsc/I3yuU8M= github.com/Azure/go-autorest/autorest/azure/auth v0.4.2 h1:iM6UAvjR97ZIeR93qTcwpKNMpV+/FTWjwEbuPD495Tk= github.com/Azure/go-autorest/autorest/azure/auth v0.4.2/go.mod h1:90gmfKdlmKgfjUpnCEpOJzsUEjrWDSLwHIG73tSXddM= -github.com/Azure/go-autorest/autorest/azure/cli v0.3.1 h1:LXl088ZQlP0SBppGFsRZonW6hSvwgL5gRByMbvUbx8U= github.com/Azure/go-autorest/autorest/azure/cli v0.3.1/go.mod h1:ZG5p860J94/0kI9mNJVoIoLgXcirM2gF5i2kWloofxw= +github.com/Azure/go-autorest/autorest/azure/cli v0.4.2 h1:dMOmEJfkLKW/7JsokJqkyoYSgmR08hi9KrhjZb+JALY= +github.com/Azure/go-autorest/autorest/azure/cli v0.4.2/go.mod h1:7qkJkT+j6b+hIpzMOwPChJhTqS8VbsqqgULzMNRugoM= github.com/Azure/go-autorest/autorest/date v0.1.0/go.mod h1:plvfp3oPSKwf2DNjlBjWF/7vwR+cUD/ELuzDCXwHUVA= -github.com/Azure/go-autorest/autorest/date v0.2.0 h1:yW+Zlqf26583pE43KhfnhFcdmSWlm5Ew6bxipnr/tbM= github.com/Azure/go-autorest/autorest/date v0.2.0/go.mod h1:vcORJHLJEh643/Ioh9+vPmf1Ij9AEBM5FuBIXLmIy0g= +github.com/Azure/go-autorest/autorest/date v0.3.0 h1:7gUk1U5M/CQbp9WoqinNzJar+8KY+LPI6wiWrP/myHw= +github.com/Azure/go-autorest/autorest/date v0.3.0/go.mod h1:BI0uouVdmngYNUzGWeSYnokU+TrmwEsOqdt8Y6sso74= github.com/Azure/go-autorest/autorest/mocks v0.1.0/go.mod h1:OTyCOPRA2IgIlWxVYxBee2F5Gr4kF2zd2J5cFRaIDN0= github.com/Azure/go-autorest/autorest/mocks v0.2.0/go.mod h1:OTyCOPRA2IgIlWxVYxBee2F5Gr4kF2zd2J5cFRaIDN0= -github.com/Azure/go-autorest/autorest/mocks v0.3.0 h1:qJumjCaCudz+OcqE9/XtEPfvtOjOmKaui4EOpFI6zZc= github.com/Azure/go-autorest/autorest/mocks v0.3.0/go.mod h1:a8FDP3DYzQ4RYfVAxAN3SVSiiO77gL2j2ronKKP0syM= -github.com/Azure/go-autorest/autorest/to v0.3.0 h1:zebkZaadz7+wIQYgC7GXaz3Wb28yKYfVkkBKwc38VF8= +github.com/Azure/go-autorest/autorest/mocks v0.4.1 h1:K0laFcLE6VLTOwNgSxaGbUcLPuGXlNkbVvq4cW4nIHk= +github.com/Azure/go-autorest/autorest/mocks v0.4.1/go.mod h1:LTp+uSrOhSkaKrUy935gNZuuIPPVsHlr9DSOxSayd+k= github.com/Azure/go-autorest/autorest/to v0.3.0/go.mod h1:MgwOyqaIuKdG4TL/2ywSsIWKAfJfgHDo8ObuUk3t5sA= +github.com/Azure/go-autorest/autorest/to v0.4.0 h1:oXVqrxakqqV1UZdSazDOPOLvOIz+XA683u8EctwboHk= +github.com/Azure/go-autorest/autorest/to v0.4.0/go.mod h1:fE8iZBn7LQR7zH/9XU2NcPR4o9jEImooCeWJcYV/zLE= github.com/Azure/go-autorest/autorest/validation v0.2.0/go.mod h1:3EEqHnBxQGHXRYq3HT1WyXAvT7LLY3tl70hw6tQIbjI= github.com/Azure/go-autorest/autorest/validation v0.3.1 h1:AgyqjAd94fwNAoTjl/WQXg4VvFeRFpO+UhNyRXqF1ac= github.com/Azure/go-autorest/autorest/validation v0.3.1/go.mod h1:yhLgjC0Wda5DYXl6JAsWyUe4KVNffhoDhG0zVzUMo3E= -github.com/Azure/go-autorest/logger v0.1.0 h1:ruG4BSDXONFRrZZJ2GUXDiUyVpayPmb1GnWeHDdaNKY= github.com/Azure/go-autorest/logger v0.1.0/go.mod h1:oExouG+K6PryycPJfVSxi/koC6LSNgds39diKLz7Vrc= -github.com/Azure/go-autorest/tracing v0.5.0 h1:TRn4WjSnkcSy5AEG3pnbtFSwNtwzjr4VYyQflFE619k= +github.com/Azure/go-autorest/logger v0.2.1 h1:IG7i4p/mDa2Ce4TRyAO8IHnVhAVF3RFU+ZtXWSmf4Tg= +github.com/Azure/go-autorest/logger v0.2.1/go.mod h1:T9E3cAhj2VqvPOtCYAvby9aBXkZmbF5NWuPV8+WeEW8= github.com/Azure/go-autorest/tracing v0.5.0/go.mod h1:r/s2XiOKccPW3HrqB+W0TQzfbtp2fGCgRFtBroKn4Dk= +github.com/Azure/go-autorest/tracing v0.6.0 h1:TYi4+3m5t6K48TGI9AUdb+IzbnSxvnvUMfuitfgcfuo= +github.com/Azure/go-autorest/tracing v0.6.0/go.mod h1:+vhtPC754Xsa23ID7GlGsrdKBpUA79WCAKPPZVC2DeU= github.com/Azure/go-ntlmssp v0.0.0-20180810175552-4a21cbd618b4/go.mod h1:chxPXzSsl7ZWRAuOIE23GDNzjWuZquvFlgA8xmpunjU= github.com/Azure/go-ntlmssp v0.0.0-20191115201650-bad6df29494a h1:3FwiePtHk5YJrooV799oo5jIfsgRdES25VdngJM03dU= github.com/Azure/go-ntlmssp v0.0.0-20191115201650-bad6df29494a/go.mod h1:chxPXzSsl7ZWRAuOIE23GDNzjWuZquvFlgA8xmpunjU= @@ -126,8 +136,9 @@ github.com/apparentlymart/go-textseg v1.0.0/go.mod h1:z96Txxhf3xSFMPmb5X/1W05FF/ github.com/apparentlymart/go-textseg/v12 v12.0.0/go.mod h1:S/4uRK2UtaQttw1GenVJEynmyUenKwP++x/+DdGV/Ec= github.com/apparentlymart/go-textseg/v13 v13.0.0 h1:Y+KvPE1NYz0xl601PVImeQfFyEy6iT90AvPUL1NNfNw= github.com/apparentlymart/go-textseg/v13 v13.0.0/go.mod h1:ZK2fH7c4NqDTLtiYLvIkEghdlcqw7yxLeM89kiTRPUo= -github.com/approvals/go-approval-tests v0.0.0-20160714161514-ad96e53bea43 h1:ePCAQPf5tUc5IMcUvu6euhSGna7jzs7eiXtJXHig6Zc= github.com/approvals/go-approval-tests v0.0.0-20160714161514-ad96e53bea43/go.mod h1:S6puKjZ9ZeqUPBv2hEBnMZGcM2J6mOsDRQcmxkMAND0= +github.com/approvals/go-approval-tests v0.0.0-20210131072903-38d0b0ec12b1 h1:uroQ0JaeVom9Ffv9xFtc7DcqrpGmyQeZCRzHD9FqPBg= +github.com/approvals/go-approval-tests v0.0.0-20210131072903-38d0b0ec12b1/go.mod h1:PJOqSY8IofNv3heAD6k8E7EfFS6okiSS9bSAasaAUME= github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= @@ -231,10 +242,12 @@ github.com/digitalocean/go-qemu v0.0.0-20210326154740-ac9e0b687001/go.mod h1:Iet github.com/digitalocean/godo v1.11.1/go.mod h1:h6faOIcZ8lWIwNQ+DN7b3CgX4Kwby5T+nbpNqkUIozU= github.com/digitalocean/godo v1.60.0 h1:o/vimtn/HKtYSakFAAZ59Zc5ASORd41S4z1X7pAXPn8= github.com/digitalocean/godo v1.60.0/go.mod h1:p7dOjjtSBqCTUksqtA5Fd3uaKs9kyTq2xcz76ulEJRU= -github.com/dimchansky/utfbom v1.1.0 h1:FcM3g+nofKgUteL8dm/UpdRXNC9KmADgTpLKsu0TRo4= github.com/dimchansky/utfbom v1.1.0/go.mod h1:rO41eb7gLfo8SF1jd9F8HplJm1Fewwi4mQvIirEdv+8= -github.com/dnaeon/go-vcr v1.0.1 h1:r8L/HqC0Hje5AXMu1ooW8oyQyOFv4GxqpL0nRP7SLLY= +github.com/dimchansky/utfbom v1.1.1 h1:vV6w1AhK4VMnhBno/TPVCoK9U/LP0PkLCS9tbxHdi/U= +github.com/dimchansky/utfbom v1.1.1/go.mod h1:SxdoEBH5qIqFocHMyGOXVAybYJdr71b1Q/j0mACtrfE= github.com/dnaeon/go-vcr v1.0.1/go.mod h1:aBB1+wY4s93YsC3HHjMBMrwTj2R9FHDzUr9KyGc8n1E= +github.com/dnaeon/go-vcr v1.1.0 h1:ReYa/UBrRyQdant9B4fNHGoCNKw6qh6P0fsdGmZpR7c= +github.com/dnaeon/go-vcr v1.1.0/go.mod h1:M7tiix8f0r6mKKJ3Yq/kqU1OYf3MnfmBWVbPx/yU9ko= github.com/docker/spdystream v0.0.0-20160310174837-449fdfce4d96/go.mod h1:Qh8CwZgvJUkLughtfhJv5dyTYa91l1fOUCrgjqmcifM= github.com/dsnet/compress v0.0.1 h1:PlZu0n3Tuv04TzpfPbrnI0HW/YwodEXDS+oPKahKF0Q= github.com/dsnet/compress v0.0.1/go.mod h1:Aw8dCMJ7RioblQeTqt88akK31OvO8Dhf5JflhBbQEHo= @@ -266,6 +279,8 @@ github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M= github.com/fatih/structtag v1.0.0/go.mod h1:IKitwq45uXL/yqi5mYghiD3w9H6eTOvI9vnk8tXMphA= github.com/fatih/structtag v1.2.0/go.mod h1:mBJUNpUnHmRKrKlQQlmCrh5PuhftFbNv8Ys4/aAZl94= +github.com/form3tech-oss/jwt-go v3.2.2+incompatible h1:TcekIExNqud5crz4xD2pavyTgWiPvpYe4Xau31I0PRk= +github.com/form3tech-oss/jwt-go v3.2.2+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/getkin/kin-openapi v0.13.0/go.mod h1:WGRs2ZMM1Q8LR1QBEwUxC6RJEfaBcD0s+pcEVXFuAjw= github.com/getkin/kin-openapi v0.37.0/go.mod h1:ZJSfy1PxJv2QQvH9EdBj3nupRTVvV42mkW6zKUlRBwk= @@ -437,6 +452,8 @@ github.com/hashicorp/consul/sdk v0.4.0 h1:zBtCfKJZcJDBvSCkQJch4ulp59m1rATFLKwNo/ github.com/hashicorp/consul/sdk v0.4.0/go.mod h1:fY08Y9z5SvJqevyZNy6WWPXiG3KwBPAvlcdx16zZ0fM= github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/go-azure-helpers v0.16.0 h1:f8LqrmC7K545DSk9EvymtuiFZ8tlTC7+XkvmAZmUeiM= +github.com/hashicorp/go-azure-helpers v0.16.0/go.mod h1:kR7+sTDEb9TOp/O80ss1UEJg1t4/BHLD/U8wHLS4BGQ= github.com/hashicorp/go-checkpoint v0.0.0-20171009173528-1545e56e46de h1:XDCSythtg8aWSRSO29uwhgh7b127fWr+m5SemqjSUL8= github.com/hashicorp/go-checkpoint v0.0.0-20171009173528-1545e56e46de/go.mod h1:xIwEieBHERyEvaeKF/TcHh1Hu+lxPM+n2vT1+g9I4m4= github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= @@ -452,8 +469,9 @@ github.com/hashicorp/go-getter/gcs/v2 v2.0.0-20200604122502-a6995fa1edad/go.mod github.com/hashicorp/go-getter/s3/v2 v2.0.0-20200604122502-a6995fa1edad h1:hwk5mQRwVvZc/f+So1kHbOhW/f7P2fEcCr2D5pSk9sI= github.com/hashicorp/go-getter/s3/v2 v2.0.0-20200604122502-a6995fa1edad/go.mod h1:kcB6Mv+0wzYXbQjTAeD/Pb85145WcFk2EElpe02fuoE= github.com/hashicorp/go-getter/v2 v2.0.0-20200511090339-3107ec4af37a/go.mod h1:QJ+LwRM91JBKBLyHoKBrcmi49i9Tu/ItpgTNXWSnpGM= -github.com/hashicorp/go-getter/v2 v2.0.0-20200604122502-a6995fa1edad h1:BfRfKjQgvwJrXF2apbeqoqeuxzDcxZIeI/eCj6HLkM4= github.com/hashicorp/go-getter/v2 v2.0.0-20200604122502-a6995fa1edad/go.mod h1:bM2M11foprILIk1Slmr2wBrJYsdQTym//+QMJqgm3F8= +github.com/hashicorp/go-getter/v2 v2.0.0 h1:wamdcQazMBZK6VwUo3HAOWLkcOJBWBoXPKfmf7/S17w= +github.com/hashicorp/go-getter/v2 v2.0.0/go.mod h1:w65fE5glbccYjndAuj1kA5lnVBGZYEaH0e5qA1kpIks= github.com/hashicorp/go-hclog v0.0.0-20180709165350-ff2cf002a8dd/go.mod h1:9bjs9uLqI8l75knNv3lV1kA55veR+WUPSiKIWcQHudI= github.com/hashicorp/go-hclog v0.8.0/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ= github.com/hashicorp/go-hclog v0.12.0 h1:d4QkX8FRTYaKaCZBoXYY8zJX2BXjWxurN/GA2tkrmZM= @@ -491,6 +509,7 @@ github.com/hashicorp/go-uuid v1.0.2/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/b github.com/hashicorp/go-version v1.0.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/hashicorp/go-version v1.1.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/hashicorp/go-version v1.2.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= +github.com/hashicorp/go-version v1.2.1/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/hashicorp/go-version v1.3.0 h1:McDWVJIU/y+u1BRV06dPaLfLCaT7fUTJLp5r04x7iNw= github.com/hashicorp/go-version v1.3.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90= @@ -526,10 +545,12 @@ github.com/hashicorp/packer-plugin-alicloud v0.0.2 h1:uBVp53+yOfzbhUjC8WtQ/7uLcf github.com/hashicorp/packer-plugin-alicloud v0.0.2/go.mod h1:RCU4CLSJwSqHoNLlA+UghRw1JXqqzCPOE6Pv/EYjtgU= github.com/hashicorp/packer-plugin-amazon v0.0.1 h1:EuyjNK9bL7WhQeIJzhBJxOx8nyc61ai5UbOsb1PIVwI= github.com/hashicorp/packer-plugin-amazon v0.0.1/go.mod h1:12c9msibyHdId+Mk/pCbdRb1KaLIhaNyxeJ6n8bZt30= -github.com/hashicorp/packer-plugin-ansible v0.0.2 h1:nvBtCedXhUI5T6Up5+bmhlY7rmk8FjWuFv9A2joK7TU= -github.com/hashicorp/packer-plugin-ansible v0.0.2/go.mod h1:ocXB4KTU+I+DBRGfMP4XE7dPlURaUnb7NJvyddZ6bh0= -github.com/hashicorp/packer-plugin-chef v0.0.1 h1:1zQwnnvftwg9PJyWjMfHfDyzfWDdb0eo9IX8fX6kd+Y= -github.com/hashicorp/packer-plugin-chef v0.0.1/go.mod h1:4iSyWfvrb4QwUDZqJ3iCb+kIsnDwOTL1yTEDXBtk3Ew= +github.com/hashicorp/packer-plugin-ansible v0.0.3 h1:pLL2ZqRt4LVBwhtcG/PVgr9WbhfYfIDJ2aWT+Q7ef9U= +github.com/hashicorp/packer-plugin-ansible v0.0.3/go.mod h1:5/wOgs7TBwziYCznulfv5AwncLHavXQr83EtpkBVlXg= +github.com/hashicorp/packer-plugin-azure v0.0.2 h1:wNEWpkIUzFr/K0ddlipn7W7oJ/m8+RiWZ1xJMsX+hbM= +github.com/hashicorp/packer-plugin-azure v0.0.2/go.mod h1:ySskXX3DJV9Z9Yzt3dyrWsN1XUcjeIOtyL7/ZNHs6zw= +github.com/hashicorp/packer-plugin-chef v0.0.2 h1:JiciRcYGHaHB0LoJ0Y4oSJXrZeH0xbnshcEYGqC3lgI= +github.com/hashicorp/packer-plugin-chef v0.0.2/go.mod h1:PxGw+J6PTW74b8MzMDEIoVYHAIr+vCS1n0etz8pqdiM= github.com/hashicorp/packer-plugin-cloudstack v0.0.1 h1:BF9nXRlA0xQV5W/+CoLjWn0aLO60gTbsxnLi/o37ktc= github.com/hashicorp/packer-plugin-cloudstack v0.0.1/go.mod h1:fx13TY2szz6cm2e99xzU3gQzKdGVwysxY2TyKr0r8MQ= github.com/hashicorp/packer-plugin-converge v0.0.1 h1:cjrNt2Q/BuSH2o2bpNV91DhWYSTN7vb4LwxwFXULcok= @@ -566,8 +587,8 @@ github.com/hashicorp/packer-plugin-parallels v0.0.1 h1:fcaaiGWdU1+X4IGadXdUhJ2si github.com/hashicorp/packer-plugin-parallels v0.0.1/go.mod h1:FGNtZ7XFBr3IYuj7uvJtSaNnyhAwe457zP464m06+20= github.com/hashicorp/packer-plugin-proxmox v0.0.2 h1:x6QW7PeKh+IJymPEt3QdpBhSRi5vqXb8qTWv7rMLuns= github.com/hashicorp/packer-plugin-proxmox v0.0.2/go.mod h1:3URutEWX1yy10qcHNJncS4OMpZknA1FyvlrfL+5usYk= -github.com/hashicorp/packer-plugin-puppet v0.0.1 h1:avOlJB2suArgqo3gn/JipLtHY0TVuTcweYA3GxVceyY= -github.com/hashicorp/packer-plugin-puppet v0.0.1/go.mod h1:HgRpw6hXYykjyceBRbrRvBT7vSU7Ofo5HIfFRMCehQc= +github.com/hashicorp/packer-plugin-puppet v0.0.2 h1:ER0znnTwRAlWqnTg3JLo//Cgj3wy+LjTVzrzcYFbT7k= +github.com/hashicorp/packer-plugin-puppet v0.0.2/go.mod h1:3KBIWHblXAoGZSl5QRjW1df4vOF0q2XOkHDjky8/fmA= github.com/hashicorp/packer-plugin-qemu v0.0.1 h1:yGnmWf4Z+ZmOJXJF6w23V2KChtTCiPHsFnfg7+LRu74= github.com/hashicorp/packer-plugin-qemu v0.0.1/go.mod h1:8Q/LCjO7oplLcLe1KLdEt7rq94h42Di6Lab2DTLNwVg= github.com/hashicorp/packer-plugin-scaleway v0.0.1 h1:FSq76WuMJNKwCvF77v06EpuLe/AJP3sG5/YrfL41kcw= @@ -586,8 +607,9 @@ github.com/hashicorp/packer-plugin-sdk v0.1.2/go.mod h1:KRjczE1/c9NV5Re+PXt3myJs github.com/hashicorp/packer-plugin-sdk v0.1.3-0.20210407232143-c217d82aefb6/go.mod h1:xePpgQgQYv/bamiypx3hH9ukidxDdcN8q0R0wLi8IEQ= github.com/hashicorp/packer-plugin-sdk v0.1.3/go.mod h1:xePpgQgQYv/bamiypx3hH9ukidxDdcN8q0R0wLi8IEQ= github.com/hashicorp/packer-plugin-sdk v0.1.4/go.mod h1:xePpgQgQYv/bamiypx3hH9ukidxDdcN8q0R0wLi8IEQ= -github.com/hashicorp/packer-plugin-sdk v0.2.0 h1:A4Dq7p4y1vscY4gMzp7GQaXyDJYYhP4ukp4fapPSOY4= github.com/hashicorp/packer-plugin-sdk v0.2.0/go.mod h1:0DiOMEBldmB0HEhp0npFSSygC8bIvW43pphEgWkp2WU= +github.com/hashicorp/packer-plugin-sdk v0.2.1 h1:NZJ9h2ddzZb6E3eaYFD7L4mSjqFia3FDoDTxDGQKNMs= +github.com/hashicorp/packer-plugin-sdk v0.2.1/go.mod h1:4V7lS35FRhukvZrW41IPctTPY7JmHPOkFZcR7XGXZPk= github.com/hashicorp/packer-plugin-tencentcloud v0.0.1 h1:DR7GETCzrK/DPFMUPbULIklCxwGhstbbz6pl+2S+UnM= github.com/hashicorp/packer-plugin-tencentcloud v0.0.1/go.mod h1:FmdacMLvDKiT6OdMAc2x4LXtqu/soLApH3jF57SWOik= github.com/hashicorp/packer-plugin-triton v0.0.0-20210421085122-768dd7c764d9 h1:No5oPI9Wa7FhTKkFJwI3hcfUVvEpgPC8QMcG9l/Vxzo= @@ -764,14 +786,16 @@ github.com/mitchellh/panicwrap v1.0.0 h1:67zIyVakCIvcs69A0FGfZjBdPleaonSgGlXRSRl github.com/mitchellh/panicwrap v1.0.0/go.mod h1:pKvZHwWrZowLUzftuFq7coarnxbBXU4aQh3N0BJOeeA= github.com/mitchellh/prefixedio v0.0.0-20151214002211-6e6954073784 h1:+DAetXqxv/mSyCkE9KBIYOZs9b68y7SUaDCxQMRjA68= github.com/mitchellh/prefixedio v0.0.0-20151214002211-6e6954073784/go.mod h1:kB1naBgV9ORnkiTVeyJOI1DavaJkG4oNIq0Af6ZVKUo= -github.com/mitchellh/reflectwalk v1.0.0 h1:9D+8oIskB4VJBN5SFlmc27fSlIBZaov1Wpk/IfikLNY= github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= +github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= +github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI= github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modocache/gover v0.0.0-20171022184752-b58185e213c5/go.mod h1:caMODM3PzxT8aQXRPkAt8xlV/e7d7w8GM5g0fa5F0D8= github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw= @@ -913,8 +937,9 @@ github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljT github.com/ugorji/go/codec v1.2.4 h1:C5VurWRRCKjuENsbM6GYVw8W++WVW9rSxoACKIvxzz8= github.com/ugorji/go/codec v1.2.4/go.mod h1:bWBu1+kIRWcF8uMklKaJrR6fTWQOwAlrIzX22pHwryA= github.com/ulikunitz/xz v0.5.5/go.mod h1:2bypXElzHzzJZwzH67Y6wb67pO62Rzfn7BSiF4ABRW8= -github.com/ulikunitz/xz v0.5.6 h1:jGHAfXawEGZQ3blwU5wnWKQJvAraT7Ftq9EXjnXYgt8= github.com/ulikunitz/xz v0.5.6/go.mod h1:2bypXElzHzzJZwzH67Y6wb67pO62Rzfn7BSiF4ABRW8= +github.com/ulikunitz/xz v0.5.8 h1:ERv8V6GKqVi23rgu5cj9pVfVzJbOqAY2Ntl88O6c2nQ= +github.com/ulikunitz/xz v0.5.8/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14= github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= github.com/valyala/fasttemplate v1.0.1/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPUpymEIMZ47gx8= github.com/valyala/fasttemplate v1.1.0/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPUpymEIMZ47gx8= @@ -948,8 +973,9 @@ github.com/zclconf/go-cty v1.4.0/go.mod h1:nHzOclRkoj++EU9ZjSrZvRG0BXIWt8c7loYc0 github.com/zclconf/go-cty v1.7.0/go.mod h1:VDR4+I79ubFBGm1uJac1226K5yANQFHeauxPBoP54+o= github.com/zclconf/go-cty v1.8.0/go.mod h1:vVKLxnk3puL4qRAv72AO+W99LUD4da90g3uUAzyuvAk= github.com/zclconf/go-cty v1.8.1/go.mod h1:vVKLxnk3puL4qRAv72AO+W99LUD4da90g3uUAzyuvAk= -github.com/zclconf/go-cty v1.8.2 h1:u+xZfBKgpycDnTNjPhGiTEYZS5qS/Sb5MqSfm7vzcjg= github.com/zclconf/go-cty v1.8.2/go.mod h1:vVKLxnk3puL4qRAv72AO+W99LUD4da90g3uUAzyuvAk= +github.com/zclconf/go-cty v1.8.3 h1:48gwZXrdSADU2UW9eZKHprxAI7APZGW9XmExpJpSjT0= +github.com/zclconf/go-cty v1.8.3/go.mod h1:vVKLxnk3puL4qRAv72AO+W99LUD4da90g3uUAzyuvAk= github.com/zclconf/go-cty-debug v0.0.0-20191215020915-b22d67c1ba0b/go.mod h1:ZRKQfBXbGkpdV6QMzT3rU1kSTAnfu1dO8dPKjYprgj8= github.com/zclconf/go-cty-yaml v1.0.1 h1:up11wlgAaDvlAGENcFDnZgkn0qUJurso7k6EpURKNF8= github.com/zclconf/go-cty-yaml v1.0.1/go.mod h1:IP3Ylp0wQpYm50IHK8OZWKMu6sPJIUgKa8XhiVHura0= @@ -985,8 +1011,10 @@ golang.org/x/crypto v0.0.0-20200220183623-bac4c82f6975/go.mod h1:LzIPMQfyMNhhGPh golang.org/x/crypto v0.0.0-20200422194213-44a606286825/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20201208171446-5f87f3452ae9/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= +golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= golang.org/x/crypto v0.0.0-20210415154028-4f45737414dc h1:+q90ECDSAQirdykUN6sPEiBXBsp8Csjcca8Oy7bgLTA= golang.org/x/crypto v0.0.0-20210415154028-4f45737414dc/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= diff --git a/provisioner/azure-dtlartifact/provisioner.go b/provisioner/azure-dtlartifact/provisioner.go deleted file mode 100644 index c48873427..000000000 --- a/provisioner/azure-dtlartifact/provisioner.go +++ /dev/null @@ -1,183 +0,0 @@ -//go:generate packer-sdc mapstructure-to-hcl2 -type Config,DtlArtifact,ArtifactParameter - -package devtestlabsartifacts - -import ( - "context" - "fmt" - "time" - - "github.com/Azure/azure-sdk-for-go/services/devtestlabs/mgmt/2018-09-15/dtl" - "github.com/hashicorp/hcl/v2/hcldec" - "github.com/hashicorp/packer/builder/azure/common/client" - dtlBuilder "github.com/hashicorp/packer/builder/azure/dtl" - - packersdk "github.com/hashicorp/packer-plugin-sdk/packer" - - "github.com/hashicorp/packer-plugin-sdk/common" - "github.com/hashicorp/packer-plugin-sdk/template/config" - "github.com/hashicorp/packer-plugin-sdk/template/interpolate" -) - -type DtlArtifact struct { - ArtifactName string `mapstructure:"artifact_name"` - ArtifactId string `mapstructure:"artifact_id"` - Parameters []ArtifactParameter `mapstructure:"parameters"` -} - -type ArtifactParameter struct { - Name string `mapstructure:"name"` - Value string `mapstructure:"value"` - Type string `mapstructure:"type"` -} - -type Config struct { - common.PackerConfig `mapstructure:",squash"` - - // Authentication via OAUTH - ClientConfig client.Config `mapstructure:",squash"` - - DtlArtifacts []DtlArtifact `mapstructure:"dtl_artifacts"` - LabName string `mapstructure:"lab_name"` - - ResourceGroupName string `mapstructure:"lab_resource_group_name"` - - VMName string `mapstructure:"vm_name"` - - // The default PollingDuration for azure is 15mins, this property will override - // that value. See [Azure DefaultPollingDuration](https://godoc.org/github.com/Azure/go-autorest/autorest#pkg-constants) - // If your Packer build is failing on the - // ARM deployment step with the error `Original Error: - // context deadline exceeded`, then you probably need to increase this timeout from - // its default of "15m" (valid time units include `s` for seconds, `m` for - // minutes, and `h` for hours.) - PollingDurationTimeout time.Duration `mapstructure:"polling_duration_timeout" required:"false"` - - AzureTags map[string]*string `mapstructure:"azure_tags"` - - Json map[string]interface{} - - ctx interpolate.Context -} - -type Provisioner struct { - config Config - communicator packersdk.Communicator -} - -func (p *Provisioner) ConfigSpec() hcldec.ObjectSpec { return p.config.FlatMapstructure().HCL2Spec() } - -func (p *Provisioner) Prepare(raws ...interface{}) error { - // // Create passthrough for winrm password so we can fill it in once we know - // // it - // p.config.ctx.Data = &EnvVarsTemplate{ - // WinRMPassword: `{{.WinRMPassword}}`, - // } - err := config.Decode(&p.config, &config.DecodeOpts{ - PluginType: "azure-dtlartifact", - Interpolate: true, - InterpolateContext: &p.config.ctx, - InterpolateFilter: &interpolate.RenderFilter{ - Exclude: []string{ - "execute_command", - }, - }, - }, raws...) - if err != nil { - return err - } - - p.config.ClientConfig.CloudEnvironmentName = "Public" - - return nil -} - -func (p *Provisioner) Communicator() packersdk.Communicator { - return p.communicator -} - -func (p *Provisioner) Provision(ctx context.Context, ui packersdk.Ui, comm packersdk.Communicator, _ map[string]interface{}) error { - - p.communicator = comm - - err := p.config.ClientConfig.SetDefaultValues() - if err != nil { - ui.Say(fmt.Sprintf("Error saving debug key: %s", err)) - return nil - } - - ///////////////////////////////////////////// - // Polling Duration Timeout - if p.config.PollingDurationTimeout == 0 { - // In the sdk, the default is 15 m. - p.config.PollingDurationTimeout = 15 * time.Minute - } - // FillParameters function captures authType and sets defaults. - err = p.config.ClientConfig.FillParameters() - if err != nil { - return err - } - - spnCloud, err := p.config.ClientConfig.GetServicePrincipalToken(ui.Say, p.config.ClientConfig.CloudEnvironment().ResourceManagerEndpoint) - if err != nil { - return err - } - - ui.Message("Creating Azure Resource Manager (ARM) client ...") - azureClient, err := dtlBuilder.NewAzureClient( - p.config.ClientConfig.SubscriptionID, - "", - p.config.ClientConfig.CloudEnvironment(), - p.config.PollingDurationTimeout, - p.config.PollingDurationTimeout, - spnCloud) - - if err != nil { - ui.Say(fmt.Sprintf("Error saving debug key: %s", err)) - return err - } - - ui.Say("Installing Artifact DTL") - dtlArtifacts := []dtl.ArtifactInstallProperties{} - - if p.config.DtlArtifacts != nil { - for i := range p.config.DtlArtifacts { - p.config.DtlArtifacts[i].ArtifactId = fmt.Sprintf("/subscriptions/%s/resourceGroups/%s/providers/Microsoft.DevTestLab/labs/%s/artifactSources/public repo/artifacts/%s", - p.config.ClientConfig.SubscriptionID, - p.config.ResourceGroupName, - p.config.LabName, - p.config.DtlArtifacts[i].ArtifactName) - - dparams := []dtl.ArtifactParameterProperties{} - for j := range p.config.DtlArtifacts[i].Parameters { - dp := &dtl.ArtifactParameterProperties{} - dp.Name = &p.config.DtlArtifacts[i].Parameters[j].Name - dp.Value = &p.config.DtlArtifacts[i].Parameters[j].Value - - dparams = append(dparams, *dp) - } - Aip := dtl.ArtifactInstallProperties{ - ArtifactID: &p.config.DtlArtifacts[i].ArtifactId, - Parameters: &dparams, - ArtifactTitle: &p.config.DtlArtifacts[i].ArtifactName, - } - dtlArtifacts = append(dtlArtifacts, Aip) - } - } - - dtlApplyArifactRequest := dtl.ApplyArtifactsRequest{ - Artifacts: &dtlArtifacts, - } - - ui.Say("Applying artifact ") - f, err := azureClient.DtlVirtualMachineClient.ApplyArtifacts(ctx, p.config.ResourceGroupName, p.config.LabName, p.config.VMName, dtlApplyArifactRequest) - - if err == nil { - err = f.WaitForCompletionRef(ctx, azureClient.DtlVirtualMachineClient.Client) - } - if err != nil { - ui.Say(fmt.Sprintf("Error Applying artifact: %s", err)) - } - ui.Say("Aftifact installed") - return err -} diff --git a/provisioner/azure-dtlartifact/provisioner.hcl2spec.go b/provisioner/azure-dtlartifact/provisioner.hcl2spec.go deleted file mode 100644 index e966230b6..000000000 --- a/provisioner/azure-dtlartifact/provisioner.hcl2spec.go +++ /dev/null @@ -1,133 +0,0 @@ -// Code generated by "packer-sdc mapstructure-to-hcl2"; DO NOT EDIT. - -package devtestlabsartifacts - -import ( - "github.com/hashicorp/hcl/v2/hcldec" - "github.com/zclconf/go-cty/cty" -) - -// FlatArtifactParameter is an auto-generated flat version of ArtifactParameter. -// Where the contents of a field with a `mapstructure:,squash` tag are bubbled up. -type FlatArtifactParameter struct { - Name *string `mapstructure:"name" cty:"name" hcl:"name"` - Value *string `mapstructure:"value" cty:"value" hcl:"value"` - Type *string `mapstructure:"type" cty:"type" hcl:"type"` -} - -// FlatMapstructure returns a new FlatArtifactParameter. -// FlatArtifactParameter is an auto-generated flat version of ArtifactParameter. -// Where the contents a fields with a `mapstructure:,squash` tag are bubbled up. -func (*ArtifactParameter) FlatMapstructure() interface{ HCL2Spec() map[string]hcldec.Spec } { - return new(FlatArtifactParameter) -} - -// HCL2Spec returns the hcl spec of a ArtifactParameter. -// This spec is used by HCL to read the fields of ArtifactParameter. -// The decoded values from this spec will then be applied to a FlatArtifactParameter. -func (*FlatArtifactParameter) HCL2Spec() map[string]hcldec.Spec { - s := map[string]hcldec.Spec{ - "name": &hcldec.AttrSpec{Name: "name", Type: cty.String, Required: false}, - "value": &hcldec.AttrSpec{Name: "value", Type: cty.String, Required: false}, - "type": &hcldec.AttrSpec{Name: "type", Type: cty.String, Required: false}, - } - return s -} - -// FlatConfig is an auto-generated flat version of Config. -// Where the contents of a field with a `mapstructure:,squash` tag are bubbled up. -type FlatConfig struct { - PackerBuildName *string `mapstructure:"packer_build_name" cty:"packer_build_name" hcl:"packer_build_name"` - PackerBuilderType *string `mapstructure:"packer_builder_type" cty:"packer_builder_type" hcl:"packer_builder_type"` - PackerCoreVersion *string `mapstructure:"packer_core_version" cty:"packer_core_version" hcl:"packer_core_version"` - PackerDebug *bool `mapstructure:"packer_debug" cty:"packer_debug" hcl:"packer_debug"` - PackerForce *bool `mapstructure:"packer_force" cty:"packer_force" hcl:"packer_force"` - PackerOnError *string `mapstructure:"packer_on_error" cty:"packer_on_error" hcl:"packer_on_error"` - PackerUserVars map[string]string `mapstructure:"packer_user_variables" cty:"packer_user_variables" hcl:"packer_user_variables"` - PackerSensitiveVars []string `mapstructure:"packer_sensitive_variables" cty:"packer_sensitive_variables" hcl:"packer_sensitive_variables"` - CloudEnvironmentName *string `mapstructure:"cloud_environment_name" required:"false" cty:"cloud_environment_name" hcl:"cloud_environment_name"` - ClientID *string `mapstructure:"client_id" cty:"client_id" hcl:"client_id"` - ClientSecret *string `mapstructure:"client_secret" cty:"client_secret" hcl:"client_secret"` - ClientCertPath *string `mapstructure:"client_cert_path" cty:"client_cert_path" hcl:"client_cert_path"` - ClientCertExpireTimeout *string `mapstructure:"client_cert_token_timeout" required:"false" cty:"client_cert_token_timeout" hcl:"client_cert_token_timeout"` - ClientJWT *string `mapstructure:"client_jwt" cty:"client_jwt" hcl:"client_jwt"` - ObjectID *string `mapstructure:"object_id" cty:"object_id" hcl:"object_id"` - TenantID *string `mapstructure:"tenant_id" required:"false" cty:"tenant_id" hcl:"tenant_id"` - SubscriptionID *string `mapstructure:"subscription_id" cty:"subscription_id" hcl:"subscription_id"` - UseAzureCLIAuth *bool `mapstructure:"use_azure_cli_auth" required:"false" cty:"use_azure_cli_auth" hcl:"use_azure_cli_auth"` - DtlArtifacts []FlatDtlArtifact `mapstructure:"dtl_artifacts" cty:"dtl_artifacts" hcl:"dtl_artifacts"` - LabName *string `mapstructure:"lab_name" cty:"lab_name" hcl:"lab_name"` - ResourceGroupName *string `mapstructure:"lab_resource_group_name" cty:"lab_resource_group_name" hcl:"lab_resource_group_name"` - VMName *string `mapstructure:"vm_name" cty:"vm_name" hcl:"vm_name"` - PollingDurationTimeout *string `mapstructure:"polling_duration_timeout" required:"false" cty:"polling_duration_timeout" hcl:"polling_duration_timeout"` - AzureTags map[string]*string `mapstructure:"azure_tags" cty:"azure_tags" hcl:"azure_tags"` - Json map[string]interface{} `cty:"json" hcl:"json"` -} - -// FlatMapstructure returns a new FlatConfig. -// FlatConfig is an auto-generated flat version of Config. -// Where the contents a fields with a `mapstructure:,squash` tag are bubbled up. -func (*Config) FlatMapstructure() interface{ HCL2Spec() map[string]hcldec.Spec } { - return new(FlatConfig) -} - -// HCL2Spec returns the hcl spec of a Config. -// This spec is used by HCL to read the fields of Config. -// The decoded values from this spec will then be applied to a FlatConfig. -func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec { - s := map[string]hcldec.Spec{ - "packer_build_name": &hcldec.AttrSpec{Name: "packer_build_name", Type: cty.String, Required: false}, - "packer_builder_type": &hcldec.AttrSpec{Name: "packer_builder_type", Type: cty.String, Required: false}, - "packer_core_version": &hcldec.AttrSpec{Name: "packer_core_version", Type: cty.String, Required: false}, - "packer_debug": &hcldec.AttrSpec{Name: "packer_debug", Type: cty.Bool, Required: false}, - "packer_force": &hcldec.AttrSpec{Name: "packer_force", Type: cty.Bool, Required: false}, - "packer_on_error": &hcldec.AttrSpec{Name: "packer_on_error", Type: cty.String, Required: false}, - "packer_user_variables": &hcldec.AttrSpec{Name: "packer_user_variables", Type: cty.Map(cty.String), Required: false}, - "packer_sensitive_variables": &hcldec.AttrSpec{Name: "packer_sensitive_variables", Type: cty.List(cty.String), Required: false}, - "cloud_environment_name": &hcldec.AttrSpec{Name: "cloud_environment_name", Type: cty.String, Required: false}, - "client_id": &hcldec.AttrSpec{Name: "client_id", Type: cty.String, Required: false}, - "client_secret": &hcldec.AttrSpec{Name: "client_secret", Type: cty.String, Required: false}, - "client_cert_path": &hcldec.AttrSpec{Name: "client_cert_path", Type: cty.String, Required: false}, - "client_cert_token_timeout": &hcldec.AttrSpec{Name: "client_cert_token_timeout", Type: cty.String, Required: false}, - "client_jwt": &hcldec.AttrSpec{Name: "client_jwt", Type: cty.String, Required: false}, - "object_id": &hcldec.AttrSpec{Name: "object_id", Type: cty.String, Required: false}, - "tenant_id": &hcldec.AttrSpec{Name: "tenant_id", Type: cty.String, Required: false}, - "subscription_id": &hcldec.AttrSpec{Name: "subscription_id", Type: cty.String, Required: false}, - "use_azure_cli_auth": &hcldec.AttrSpec{Name: "use_azure_cli_auth", Type: cty.Bool, Required: false}, - "dtl_artifacts": &hcldec.BlockListSpec{TypeName: "dtl_artifacts", Nested: hcldec.ObjectSpec((*FlatDtlArtifact)(nil).HCL2Spec())}, - "lab_name": &hcldec.AttrSpec{Name: "lab_name", Type: cty.String, Required: false}, - "lab_resource_group_name": &hcldec.AttrSpec{Name: "lab_resource_group_name", Type: cty.String, Required: false}, - "vm_name": &hcldec.AttrSpec{Name: "vm_name", Type: cty.String, Required: false}, - "polling_duration_timeout": &hcldec.AttrSpec{Name: "polling_duration_timeout", Type: cty.String, Required: false}, - "azure_tags": &hcldec.AttrSpec{Name: "azure_tags", Type: cty.Map(cty.String), Required: false}, - "json": &hcldec.AttrSpec{Name: "json", Type: cty.Map(cty.String), Required: false}, - } - return s -} - -// FlatDtlArtifact is an auto-generated flat version of DtlArtifact. -// Where the contents of a field with a `mapstructure:,squash` tag are bubbled up. -type FlatDtlArtifact struct { - ArtifactName *string `mapstructure:"artifact_name" cty:"artifact_name" hcl:"artifact_name"` - ArtifactId *string `mapstructure:"artifact_id" cty:"artifact_id" hcl:"artifact_id"` - Parameters []FlatArtifactParameter `mapstructure:"parameters" cty:"parameters" hcl:"parameters"` -} - -// FlatMapstructure returns a new FlatDtlArtifact. -// FlatDtlArtifact is an auto-generated flat version of DtlArtifact. -// Where the contents a fields with a `mapstructure:,squash` tag are bubbled up. -func (*DtlArtifact) FlatMapstructure() interface{ HCL2Spec() map[string]hcldec.Spec } { - return new(FlatDtlArtifact) -} - -// HCL2Spec returns the hcl spec of a DtlArtifact. -// This spec is used by HCL to read the fields of DtlArtifact. -// The decoded values from this spec will then be applied to a FlatDtlArtifact. -func (*FlatDtlArtifact) HCL2Spec() map[string]hcldec.Spec { - s := map[string]hcldec.Spec{ - "artifact_name": &hcldec.AttrSpec{Name: "artifact_name", Type: cty.String, Required: false}, - "artifact_id": &hcldec.AttrSpec{Name: "artifact_id", Type: cty.String, Required: false}, - "parameters": &hcldec.BlockListSpec{TypeName: "parameters", Nested: hcldec.ObjectSpec((*FlatArtifactParameter)(nil).HCL2Spec())}, - } - return s -} diff --git a/provisioner/azure-dtlartifact/version/version.go b/provisioner/azure-dtlartifact/version/version.go deleted file mode 100644 index 5140ec7ba..000000000 --- a/provisioner/azure-dtlartifact/version/version.go +++ /dev/null @@ -1,13 +0,0 @@ -package version - -import ( - "github.com/hashicorp/packer-plugin-sdk/version" - packerVersion "github.com/hashicorp/packer/version" -) - -var AzureDTLPluginVersion *version.PluginVersion - -func init() { - AzureDTLPluginVersion = version.InitializePluginVersion( - packerVersion.Version, packerVersion.VersionPrerelease) -} diff --git a/provisioner/salt-masterless/provisioner.go b/provisioner/salt-masterless/provisioner.go index 790f62a92..0d653fcd2 100644 --- a/provisioner/salt-masterless/provisioner.go +++ b/provisioner/salt-masterless/provisioner.go @@ -262,7 +262,7 @@ func (p *Provisioner) Provision(ctx context.Context, ui packersdk.Ui, comm packe return fmt.Errorf("Unable to create Salt state directory: %s", err) } req.Dst = path - req.Mode = getter.ModeAny + req.GetMode = getter.ModeAny if _, err := client.Get(ctx, &req); err != nil { return fmt.Errorf("Unable to download Salt formula from %s: %s", i, err) } diff --git a/website/content/docs/builders/azure/arm.mdx b/website/content/docs/builders/azure/arm.mdx deleted file mode 100644 index aabf651a4..000000000 --- a/website/content/docs/builders/azure/arm.mdx +++ /dev/null @@ -1,496 +0,0 @@ ---- -description: Packer supports building VHDs in Azure Resource manager. -page_title: Azure arm - Builders ---- - -# Azure Resource Manager Builder - -Type: `azure-arm` -Artifact BuilderId: `Azure.ResourceManagement.VMImage` - -Packer supports building Virtual Hard Disks (VHDs) and Managed Images in [Azure Resource -Manager](https://azure.microsoft.com/en-us/documentation/articles/resource-group-overview/). -Azure provides new users a [`$200` credit for the first 30 -days](https://azure.microsoft.com/en-us/free/); after which you will incur -costs for VMs built and stored using Packer. - -Azure uses a combination of OAuth and Active Directory to authorize requests to -the ARM API. Learn how to [authorize access to -ARM](/docs/builders/azure#authentication-for-azure). - -The documentation below references command output from the [Azure -CLI](https://azure.microsoft.com/en-us/documentation/articles/xplat-cli-install/). - -## Configuration Reference - -There are many configuration options available for the builder. We'll start -with authentication parameters, then go over the Azure ARM builder specific -options. In addition to the options listed here, a [communicator](/docs/templates/legacy_json_templates/communicator) can be configured for this builder. - -### Authentication options - -@include 'builder/azure/common/client/Config.mdx' - -#### Managed Identity - -If you're running Packer on an Azure VM with a [managed identity](/docs/builders/azure#azure-managed-identity) you don't need to specify any additional configuration options. As Packer will attempt to use the Managed Identity and subscription of the VM that Packer is running on. - -#### Interactive User Authentication - -To use interactive user authentication, you should specify `subscription_id` only. -Packer will use cached credentials or redirect you to a website to log in. - -#### Service Principal - -To use a [service principal](/docs/builders/azure#azure-active-directory-service-principal) -you should specify `subscription_id`, `client_id` and one of `client_secret`, -`client_cert_path` or `client_jwt`. - -- `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, unless build_resource_group_name option is - specified in which case it needs to have owner access to the existing - resource group specified in build_resource_group_name parameter.** - -- `client_id` (string) - The Active Directory service principal associated with - your builder. - -- `client_secret` (string) - The password or secret for your service principal. - -- `client_cert_path` (string) - The location of a PEM file containing a - certificate and private key for service principal. - -- `client_cert_token_timeout` (duration string | ex: "1h30m12s") - How long to set the expire time on the token created when using - `client_cert_path`. - -- `client_jwt` (string) - The bearer JWT assertion signed using a certificate - associated with your service principal principal. See [Azure Active - Directory docs](https://docs.microsoft.com/en-us/azure/active-directory/develop/active-directory-certificate-credentials) - for more information. - -### Azure ARM builder specific options - -The Azure builder can create either a VHD or a managed image. If you are -creating a VHD, you **must** start with a VHD. Likewise, if you want to create -a managed image you **must** start with a managed image. - -### Required: - -@include 'builder/azure/arm/Config-required.mdx' - -When creating a VHD the following additional 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 additional 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. - -Creating a managed image using a [Shared Gallery image](https://azure.microsoft.com/en-us/blog/announcing-the-public-preview-of-shared-image-gallery/) as the source can be achieved by specifying the [shared_image_gallery](#shared_image_gallery) configuration option. - -#### Resource Group Usage - -The Azure builder can either provision resources into a new resource group that -it controls (default) or an existing one. The advantage of using a packer -defined resource group is that failed resource cleanup is easier because you -can simply remove the entire resource group, however this means that the -provided credentials must have permission to create and remove resource groups. -By using an existing resource group you can scope the provided credentials to -just this group, however failed builds are more likely to leave unused -artifacts. - -To have Packer create a resource group you **must** provide: - -- `location` (string) Azure datacenter in which your VM will build. - - CLI example `az account list-locations` - -and optionally: - -- `temp_resource_group_name` (string) name assigned to the temporary resource - group created during the build. If this value is not set, a random value - will be assigned. This resource group is deleted at the end of the build. - -To use an existing resource group you **must** provide: - -- `build_resource_group_name` (string) - Specify an existing resource group - to run the build in. - -Providing `temp_resource_group_name` or `location` in combination with -`build_resource_group_name` is not allowed. - -### Optional: - -@include 'builder/azure/arm/Config-not-required.mdx' - -@include 'builder/azure/common/client/Config-not-required.mdx' - -### Communicator Config - -In addition to the builder options, a communicator may also be defined: - -@include 'packer-plugin-sdk/communicator/Config-not-required.mdx' - -@include 'packer-plugin-sdk/communicator/SSH-not-required.mdx' - -@include 'packer-plugin-sdk/communicator/SSH-Private-Key-File-not-required.mdx' - -## Basic Example - -Here is a basic example for Azure. - - - - -```hcl -source "azure-arm" "basic-example" { - client_id = "fe354398-d7sf-4dc9-87fd-c432cd8a7e09" - client_secret = "keepitsecret&#*$" - resource_group_name = "packerdemo" - storage_account = "virtualmachines" - subscription_id = "44cae533-4247-4093-42cf-897ded6e7823" - tenant_id = "de39842a-caba-497e-a798-7896aea43218" - - capture_container_name = "images" - capture_name_prefix = "packer" - - os_type = "Linux" - image_publisher = "Canonical" - image_offer = "UbuntuServer" - image_sku = "14.04.4-LTS" - - azure_tags = { - dept = "engineering" - } - - location = "West US" - vm_size = "Standard_A2" -} - -build { - sources = ["sources.azure-arm.basic-example"] -} -``` - - - - -```json -{ - "type": "azure-arm", - - "client_id": "fe354398-d7sf-4dc9-87fd-c432cd8a7e09", - "client_secret": "keepitsecret&#*$", - "resource_group_name": "packerdemo", - "storage_account": "virtualmachines", - "subscription_id": "44cae533-4247-4093-42cf-897ded6e7823", - "tenant_id": "de39842a-caba-497e-a798-7896aea43218", - - "capture_container_name": "images", - "capture_name_prefix": "packer", - - "os_type": "Linux", - "image_publisher": "Canonical", - "image_offer": "UbuntuServer", - "image_sku": "14.04.4-LTS", - - "azure_tags": { - "dept": "engineering" - }, - - "location": "West US", - "vm_size": "Standard_A2" -} -``` - - - - -## Deprovision - -Azure VMs should be deprovisioned at the end of every build. For Windows this -means executing sysprep, and for Linux this means executing the waagent -deprovision process. - -Please refer to the Azure -[examples](https://github.com/hashicorp/packer/tree/master/builder/azure/examples) for -complete examples showing the deprovision process. - -### Windows - -The following provisioner snippet shows how to sysprep a Windows VM. -Deprovision should be the last operation executed by a build. The code below -will wait for sysprep to write the image status in the registry and will exit -after that. The possible states, in case you want to wait for another state, -[are documented -here](https://technet.microsoft.com/en-us/library/hh824815.aspx) - - - - -```json -{ - "provisioners": [ - { - "type": "powershell", - "inline": [ - " # NOTE: the following *3* lines are only needed if the you have installed the Guest Agent.", - " while ((Get-Service RdAgent).Status -ne 'Running') { Start-Sleep -s 5 }", - " while ((Get-Service WindowsAzureTelemetryService).Status -ne 'Running') { Start-Sleep -s 5 }", - " while ((Get-Service WindowsAzureGuestAgent).Status -ne 'Running') { Start-Sleep -s 5 }", - - "& $env:SystemRoot\\System32\\Sysprep\\Sysprep.exe /oobe /generalize /quiet /quit /mode:vm", - "while($true) { $imageState = Get-ItemProperty HKLM:\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Setup\\State | Select ImageState; if($imageState.ImageState -ne 'IMAGE_STATE_GENERALIZE_RESEAL_TO_OOBE') { Write-Output $imageState.ImageState; Start-Sleep -s 10 } else { break } }" - ] - } - ] -} -``` - - - - -```hcl -provisioner "powershell" { - inline = [ - " # NOTE: the following *3* lines are only needed if the you have installed the Guest Agent.", - " while ((Get-Service RdAgent).Status -ne 'Running') { Start-Sleep -s 5 }", - " while ((Get-Service WindowsAzureTelemetryService).Status -ne 'Running') { Start-Sleep -s 5 }", - " while ((Get-Service WindowsAzureGuestAgent).Status -ne 'Running') { Start-Sleep -s 5 }", - - "& $env:SystemRoot\\System32\\Sysprep\\Sysprep.exe /oobe /generalize /quiet /quit /mode:vm", - "while($true) { $imageState = Get-ItemProperty HKLM:\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Setup\\State | Select ImageState; if($imageState.ImageState -ne 'IMAGE_STATE_GENERALIZE_RESEAL_TO_OOBE') { Write-Output $imageState.ImageState; Start-Sleep -s 10 } else { break } }" - ] -} -``` - - - - -The Windows Guest Agent participates in the Sysprep process. The agent must be -fully installed before the VM can be sysprep'ed. To ensure this is true all -agent services must be running before executing sysprep.exe. The above JSON -snippet shows one way to do this in the PowerShell provisioner. This snippet is -**only** required if the VM is configured to install the agent, which is the -default. To learn more about disabling the Windows Guest Agent please see -[Install the VM -Agent](https://docs.microsoft.com/en-us/azure/virtual-machines/extensions/agent-windows#install-the-vm-agent). - -Please note that sysprep can get stuck in infinite loops if it is not configured -correctly -- for example, if it is waiting for a reboot that you never perform. - -### Linux - -The following provisioner snippet shows how to deprovision a Linux VM. -Deprovision should be the last operation executed by a build. - - - - -```json -{ - "provisioners": [ - { - "execute_command": "chmod +x {{ .Path }}; {{ .Vars }} sudo -E sh '{{ .Path }}'", - "inline": [ - "/usr/sbin/waagent -force -deprovision+user && export HISTSIZE=0 && sync" - ], - "inline_shebang": "/bin/sh -x", - "type": "shell" - } - ] -} -``` - - - - -```hcl -provisioner "shell" { - execute_command = "chmod +x {{ .Path }}; {{ .Vars }} sudo -E sh '{{ .Path }}'" - inline = [ - "/usr/sbin/waagent -force -deprovision+user && export HISTSIZE=0 && sync" - ] - inline_shebang = "/bin/sh -x" -} -``` - - - - -To learn more about the Linux deprovision process please see WALinuxAgent's -[README](https://github.com/Azure/WALinuxAgent/blob/master/README.md). - -#### skip_clean - -Customers have reported issues with the deprovision process where the builder -hangs. The error message is similar to the following. - - Build 'azure-arm' errored: Retryable error: Error removing temporary script at /tmp/script_9899.sh: ssh: handshake failed: EOF - -One solution is to set skip_clean to true in the provisioner. This prevents -Packer from cleaning up any helper scripts uploaded to the VM during the build. - -## Defaults - -The Azure builder attempts to pick default values that provide for a just works -experience. These values can be changed by the user to more suitable values. - -- The default user name is Packer not root as in other builders. Most distros - on Azure do not allow root to SSH to a VM hence the need for a non-root - default user. Set the ssh_username option to override the default value. -- The default VM size is Standard_A1. Set the vm_size option to override - the default value. -- The default image version is latest. Set the image_version option to - override the default value. -- By default a temporary resource group will be created and destroyed as part - of the build. If you do not have permissions to do so, use - `build_resource_group_name` to specify an existing resource group to run - the build in. - -## Implementation - -~> **Warning!** This is an advanced topic. You do not need to understand -the implementation to use the Azure builder. - -The Azure builder uses ARM -[templates](https://azure.microsoft.com/en-us/documentation/articles/resource-group-authoring-templates/) -to deploy resources. ARM templates allow you to express the what without having -to express the how. - -The Azure builder works under the assumption that it creates everything it -needs to execute a build. When the build has completed it simply deletes the -resource group to cleanup any runtime resources. Resource groups are named -using the form `packer-Resource-Group-`. The value `` is a -random value that is generated at every invocation of packer. The `` -value is re-used as much as possible when naming resources, so users can better -identify and group these transient resources when seen in their subscription. - -> The VHD is created on a user specified storage account, not a random one -> created at runtime. When a virtual machine is captured the resulting VHD is -> stored on the same storage account as the source VHD. The VHD created by -> Packer must persist after a build is complete, which is why the storage -> account is set by the user. - -The basic steps for a build are: - -1. Create a resource group. -2. Validate and deploy a VM template. -3. Execute provision - defined by the user; typically shell commands. -4. Power off and capture the VM. -5. Delete the resource group. -6. Delete the temporary VM's OS disk. - -The templates used for a build are currently fixed in the code. There is a -template for Linux, Windows, and KeyVault. The templates are themselves -templated with place holders for names, passwords, SSH keys, certificates, etc. - -### What's Randomized? - -The Azure builder creates the following random values at runtime. - -- Administrator Password: a random 32-character value using the _password - alphabet_. -- Certificate: a 2,048-bit certificate used to secure WinRM communication. - The certificate is valid for 24-hours, which starts roughly at invocation - time. -- Certificate Password: a random 32-character value using the _password - alphabet_ used to protect the private key of the certificate. -- Compute Name: a random 15-character name prefixed with pkrvm; the name of - the VM. -- Deployment Name: a random 15-character name prefixed with pkfdp; the name - of the deployment. -- KeyVault Name: a random 15-character name prefixed with pkrkv. -- NIC Name: a random 15-character name prefixed with pkrni. -- Public IP Name: a random 15-character name prefixed with pkrip. -- OS Disk Name: a random 15-character name prefixed with pkros. -- Data Disk Name: a random 15-character name prefixed with pkrdd. -- Resource Group Name: a random 33-character name prefixed with - packer-Resource-Group-. -- Subnet Name: a random 15-character name prefixed with pkrsn. -- SSH Key Pair: a 2,048-bit asymmetric key pair; can be overridden by the - user. -- Virtual Network Name: a random 15-character name prefixed with pkrvn. - -The default alphabet used for random values is -**0123456789bcdfghjklmnpqrstvwxyz**. The alphabet was reduced (no vowels) to -prevent running afoul of Azure decency controls. - -The password alphabet used for random values is -**0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ**. - -### Deprecation Warning - -You may see a scary-looking deprecation warning when you run the Azure builder: - -``` -==> azure-arm: Warning: You are using Azure Packer Builder to create VHDs which -is being deprecated, consider using Managed Images. Learn more -http://aka.ms/packermanagedimage -``` - -Don't panic. Your build won't stop working next week. - -Long-term, Azure wants everyone to move to using managed images and managed -disks because they hide the complexity with respect to storage account -performance. Managed disks can be exported to a VHD. If this is deprecated, -it will be done in a transparent process by the Microsoft team who help -maintain Packer. - -In the future, Packer may remove VHD support but add a post-processor that can -automate the export to a storage account. - -### Windows - -The Windows implementation is very similar to the Linux build, with the -exception that it deploys a template to configure KeyVault. Packer communicates -with a Windows VM using the WinRM protocol. Windows VMs on Azure default to -using both password and certificate based authentication for WinRM. The -password is easily set via the VM ARM template, but the certificate requires an -intermediary. The intermediary for Azure is KeyVault. The certificate is -uploaded to a new KeyVault provisioned in the same resource group as the VM. -When the Windows VM is deployed, it links to the certificate in KeyVault, and -Azure will ensure the certificate is injected as part of deployment. - -The basic steps for a Windows build are: - -1. Create a resource group. -2. Validate and deploy a KeyVault template. -3. Validate and deploy a VM template. -4. Execute provision - defined by the user; typically shell commands. -5. Power off and capture the VM. -6. Delete the resource group. -7. Delete the temporary VM's OS disk. - -A Windows build requires two templates and two deployments. Unfortunately, the -KeyVault and VM cannot be deployed at the same time hence the need for two -templates and deployments. The time required to deploy a KeyVault template is -minimal, so overall impact is small. - -See the -[examples/azure](https://github.com/hashicorp/packer/tree/master/builder/azure/examples) -folder in the Packer project for more examples. diff --git a/website/content/docs/builders/azure/chroot.mdx b/website/content/docs/builders/azure/chroot.mdx deleted file mode 100644 index bd5caca17..000000000 --- a/website/content/docs/builders/azure/chroot.mdx +++ /dev/null @@ -1,295 +0,0 @@ ---- -description: > - The azure-chroot Packer builder is able to create Azure Managed Images - leveraging - - a VM in Azure. -page_title: Azure chroot - Builders ---- - -# Azure Builder (chroot) - -Type: `azure-chroot` -Artifact BuilderId: `azure.chroot` - -The `azure-chroot` builder is able to build Azure managed disk (MD) images. For -more information on managed disks, see [Azure Managed Disks Overview](https://docs.microsoft.com/en-us/azure/virtual-machines/windows/managed-disks-overview). - -The difference between this builder and the `azure-arm` builder is that this -builder is able to build a managed disk image without launching a new Azure VM -for every build, but instead use an already-running Azure VM. This can -dramatically speed up image builds. It also allows for more deterministic image -content and enables some capabilities that are not possible with the -`azure-arm` builder. - -> **This is an advanced builder** If you're just getting started with Packer, -> it is recommend to start with the [azure-arm builder](/docs/builders/azure-arm), -> which is much easier to use. - -## How Does it Work? - -This builder works by creating a new MD from either an existing source or from -scratch and attaching it to the (already existing) Azure VM where Packer is -running. Once attached, a [chroot](https://en.wikipedia.org/wiki/Chroot) is set -up and made available to the [provisioners](/docs/provisioners). -After provisioning, the MD is detached, snapshotted and a MD image is created. - -Using this process, minutes can be shaved off the image creation process -because Packer does not need to launch a VM instance. - -There are some restrictions however: - -- The host system must be a similar system (generally the same OS version, - kernel versions, etc.) as the image being built. -- If the source is a managed disk, it must be made available in the same - region as the host system. -- The host system SKU has to allow for all of the specified disks to be - attached. - -## Configuration Reference - -There are many configuration options available for the builder. We'll start -with authentication parameters, then go over the Azure chroot builder specific -options. - -### Authentication options - -None of the authentication options are required, but depending on which -ones are specified a different authentication method may be used. See the -[shared Azure builders documentation](/docs/builders/azure) for more -information. - -@include 'builder/azure/common/client/Config-not-required.mdx' - -### Azure chroot builder specific options - -#### Required: - -@include 'builder/azure/chroot/Config-required.mdx' - -#### Optional: - -@include 'builder/azure/chroot/Config-not-required.mdx' - -#### Output options: - -At least one of these options needs to be specified: - -- `image_resource_id` (string) - The managed image to create using this build. - -- `shared_image_destination` (object) - The shared image to create using this build. - -Where `shared_image_destination` is an object with the following properties: - -@include 'builder/azure/chroot/SharedImageGalleryDestination-required.mdx' - -@include 'builder/azure/chroot/SharedImageGalleryDestination-not-required.mdx' - -And `target_regions` is an array of objects with the following properties: - -@include 'builder/azure/chroot/TargetRegion-required.mdx' - -@include 'builder/azure/chroot/TargetRegion-not-required.mdx' - -## Chroot Mounts - -The `chroot_mounts` configuration can be used to mount specific devices within -the chroot. By default, the following additional mounts are added into the -chroot by Packer: - -- `/proc` (proc) -- `/sys` (sysfs) -- `/dev` (bind to real `/dev`) -- `/dev/pts` (devpts) -- `/proc/sys/fs/binfmt_misc` (binfmt_misc) - -These default mounts are usually good enough for anyone and are sane defaults. -However, if you want to change or add the mount points, you may using the -`chroot_mounts` configuration. Here is an example configuration which only -mounts `/prod` and `/dev`: - -```json -{ - "chroot_mounts": [ - ["proc", "proc", "/proc"], - ["bind", "/dev", "/dev"] - ] -} -``` - -`chroot_mounts` is a list of a 3-tuples of strings. The three components of the -3-tuple, in order, are: - -- The filesystem type. If this is "bind", then Packer will properly bind the - filesystem to another mount point. - -- The source device. - -- The mount directory. - -## Additional template function - -Because this builder runs on an Azure VM, there is an additional template function -available called `vm`, which returns the following VM metadata: - -- name -- subscription_id -- resource_group -- location -- resource_id - -This function can be used in the configuration templates, for example, use - -```text -"{{ vm `subscription_id` }}" -``` - -to fill in the subscription ID of the VM in any of the configuration options. - -## Examples - -Here are some examples using this builder. -This builder requires privileged actions, such as mounting disks, running -`chroot` and other admin commands. Usually it needs to be run with root -permissions, for example: - -```shell-session -$ sudo -E packer build example.pkr.json -``` - -### Using a VM with a Managed Identity - -On a VM with a system-assigned managed identity that has the contributor role -on its own resource group, the following config can be used to create an -updated Debian image: - - - - - -```hcl -source "azure-chroot" "example" { - image_resource_id = "/subscriptions/{{vm `subscription_id`}}/resourceGroups/{{vm `resource_group`}}/providers/Microsoft.Compute/images/MyDebianOSImage-{{timestamp}}" - source = "credativ:Debian:9:latest" -} - -build { - sources = ["source.azure-chroot.example"] - - provisioner "shell" { - inline = ["apt-get update", "apt-get upgrade -y"] - inline_shebang = "/bin/sh -x" - } -} -``` - - - - - -```json -{ - "builders": [ - { - "type": "azure-chroot", - - "image_resource_id": "/subscriptions/{{vm `subscription_id`}}/resourceGroups/{{vm `resource_group`}}/providers/Microsoft.Compute/images/MyDebianOSImage-{{timestamp}}", - "source": "credativ:Debian:9:latest" - } - ], - "provisioners": [ - { - "inline": ["apt-get update", "apt-get upgrade -y"], - "inline_shebang": "/bin/sh -x", - "type": "shell" - } - ] -} -``` - - - - -### Using a Service Principal - -Here is an example that creates a Debian image with updated packages. Specify -all environment variables (`ARM_CLIENT_ID`, `ARM_CLIENT_SECRET`, -`ARM_SUBSCRIPTION_ID`) to use a service principal. -The identity you choose should have permission to create disks and images and also -to update your VM. -Set the `ARM_IMAGE_RESOURCEGROUP_ID` variable to an existing resource group in the -subscription where the resulting image will be created. - - - - -```hcl -variable "client_id" { - type = string -} -variable "client_secret" { - type = string -} -variable "subscription_id" { - type = string -} -variable "resource_group" { - type = string -} - -source "azure-chroot" "basic-example" { - client_id = var.client_id - client_secret = var.client_secret - subscription_id = var.subscription_id - - image_resource_id = "/subscriptions/${var.subscription_id}/resourceGroups/${var.resource_group}/providers/Microsoft.Compute/images/MyDebianOSImage-{{timestamp}}" - - source = "credativ:Debian:9:latest" -} - -build { - sources = ["sources.azure-chroot.basic-example"] - - provisioner "shell" { - inline = ["apt-get update", "apt-get upgrade -y"] - inline_shebang = "/bin/sh -x" - } -} -``` - - - - -```json -{ - "variables": { - "client_id": "{{env `ARM_CLIENT_ID`}}", - "client_secret": "{{env `ARM_CLIENT_SECRET`}}", - "subscription_id": "{{env `ARM_SUBSCRIPTION_ID`}}", - "resource_group": "{{env `ARM_IMAGE_RESOURCEGROUP_ID`}}" - }, - "builders": [ - { - "type": "azure-chroot", - - "client_id": "{{user `client_id`}}", - "client_secret": "{{user `client_secret`}}", - "subscription_id": "{{user `subscription_id`}}", - - "image_resource_id": "/subscriptions/{{user `subscription_id`}}/resourceGroups/{{user `resource_group`}}/providers/Microsoft.Compute/images/MyDebianOSImage-{{timestamp}}", - - "source": "credativ:Debian:9:latest" - } - ], - "provisioners": [ - { - "inline": ["apt-get update", "apt-get upgrade -y"], - "inline_shebang": "/bin/sh -x", - "type": "shell" - } - ] -} -``` - - - diff --git a/website/content/docs/builders/azure/index.mdx b/website/content/docs/builders/azure/index.mdx deleted file mode 100644 index 4999c0112..000000000 --- a/website/content/docs/builders/azure/index.mdx +++ /dev/null @@ -1,117 +0,0 @@ ---- -description: > - Packer is able to create Azure VM images. To achieve this, Packer comes with - - multiple builders depending on the strategy you want to use to build the - images. -page_title: Azure images - Builders ---- - -# Azure Virtual Machine Image Builders - -Packer can create Azure virtual machine images through variety of ways -depending on the strategy that you want to use for building the images. -Packer supports the following builders for Azure images at the moment: - -- [azure-arm](/docs/builders/azure-arm) - Uses Azure Resource - Manager (ARM) to launch a virtual machine (VM) from which a new image is - captured after provisioning. If in doubt, use this builder; it is the - easiest builder to get started with. - -- [azure-chroot](/docs/builders/azure-chroot) - Uses ARM to create - a managed disk that is attached to an existing Azure VM that Packer is - running on. Provisioning leverages [Chroot](https://en.wikipedia.org/wiki/Chroot) - environment. After provisioning, the disk is detached an image is created - from this disk. This is an **advanced builder and should not be used by - newcomers**. However, it is also the fastest way to build a VM image in - Azure. - --> **Don't know which builder to use?** If in doubt, use the [azure-arm -builder](/docs/builders/azure-arm). It is much easier to use. - -# Authentication for Azure - -The Packer Azure builders provide a couple of ways to authenticate to Azure. The -following methods are available and are explained below: - -- Azure Active Directory interactive login. Interactive login is available - for the Public and US Gov clouds only. -- Azure Managed Identity -- Azure Active Directory Service Principal -- Azure CLI - --> **Don't know which authentication method to use?** Go with interactive -login to try out the builders. If you need Packer to run automatically, -switch to using a Service Principal or Managed Identity. - -No matter which method you choose, the identity you use will need the -appropriate permissions on Azure resources for Packer to operate. The minimal -set of permissions is highly dependent on the builder and its configuration. -An easy way to get started is to assign the identity the `Contributor` role at -the subscription level. - -## Azure Active Directory interactive login - -If your organization allows it, you can use a command line interactive login -method based on oAuth 'device code flow'. Packer will select this method when -you only specify a `subscription_id` in your builder configuration. When you -run Packer, it will ask you to visit a web site and input a code. This web site -will then authenticate you, satisfying any two-factor authentication policies -that your organization might have. The tokens are cached under the `.azure/packer` -directory in your home directory and will be reused if they are still valid -on subsequent runs. - -Please note that the interactive login is only available on the Azure public -cloud, not on sovereign/government clouds. - -## Azure Managed Identity - -Azure provides the option to assign an identity to a virtual machine ([Azure -documentation](https://docs.microsoft.com/en-us/azure/active-directory/managed-identities-azure-resources/qs-configure-portal-windows-vm)). Packer can -use a system assigned identity for a VM where Packer is running to orchestrate -Azure API's. This is the default behavior and requires no configuration -properties to be set. It does, however, require that you run Packer on an -Azure VM. - -To enable this method, [let Azure assign a system-assigned identity to your VM](https://docs.microsoft.com/en-us/azure/active-directory/managed-identities-azure-resources/qs-configure-portal-windows-vm). -Then, [grant your VM access to the appropriate resources](https://docs.microsoft.com/en-us/azure/active-directory/managed-identities-azure-resources/howto-assign-access-portal). -To get started, try assigning the `Contributor` role at the subscription level to -your VM. Then, when you discover your exact scenario, scope the permissions -appropriately or isolate Packer builds in a separate subscription. - -## Azure Active Directory Service Principal - -Azure Active Directory models service accounts as 'Service Principal' (SP) -objects. An SP represents an application accessing your Azure resources. It -is identified by a client ID (aka application ID) and can use a password or a -certificate to authenticate. To use a Service Principal, specify the -`subscription_id` and `client_id`, as well as either `client_secret`, -`client_cert_path` or `client_jwt`. Each of these last three represent a different -way to authenticate the SP to AAD: - -- `client_secret` - allows the user to provide a password/secret registered - for the AAD SP. -- `client_cert_path` - allows usage of a certificate to be used to - authenticate as the specified AAD SP. -- `client_cert_token_timeout` - How long to set the expire time on the token created when using - `client_cert_path`. -- `client_jwt` - For advanced scenario's where the used cannot provide Packer - the full certificate, they can provide a JWT bearer token for client auth - (RFC 7523, Sec. 2.2). These bearer tokens are created and signed using a - certificate registered in AAD and have a user-chosen expiry time, limiting - the validity of the token. This is also the underlying mechanism used to - authenticate when using `client_cert_path`. - -To create a service principal, you can follow [the Azure documentation on this -subject](https://docs.microsoft.com/en-us/cli/azure/create-an-azure-service-principal-azure-cli?view=azure-cli-latest). - -## Azure CLI - -This method will skip all other options provided and only use the credentials that the az cli is authenticated with. -Works with both normal user (`az login`) as well as service principal (`az login --service-principal --username APP_ID --password PASSWORD --tenant TENANT_ID`). - -To enable az cli authentication, use the following: - -- `"use_azure_cli_auth": true` - -This mode will use the `tenant_id` and `subscription_id` from the current active az session which can be found by running: `az account show` diff --git a/website/content/partials/builder/azure/arm/Config-not-required.mdx b/website/content/partials/builder/azure/arm/Config-not-required.mdx deleted file mode 100644 index 7ccb714c5..000000000 --- a/website/content/partials/builder/azure/arm/Config-not-required.mdx +++ /dev/null @@ -1,309 +0,0 @@ - - -- `user_assigned_managed_identities` ([]string) - A list of one or more fully-qualified resource IDs of user assigned - managed identities to be configured on the VM. - See [documentation](https://docs.microsoft.com/en-us/azure/active-directory/managed-identities-azure-resources/how-to-use-vm-token) - for how to acquire tokens within the VM. - To assign a user assigned managed identity to a VM, the provided account or service principal must have [Managed Identity Operator](https://docs.microsoft.com/en-us/azure/role-based-access-control/built-in-roles#managed-identity-operator) - and [Virtual Machine Contributor](https://docs.microsoft.com/en-us/azure/role-based-access-control/built-in-roles#virtual-machine-contributor) role assignments. - -- `capture_name_prefix` (string) - VHD prefix. - -- `capture_container_name` (string) - Destination container name. - -- `shared_image_gallery` (SharedImageGallery) - Use a [Shared Gallery - image](https://azure.microsoft.com/en-us/blog/announcing-the-public-preview-of-shared-image-gallery/) - as the source for this build. *VHD targets are incompatible with this - build type* - the target must be a *Managed Image*. When using shared_image_gallery as a source, image_publisher, - image_offer, image_sku, image_version, and custom_managed_image_name should not be set. - - In JSON - ```json - "shared_image_gallery": { - "subscription": "00000000-0000-0000-0000-00000000000", - "resource_group": "ResourceGroup", - "gallery_name": "GalleryName", - "image_name": "ImageName", - "image_version": "1.0.0" - } - "managed_image_name": "TargetImageName", - "managed_image_resource_group_name": "TargetResourceGroup" - ``` - In HCL2 - ```hcl - shared_image_gallery { - subscription = "00000000-0000-0000-0000-00000000000" - resource_group = "ResourceGroup" - gallery_name = "GalleryName" - image_name = "ImageName" - image_version = "1.0.0" - } - managed_image_name = "TargetImageName" - managed_image_resource_group_name = "TargetResourceGroup" - ``` - -- `shared_image_gallery_destination` (SharedImageGalleryDestination) - The name of the Shared Image Gallery under which the managed image will be published as Shared Gallery Image version. - - Following is an example. - - In JSON - ```json - "shared_image_gallery_destination": { - "subscription": "00000000-0000-0000-0000-00000000000", - "resource_group": "ResourceGroup", - "gallery_name": "GalleryName", - "image_name": "ImageName", - "image_version": "1.0.0", - "replication_regions": ["regionA", "regionB", "regionC"], - "storage_account_type": "Standard_LRS" - } - "managed_image_name": "TargetImageName", - "managed_image_resource_group_name": "TargetResourceGroup" - ``` - In HCL2 - ```hcl - shared_image_gallery_destination { - subscription = "00000000-0000-0000-0000-00000000000" - resource_group = "ResourceGroup" - gallery_name = "GalleryName" - image_name = "ImageName" - image_version = "1.0.0" - replication_regions = ["regionA", "regionB", "regionC"] - storage_account_type = "Standard_LRS" - } - managed_image_name = "TargetImageName" - managed_image_resource_group_name = "TargetResourceGroup" - ``` - -- `shared_image_gallery_timeout` (duration string | ex: "1h5m2s") - How long to wait for an image to be published to the shared image - gallery before timing out. If your Packer build is failing on the - Publishing to Shared Image Gallery step with the error `Original Error: - context deadline exceeded`, but the image is present when you check your - Azure dashboard, then you probably need to increase this timeout from - its default of "60m" (valid time units include `s` for seconds, `m` for - minutes, and `h` for hours.) - -- `shared_gallery_image_version_end_of_life_date` (string) - The end of life date (2006-01-02T15:04:05.99Z) of the gallery Image Version. This property - can be used for decommissioning purposes. - -- `shared_image_gallery_replica_count` (int32) - The number of replicas of the Image Version to be created per region. This - property would take effect for a region when regionalReplicaCount is not specified. - Replica count must be between 1 and 10. - -- `shared_gallery_image_version_exclude_from_latest` (bool) - If set to true, Virtual Machines deployed from the latest version of the - Image Definition won't use this Image Version. - -- `image_version` (string) - Specify a specific version of an OS to boot from. - Defaults to `latest`. There may be a difference in versions available - across regions due to image synchronization latency. To ensure a consistent - version across regions set this value to one that is available in all - regions where you are deploying. - - CLI example - `az vm image list --location westus --publisher Canonical --offer UbuntuServer --sku 16.04.0-LTS --all` - -- `location` (string) - Azure datacenter in which your VM will build. - -- `vm_size` (string) - Size of the VM used for building. This can be changed when you deploy a - VM from your VHD. See - [pricing](https://azure.microsoft.com/en-us/pricing/details/virtual-machines/) - information. Defaults to `Standard_A1`. - - CLI example `az vm list-sizes --location westus` - -- `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 to learn more about managed images. - -- `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 to - learn more about managed images. - -- `managed_image_storage_account_type` (string) - Specify the storage account - type for a managed image. Valid values are Standard_LRS and Premium_LRS. - The default is Standard_LRS. - -- `managed_image_os_disk_snapshot_name` (string) - If - managed_image_os_disk_snapshot_name is set, a snapshot of the OS disk - is created with the same name as this value before the VM is captured. - -- `managed_image_data_disk_snapshot_prefix` (string) - If - managed_image_data_disk_snapshot_prefix is set, snapshot of the data - disk(s) is created with the same prefix as this value before the VM is - captured. - -- `keep_os_disk` (bool) - If - keep_os_disk is set, the OS disk is not deleted. - The default is false. - -- `managed_image_zone_resilient` (bool) - Store the image in zone-resilient storage. You need to create it in a - region that supports [availability - zones](https://docs.microsoft.com/en-us/azure/availability-zones/az-overview). - -- `azure_tags` (map[string]string) - Name/value pair tags to apply to every resource deployed i.e. Resource - Group, VM, NIC, VNET, Public IP, KeyVault, etc. The user can define up - to 15 tags. Tag names cannot exceed 512 characters, and tag values - cannot exceed 256 characters. - -- `azure_tag` ([]{name string, value string}) - Same as [`azure_tags`](#azure_tags) but defined as a singular repeatable block - containing a `name` and a `value` field. In HCL2 mode the - [`dynamic_block`](/docs/templates/hcl_templates/expressions#dynamic-blocks) - will allow you to create those programatically. - -- `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. - -- `temp_compute_name` (string) - temporary name assigned to the VM. If this - value is not set, a random value will be assigned. Knowing the resource - group and VM name allows one to execute commands to update the VM during a - Packer build, e.g. attach a resource disk to the VM. - -- `temp_nic_name` (string) - temporary name assigned to the Nic. If this - value is not set, a random value will be assigned. Being able to assign a custom - nicname could ease deployment if naming conventions are used. - -- `temp_resource_group_name` (string) - name assigned to the temporary resource group created during the build. - If this value is not set, a random value will be assigned. This resource - group is deleted at the end of the build. - -- `build_resource_group_name` (string) - Specify an existing resource group to run the build in. - -- `build_key_vault_name` (string) - Specify an existing key vault to use for uploading certificates to the - instance to connect. - -- `build_key_vault_sku` (string) - Specify the KeyVault SKU to create during the build. Valid values are - standard or premium. The default value is standard. - -- `private_virtual_network_with_public_ip` (bool) - This value allows you to - set a virtual_network_name and obtain a public IP. If this value is not - set and virtual_network_name is defined Packer is only allowed to be - executed from a host on the same subnet / virtual network. - -- `virtual_network_name` (string) - Use a pre-existing virtual network for the - VM. This option enables private communication with the VM, no public IP - address is used or provisioned (unless you set - private_virtual_network_with_public_ip). - -- `virtual_network_subnet_name` (string) - If virtual_network_name is set, - this value may also be set. If virtual_network_name is set, and this - value is not set the builder attempts to determine the subnet to use with - the virtual network. If the subnet cannot be found, or it cannot be - disambiguated, this value should be set. - -- `virtual_network_resource_group_name` (string) - If virtual_network_name is - set, this value may also be set. If virtual_network_name is set, and - this value is not set the builder attempts to determine the resource group - containing the virtual network. If the resource group cannot be found, or - it cannot be disambiguated, this value should be set. - -- `custom_data_file` (string) - Specify a file containing custom data to inject into the cloud-init - process. The contents of the file are read and injected into the ARM - template. The custom data will be passed to cloud-init for processing at - the time of provisioning. See - [documentation](http://cloudinit.readthedocs.io/en/latest/topics/examples.html) - to learn more about custom data, and how it can be used to influence the - provisioning process. - -- `plan_info` (PlanInformation) - Used for creating images from Marketplace images. Please refer to - [Deploy an image with Marketplace - terms](https://aka.ms/azuremarketplaceapideployment) for more details. - Not all Marketplace images support programmatic deployment, and support - is controlled by the image publisher. - - An example plan\_info object is defined below. - - ```json - { - "plan_info": { - "plan_name": "rabbitmq", - "plan_product": "rabbitmq", - "plan_publisher": "bitnami" - } - } - ``` - - `plan_name` (string) - The plan name, required. `plan_product` (string) - - The plan product, required. `plan_publisher` (string) - The plan publisher, - required. `plan_promotion_code` (string) - Some images accept a promotion - code, optional. - - Images created from the Marketplace with `plan_info` **must** specify - `plan_info` whenever the image is deployed. The builder automatically adds - tags to the image to ensure this information is not lost. The following - tags are added. - - ```text - 1. PlanName - 2. PlanProduct - 3. PlanPublisher - 4. PlanPromotionCode - ``` - -- `polling_duration_timeout` (duration string | ex: "1h5m2s") - The default PollingDuration for azure is 15mins, this property will override - that value. See [Azure DefaultPollingDuration](https://godoc.org/github.com/Azure/go-autorest/autorest#pkg-constants) - If your Packer build is failing on the - ARM deployment step with the error `Original Error: - context deadline exceeded`, then you probably need to increase this timeout from - its default of "15m" (valid time units include `s` for seconds, `m` for - minutes, and `h` for hours.) - -- `os_type` (string) - If either Linux or Windows is specified Packer will - automatically configure authentication credentials for the provisioned - machine. For Linux this configures an SSH authorized key. For Windows - this configures a WinRM certificate. - -- `temp_os_disk_name` (string) - temporary name assigned to the OSDisk. If this - value is not set, a random value will be assigned. Being able to assign a custom - osDiskName could ease deployment if naming conventions are used. - -- `os_disk_size_gb` (int32) - Specify the size of the OS disk in GB - (gigabytes). Values of zero or less than zero are ignored. - -- `disk_additional_size` ([]int32) - The size(s) of any additional hard disks for the VM in gigabytes. If - this is not specified then the VM will only contain an OS disk. The - number of additional disks and maximum size of a disk depends on the - configuration of your VM. See - [Windows](https://docs.microsoft.com/en-us/azure/virtual-machines/windows/about-disks-and-vhds) - or - [Linux](https://docs.microsoft.com/en-us/azure/virtual-machines/linux/about-disks-and-vhds) - for more information. - - For VHD builds the final artifacts will be named - `PREFIX-dataDisk-.UUID.vhd` and stored in the specified capture - container along side the OS disk. The additional disks are included in - the deployment template `PREFIX-vmTemplate.UUID`. - - For Managed build the final artifacts are included in the managed image. - The additional disk will have the same storage account type as the OS - disk, as specified with the `managed_image_storage_account_type` - setting. - -- `disk_caching_type` (string) - Specify the disk caching type. Valid values - are None, ReadOnly, and ReadWrite. The default value is ReadWrite. - -- `allowed_inbound_ip_addresses` ([]string) - Specify the list of IP addresses and CIDR blocks that should be - allowed access to the VM. If provided, an Azure Network Security - Group will be created with corresponding rules and be bound to - the subnet of the VM. - Providing `allowed_inbound_ip_addresses` in combination with - `virtual_network_name` is not allowed. - -- `boot_diag_storage_account` (string) - Specify storage to store Boot Diagnostics -- Enabling this option - will create 2 Files in the specified storage account. (serial console log & screehshot file) - once the build is completed, it has to be removed manually. - see [here](https://docs.microsoft.com/en-us/azure/virtual-machines/troubleshooting/boot-diagnostics) for more info - -- `custom_resource_build_prefix` (string) - specify custom azure resource names during build limited to max 10 characters - this will set the prefix for the resources. The actuall resource names will be - `custom_resource_build_prefix` + resourcetype + 5 character random alphanumeric string - -- `async_resourcegroup_delete` (bool) - If you want packer to delete the - temporary resource group asynchronously set this value. It's a boolean - value and defaults to false. Important Setting this true means that - your builds are faster, however any failed deletes are not reported. - - diff --git a/website/content/partials/builder/azure/arm/Config-required.mdx b/website/content/partials/builder/azure/arm/Config-required.mdx deleted file mode 100644 index eb4bd5cc3..000000000 --- a/website/content/partials/builder/azure/arm/Config-required.mdx +++ /dev/null @@ -1,40 +0,0 @@ - - -- `image_publisher` (string) - Name of the publisher to use for your base image (Azure Marketplace Images only). See - [documentation](https://docs.microsoft.com/en-us/cli/azure/vm/image) - for details. - - CLI example `az vm image list-publishers --location westus` - -- `image_offer` (string) - Name of the publisher's offer to use for your base image (Azure Marketplace Images only). See - [documentation](https://docs.microsoft.com/en-us/cli/azure/vm/image) - for details. - - CLI example - `az vm image list-offers --location westus --publisher Canonical` - -- `image_sku` (string) - SKU of the image offer to use for your base image (Azure Marketplace Images only). See - [documentation](https://docs.microsoft.com/en-us/cli/azure/vm/image) - for details. - - CLI example - `az vm image list-skus --location westus --publisher Canonical --offer UbuntuServer` - -- `image_url` (string) - URL to a custom VHD to use for your base image. If this value is set, - image_publisher, image_offer, image_sku, or image_version should not be set. - -- `custom_managed_image_name` (string) - Name of a custom managed image to use for your base image. If this value is set, do - not set image_publisher, image_offer, image_sku, or image_version. - If this value is set, the option - `custom_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. - -- `custom_managed_image_resource_group_name` (string) - Name of a custom managed image's resource group to use for your base image. If this - value is set, image_publisher, image_offer, image_sku, or image_version should not be set. - If this value is set, the option - `custom_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. - - diff --git a/website/content/partials/builder/azure/arm/PlanInformation-not-required.mdx b/website/content/partials/builder/azure/arm/PlanInformation-not-required.mdx deleted file mode 100644 index df20d3fa9..000000000 --- a/website/content/partials/builder/azure/arm/PlanInformation-not-required.mdx +++ /dev/null @@ -1,11 +0,0 @@ - - -- `plan_name` (string) - Plan Name - -- `plan_product` (string) - Plan Product - -- `plan_publisher` (string) - Plan Publisher - -- `plan_promotion_code` (string) - Plan Promotion Code - - diff --git a/website/content/partials/builder/azure/arm/SharedImageGallery-not-required.mdx b/website/content/partials/builder/azure/arm/SharedImageGallery-not-required.mdx deleted file mode 100644 index 3d7259951..000000000 --- a/website/content/partials/builder/azure/arm/SharedImageGallery-not-required.mdx +++ /dev/null @@ -1,17 +0,0 @@ - - -- `subscription` (string) - Subscription - -- `resource_group` (string) - Resource Group - -- `gallery_name` (string) - Gallery Name - -- `image_name` (string) - Image Name - -- `image_version` (string) - Specify a specific version of an OS to boot from. - Defaults to latest. There may be a difference in versions available - across regions due to image synchronization latency. To ensure a consistent - version across regions set this value to one that is available in all - regions where you are deploying. - - diff --git a/website/content/partials/builder/azure/arm/SharedImageGalleryDestination-not-required.mdx b/website/content/partials/builder/azure/arm/SharedImageGalleryDestination-not-required.mdx deleted file mode 100644 index 53d413431..000000000 --- a/website/content/partials/builder/azure/arm/SharedImageGalleryDestination-not-required.mdx +++ /dev/null @@ -1,18 +0,0 @@ - - -- `subscription` (string) - Sig Destination Subscription - -- `resource_group` (string) - Sig Destination Resource Group - -- `gallery_name` (string) - Sig Destination Gallery Name - -- `image_name` (string) - Sig Destination Image Name - -- `image_version` (string) - Sig Destination Image Version - -- `replication_regions` ([]string) - Sig Destination Replication Regions - -- `storage_account_type` (string) - Specify a storage account type for the Shared Image Gallery Image Version. - Defaults to `Standard_LRS`. Accepted values are `Standard_LRS` and `Standard_ZRS` - - diff --git a/website/content/partials/builder/azure/chroot/Config-not-required.mdx b/website/content/partials/builder/azure/chroot/Config-not-required.mdx deleted file mode 100644 index 4508bd71e..000000000 --- a/website/content/partials/builder/azure/chroot/Config-not-required.mdx +++ /dev/null @@ -1,66 +0,0 @@ - - -- `from_scratch` (bool) - When set to `true`, starts with an empty, unpartitioned disk. Defaults to `false`. - -- `command_wrapper` (string) - How to run shell commands. This may be useful to set environment variables or perhaps run - a command with sudo or so on. This is a configuration template where the `.Command` variable - is replaced with the command to be run. Defaults to `{{.Command}}`. - -- `pre_mount_commands` ([]string) - A series of commands to execute after attaching the root volume and before mounting the chroot. - This is not required unless using `from_scratch`. If so, this should include any partitioning - and filesystem creation commands. The path to the device is provided by `{{.Device}}`. - -- `mount_options` ([]string) - Options to supply the `mount` command when mounting devices. Each option will be prefixed with - `-o` and supplied to the `mount` command ran by Packer. Because this command is ran in a shell, - user discretion is advised. See this manual page for the `mount` command for valid file system specific options. - -- `mount_partition` (string) - The partition number containing the / partition. By default this is the first partition of the volume. - -- `mount_path` (string) - The path where the volume will be mounted. This is where the chroot environment will be. This defaults - to `/mnt/packer-amazon-chroot-volumes/{{.Device}}`. This is a configuration template where the `.Device` - variable is replaced with the name of the device where the volume is attached. - -- `post_mount_commands` ([]string) - As `pre_mount_commands`, but the commands are executed after mounting the root device and before the - extra mount and copy steps. The device and mount path are provided by `{{.Device}}` and `{{.MountPath}}`. - -- `chroot_mounts` ([][]string) - This is a list of devices to mount into the chroot environment. This configuration parameter requires - some additional documentation which is in the "Chroot Mounts" section below. Please read that section - for more information on how to use this. - -- `copy_files` ([]string) - Paths to files on the running Azure instance that will be copied into the chroot environment prior to - provisioning. Defaults to `/etc/resolv.conf` so that DNS lookups work. Pass an empty list to skip copying - `/etc/resolv.conf`. You may need to do this if you're building an image that uses systemd. - -- `os_disk_size_gb` (int32) - Try to resize the OS disk to this size on the first copy. Disks can only be englarged. If not specified, - the disk will keep its original size. Required when using `from_scratch` - -- `os_disk_storage_account_type` (string) - The [storage SKU](https://docs.microsoft.com/en-us/rest/api/compute/disks/createorupdate#diskstorageaccounttypes) - to use for the OS Disk. Defaults to `Standard_LRS`. - -- `os_disk_cache_type` (string) - The [cache type](https://docs.microsoft.com/en-us/rest/api/compute/images/createorupdate#cachingtypes) - specified in the resulting image and for attaching it to the Packer VM. Defaults to `ReadOnly` - -- `data_disk_storage_account_type` (string) - The [storage SKU](https://docs.microsoft.com/en-us/rest/api/compute/disks/createorupdate#diskstorageaccounttypes) - to use for datadisks. Defaults to `Standard_LRS`. - -- `data_disk_cache_type` (string) - The [cache type](https://docs.microsoft.com/en-us/rest/api/compute/images/createorupdate#cachingtypes) - specified in the resulting image and for attaching it to the Packer VM. Defaults to `ReadOnly` - -- `image_hyperv_generation` (string) - The [Hyper-V generation type](https://docs.microsoft.com/en-us/rest/api/compute/images/createorupdate#hypervgenerationtypes) for Managed Image output. - Defaults to `V1`. - -- `temporary_os_disk_id` (string) - The id of the temporary OS disk that will be created. Will be generated if not set. - -- `temporary_os_disk_snapshot_id` (string) - The id of the temporary OS disk snapshot that will be created. Will be generated if not set. - -- `temporary_data_disk_id_prefix` (string) - The prefix for the resource ids of the temporary data disks that will be created. The disks will be suffixed with a number. Will be generated if not set. - -- `temporary_data_disk_snapshot_id` (string) - The prefix for the resource ids of the temporary data disk snapshots that will be created. The snapshots will be suffixed with a number. Will be generated if not set. - -- `skip_cleanup` (bool) - If set to `true`, leaves the temporary disks and snapshots behind in the Packer VM resource group. Defaults to `false` - -- `image_resource_id` (string) - The managed image to create using this build. - -- `shared_image_destination` (SharedImageGalleryDestination) - The shared image to create using this build. - - diff --git a/website/content/partials/builder/azure/chroot/Config-required.mdx b/website/content/partials/builder/azure/chroot/Config-required.mdx deleted file mode 100644 index 655da4bcd..000000000 --- a/website/content/partials/builder/azure/chroot/Config-required.mdx +++ /dev/null @@ -1,8 +0,0 @@ - - -- `source` (string) - One of the following can be used as a source for an image: - - a shared image version resource ID - - a managed disk resource ID - - a publisher:offer:sku:version specifier for plaform image sources. - - diff --git a/website/content/partials/builder/azure/chroot/Config.mdx b/website/content/partials/builder/azure/chroot/Config.mdx deleted file mode 100644 index e104d62f7..000000000 --- a/website/content/partials/builder/azure/chroot/Config.mdx +++ /dev/null @@ -1,6 +0,0 @@ - - -Config is the configuration that is chained through the steps and settable -from the template. - - diff --git a/website/content/partials/builder/azure/chroot/SharedImageGalleryDestination-not-required.mdx b/website/content/partials/builder/azure/chroot/SharedImageGalleryDestination-not-required.mdx deleted file mode 100644 index 4a90d461f..000000000 --- a/website/content/partials/builder/azure/chroot/SharedImageGalleryDestination-not-required.mdx +++ /dev/null @@ -1,7 +0,0 @@ - - -- `target_regions` ([]TargetRegion) - Target Regions - -- `exclude_from_latest` (bool) - Exclude From Latest - - diff --git a/website/content/partials/builder/azure/chroot/SharedImageGalleryDestination-required.mdx b/website/content/partials/builder/azure/chroot/SharedImageGalleryDestination-required.mdx deleted file mode 100644 index 7ec91ff39..000000000 --- a/website/content/partials/builder/azure/chroot/SharedImageGalleryDestination-required.mdx +++ /dev/null @@ -1,11 +0,0 @@ - - -- `resource_group` (string) - Resource Group - -- `gallery_name` (string) - Gallery Name - -- `image_name` (string) - Image Name - -- `image_version` (string) - Image Version - - diff --git a/website/content/partials/builder/azure/chroot/SharedImageGalleryDestination.mdx b/website/content/partials/builder/azure/chroot/SharedImageGalleryDestination.mdx deleted file mode 100644 index 565c5eda1..000000000 --- a/website/content/partials/builder/azure/chroot/SharedImageGalleryDestination.mdx +++ /dev/null @@ -1,6 +0,0 @@ - - -SharedImageGalleryDestination models an image version in a Shared -Image Gallery that can be used as a destination. - - diff --git a/website/content/partials/builder/azure/chroot/TargetRegion-not-required.mdx b/website/content/partials/builder/azure/chroot/TargetRegion-not-required.mdx deleted file mode 100644 index d277b7f54..000000000 --- a/website/content/partials/builder/azure/chroot/TargetRegion-not-required.mdx +++ /dev/null @@ -1,7 +0,0 @@ - - -- `replicas` (int32) - Number of replicas in this region. Default: 1 - -- `storage_account_type` (string) - Storage account type: Standard_LRS or Standard_ZRS. Default: Standard_ZRS - - diff --git a/website/content/partials/builder/azure/chroot/TargetRegion-required.mdx b/website/content/partials/builder/azure/chroot/TargetRegion-required.mdx deleted file mode 100644 index c76629422..000000000 --- a/website/content/partials/builder/azure/chroot/TargetRegion-required.mdx +++ /dev/null @@ -1,5 +0,0 @@ - - -- `name` (string) - Name of the Azure region - - diff --git a/website/content/partials/builder/azure/chroot/TargetRegion.mdx b/website/content/partials/builder/azure/chroot/TargetRegion.mdx deleted file mode 100644 index 28ac589e2..000000000 --- a/website/content/partials/builder/azure/chroot/TargetRegion.mdx +++ /dev/null @@ -1,5 +0,0 @@ - - -TargetRegion describes a region where the shared image should be replicated - - diff --git a/website/content/partials/builder/azure/common/client/Config-not-required.mdx b/website/content/partials/builder/azure/common/client/Config-not-required.mdx deleted file mode 100644 index 85f3489a5..000000000 --- a/website/content/partials/builder/azure/common/client/Config-not-required.mdx +++ /dev/null @@ -1,36 +0,0 @@ - - -- `cloud_environment_name` (string) - One of Public, China, Germany, or - USGovernment. Defaults to Public. Long forms such as - USGovernmentCloud and AzureUSGovernmentCloud are also supported. - -- `client_id` (string) - The application ID of the AAD Service Principal. - Requires either `client_secret`, `client_cert_path` or `client_jwt` to be set as well. - -- `client_secret` (string) - A password/secret registered for the AAD SP. - -- `client_cert_path` (string) - The path to a pem-encoded certificate that will be used to authenticate - as the specified AAD SP. - -- `client_cert_token_timeout` (duration string | ex: "1h5m2s") - The timeout for the JWT Token when using a [client certificate](#client_cert_path). Defaults to 1 hour. - -- `client_jwt` (string) - A JWT bearer token for client auth (RFC 7523, Sec. 2.2) that will be used - to authenticate the AAD SP. Provides more control over token the expiration - when using certificate authentication than when using `client_cert_path`. - -- `object_id` (string) - The object ID for the AAD SP. Optional, will be derived from the oAuth token if left empty. - -- `tenant_id` (string) - The Active Directory tenant identifier with which your `client_id` and - `subscription_id` are associated. If not specified, `tenant_id` will be - looked up using `subscription_id`. - -- `subscription_id` (string) - The subscription to use. - -- `use_azure_cli_auth` (bool) - Flag to use Azure CLI authentication. Defaults to false. - CLI auth will use the information from an active `az login` session to connect to Azure and set the subscription id and tenant id associated to the signed in account. - If enabled, it will use the authentication provided by the `az` CLI. - Azure CLI authentication will use the credential marked as `isDefault` and can be verified using `az account show`. - Works with normal authentication (`az login`) and service principals (`az login --service-principal --username APP_ID --password PASSWORD --tenant TENANT_ID`). - Ignores all other configurations if enabled. - - diff --git a/website/content/partials/builder/azure/common/client/Config.mdx b/website/content/partials/builder/azure/common/client/Config.mdx deleted file mode 100644 index 16806af81..000000000 --- a/website/content/partials/builder/azure/common/client/Config.mdx +++ /dev/null @@ -1,12 +0,0 @@ - - -Config allows for various ways to authenticate Azure clients. -When `client_id` and `subscription_id` are specified, Packer will use the -specified Azure Active Directory (AAD) Service Principal (SP). -If only `subscription_id` is specified, Packer will try to interactively -log on the current user (tokens will be cached). -If none of these options are specified, Packer will attempt to use the -Managed Identity and subscription of the VM that Packer is running on. -This will only work if Packer is running on an Azure VM. - - diff --git a/website/content/partials/builder/azure/dtl/ArtifactParameter-not-required.mdx b/website/content/partials/builder/azure/dtl/ArtifactParameter-not-required.mdx deleted file mode 100644 index fc507c1bd..000000000 --- a/website/content/partials/builder/azure/dtl/ArtifactParameter-not-required.mdx +++ /dev/null @@ -1,9 +0,0 @@ - - -- `name` (string) - Name - -- `value` (string) - Value - -- `type` (string) - Type - - diff --git a/website/content/partials/builder/azure/dtl/Config-not-required.mdx b/website/content/partials/builder/azure/dtl/Config-not-required.mdx deleted file mode 100644 index afb160163..000000000 --- a/website/content/partials/builder/azure/dtl/Config-not-required.mdx +++ /dev/null @@ -1,169 +0,0 @@ - - -- `capture_name_prefix` (string) - Capture - -- `capture_container_name` (string) - Capture Container Name - -- `shared_image_gallery` (SharedImageGallery) - Use a [Shared Gallery - image](https://azure.microsoft.com/en-us/blog/announcing-the-public-preview-of-shared-image-gallery/) - as the source for this build. *VHD targets are incompatible with this - build type* - the target must be a *Managed Image*. - - ```json - "shared_image_gallery": { - "subscription": "00000000-0000-0000-0000-00000000000", - "resource_group": "ResourceGroup", - "gallery_name": "GalleryName", - "image_name": "ImageName", - "image_version": "1.0.0" - } - "managed_image_name": "TargetImageName", - "managed_image_resource_group_name": "TargetResourceGroup" - ``` - -- `shared_image_gallery_destination` (SharedImageGalleryDestination) - The name of the Shared Image Gallery under which the managed image will be published as Shared Gallery Image version. - - Following is an example. - - ```json - "shared_image_gallery_destination": { - "resource_group": "ResourceGroup", - "gallery_name": "GalleryName", - "image_name": "ImageName", - "image_version": "1.0.0", - "replication_regions": ["regionA", "regionB", "regionC"] - } - "managed_image_name": "TargetImageName", - "managed_image_resource_group_name": "TargetResourceGroup" - ``` - -- `shared_image_gallery_timeout` (duration string | ex: "1h5m2s") - How long to wait for an image to be published to the shared image - gallery before timing out. If your Packer build is failing on the - Publishing to Shared Image Gallery step with the error `Original Error: - context deadline exceeded`, but the image is present when you check your - Azure dashboard, then you probably need to increase this timeout from - its default of "60m" (valid time units include `s` for seconds, `m` for - minutes, and `h` for hours.) - -- `image_publisher` (string) - PublisherName for your base image. See - [documentation](https://docs.microsoft.com/en-us/cli/azure/vm/image) - for details. - - CLI example `az vm image list-publishers --location westus` - -- `image_offer` (string) - Offer for your base image. See - [documentation](https://docs.microsoft.com/en-us/cli/azure/vm/image) - for details. - - CLI example - `az vm image list-offers --location westus --publisher Canonical` - -- `image_sku` (string) - SKU for your base image. See - [documentation](https://docs.microsoft.com/en-us/cli/azure/vm/image) - for details. - - CLI example - `az vm image list-skus --location westus --publisher Canonical --offer UbuntuServer` - -- `image_version` (string) - Specify a specific version of an OS to boot from. - Defaults to `latest`. There may be a difference in versions available - across regions due to image synchronization latency. To ensure a consistent - version across regions set this value to one that is available in all - regions where you are deploying. - - CLI example - `az vm image list --location westus --publisher Canonical --offer UbuntuServer --sku 16.04.0-LTS --all` - -- `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. - -- `custom_managed_image_resource_group_name` (string) - Specify the source managed image's resource group used to use. If this - value is set, do not set image\_publisher, image\_offer, image\_sku, or - image\_version. If this value is set, the value - `custom_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. - -- `custom_managed_image_name` (string) - Specify the source managed image's name to use. If this value is set, do - not set image\_publisher, image\_offer, image\_sku, or image\_version. - If this value is set, the value - `custom_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. - -- `location` (string) - Location - -- `vm_size` (string) - Size of the VM used for building. This can be changed when you deploy a - VM from your VHD. See - [pricing](https://azure.microsoft.com/en-us/pricing/details/virtual-machines/) - information. Defaults to `Standard_A1`. - - CLI example `az vm list-sizes --location westus` - -- `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 to learn more about managed images. - -- `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 to - learn more about managed images. - -- `managed_image_storage_account_type` (string) - Specify the storage account - type for a managed image. Valid values are Standard_LRS and Premium_LRS. - The default is Standard_LRS. - -- `azure_tags` (map[string]\*string) - the user can define up to 15 - tags. Tag names cannot exceed 512 characters, and tag values cannot exceed - 256 characters. Tags are applied to every resource deployed by a Packer - build, i.e. Resource Group, VM, NIC, VNET, Public IP, KeyVault, etc. - -- `plan_id` (string) - Used for creating images from Marketplace images. Please refer to - [Deploy an image with Marketplace - terms](https://aka.ms/azuremarketplaceapideployment) for more details. - Not all Marketplace images support programmatic deployment, and support - is controlled by the image publisher. - Plan_id is a string with unique identifier for the plan associated with images. - Ex plan_id="1-12ab" - -- `polling_duration_timeout` (duration string | ex: "1h5m2s") - The default PollingDuration for azure is 15mins, this property will override - that value. See [Azure DefaultPollingDuration](https://godoc.org/github.com/Azure/go-autorest/autorest#pkg-constants) - If your Packer build is failing on the - ARM deployment step with the error `Original Error: - context deadline exceeded`, then you probably need to increase this timeout from - its default of "15m" (valid time units include `s` for seconds, `m` for - minutes, and `h` for hours.) - -- `os_type` (string) - If either Linux or Windows is specified Packer will - automatically configure authentication credentials for the provisioned - machine. For Linux this configures an SSH authorized key. For Windows - this configures a WinRM certificate. - -- `os_disk_size_gb` (int32) - Specify the size of the OS disk in GB - (gigabytes). Values of zero or less than zero are ignored. - -- `disk_additional_size` ([]int32) - For Managed build the final artifacts are included in the managed image. - The additional disk will have the same storage account type as the OS - disk, as specified with the `managed_image_storage_account_type` - setting. - -- `disk_caching_type` (string) - Specify the disk caching type. Valid values - are None, ReadOnly, and ReadWrite. The default value is ReadWrite. - -- `storage_type` (string) - DTL values - -- `lab_virtual_network_name` (string) - Lab Virtual Network Name - -- `lab_name` (string) - Lab Name - -- `lab_subnet_name` (string) - Lab Subnet Name - -- `lab_resource_group_name` (string) - Lab Resource Group Name - -- `dtl_artifacts` ([]DtlArtifact) - Dtl Artifacts - -- `vm_name` (string) - VM Name - - diff --git a/website/content/partials/builder/azure/dtl/DtlArtifact-not-required.mdx b/website/content/partials/builder/azure/dtl/DtlArtifact-not-required.mdx deleted file mode 100644 index 4df27fc30..000000000 --- a/website/content/partials/builder/azure/dtl/DtlArtifact-not-required.mdx +++ /dev/null @@ -1,11 +0,0 @@ - - -- `artifact_name` (string) - Artifact Name - -- `repository_name` (string) - Repository Name - -- `artifact_id` (string) - Artifact Id - -- `parameters` ([]ArtifactParameter) - Parameters - - diff --git a/website/content/partials/builder/azure/dtl/SharedImageGallery-not-required.mdx b/website/content/partials/builder/azure/dtl/SharedImageGallery-not-required.mdx deleted file mode 100644 index 7869d459a..000000000 --- a/website/content/partials/builder/azure/dtl/SharedImageGallery-not-required.mdx +++ /dev/null @@ -1,13 +0,0 @@ - - -- `subscription` (string) - Subscription - -- `resource_group` (string) - Resource Group - -- `gallery_name` (string) - Gallery Name - -- `image_name` (string) - Image Name - -- `image_version` (string) - Image Version - - diff --git a/website/content/partials/builder/azure/dtl/SharedImageGalleryDestination-not-required.mdx b/website/content/partials/builder/azure/dtl/SharedImageGalleryDestination-not-required.mdx deleted file mode 100644 index 6cd1f91a5..000000000 --- a/website/content/partials/builder/azure/dtl/SharedImageGalleryDestination-not-required.mdx +++ /dev/null @@ -1,13 +0,0 @@ - - -- `resource_group` (string) - Sig Destination Resource Group - -- `gallery_name` (string) - Sig Destination Gallery Name - -- `image_name` (string) - Sig Destination Image Name - -- `image_version` (string) - Sig Destination Image Version - -- `replication_regions` ([]string) - Sig Destination Replication Regions - - diff --git a/website/data/docs-nav-data.json b/website/data/docs-nav-data.json index 8f11a96a2..bc372b0b4 100644 --- a/website/data/docs-nav-data.json +++ b/website/data/docs-nav-data.json @@ -679,23 +679,6 @@ "title": "Overview", "path": "builders" }, - { - "title": "Azure", - "routes": [ - { - "title": "Overview", - "path": "builders/azure" - }, - { - "title": "ARM", - "path": "builders/azure/arm" - }, - { - "title": "chroot", - "path": "builders/azure/chroot" - } - ] - }, { "title": "File", "path": "builders/file" diff --git a/website/data/docs-remote-plugins.json b/website/data/docs-remote-plugins.json index 45a0a687a..d5e2b0827 100644 --- a/website/data/docs-remote-plugins.json +++ b/website/data/docs-remote-plugins.json @@ -18,6 +18,12 @@ "repo": "hashicorp/packer-plugin-amazon", "version": "latest" }, + { + "title": "Azure", + "path": "azure", + "repo": "hashicorp/packer-plugin-azure", + "version": "latest" + }, { "title": "Chef", "path": "chef",