From 0a456d18572773b673dce71c885c5d178a75d212 Mon Sep 17 00:00:00 2001 From: Jenna Goldstrich Date: Thu, 6 Jul 2023 13:11:42 -0700 Subject: [PATCH 01/10] Start DTL builder work --- builder/azure/arm/azure_client.go | 8 +- builder/azure/common/constants/stateBag.go | 1 + .../azure/common/template/template_builder.go | 6 + builder/azure/dtl/azure_client.go | 301 ++++++++++-------- builder/azure/dtl/builder.go | 85 ++--- builder/azure/dtl/config.go | 6 +- builder/azure/dtl/config_test.go | 8 +- builder/azure/dtl/resource_resolver.go | 90 +----- builder/azure/dtl/step_capture_image.go | 49 ++- .../azure/dtl/step_delete_virtual_machine.go | 16 +- builder/azure/dtl/step_deploy_template.go | 115 +++---- builder/azure/dtl/step_power_off_compute.go | 7 +- .../step_publish_to_shared_image_gallery.go | 55 ++-- builder/azure/dtl/template_factory.go | 49 ++- go.mod | 1 - go.sum | 3 - 16 files changed, 382 insertions(+), 418 deletions(-) diff --git a/builder/azure/arm/azure_client.go b/builder/azure/arm/azure_client.go index c1008ab0..d87237e9 100644 --- a/builder/azure/arm/azure_client.go +++ b/builder/azure/arm/azure_client.go @@ -184,11 +184,11 @@ func NewAzureClient(ctx context.Context, isVHDBuild bool, cloud *environments.En azureClient.StorageAccountsClient.Client.UserAgent = fmt.Sprintf("%s %s", useragent.String(version.AzurePluginVersion.FormattedVersion()), azureClient.StorageAccountsClient.Client.UserAgent) azureClient.StorageAccountsClient.Client.PollingDuration = pollingDuration - api := environments.AzurePublic().ResourceManager - networkMetaClient, err := hashiNetworkMetaSDK.NewClientWithBaseURI(api, func(c *resourcemanager.Client) { + networkMetaClient, err := hashiNetworkMetaSDK.NewClientWithBaseURI(cloud.ResourceManager, func(c *resourcemanager.Client) { c.Client.Authorizer = resourceManagerAuthorizer c.Client.UserAgent = "some-user-agent" }) + if err != nil { return nil, nil, err } @@ -281,7 +281,7 @@ func buildAuthorizer(ctx context.Context, authOpts NewSDKAuthOptions, env enviro var authConfig auth.Credentials switch authOpts.AuthType { case AuthTypeDeviceLogin: - return nil, fmt.Errorf("DeviceLogin is not supported, however you can use the Azure CLI `az login --use-device-code` to use a device code, and then use CLI authentication") + return nil, fmt.Errorf("DeviceLogin is not supported in v2 of the Azure Packer Plugin, however you can use the Azure CLI `az login --use-device-code` to use a device code, and then use CLI authentication") case AuthTypeAzureCLI: authConfig = auth.Credentials{ Environment: env, @@ -322,7 +322,6 @@ func buildAuthorizer(ctx context.Context, authOpts NewSDKAuthOptions, env enviro authorizer, err := auth.NewAuthorizerFromCredentials(ctx, authConfig, api) if err != nil { return nil, err - //fmt.Errorf("building Resource Manager authorizer from credentials: %+v", err) } return authorizer, nil } @@ -339,5 +338,4 @@ func getObjectIdFromToken(token string) (string, error) { return "", err } return claims["oid"].(string), nil - } diff --git a/builder/azure/common/constants/stateBag.go b/builder/azure/common/constants/stateBag.go index ad257389..30ea5760 100644 --- a/builder/azure/common/constants/stateBag.go +++ b/builder/azure/common/constants/stateBag.go @@ -70,4 +70,5 @@ const ( ArmBuildDiskEncryptionSetId string = "arm.ArmBuildDiskEncryptionSetId" ArmSubscription string = "arm.Subscription" ArmBuildVMInternalId string = "arm.BuildVMInternalId" + DtlLabName string = "dtl.LabName" ) diff --git a/builder/azure/common/template/template_builder.go b/builder/azure/common/template/template_builder.go index dead567e..6101596d 100644 --- a/builder/azure/common/template/template_builder.go +++ b/builder/azure/common/template/template_builder.go @@ -735,6 +735,9 @@ const BasicTemplate = `{ "publicIPAddressName": { "type": "string" }, + "publicIPAddressSku": { + "type": "string" + }, "subnetName": { "type": "string" }, @@ -785,6 +788,9 @@ const BasicTemplate = `{ "type": "Microsoft.Network/publicIPAddresses", "name": "[parameters('publicIPAddressName')]", "location": "[variables('location')]", + "sku": { + "name": "[parameters('publicIPAddressSku')]", + } "properties": { "publicIPAllocationMethod": "[variables('publicIPAddressType')]", "dnsSettings": { diff --git a/builder/azure/dtl/azure_client.go b/builder/azure/dtl/azure_client.go index ba4fe7b6..b1224260 100644 --- a/builder/azure/dtl/azure_client.go +++ b/builder/azure/dtl/azure_client.go @@ -4,25 +4,27 @@ package dtl import ( + "context" "encoding/json" "fmt" + "github.com/golang-jwt/jwt" "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-azure/builder/azure/common" + hashiImagesSDK "github.com/hashicorp/go-azure-sdk/resource-manager/compute/2022-03-01/images" + hashiVMSDK "github.com/hashicorp/go-azure-sdk/resource-manager/compute/2022-03-01/virtualmachines" + hashiGalleryImagesSDK "github.com/hashicorp/go-azure-sdk/resource-manager/compute/2022-03-03/galleryimages" + hashiGalleryImageVersionsSDK "github.com/hashicorp/go-azure-sdk/resource-manager/compute/2022-03-03/galleryimageversions" + hashiDTLSDK "github.com/hashicorp/go-azure-sdk/resource-manager/devtestlab/2018-09-15" + hashiNetworkSDK "github.com/hashicorp/go-azure-sdk/resource-manager/network/2022-09-01" + "github.com/hashicorp/go-azure-sdk/sdk/auth" + authWrapper "github.com/hashicorp/go-azure-sdk/sdk/auth/autorest" + "github.com/hashicorp/go-azure-sdk/sdk/client/resourcemanager" + "github.com/hashicorp/go-azure-sdk/sdk/environments" "github.com/hashicorp/packer-plugin-azure/version" "github.com/hashicorp/packer-plugin-sdk/useragent" ) @@ -32,32 +34,15 @@ const ( ) 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 + InspectorMaxLength int + LastError azureErrorResponse + + hashiVMSDK.VirtualMachinesClient + hashiImagesSDK.ImagesClient + NetworkMetaClient hashiNetworkSDK.Client + hashiGalleryImageVersionsSDK.GalleryImageVersionsClient + hashiGalleryImagesSDK.GalleryImagesClient + DtlMetaClient hashiDTLSDK.Client } func getCaptureResponse(body string) *CaptureTemplate { @@ -74,41 +59,6 @@ func getCaptureResponse(body string) *CaptureTemplate { 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 { @@ -134,74 +84,167 @@ func byConcatDecorators(decorators ...autorest.RespondDecorator) autorest.Respon } } -func NewAzureClient(subscriptionID, resourceGroupName string, - cloud *azure.Environment, SharedGalleryTimeout time.Duration, CustomImageCaptureTimeout time.Duration, PollingDuration time.Duration, - servicePrincipalToken *adal.ServicePrincipalToken) (*AzureClient, error) { +type NewSDKAuthOptions struct { + AuthType string + ClientID string + ClientSecret string + ClientJWT string + ClientCertPath string + TenantID string + SubscriptionID string +} + +// Returns an Azure Client used for the Azure Resource Manager +// Also returns the Azure object ID for the authentication method used in the build +func NewAzureClient(ctx context.Context, subscriptionID, resourceGroupName string, + cloud *environments.Environment, SharedGalleryTimeout time.Duration, CustomImageCaptureTimeout time.Duration, PollingDuration time.Duration, newSdkAuthOptions NewSDKAuthOptions) (*AzureClient, *string, 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 = CustomImageCaptureTimeout - - 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) + if cloud == nil || cloud.ResourceManager == nil { + // TODO Throw error message that helps users solve this problem + return nil, nil, fmt.Errorf("Azure Environment not configured correctly") + } + resourceManagerEndpoint, _ := cloud.ResourceManager.Endpoint() + resourceManagerAuthorizer, err := buildResourceManagerAuthorizer(ctx, newSdkAuthOptions, *cloud) + if err != nil { + return nil, nil, err + } + dtlMetaClient := hashiDTLSDK.NewClientWithBaseURI(*resourceManagerEndpoint, func(c *autorest.Client) { + c.Authorizer = authWrapper.AutorestAuthorizer(resourceManagerAuthorizer) + c.UserAgent = "some-user-agent" + }) + azureClient.DtlMetaClient = dtlMetaClient + + azureClient.GalleryImageVersionsClient = hashiGalleryImageVersionsSDK.NewGalleryImageVersionsClientWithBaseURI(*resourceManagerEndpoint) + azureClient.GalleryImageVersionsClient.Client.Authorizer = authWrapper.AutorestAuthorizer(resourceManagerAuthorizer) + azureClient.GalleryImageVersionsClient.Client.RequestInspector = withInspection(maxlen) + azureClient.GalleryImageVersionsClient.Client.ResponseInspector = byConcatDecorators(byInspecting(maxlen), errorCapture(azureClient)) + azureClient.GalleryImageVersionsClient.Client.UserAgent = fmt.Sprintf("%s %s", useragent.String(version.AzurePluginVersion.FormattedVersion()), azureClient.GalleryImageVersionsClient.Client.UserAgent) + azureClient.GalleryImageVersionsClient.Client.PollingDuration = PollingDuration + + azureClient.GalleryImagesClient = hashiGalleryImagesSDK.NewGalleryImagesClientWithBaseURI(*resourceManagerEndpoint) + azureClient.GalleryImagesClient.Client.Authorizer = authWrapper.AutorestAuthorizer(resourceManagerAuthorizer) + azureClient.GalleryImagesClient.Client.RequestInspector = withInspection(maxlen) + azureClient.GalleryImagesClient.Client.ResponseInspector = byConcatDecorators(byInspecting(maxlen), errorCapture(azureClient)) + azureClient.GalleryImagesClient.Client.UserAgent = fmt.Sprintf("%s %s", useragent.String(version.AzurePluginVersion.FormattedVersion()), azureClient.GalleryImagesClient.Client.UserAgent) azureClient.GalleryImagesClient.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.ImagesClient = hashiImagesSDK.NewImagesClientWithBaseURI(*resourceManagerEndpoint) + azureClient.ImagesClient.Client.Authorizer = authWrapper.AutorestAuthorizer(resourceManagerAuthorizer) + azureClient.ImagesClient.Client.RequestInspector = withInspection(maxlen) + azureClient.ImagesClient.Client.ResponseInspector = byConcatDecorators(byInspecting(maxlen), errorCapture(azureClient)) + azureClient.ImagesClient.Client.UserAgent = fmt.Sprintf("%s %s", useragent.String(version.AzurePluginVersion.FormattedVersion()), azureClient.ImagesClient.Client.UserAgent) + azureClient.ImagesClient.Client.PollingDuration = PollingDuration + + networkMetaClient, err := hashiNetworkSDK.NewClientWithBaseURI(cloud.ResourceManager, func(c *resourcemanager.Client) { + c.Client.Authorizer = resourceManagerAuthorizer + c.Client.UserAgent = "some-user-agent" + }) - return azureClient, nil + if err != nil { + return nil, nil, err + } + azureClient.NetworkMetaClient = *networkMetaClient + token, err := resourceManagerAuthorizer.Token(ctx, &http.Request{}) + if err != nil { + return nil, nil, err + } + objectId, err := getObjectIdFromToken(token.AccessToken) + if err != nil { + return nil, nil, err + } + return azureClient, &objectId, nil +} + +const ( + AuthTypeDeviceLogin = "DeviceLogin" + AuthTypeMSI = "ManagedIdentity" + AuthTypeClientSecret = "ClientSecret" + AuthTypeClientCert = "ClientCertificate" + AuthTypeClientBearerJWT = "ClientBearerJWT" + AuthTypeAzureCLI = "AzureCLI" +) + +func buildResourceManagerAuthorizer(ctx context.Context, authOpts NewSDKAuthOptions, env environments.Environment) (auth.Authorizer, error) { + authorizer, err := buildAuthorizer(ctx, authOpts, env, env.ResourceManager) + if err != nil { + return nil, fmt.Errorf("building Resource Manager authorizer from credentials: %+v", err) + } + return authorizer, nil +} + +func buildStorageAuthorizer(ctx context.Context, authOpts NewSDKAuthOptions, env environments.Environment) (auth.Authorizer, error) { + authorizer, err := buildAuthorizer(ctx, authOpts, env, env.Storage) + if err != nil { + return nil, fmt.Errorf("building Storage authorizer from credentials: %+v", err) + } + return authorizer, nil +} + +func buildAuthorizer(ctx context.Context, authOpts NewSDKAuthOptions, env environments.Environment, api environments.Api) (auth.Authorizer, error) { + var authConfig auth.Credentials + switch authOpts.AuthType { + case AuthTypeDeviceLogin: + return nil, fmt.Errorf("DeviceLogin is not supported in v2 of the Azure Packer Plugin, however you can use the Azure CLI `az login --use-device-code` to use a device code, and then use CLI authentication") + case AuthTypeAzureCLI: + authConfig = auth.Credentials{ + Environment: env, + EnableAuthenticatingUsingAzureCLI: true, + } + case AuthTypeMSI: + authConfig = auth.Credentials{ + Environment: env, + EnableAuthenticatingUsingManagedIdentity: true, + } + case AuthTypeClientSecret: + authConfig = auth.Credentials{ + Environment: env, + EnableAuthenticatingUsingClientSecret: true, + ClientID: authOpts.ClientID, + ClientSecret: authOpts.ClientSecret, + TenantID: authOpts.TenantID, + } + case AuthTypeClientCert: + authConfig = auth.Credentials{ + Environment: env, + EnableAuthenticatingUsingClientCertificate: true, + ClientID: authOpts.ClientID, + ClientCertificatePath: authOpts.ClientCertPath, + ClientCertificatePassword: "", + } + case AuthTypeClientBearerJWT: + authConfig = auth.Credentials{ + Environment: env, + EnableAuthenticationUsingOIDC: true, + ClientID: authOpts.ClientID, + TenantID: authOpts.TenantID, + OIDCAssertionToken: authOpts.ClientJWT, + } + default: + panic("AuthType not set") + } + authorizer, err := auth.NewAuthorizerFromCredentials(ctx, authConfig, api) + if err != nil { + return nil, err + } + return authorizer, nil } +func getObjectIdFromToken(token string) (string, error) { + claims := jwt.MapClaims{} + var p jwt.Parser + var err error + + _, _, err = p.ParseUnverified(token, claims) + + if err != nil { + return "", err + } + return claims["oid"].(string), nil +} func getInspectorMaxLength() int64 { value, ok := os.LookupEnv(EnvPackerLogAzureMaxLen) if !ok { diff --git a/builder/azure/dtl/builder.go b/builder/azure/dtl/builder.go index e00301fe..38973e25 100644 --- a/builder/azure/dtl/builder.go +++ b/builder/azure/dtl/builder.go @@ -12,10 +12,11 @@ import ( "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/golang-jwt/jwt" + hashiGalleryImagesSDK "github.com/hashicorp/go-azure-sdk/resource-manager/compute/2022-03-03/galleryimages" + hashiDTLCustomImagesSDK "github.com/hashicorp/go-azure-sdk/resource-manager/devtestlab/2018-09-15/customimages" + hashiDTLLabsSDK "github.com/hashicorp/go-azure-sdk/resource-manager/devtestlab/2018-09-15/labs" + hashiDTLVNETSDK "github.com/hashicorp/go-azure-sdk/resource-manager/devtestlab/2018-09-15/virtualnetworks" "github.com/hashicorp/hcl/v2/hcldec" packerAzureCommon "github.com/hashicorp/packer-plugin-azure/builder/azure/common" "github.com/hashicorp/packer-plugin-azure/builder/azure/common/constants" @@ -71,20 +72,26 @@ func (b *Builder) Run(ctx context.Context, ui packersdk.Ui, hook packersdk.Hook) b.stateBag.Put("hook", hook) b.stateBag.Put(constants.Ui, ui) - spnCloud, err := b.getServicePrincipalToken(ui.Say) - if err != nil { - return nil, err + // Pass in relevant auth information for hashicorp/go-azure-sdk + authOptions := NewSDKAuthOptions{ + AuthType: b.config.ClientConfig.AuthType(), + ClientID: b.config.ClientConfig.ClientID, + ClientSecret: b.config.ClientConfig.ClientSecret, + ClientJWT: b.config.ClientConfig.ClientJWT, + ClientCertPath: b.config.ClientConfig.ClientCertPath, + TenantID: b.config.ClientConfig.TenantID, + SubscriptionID: b.config.ClientConfig.SubscriptionID, } - ui.Message("Creating Azure DevTestLab (DTL) client ...") - azureClient, err := NewAzureClient( + azureClient, objectId, err := NewAzureClient( + ctx, b.config.ClientConfig.SubscriptionID, b.config.LabResourceGroupName, - b.config.ClientConfig.CloudEnvironment(), + b.config.ClientConfig.NewCloudEnvironment(), b.config.SharedGalleryTimeout, b.config.CustomImageCaptureTimeout, b.config.PollingDurationTimeout, - spnCloud) + authOptions) if err != nil { return nil, err @@ -95,7 +102,7 @@ func (b *Builder) Run(ctx context.Context, ui packersdk.Ui, hook packersdk.Hook) return nil, err } if b.config.ClientConfig.ObjectID == "" { - b.config.ClientConfig.ObjectID = getObjectIdFromToken(ui, spnCloud) + b.config.ClientConfig.ObjectID = *objectId } else { ui.Message("You have provided Object_ID which is no longer needed, azure packer builder determines this dynamically from the authentication token") } @@ -106,15 +113,13 @@ func (b *Builder) Run(ctx context.Context, ui packersdk.Ui, hook packersdk.Hook) 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, "") + customImageResourceId := hashiDTLCustomImagesSDK.NewCustomImageID(b.config.ClientConfig.SubscriptionID, b.config.ManagedImageResourceGroupName, b.config.LabName, b.config.ManagedImageName) + _, err = azureClient.DtlMetaClient.CustomImages.Get(ctx, customImageResourceId, hashiDTLCustomImagesSDK.DefaultGetOperationOptions()) 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) - } + err := azureClient.DtlMetaClient.CustomImages.DeleteThenPoll(ctx, customImageResourceId) if err != nil { return nil, fmt.Errorf("failed to delete the managed image named %s : %s", b.config.ManagedImageName, azureClient.LastError.Error()) } @@ -136,12 +141,16 @@ func (b *Builder) Run(ctx context.Context, ui packersdk.Ui, hook packersdk.Hook) deploymentName := b.stateBag.Get(constants.ArmDeploymentName).(string) + b.stateBag.Put(constants.DtlLabName, b.config.LabName) // 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) + sigSubscriptionID := b.stateBag.Get(constants.ArmSubscription).(string) + galleryId := hashiGalleryImagesSDK.NewGalleryImageID(sigSubscriptionID, b.config.SharedGalleryDestination.SigDestinationResourceGroup, b.config.SharedGalleryDestination.SigDestinationGalleryName, b.config.SharedGalleryDestination.SigDestinationImageName) + _, err = azureClient.GalleryImagesClient.Get(ctx, galleryId) 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) + return nil, fmt.Errorf("the Shared Gallery Image '%s' to which to publish the managed image version to does not exist in the resource group '%s' or does not contain managed image '%s'", b.config.SharedGalleryDestination.SigDestinationGalleryName, b.config.SharedGalleryDestination.SigDestinationResourceGroup, b.config.SharedGalleryDestination.SigDestinationImageName) } + // SIG requires that replication regions include the region in which the Managed Image resides managedImageLocation := normalizeAzureRegion(b.stateBag.Get(constants.ArmLocation).(string)) foundMandatoryReplicationRegion := false @@ -162,12 +171,15 @@ func (b *Builder) Run(ctx context.Context, ui packersdk.Ui, hook packersdk.Hook) } // Find the lab location - lab, err := azureClient.DtlLabsClient.Get(ctx, b.config.LabResourceGroupName, b.config.LabName, "") + labResourceId := hashiDTLLabsSDK.NewLabID(b.config.ClientConfig.SubscriptionID, b.config.LabResourceGroupName, b.config.LabName) + lab, err := azureClient.DtlMetaClient.Labs.Get(ctx, labResourceId, hashiDTLLabsSDK.DefaultGetOperationOptions()) if err != nil { return nil, fmt.Errorf("Unable to fetch the Lab %s information in %s resource group", b.config.LabName, b.config.LabResourceGroupName) } + if lab.Model == nil { - b.config.Location = *lab.Location + } + b.config.Location = *lab.Model.Location if b.config.LabVirtualNetworkName == "" || b.config.LabSubnetName == "" { virtualNetwork, subnet, err := b.getSubnetInformation(ctx, ui, *azureClient) @@ -290,6 +302,8 @@ func (b *Builder) writeSSHPrivateKey(ui packersdk.Ui, debugKeyPath string) { 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.ArmNewSDKTags, b.config.AzureTags) stateBag.Put(constants.ArmTags, b.config.AzureTags) stateBag.Put(constants.ArmComputeName, b.config.tmpComputeName) stateBag.Put(constants.ArmDeploymentName, b.config.tmpDeploymentName) @@ -313,6 +327,7 @@ func (b *Builder) configureStateBag(stateBag multistep.StateBag) { stateBag.Put(constants.ArmManagedImageSharedGalleryImageVersion, b.config.SharedGalleryDestination.SigDestinationImageVersion) stateBag.Put(constants.ArmManagedImageSubscription, b.config.ClientConfig.SubscriptionID) } + stateBag.Put(constants.ArmSubscription, b.config.ClientConfig.SubscriptionID) } // Parameters that are only known at runtime after querying Azure. @@ -329,18 +344,20 @@ func (b *Builder) getServicePrincipalToken(say func(string)) (*adal.ServicePrinc } 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, "") + num := int64(10) + labResourceId := hashiDTLVNETSDK.NewLabID(b.config.ClientConfig.SubscriptionID, b.config.LabResourceGroupName, b.config.LabName) + virtualNetworkPage, err := azClient.DtlMetaClient.VirtualNetworks.List(ctx, labResourceId, hashiDTLVNETSDK.ListOperationOptions{Top: &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 { + virtualNetworks := virtualNetworkPage.Model + for _, virtualNetwork := range *virtualNetworks { + for _, subnetOverride := range *virtualNetwork.Properties.SubnetOverrides { + // Check if the Subnet is allowed to create VMs having Public IP - if subnetOverride.UseInVMCreationPermission == dtl.Allow && subnetOverride.UsePublicIPAddressPermission == dtl.Allow { + if *subnetOverride.UseInVMCreationPermission == hashiDTLVNETSDK.UsagePermissionTypeAllow && *subnetOverride.UsePublicIPAddressPermission == hashiDTLVNETSDK.UsagePermissionTypeAllow { // 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. @@ -351,22 +368,6 @@ func (b *Builder) getSubnetInformation(ctx context.Context, ui packersdk.Ui, azC 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/config.go b/builder/azure/dtl/config.go index bf0cf8ba..c56f305a 100644 --- a/builder/azure/dtl/config.go +++ b/builder/azure/dtl/config.go @@ -218,7 +218,7 @@ type Config struct { // 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. - AzureTags map[string]*string `mapstructure:"azure_tags" required:"false"` + AzureTags map[string]string `mapstructure:"azure_tags" required:"false"` // Used for creating images from Marketplace images. Please refer to // [Deploy an image with Marketplace @@ -575,8 +575,8 @@ func assertTagProperties(c *Config, errs *packersdk.MultiError) { 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))) + if len(v) > 256 { + errs = packersdk.MultiErrorAppend(errs, fmt.Errorf("the tag name %q exceeds (%d) the 256 character limit", v, len(v))) } } } diff --git a/builder/azure/dtl/config_test.go b/builder/azure/dtl/config_test.go index 49a69613..f8cf79ab 100644 --- a/builder/azure/dtl/config_test.go +++ b/builder/azure/dtl/config_test.go @@ -266,13 +266,13 @@ func TestConfigShouldAcceptTags(t *testing.T) { } value := config.AzureTags["tag01"] - if *value != "value01" { - t.Errorf("expected AzureTags[\"tag01\"] to have value \"value01\", but got %q", *value) + if value != "value01" { + t.Errorf("expected AzureTags[\"tag01\"] to have value \"value01\", but got %q", value) } value = config.AzureTags["tag02"] - if *value != "value02" { - t.Errorf("expected AzureTags[\"tag02\"] to have value \"value02\", but got %q", *value) + if value != "value02" { + t.Errorf("expected AzureTags[\"tag02\"] to have value \"value02\", but got %q", value) } } diff --git a/builder/azure/dtl/resource_resolver.go b/builder/azure/dtl/resource_resolver.go index 46c56a86..199879ed 100644 --- a/builder/azure/dtl/resource_resolver.go +++ b/builder/azure/dtl/resource_resolver.go @@ -16,7 +16,8 @@ import ( "fmt" "strings" - "github.com/Azure/azure-sdk-for-go/services/compute/mgmt/2018-04-01/compute" + "github.com/hashicorp/go-azure-helpers/resourcemanager/commonids" + hashiImagesSDK "github.com/hashicorp/go-azure-sdk/resource-manager/compute/2022-03-01/images" ) type resourceResolver struct { @@ -27,44 +28,23 @@ type resourceResolver struct { func newResourceResolver(client *AzureClient) *resourceResolver { return &resourceResolver{ - client: client, - findVirtualNetworkResourceGroup: findVirtualNetworkResourceGroup, - findVirtualNetworkSubnet: findVirtualNetworkSubnet, + client: client, } } 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) + image, err := findManagedImageByName(s.client, c.ClientConfig.SubscriptionID, c.CustomManagedImageName, c.CustomManagedImageResourceGroupName) if err != nil { return err } - c.customManagedImageID = *image.ID + 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 != "" } @@ -75,70 +55,18 @@ func getResourceGroupNameFromId(id string) string { return xs[4] } -func findManagedImageByName(client *AzureClient, name, resourceGroupName string) (*compute.Image, error) { - images, err := client.ImagesClient.ListByResourceGroupComplete(context.TODO(), resourceGroupName) +func findManagedImageByName(client *AzureClient, name, subscriptionId, resourceGroupName string) (*hashiImagesSDK.Image, error) { + id := commonids.NewResourceGroupID(subscriptionId, resourceGroupName) + images, err := client.ImagesClient.ListByResourceGroupComplete(context.TODO(), id) if err != nil { return nil, err } - for images.NotDone() { - image := images.Value() + for _, image := range images.Items { 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_capture_image.go b/builder/azure/dtl/step_capture_image.go index 4272410b..a0c8939d 100644 --- a/builder/azure/dtl/step_capture_image.go +++ b/builder/azure/dtl/step_capture_image.go @@ -7,8 +7,7 @@ import ( "context" "fmt" - "github.com/Azure/azure-sdk-for-go/services/devtestlabs/mgmt/2018-09-15/dtl" - + hashiDTLCustomImagesSDK "github.com/hashicorp/go-azure-sdk/resource-manager/devtestlab/2018-09-15/customimages" "github.com/hashicorp/packer-plugin-azure/builder/azure/common/constants" "github.com/hashicorp/packer-plugin-sdk/multistep" packersdk "github.com/hashicorp/packer-plugin-sdk/packer" @@ -26,9 +25,6 @@ type StepCaptureImage struct { 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) @@ -51,46 +47,43 @@ func (s *StepCaptureImage) captureImageFromVM(ctx context.Context) error { s.config.LabName, s.config.tmpComputeName) - customImageProperties := dtl.CustomImageProperties{} + customImageProperties := hashiDTLCustomImagesSDK.CustomImageProperties{} if s.config.OSType == constants.Target_Linux { - deprovision := dtl.DeprovisionRequested + deprovision := hashiDTLCustomImagesSDK.LinuxOsStateDeprovisionRequested if s.config.SkipSysprep { - deprovision = dtl.DeprovisionApplied + deprovision = hashiDTLCustomImagesSDK.LinuxOsStateDeprovisionApplied } - customImageProperties = dtl.CustomImageProperties{ - VM: &dtl.CustomImagePropertiesFromVM{ - LinuxOsInfo: &dtl.LinuxOsInfo{ - LinuxOsState: deprovision, + customImageProperties = hashiDTLCustomImagesSDK.CustomImageProperties{ + VM: &hashiDTLCustomImagesSDK.CustomImagePropertiesFromVM{ + LinuxOsInfo: &hashiDTLCustomImagesSDK.LinuxOsInfo{ + LinuxOsState: &deprovision, }, - SourceVMID: &imageID, + SourceVMId: &imageID, }, } } else if s.config.OSType == constants.Target_Windows { - deprovision := dtl.SysprepRequested + deprovision := hashiDTLCustomImagesSDK.WindowsOsStateSysprepRequested if s.config.SkipSysprep { - deprovision = dtl.SysprepApplied + deprovision = hashiDTLCustomImagesSDK.WindowsOsStateSysprepApplied } - customImageProperties = dtl.CustomImageProperties{ - VM: &dtl.CustomImagePropertiesFromVM{ - WindowsOsInfo: &dtl.WindowsOsInfo{ - WindowsOsState: deprovision, + customImageProperties = hashiDTLCustomImagesSDK.CustomImageProperties{ + VM: &hashiDTLCustomImagesSDK.CustomImagePropertiesFromVM{ + WindowsOsInfo: &hashiDTLCustomImagesSDK.WindowsOsInfo{ + WindowsOsState: &deprovision, }, - SourceVMID: &imageID, + SourceVMId: &imageID, }, } } - customImage := &dtl.CustomImage{ - Name: &s.config.ManagedImageName, - CustomImageProperties: &customImageProperties, + customImage := &hashiDTLCustomImagesSDK.CustomImage{ + Name: &s.config.ManagedImageName, + Properties: customImageProperties, } - f, err := s.client.DtlCustomImageClient.CreateOrUpdate(ctx, s.config.LabResourceGroupName, s.config.LabName, s.config.ManagedImageName, *customImage) - if err == nil { - s.say("Waiting for Capture Image to complete") - err = f.WaitForCompletionRef(ctx, s.client.DtlCustomImageClient.Client) - } + customImageId := hashiDTLCustomImagesSDK.NewCustomImageID(s.config.ClientConfig.SubscriptionID, s.config.LabResourceGroupName, s.config.LabName, s.config.ManagedImageName) + err := s.client.DtlMetaClient.CustomImages.CreateOrUpdateThenPoll(ctx, customImageId, *customImage) if err != nil { s.say("Error from Capture Image") s.say(s.client.LastError.Error()) diff --git a/builder/azure/dtl/step_delete_virtual_machine.go b/builder/azure/dtl/step_delete_virtual_machine.go index 44bc24c0..8f809e03 100644 --- a/builder/azure/dtl/step_delete_virtual_machine.go +++ b/builder/azure/dtl/step_delete_virtual_machine.go @@ -7,6 +7,7 @@ import ( "context" "fmt" + hashiDTLVMSDK "github.com/hashicorp/go-azure-sdk/resource-manager/devtestlab/2018-09-15/virtualmachines" "github.com/hashicorp/packer-plugin-azure/builder/azure/common/constants" "github.com/hashicorp/packer-plugin-sdk/multistep" packersdk "github.com/hashicorp/packer-plugin-sdk/packer" @@ -15,7 +16,7 @@ import ( type StepDeleteVirtualMachine struct { client *AzureClient config *Config - delete func(ctx context.Context, resourceGroupName string, computeName string, state multistep.StateBag) error + delete func(ctx context.Context, resourceGroupName string, subscriptionId string, labName string, computeName string) error say func(message string) error func(e error) } @@ -32,11 +33,9 @@ func NewStepDeleteVirtualMachine(client *AzureClient, ui packersdk.Ui, config *C 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) - } +func (s *StepDeleteVirtualMachine) deleteVirtualMachine(ctx context.Context, subscriptionId string, labName string, resourceGroupName string, vmName string) error { + vmId := hashiDTLVMSDK.NewVirtualMachineID(subscriptionId, resourceGroupName, labName, vmName) + err := s.client.DtlMetaClient.VirtualMachines.DeleteThenPoll(ctx, vmId) if err != nil { s.say("Error from delete VM") s.say(s.client.LastError.Error()) @@ -50,11 +49,14 @@ func (s *StepDeleteVirtualMachine) Run(ctx context.Context, state multistep.Stat var resourceGroupName = state.Get(constants.ArmResourceGroupName).(string) var computeName = state.Get(constants.ArmComputeName).(string) + var dtlLabName = state.Get(constants.DtlLabName).(string) + var subscriptionId = state.Get(constants.ArmSubscription).(string) s.say(fmt.Sprintf(" -> ResourceGroupName : '%s'", resourceGroupName)) + s.say(fmt.Sprintf(" -> ComputeName : '%s'", computeName)) - err := s.deleteVirtualMachine(ctx, resourceGroupName, computeName, state) + err := s.deleteVirtualMachine(ctx, subscriptionId, dtlLabName, resourceGroupName, computeName) s.say("Deleting virtual machine ...Complete") return processStepResult(err, s.error, state) diff --git a/builder/azure/dtl/step_deploy_template.go b/builder/azure/dtl/step_deploy_template.go index ef8407fb..f5e03fa7 100644 --- a/builder/azure/dtl/step_deploy_template.go +++ b/builder/azure/dtl/step_deploy_template.go @@ -11,7 +11,15 @@ import ( "strings" "time" - "github.com/Azure/azure-sdk-for-go/services/devtestlabs/mgmt/2018-09-15/dtl" + "github.com/hashicorp/go-azure-helpers/resourcemanager/commonids" + hashiNetworkSecurityGroupsSDK "github.com/hashicorp/go-azure-sdk/resource-manager/network/2022-09-01/networksecuritygroups" + hashiVirtualNetworksSDK "github.com/hashicorp/go-azure-sdk/resource-manager/network/2022-09-01/virtualnetworks" + hashiDeploymentOperationsSDK "github.com/hashicorp/go-azure-sdk/resource-manager/resources/2022-09-01/deploymentoperations" + hashiDeploymentsSDK "github.com/hashicorp/go-azure-sdk/resource-manager/resources/2022-09-01/deployments" + + hashiLabsSDK "github.com/hashicorp/go-azure-sdk/resource-manager/devtestlab/2018-09-15/labs" + hashiDTLVMSDK "github.com/hashicorp/go-azure-sdk/resource-manager/devtestlab/2018-09-15/virtualmachines" + "github.com/hashicorp/go-azure-sdk/resource-manager/network/2022-09-01/networkinterfaces" "github.com/hashicorp/packer-plugin-azure/builder/azure/common/constants" "github.com/hashicorp/packer-plugin-sdk/multistep" packersdk "github.com/hashicorp/packer-plugin-sdk/packer" @@ -49,16 +57,19 @@ func NewStepDeployTemplate(client *AzureClient, ui packersdk.Ui, config *Config, 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, "") + subscriptionId := s.config.ClientConfig.SubscriptionID + labName := s.config.LabName + labResourceId := hashiDTLVMSDK.NewLabID(subscriptionId, resourceGroupName, labName) + vmlistPage, err := s.client.DtlMetaClient.VirtualMachines.List(ctx, labResourceId, hashiDTLVMSDK.DefaultListOperationOptions()) 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 { + vmList := vmlistPage.Model + for _, vm := range *vmList { + if *vm.Name == s.config.tmpComputeName { return fmt.Errorf("Error: Virtual Machine %s already exists. Please use another name", s.config.tmpComputeName) } } @@ -69,17 +80,16 @@ func (s *StepDeployTemplate) deployTemplate(ctx context.Context, resourceGroupNa 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) - } + labId := hashiLabsSDK.NewLabID(subscriptionId, s.config.tmpResourceGroupName, labName) + err = s.client.DtlMetaClient.Labs.CreateEnvironmentThenPoll(ctx, labId, *labMachine) 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) + vmResourceId := hashiDTLVMSDK.NewVirtualMachineID(subscriptionId, s.config.tmpResourceGroupName, labName, s.config.tmpComputeName) + vm, err := s.client.DtlMetaClient.VirtualMachines.Get(ctx, vmResourceId, hashiDTLVMSDK.GetOperationOptions{Expand: &expand}) if err != nil { s.say(s.client.LastError.Error()) } @@ -87,14 +97,16 @@ func (s *StepDeployTemplate) deployTemplate(ctx context.Context, resourceGroupNa // set tmpFQDN to the PrivateIP or to the real FQDN depending on // publicIP being allowed or not if s.config.DisallowPublicIP { - resp, err := s.client.InterfacesClient.Get(ctx, s.config.tmpResourceGroupName, s.config.tmpNicName, "") + interfaceID := commonids.NewNetworkInterfaceID(subscriptionId, resourceGroupName, s.config.tmpNicName) + resp, err := s.client.NetworkMetaClient.NetworkInterfaces.Get(ctx, interfaceID, networkinterfaces.DefaultGetOperationOptions()) if err != nil { s.say(s.client.LastError.Error()) return err } - s.config.tmpFQDN = *(*resp.IPConfigurations)[0].PrivateIPAddress + // TODO This operation seems kinda off, but I don't wanna spend time digging into it right now + s.config.tmpFQDN = *(*resp.Model.Properties.IPConfigurations)[0].Properties.PrivateIPAddress } else { - s.config.tmpFQDN = *vm.Fqdn + s.config.tmpFQDN = *vm.Model.Properties.Fqdn } s.say(fmt.Sprintf(" -> VM FQDN/IP : '%s'", s.config.tmpFQDN)) state.Put(constants.SSHHost, s.config.tmpFQDN) @@ -111,39 +123,31 @@ func (s *StepDeployTemplate) deployTemplate(ctx context.Context, resourceGroupNa winrma) var hostname = "hostName" - dp := &dtl.ArtifactParameterProperties{} + dp := &hashiDTLVMSDK.ArtifactParameterProperties{} dp.Name = &hostname dp.Value = &s.config.tmpFQDN - dparams := []dtl.ArtifactParameterProperties{*dp} + dparams := []hashiDTLVMSDK.ArtifactParameterProperties{*dp} - winrmArtifact := &dtl.ArtifactInstallProperties{ + winrmArtifact := &hashiDTLVMSDK.ArtifactInstallProperties{ ArtifactTitle: &winrma, - ArtifactID: &artifactid, + ArtifactId: &artifactid, Parameters: &dparams, } - dtlArtifacts := []dtl.ArtifactInstallProperties{*winrmArtifact} - dtlArtifactsRequest := dtl.ApplyArtifactsRequest{Artifacts: &dtlArtifacts} + dtlArtifacts := []hashiDTLVMSDK.ArtifactInstallProperties{*winrmArtifact} + dtlArtifactsRequest := hashiDTLVMSDK.ApplyArtifactsRequest{Artifacts: &dtlArtifacts} - // infinite loop until the artifacts have been applied + // TODO replaced infinite loop with one time try, this should not fail imo, maybe they were actually running into failures after polling? for { - f, err := s.client.DtlVirtualMachineClient.ApplyArtifacts(ctx, s.config.tmpResourceGroupName, s.config.LabName, s.config.tmpComputeName, dtlArtifactsRequest) - if err == nil { - s.say("WinRM artifact deployment started, waiting for completion") - err = f.WaitForCompletionRef(ctx, s.client.DtlVirtualMachineClient.Client) - if err != nil { - s.say(s.client.LastError.Error()) - return err - } - break - } else { + err := s.client.DtlMetaClient.VirtualMachines.ApplyArtifactsThenPoll(ctx, vmResourceId, dtlArtifactsRequest) + if err != nil { s.say("WinRM artifact deployment failed, sleeping a minute and retrying") time.Sleep(60 * time.Second) } } } - xs := strings.Split(*vm.LabVirtualMachineProperties.ComputeID, "/") + xs := strings.Split(*vm.Model.Properties.ComputeId, "/") s.config.VMCreationResourceGroup = xs[4] // Resuing the Resource group name from common constants as all steps depend on it. @@ -185,7 +189,7 @@ func (s *StepDeployTemplate) getImageDetails(ctx context.Context, resourceGroupN return imageType, imageName, nil } -func deleteResource(ctx context.Context, client *AzureClient, resourceType string, resourceName string, resourceGroupName string) error { +func deleteResource(ctx context.Context, client *AzureClient, subscriptionId string, resourceType string, resourceName string, resourceGroupName string) error { switch resourceType { case "Microsoft.Compute/virtualMachines": f, err := client.VirtualMachinesClient.Delete(ctx, resourceGroupName, resourceName) @@ -193,53 +197,54 @@ func deleteResource(ctx context.Context, client *AzureClient, resourceType strin err = f.WaitForCompletionRef(ctx, client.VirtualMachinesClient.Client) } return err + case "Microsoft.KeyVault/vaults": + id := commonids.NewKeyVaultID(subscriptionId, resourceGroupName, resourceName) + _, err := client.VaultsClient.Delete(ctx, id) + return err case "Microsoft.Network/networkInterfaces": - f, err := client.InterfacesClient.Delete(ctx, resourceGroupName, resourceName) - if err == nil { - err = f.WaitForCompletionRef(ctx, client.InterfacesClient.Client) - } + interfaceID := commonids.NewNetworkInterfaceID(subscriptionId, resourceGroupName, resourceName) + err := client.NetworkMetaClient.NetworkInterfaces.DeleteThenPoll(ctx, interfaceID) return err case "Microsoft.Network/virtualNetworks": - f, err := client.VirtualNetworksClient.Delete(ctx, resourceGroupName, resourceName) - if err == nil { - err = f.WaitForCompletionRef(ctx, client.VirtualNetworksClient.Client) - } + vnetID := hashiVirtualNetworksSDK.NewVirtualNetworkID(subscriptionId, resourceGroupName, resourceName) + err := client.NetworkMetaClient.VirtualNetworks.DeleteThenPoll(ctx, vnetID) + return err + case "Microsoft.Network/networkSecurityGroups": + secGroupId := hashiNetworkSecurityGroupsSDK.NewNetworkSecurityGroupID(subscriptionId, resourceGroupName, resourceName) + err := client.NetworkMetaClient.NetworkSecurityGroups.DeleteThenPoll(ctx, secGroupId) return err case "Microsoft.Network/publicIPAddresses": - f, err := client.PublicIPAddressesClient.Delete(ctx, resourceGroupName, resourceName) - if err == nil { - err = f.WaitForCompletionRef(ctx, client.PublicIPAddressesClient.Client) - } + ipID := commonids.NewPublicIPAddressID(subscriptionId, resourceGroupName, resourceName) + err := client.NetworkMetaClient.PublicIPAddresses.DeleteThenPoll(ctx, ipID) return err } return nil } -func (s *StepDeployTemplate) deleteImage(ctx context.Context, imageType string, imageName string, resourceGroupName string) error { +func (s *StepDeployTemplate) deleteImage(ctx context.Context, imageName string, resourceGroupName string, isManagedDisk bool, subscriptionId string, storageAccountName string) error { // Managed disk - if imageType == "Microsoft.Compute/disks" { + if isManagedDisk { 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) + diskId := hashiDisksSDK.NewDiskID(subscriptionId, resourceGroupName, diskName) + + if err := s.client.DisksClient.DeleteThenPoll(ctx, diskId); err != nil { + return err } - return err + return nil } + // VHD image u, err := url.Parse(imageName) if err != nil { return err } xs := strings.Split(u.Path, "/") + var blobName = strings.Join(xs[2:], "/") 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) + _, err = s.client.GiovanniBlobClient.Delete(ctx, storageAccountName, "images", blobName, giovanniBlobStorageSDK.DeleteInput{}) return err } diff --git a/builder/azure/dtl/step_power_off_compute.go b/builder/azure/dtl/step_power_off_compute.go index b72b11ae..497824d6 100644 --- a/builder/azure/dtl/step_power_off_compute.go +++ b/builder/azure/dtl/step_power_off_compute.go @@ -7,6 +7,7 @@ import ( "context" "fmt" + hashiDTLVMSDK "github.com/hashicorp/go-azure-sdk/resource-manager/devtestlab/2018-09-15/virtualmachines" "github.com/hashicorp/packer-plugin-azure/builder/azure/common/constants" "github.com/hashicorp/packer-plugin-sdk/multistep" packersdk "github.com/hashicorp/packer-plugin-sdk/packer" @@ -35,10 +36,8 @@ func NewStepPowerOffCompute(client *AzureClient, ui packersdk.Ui, config *Config 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) - } + vmResourceId := hashiDTLVMSDK.NewVirtualMachineID(s.config.ClientConfig.SubscriptionID, s.config.tmpResourceGroupName, labName, computeName) + err := s.client.DtlMetaClient.VirtualMachines.StopThenPoll(ctx, vmResourceId) if err != nil { s.say(s.client.LastError.Error()) } diff --git a/builder/azure/dtl/step_publish_to_shared_image_gallery.go b/builder/azure/dtl/step_publish_to_shared_image_gallery.go index 2c08e1bf..41450773 100644 --- a/builder/azure/dtl/step_publish_to_shared_image_gallery.go +++ b/builder/azure/dtl/step_publish_to_shared_image_gallery.go @@ -7,7 +7,7 @@ import ( "context" "fmt" - "github.com/Azure/azure-sdk-for-go/services/compute/mgmt/2019-03-01/compute" + hashiGalleryImageVersionsSDK "github.com/hashicorp/go-azure-sdk/resource-manager/compute/2022-03-03/galleryimageversions" "github.com/hashicorp/packer-plugin-azure/builder/azure/common/constants" "github.com/hashicorp/packer-plugin-sdk/multistep" packersdk "github.com/hashicorp/packer-plugin-sdk/packer" @@ -15,7 +15,7 @@ import ( 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) + publish func(ctx context.Context, subscriptionID, managedImageID, sigDestinationResourceGroup, sigDestinationGalleryName, sigDestinationImageName, sigDestinationImageVersion string, sigReplicationRegions []string, location string, tags map[string]string) (string, error) say func(message string) error func(e error) toSIG func() bool @@ -39,52 +39,45 @@ func NewStepPublishToSharedImageGallery(client *AzureClient, ui packersdk.Ui, co 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) { +func (s *StepPublishToSharedImageGallery) publishToSig(ctx context.Context, subscriptionID, managedImageID, sigDestinationResourceGroup, sigDestinationGalleryName, sigDestinationImageName, sigDestinationImageVersion string, sigReplicationRegions []string, location string, tags map[string]string) (string, error) { - replicationRegions := make([]compute.TargetRegion, len(miSigReplicationRegions)) - for i, v := range miSigReplicationRegions { + replicationRegions := make([]hashiGalleryImageVersionsSDK.TargetRegion, len(sigReplicationRegions)) + for i, v := range sigReplicationRegions { regionName := v - replicationRegions[i] = compute.TargetRegion{Name: ®ionName} + replicationRegions[i] = hashiGalleryImageVersionsSDK.TargetRegion{Name: regionName} } - galleryImageVersion := compute.GalleryImageVersion{ - Location: &location, - Tags: tags, - GalleryImageVersionProperties: &compute.GalleryImageVersionProperties{ - PublishingProfile: &compute.GalleryImageVersionPublishingProfile{ - Source: &compute.GalleryArtifactSource{ - ManagedImage: &compute.ManagedArtifact{ - ID: &mdiID, - }, + galleryImageVersion := hashiGalleryImageVersionsSDK.GalleryImageVersion{ + Location: location, + Tags: &tags, + Properties: &hashiGalleryImageVersionsSDK.GalleryImageVersionProperties{ + StorageProfile: hashiGalleryImageVersionsSDK.GalleryImageVersionStorageProfile{ + Source: &hashiGalleryImageVersionsSDK.GalleryArtifactVersionFullSource{ + Id: &managedImageID, }, + }, + PublishingProfile: &hashiGalleryImageVersionsSDK.GalleryArtifactPublishingProfileBase{ 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) + galleryImageVersionId := hashiGalleryImageVersionsSDK.NewImageVersionID(subscriptionID, sigDestinationResourceGroup, sigDestinationGalleryName, sigDestinationImageName, sigDestinationImageVersion) + err := s.client.GalleryImageVersionsClient.CreateOrUpdateThenPoll(ctx, galleryImageVersionId, galleryImageVersion) if err != nil { s.say(s.client.LastError.Error()) return "", err } - - createdSGImageVersion, err := f.Result(s.client.GalleryImageVersionsClient) + createdSIGImageVersion, err := s.client.GalleryImageVersionsClient.Get(ctx, galleryImageVersionId, hashiGalleryImageVersionsSDK.DefaultGetOperationOptions()) 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 + s.say(fmt.Sprintf(" -> Shared Gallery Image Version ID : '%s'", *(createdSIGImageVersion.Model.Id))) + return *(createdSIGImageVersion.Model.Id), nil } func (s *StepPublishToSharedImageGallery) Run(ctx context.Context, stateBag multistep.StateBag) multistep.StepAction { @@ -99,20 +92,20 @@ func (s *StepPublishToSharedImageGallery) Run(ctx context.Context, stateBag mult 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 tags = stateBag.Get(constants.ArmNewSDKTags).(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) + var managedImageID = 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(" -> MDI ID used for SIG publish : '%s'", managedImageID)) 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) + createdGalleryImageVersionID, err := s.publish(ctx, managedImageSubscription, managedImageID, miSigPubRg, miSIGalleryName, miSGImageName, miSGImageVersion, miSigReplicationRegions, location, tags) if err != nil { stateBag.Put(constants.Error, err) diff --git a/builder/azure/dtl/template_factory.go b/builder/azure/dtl/template_factory.go index c0c96f3e..6fe6dd0c 100644 --- a/builder/azure/dtl/template_factory.go +++ b/builder/azure/dtl/template_factory.go @@ -6,10 +6,10 @@ package dtl import ( "fmt" - "github.com/Azure/azure-sdk-for-go/services/devtestlabs/mgmt/2018-09-15/dtl" + hashiDTLLabsSDK "github.com/hashicorp/go-azure-sdk/resource-manager/devtestlab/2018-09-15/labs" ) -type templateFactoryFuncDtl func(*Config) (*dtl.LabVirtualMachineCreationParameter, error) +type templateFactoryFuncDtl func(*Config) (*hashiDTLLabsSDK.LabVirtualMachineCreationParameter, error) func newBool(val bool) *bool { b := true @@ -32,9 +32,9 @@ func getCustomImageId(config *Config) *string { return nil } -func GetVirtualMachineDeployment(config *Config) (*dtl.LabVirtualMachineCreationParameter, error) { +func GetVirtualMachineDeployment(config *Config) (*hashiDTLLabsSDK.LabVirtualMachineCreationParameter, error) { - galleryImageRef := dtl.GalleryImageReference{ + galleryImageRef := hashiDTLLabsSDK.GalleryImageReference{ Offer: &config.ImageOffer, Publisher: &config.ImagePublisher, Sku: &config.ImageSku, @@ -48,7 +48,7 @@ func GetVirtualMachineDeployment(config *Config) (*dtl.LabVirtualMachineCreation config.LabName, config.LabVirtualNetworkName) - dtlArtifacts := []dtl.ArtifactInstallProperties{} + dtlArtifacts := []hashiDTLLabsSDK.ArtifactInstallProperties{} if config.DtlArtifacts != nil { for i := range config.DtlArtifacts { @@ -62,51 +62,50 @@ func GetVirtualMachineDeployment(config *Config) (*dtl.LabVirtualMachineCreation config.DtlArtifacts[i].RepositoryName, config.DtlArtifacts[i].ArtifactName) - dparams := []dtl.ArtifactParameterProperties{} + dparams := []hashiDTLLabsSDK.ArtifactParameterProperties{} for j := range config.DtlArtifacts[i].Parameters { - dp := &dtl.ArtifactParameterProperties{} + dp := &hashiDTLLabsSDK.ArtifactParameterProperties{} dp.Name = &config.DtlArtifacts[i].Parameters[j].Name dp.Value = &config.DtlArtifacts[i].Parameters[j].Value dparams = append(dparams, *dp) } - dtlArtifact := &dtl.ArtifactInstallProperties{ + dtlArtifact := &hashiDTLLabsSDK.ArtifactInstallProperties{ ArtifactTitle: &config.DtlArtifacts[i].ArtifactName, - ArtifactID: &config.DtlArtifacts[i].ArtifactId, + ArtifactId: &config.DtlArtifacts[i].ArtifactId, Parameters: &dparams, } dtlArtifacts = append(dtlArtifacts, *dtlArtifact) } } - labMachineProps := &dtl.LabVirtualMachineCreationParameterProperties{ - CreatedByUserID: &config.ClientConfig.ClientID, - OwnerObjectID: &config.ClientConfig.ObjectID, - OsType: &config.OSType, + labMachineProps := &hashiDTLLabsSDK.LabVirtualMachineCreationParameterProperties{ + OwnerUserPrincipalName: &config.ClientConfig.ClientID, + OwnerObjectId: &config.ClientConfig.ObjectID, Size: &config.VMSize, UserName: &config.UserName, Password: &config.Password, - SSHKey: &config.sshAuthorizedKey, - IsAuthenticationWithSSHKey: newBool(true), + SshKey: &config.sshAuthorizedKey, + IsAuthenticationWithSshKey: newBool(true), LabSubnetName: &config.LabSubnetName, - LabVirtualNetworkID: &labVirtualNetworkID, + LabVirtualNetworkId: &labVirtualNetworkID, DisallowPublicIPAddress: &config.DisallowPublicIP, GalleryImageReference: &galleryImageRef, - CustomImageID: getCustomImageId(config), - PlanID: &config.PlanID, + CustomImageId: getCustomImageId(config), + PlanId: &config.PlanID, - AllowClaim: newBool(false), - StorageType: &config.StorageType, - VirtualMachineCreationSource: dtl.FromGalleryImage, - Artifacts: &dtlArtifacts, + AllowClaim: newBool(false), + StorageType: &config.StorageType, + Artifacts: &dtlArtifacts, } - labMachine := &dtl.LabVirtualMachineCreationParameter{ + labMachine := &hashiDTLLabsSDK.LabVirtualMachineCreationParameter{ Name: &config.tmpComputeName, Location: &config.Location, - Tags: config.AzureTags, - LabVirtualMachineCreationParameterProperties: labMachineProps, + // TODO + //Tags: config.AzureTags, + Properties: labMachineProps, } return labMachine, nil diff --git a/go.mod b/go.mod index 7374eb2a..91bb8c99 100644 --- a/go.mod +++ b/go.mod @@ -11,7 +11,6 @@ require ( github.com/Azure/go-autorest/autorest/date v0.3.0 // indirect github.com/Azure/go-autorest/autorest/to v0.4.0 github.com/approvals/go-approval-tests v0.0.0-20210131072903-38d0b0ec12b1 - github.com/dnaeon/go-vcr v1.1.0 // indirect github.com/golang-jwt/jwt v3.2.2+incompatible github.com/google/go-cmp v0.5.9 github.com/hashicorp/go-azure-helpers v0.56.0 diff --git a/go.sum b/go.sum index 1144e0dc..41434e13 100644 --- a/go.sum +++ b/go.sum @@ -133,8 +133,6 @@ github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZm github.com/dimchansky/utfbom v1.1.0/go.mod h1:rO41eb7gLfo8SF1jd9F8HplJm1Fewwi4mQvIirEdv+8= 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.1.0 h1:ReYa/UBrRyQdant9B4fNHGoCNKw6qh6P0fsdGmZpR7c= -github.com/dnaeon/go-vcr v1.1.0/go.mod h1:M7tiix8f0r6mKKJ3Yq/kqU1OYf3MnfmBWVbPx/yU9ko= github.com/docker/distribution v2.7.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= github.com/docker/docker v1.4.2-0.20200319182547-c7ad2b866182/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec= @@ -413,7 +411,6 @@ github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJ 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/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= -github.com/modocache/gover v0.0.0-20171022184752-b58185e213c5/go.mod h1:caMODM3PzxT8aQXRPkAt8xlV/e7d7w8GM5g0fa5F0D8= github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc= github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/nu7hatch/gouuid v0.0.0-20131221200532-179d4d0c4d8d h1:VhgPp6v9qf9Agr/56bj7Y/xa04UccTW04VP0Qed4vnQ= From e0ca2555a3c8cf79127c3350eb3d96894bfc1e18 Mon Sep 17 00:00:00 2001 From: Jenna Goldstrich Date: Thu, 6 Jul 2023 20:04:11 -0700 Subject: [PATCH 02/10] DTL almost done! Just need to get VMID instead of capture template method and start testing --- builder/azure/arm/step_deploy_template.go | 1 - builder/azure/dtl/azure_client.go | 15 +++++++ builder/azure/dtl/step_deploy_template.go | 54 ++++++++++++++--------- go.sum | 4 ++ 4 files changed, 52 insertions(+), 22 deletions(-) diff --git a/builder/azure/arm/step_deploy_template.go b/builder/azure/arm/step_deploy_template.go index e7f5af23..33efe269 100644 --- a/builder/azure/arm/step_deploy_template.go +++ b/builder/azure/arm/step_deploy_template.go @@ -216,7 +216,6 @@ func deleteResource(ctx context.Context, client *AzureClient, subscriptionId str switch resourceType { case "Microsoft.Compute/virtualMachines": vmID := hashiVMSDK.NewVirtualMachineID(subscriptionId, resourceGroupName, resourceName) - // TODO don't rely on default operations, set hard delete to false if err := client.VirtualMachinesClient.DeleteThenPoll(ctx, vmID, hashiVMSDK.DefaultDeleteOperationOptions()); err != nil { return err } diff --git a/builder/azure/dtl/azure_client.go b/builder/azure/dtl/azure_client.go index b1224260..6b814b37 100644 --- a/builder/azure/dtl/azure_client.go +++ b/builder/azure/dtl/azure_client.go @@ -17,9 +17,11 @@ import ( "github.com/Azure/go-autorest/autorest" hashiImagesSDK "github.com/hashicorp/go-azure-sdk/resource-manager/compute/2022-03-01/images" hashiVMSDK "github.com/hashicorp/go-azure-sdk/resource-manager/compute/2022-03-01/virtualmachines" + hashiDisksSDK "github.com/hashicorp/go-azure-sdk/resource-manager/compute/2022-03-02/disks" hashiGalleryImagesSDK "github.com/hashicorp/go-azure-sdk/resource-manager/compute/2022-03-03/galleryimages" hashiGalleryImageVersionsSDK "github.com/hashicorp/go-azure-sdk/resource-manager/compute/2022-03-03/galleryimageversions" hashiDTLSDK "github.com/hashicorp/go-azure-sdk/resource-manager/devtestlab/2018-09-15" + hashiVaultsSDK "github.com/hashicorp/go-azure-sdk/resource-manager/keyvault/2023-02-01/vaults" hashiNetworkSDK "github.com/hashicorp/go-azure-sdk/resource-manager/network/2022-09-01" "github.com/hashicorp/go-azure-sdk/sdk/auth" authWrapper "github.com/hashicorp/go-azure-sdk/sdk/auth/autorest" @@ -27,6 +29,7 @@ import ( "github.com/hashicorp/go-azure-sdk/sdk/environments" "github.com/hashicorp/packer-plugin-azure/version" "github.com/hashicorp/packer-plugin-sdk/useragent" + giovanniBlobStorageSDK "github.com/tombuildsstuff/giovanni/storage/2020-08-04/blob/blobs" ) const ( @@ -37,8 +40,11 @@ type AzureClient struct { InspectorMaxLength int LastError azureErrorResponse + GiovanniBlobClient giovanniBlobStorageSDK.Client + hashiDisksSDK.DisksClient hashiVMSDK.VirtualMachinesClient hashiImagesSDK.ImagesClient + hashiVaultsSDK.VaultsClient NetworkMetaClient hashiNetworkSDK.Client hashiGalleryImageVersionsSDK.GalleryImageVersionsClient hashiGalleryImagesSDK.GalleryImagesClient @@ -112,6 +118,10 @@ func NewAzureClient(ctx context.Context, subscriptionID, resourceGroupName strin if err != nil { return nil, nil, err } + storageAccountAuthorizer, err := buildStorageAuthorizer(ctx, newSdkAuthOptions, *cloud) + if err != nil { + return nil, nil, err + } dtlMetaClient := hashiDTLSDK.NewClientWithBaseURI(*resourceManagerEndpoint, func(c *autorest.Client) { c.Authorizer = authWrapper.AutorestAuthorizer(resourceManagerAuthorizer) c.UserAgent = "some-user-agent" @@ -148,6 +158,11 @@ func NewAzureClient(ctx context.Context, subscriptionID, resourceGroupName strin return nil, nil, err } azureClient.NetworkMetaClient = *networkMetaClient + blobClient := giovanniBlobStorageSDK.New() + azureClient.GiovanniBlobClient = blobClient + azureClient.GiovanniBlobClient.Authorizer = authWrapper.AutorestAuthorizer(storageAccountAuthorizer) + azureClient.GiovanniBlobClient.Client.RequestInspector = withInspection(maxlen) + azureClient.GiovanniBlobClient.Client.ResponseInspector = byConcatDecorators(byInspecting(maxlen), errorCapture(azureClient)) token, err := resourceManagerAuthorizer.Token(ctx, &http.Request{}) if err != nil { return nil, nil, err diff --git a/builder/azure/dtl/step_deploy_template.go b/builder/azure/dtl/step_deploy_template.go index f5e03fa7..52c37b26 100644 --- a/builder/azure/dtl/step_deploy_template.go +++ b/builder/azure/dtl/step_deploy_template.go @@ -12,10 +12,11 @@ import ( "time" "github.com/hashicorp/go-azure-helpers/resourcemanager/commonids" + hashiVMSDK "github.com/hashicorp/go-azure-sdk/resource-manager/compute/2022-03-01/virtualmachines" + hashiDisksSDK "github.com/hashicorp/go-azure-sdk/resource-manager/compute/2022-03-02/disks" hashiNetworkSecurityGroupsSDK "github.com/hashicorp/go-azure-sdk/resource-manager/network/2022-09-01/networksecuritygroups" hashiVirtualNetworksSDK "github.com/hashicorp/go-azure-sdk/resource-manager/network/2022-09-01/virtualnetworks" - hashiDeploymentOperationsSDK "github.com/hashicorp/go-azure-sdk/resource-manager/resources/2022-09-01/deploymentoperations" - hashiDeploymentsSDK "github.com/hashicorp/go-azure-sdk/resource-manager/resources/2022-09-01/deployments" + giovanniBlobStorageSDK "github.com/tombuildsstuff/giovanni/storage/2020-08-04/blob/blobs" hashiLabsSDK "github.com/hashicorp/go-azure-sdk/resource-manager/devtestlab/2018-09-15/labs" hashiDTLVMSDK "github.com/hashicorp/go-azure-sdk/resource-manager/devtestlab/2018-09-15/virtualmachines" @@ -28,9 +29,9 @@ import ( 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 + delete func(ctx context.Context, client *AzureClient, subscriptionID, resourceType string, resourceName string, resourceGroupName string) error + disk func(ctx context.Context, subscriptionId string, resourceGroupName string, computeName string) (string, string, error) + deleteDisk func(ctx context.Context, imageName string, resourceGroupName string, isManagedDisk bool, subscriptionId string, storageAccountName string) error say func(message string) error func(e error) config *Config @@ -170,33 +171,44 @@ func (s *StepDeployTemplate) Run(ctx context.Context, state multistep.StateBag) s.error, state) } -func (s *StepDeployTemplate) getImageDetails(ctx context.Context, resourceGroupName string, computeName string) (string, string, error) { +func (s *StepDeployTemplate) getImageDetails(ctx context.Context, subscriptionId string, 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, "") + var imageName, imageType string + vmID := hashiVMSDK.NewVirtualMachineID(subscriptionId, resourceGroupName, computeName) + vm, err := s.client.VirtualMachinesClient.Get(ctx, vmID, hashiVMSDK.DefaultGetOperationOptions()) 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 - } } + if err != nil { + s.say(s.client.LastError.Error()) + return "", "", err + } + if model := vm.Model; model == nil { + return "", "", errors.New("TODO") + } + if vm.Model.Properties.StorageProfile.OsDisk.Vhd != nil { + imageType = "image" + imageName = *vm.Model.Properties.StorageProfile.OsDisk.Vhd.Uri + return imageType, imageName, nil + } + + if vm.Model.Properties.StorageProfile.OsDisk.ManagedDisk.Id == nil { + return "", "", fmt.Errorf("unable to obtain a OS disk for %q, please check that the instance has been created", computeName) + } + + imageType = "Microsoft.Compute/disks" + imageName = *vm.Model.Properties.StorageProfile.OsDisk.ManagedDisk.Id + return imageType, imageName, nil } func deleteResource(ctx context.Context, client *AzureClient, subscriptionId string, 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) + vmID := hashiVMSDK.NewVirtualMachineID(subscriptionId, resourceGroupName, resourceName) + if err := client.VirtualMachinesClient.DeleteThenPoll(ctx, vmID, hashiVMSDK.DefaultDeleteOperationOptions()); err != nil { + return err } - return err case "Microsoft.KeyVault/vaults": id := commonids.NewKeyVaultID(subscriptionId, resourceGroupName, resourceName) _, err := client.VaultsClient.Delete(ctx, id) diff --git a/go.sum b/go.sum index 41434e13..e4adfb4b 100644 --- a/go.sum +++ b/go.sum @@ -114,6 +114,8 @@ github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6D github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= +github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI= +github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/containerd/cgroups v0.0.0-20190919134610-bf292b21730f/go.mod h1:OApqhQ4XNSNC13gXIwDjhOQxjWa/NxkwZXJ1EvqT0ko= github.com/containerd/console v0.0.0-20180822173158-c12b1e7919c1/go.mod h1:Tj/on1eG8kiEhd0+fhSDzsPAFESxzBBvdyEgyryXffw= github.com/containerd/containerd v1.3.2/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= @@ -144,6 +146,7 @@ github.com/dylanmei/winrmtest v0.0.0-20170819153634-c2fbb09e6c08 h1:0bp6/GrNOrTD github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= +github.com/envoyproxy/go-control-plane v0.10.2-0.20220325020618-49ff273808a1/go.mod h1:KJwIaB5Mv44NWtYuAOFCVOjcI94vtpEz2JU/D2v6IjE= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU= @@ -220,6 +223,7 @@ github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/martian/v3 v3.2.1 h1:d8MncMlErDFTwQGBK1xhv026j9kqhvw1Qv9IbWT1VLQ= +github.com/google/martian/v3 v3.2.1/go.mod h1:oBOf6HBosgwRXnUGWUB05QECsc6uvmMiJ3+6W4l/CUk= github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= From f9938b985c4661f4e49f91126dd8aed6ff7bbe35 Mon Sep 17 00:00:00 2001 From: Jenna Goldstrich Date: Thu, 6 Jul 2023 20:17:39 -0700 Subject: [PATCH 03/10] Port DTL provisioner to new SDK --- builder/azure/dtl/azure_client.go | 2 +- builder/azure/dtl/builder.go | 1 - builder/azure/dtl/step_deploy_template.go | 3 +- go.sum | 4 -- provisioner/azure-dtlartifact/provisioner.go | 43 +++++++++++--------- 5 files changed, 27 insertions(+), 26 deletions(-) diff --git a/builder/azure/dtl/azure_client.go b/builder/azure/dtl/azure_client.go index 6b814b37..8f76534a 100644 --- a/builder/azure/dtl/azure_client.go +++ b/builder/azure/dtl/azure_client.go @@ -102,7 +102,7 @@ type NewSDKAuthOptions struct { // Returns an Azure Client used for the Azure Resource Manager // Also returns the Azure object ID for the authentication method used in the build -func NewAzureClient(ctx context.Context, subscriptionID, resourceGroupName string, +func NewAzureClient(ctx context.Context, subscriptionID string, cloud *environments.Environment, SharedGalleryTimeout time.Duration, CustomImageCaptureTimeout time.Duration, PollingDuration time.Duration, newSdkAuthOptions NewSDKAuthOptions) (*AzureClient, *string, error) { var azureClient = &AzureClient{} diff --git a/builder/azure/dtl/builder.go b/builder/azure/dtl/builder.go index 38973e25..6989cb05 100644 --- a/builder/azure/dtl/builder.go +++ b/builder/azure/dtl/builder.go @@ -86,7 +86,6 @@ func (b *Builder) Run(ctx context.Context, ui packersdk.Ui, hook packersdk.Hook) azureClient, objectId, err := NewAzureClient( ctx, b.config.ClientConfig.SubscriptionID, - b.config.LabResourceGroupName, b.config.ClientConfig.NewCloudEnvironment(), b.config.SharedGalleryTimeout, b.config.CustomImageCaptureTimeout, diff --git a/builder/azure/dtl/step_deploy_template.go b/builder/azure/dtl/step_deploy_template.go index 52c37b26..ceca4e92 100644 --- a/builder/azure/dtl/step_deploy_template.go +++ b/builder/azure/dtl/step_deploy_template.go @@ -61,7 +61,9 @@ func (s *StepDeployTemplate) deployTemplate(ctx context.Context, resourceGroupNa subscriptionId := s.config.ClientConfig.SubscriptionID labName := s.config.LabName + // TODO Talk to Tom(s) about this, we have to have two different Labs IDs in different calls, so we can probably move this into the commonids package labResourceId := hashiDTLVMSDK.NewLabID(subscriptionId, resourceGroupName, labName) + labId := hashiLabsSDK.NewLabID(subscriptionId, s.config.tmpResourceGroupName, labName) vmlistPage, err := s.client.DtlMetaClient.VirtualMachines.List(ctx, labResourceId, hashiDTLVMSDK.DefaultListOperationOptions()) if err != nil { s.say(s.client.LastError.Error()) @@ -81,7 +83,6 @@ func (s *StepDeployTemplate) deployTemplate(ctx context.Context, resourceGroupNa return err } - labId := hashiLabsSDK.NewLabID(subscriptionId, s.config.tmpResourceGroupName, labName) err = s.client.DtlMetaClient.Labs.CreateEnvironmentThenPoll(ctx, labId, *labMachine) if err != nil { s.say(s.client.LastError.Error()) diff --git a/go.sum b/go.sum index e4adfb4b..41434e13 100644 --- a/go.sum +++ b/go.sum @@ -114,8 +114,6 @@ github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6D github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= -github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI= -github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/containerd/cgroups v0.0.0-20190919134610-bf292b21730f/go.mod h1:OApqhQ4XNSNC13gXIwDjhOQxjWa/NxkwZXJ1EvqT0ko= github.com/containerd/console v0.0.0-20180822173158-c12b1e7919c1/go.mod h1:Tj/on1eG8kiEhd0+fhSDzsPAFESxzBBvdyEgyryXffw= github.com/containerd/containerd v1.3.2/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= @@ -146,7 +144,6 @@ github.com/dylanmei/winrmtest v0.0.0-20170819153634-c2fbb09e6c08 h1:0bp6/GrNOrTD github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= -github.com/envoyproxy/go-control-plane v0.10.2-0.20220325020618-49ff273808a1/go.mod h1:KJwIaB5Mv44NWtYuAOFCVOjcI94vtpEz2JU/D2v6IjE= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU= @@ -223,7 +220,6 @@ github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/martian/v3 v3.2.1 h1:d8MncMlErDFTwQGBK1xhv026j9kqhvw1Qv9IbWT1VLQ= -github.com/google/martian/v3 v3.2.1/go.mod h1:oBOf6HBosgwRXnUGWUB05QECsc6uvmMiJ3+6W4l/CUk= github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= diff --git a/provisioner/azure-dtlartifact/provisioner.go b/provisioner/azure-dtlartifact/provisioner.go index e84c3092..d240fadc 100644 --- a/provisioner/azure-dtlartifact/provisioner.go +++ b/provisioner/azure-dtlartifact/provisioner.go @@ -11,11 +11,11 @@ import ( "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-plugin-azure/builder/azure/common/client" dtlBuilder "github.com/hashicorp/packer-plugin-azure/builder/azure/dtl" + hashiDTLVMSDK "github.com/hashicorp/go-azure-sdk/resource-manager/devtestlab/2018-09-15/virtualmachines" packersdk "github.com/hashicorp/packer-plugin-sdk/packer" "github.com/hashicorp/packer-plugin-sdk/common" @@ -125,20 +125,25 @@ func (p *Provisioner) Provision(ctx context.Context, ui packersdk.Ui, comm packe return err } - spnCloud, err := p.config.ClientConfig.GetServicePrincipalToken(ui.Say, p.config.ClientConfig.CloudEnvironment().ResourceManagerEndpoint) - if err != nil { - return err + // Pass in relevant auth information for hashicorp/go-azure-sdk + authOptions := dtlBuilder.NewSDKAuthOptions{ + AuthType: p.config.ClientConfig.AuthType(), + ClientID: p.config.ClientConfig.ClientID, + ClientSecret: p.config.ClientConfig.ClientSecret, + ClientJWT: p.config.ClientConfig.ClientJWT, + ClientCertPath: p.config.ClientConfig.ClientCertPath, + TenantID: p.config.ClientConfig.TenantID, + SubscriptionID: p.config.ClientConfig.SubscriptionID, } - ui.Message("Creating Azure DevTestLab (DTL) client ...") - azureClient, err := dtlBuilder.NewAzureClient( + azureClient, _, err := dtlBuilder.NewAzureClient( + ctx, p.config.ClientConfig.SubscriptionID, - "", - p.config.ClientConfig.CloudEnvironment(), + p.config.ClientConfig.NewCloudEnvironment(), p.config.PollingDurationTimeout, p.config.PollingDurationTimeout, p.config.PollingDurationTimeout, - spnCloud) + authOptions) if err != nil { ui.Say(fmt.Sprintf("Error saving debug key: %s", err)) @@ -146,7 +151,7 @@ func (p *Provisioner) Provision(ctx context.Context, ui packersdk.Ui, comm packe } ui.Say("Installing Artifact DTL") - dtlArtifacts := []dtl.ArtifactInstallProperties{} + dtlArtifacts := []hashiDTLVMSDK.ArtifactInstallProperties{} if p.config.DtlArtifacts != nil { for i := range p.config.DtlArtifacts { @@ -156,16 +161,16 @@ func (p *Provisioner) Provision(ctx context.Context, ui packersdk.Ui, comm packe p.config.LabName, p.config.DtlArtifacts[i].ArtifactName) - dparams := []dtl.ArtifactParameterProperties{} + dparams := []hashiDTLVMSDK.ArtifactParameterProperties{} for j := range p.config.DtlArtifacts[i].Parameters { - dp := &dtl.ArtifactParameterProperties{} + dp := &hashiDTLVMSDK.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, + Aip := hashiDTLVMSDK.ArtifactInstallProperties{ + ArtifactId: &p.config.DtlArtifacts[i].ArtifactId, Parameters: &dparams, ArtifactTitle: &p.config.DtlArtifacts[i].ArtifactName, } @@ -173,19 +178,19 @@ func (p *Provisioner) Provision(ctx context.Context, ui packersdk.Ui, comm packe } } - dtlApplyArifactRequest := dtl.ApplyArtifactsRequest{ + dtlApplyArifactRequest := hashiDTLVMSDK.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) - } + vmResourceId := hashiDTLVMSDK.NewVirtualMachineID(p.config.ClientConfig.SubscriptionID, p.config.ResourceGroupName, p.config.LabName, p.config.VMName) + err = azureClient.DtlMetaClient.VirtualMachines.ApplyArtifactsThenPoll(ctx, vmResourceId, dtlApplyArifactRequest) + if err != nil { ui.Say(fmt.Sprintf("Error Applying artifact: %s", err)) } + ui.Say("Aftifact installed") return err } From be92155534e5920f0da9942c201de091485a1756 Mon Sep 17 00:00:00 2001 From: Jenna Goldstrich Date: Thu, 6 Jul 2023 20:29:58 -0700 Subject: [PATCH 04/10] Make generate --- builder/azure/dtl/config.hcl2spec.go | 2 +- docs-partials/builder/azure/dtl/Config-not-required.mdx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/builder/azure/dtl/config.hcl2spec.go b/builder/azure/dtl/config.hcl2spec.go index 18a3be9c..e5992e3d 100644 --- a/builder/azure/dtl/config.hcl2spec.go +++ b/builder/azure/dtl/config.hcl2spec.go @@ -76,7 +76,7 @@ type FlatConfig struct { ManagedImageResourceGroupName *string `mapstructure:"managed_image_resource_group_name" required:"true" cty:"managed_image_resource_group_name" hcl:"managed_image_resource_group_name"` ManagedImageName *string `mapstructure:"managed_image_name" required:"true" 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"` + 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"` diff --git a/docs-partials/builder/azure/dtl/Config-not-required.mdx b/docs-partials/builder/azure/dtl/Config-not-required.mdx index fb2859df..9c51166c 100644 --- a/docs-partials/builder/azure/dtl/Config-not-required.mdx +++ b/docs-partials/builder/azure/dtl/Config-not-required.mdx @@ -87,7 +87,7 @@ 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 +- `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. From 9f471ab71faac04fe23abf20dc30c3b46e7ce8f0 Mon Sep 17 00:00:00 2001 From: Jenna Goldstrich Date: Thu, 6 Jul 2023 20:49:08 -0700 Subject: [PATCH 05/10] Accidently commited playing around with this field, but was missing comma --- builder/azure/common/template/template_builder.go | 6 ------ 1 file changed, 6 deletions(-) diff --git a/builder/azure/common/template/template_builder.go b/builder/azure/common/template/template_builder.go index 6101596d..dead567e 100644 --- a/builder/azure/common/template/template_builder.go +++ b/builder/azure/common/template/template_builder.go @@ -735,9 +735,6 @@ const BasicTemplate = `{ "publicIPAddressName": { "type": "string" }, - "publicIPAddressSku": { - "type": "string" - }, "subnetName": { "type": "string" }, @@ -788,9 +785,6 @@ const BasicTemplate = `{ "type": "Microsoft.Network/publicIPAddresses", "name": "[parameters('publicIPAddressName')]", "location": "[variables('location')]", - "sku": { - "name": "[parameters('publicIPAddressSku')]", - } "properties": { "publicIPAllocationMethod": "[variables('publicIPAddressType')]", "dnsSettings": { From 26d6f1fd3c756aa79a6eeb3b3dba6efec1427c45 Mon Sep 17 00:00:00 2001 From: Jenna Goldstrich Date: Thu, 6 Jul 2023 20:57:38 -0700 Subject: [PATCH 06/10] Appease the lint lord --- builder/azure/dtl/azure_client.go | 18 ++---------------- builder/azure/dtl/builder.go | 8 -------- builder/azure/dtl/resource_resolver.go | 11 +---------- 3 files changed, 3 insertions(+), 34 deletions(-) diff --git a/builder/azure/dtl/azure_client.go b/builder/azure/dtl/azure_client.go index 8f76534a..00739cc8 100644 --- a/builder/azure/dtl/azure_client.go +++ b/builder/azure/dtl/azure_client.go @@ -5,15 +5,15 @@ package dtl import ( "context" - "encoding/json" "fmt" - "github.com/golang-jwt/jwt" "math" "net/http" "os" "strconv" "time" + "github.com/golang-jwt/jwt" + "github.com/Azure/go-autorest/autorest" hashiImagesSDK "github.com/hashicorp/go-azure-sdk/resource-manager/compute/2022-03-01/images" hashiVMSDK "github.com/hashicorp/go-azure-sdk/resource-manager/compute/2022-03-01/virtualmachines" @@ -51,20 +51,6 @@ type AzureClient struct { DtlMetaClient hashiDTLSDK.Client } -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 -} - func errorCapture(client *AzureClient) autorest.RespondDecorator { return func(r autorest.Responder) autorest.Responder { return autorest.ResponderFunc(func(resp *http.Response) error { diff --git a/builder/azure/dtl/builder.go b/builder/azure/dtl/builder.go index 6989cb05..b38bfffd 100644 --- a/builder/azure/dtl/builder.go +++ b/builder/azure/dtl/builder.go @@ -12,7 +12,6 @@ import ( "runtime" "strings" - "github.com/Azure/go-autorest/autorest/adal" hashiGalleryImagesSDK "github.com/hashicorp/go-azure-sdk/resource-manager/compute/2022-03-03/galleryimages" hashiDTLCustomImagesSDK "github.com/hashicorp/go-azure-sdk/resource-manager/devtestlab/2018-09-15/customimages" hashiDTLLabsSDK "github.com/hashicorp/go-azure-sdk/resource-manager/devtestlab/2018-09-15/labs" @@ -174,9 +173,6 @@ func (b *Builder) Run(ctx context.Context, ui packersdk.Ui, hook packersdk.Hook) lab, err := azureClient.DtlMetaClient.Labs.Get(ctx, labResourceId, hashiDTLLabsSDK.DefaultGetOperationOptions()) if err != nil { return nil, fmt.Errorf("Unable to fetch the Lab %s information in %s resource group", b.config.LabName, b.config.LabResourceGroupName) - } - if lab.Model == nil { - } b.config.Location = *lab.Model.Location @@ -338,10 +334,6 @@ 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 := int64(10) labResourceId := hashiDTLVNETSDK.NewLabID(b.config.ClientConfig.SubscriptionID, b.config.LabResourceGroupName, b.config.LabName) diff --git a/builder/azure/dtl/resource_resolver.go b/builder/azure/dtl/resource_resolver.go index 199879ed..c41cf6c5 100644 --- a/builder/azure/dtl/resource_resolver.go +++ b/builder/azure/dtl/resource_resolver.go @@ -21,9 +21,7 @@ import ( ) type resourceResolver struct { - client *AzureClient - findVirtualNetworkResourceGroup func(*AzureClient, string) (string, error) - findVirtualNetworkSubnet func(*AzureClient, string, string) (string, error) + client *AzureClient } func newResourceResolver(client *AzureClient) *resourceResolver { @@ -49,12 +47,6 @@ 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, subscriptionId, resourceGroupName string) (*hashiImagesSDK.Image, error) { id := commonids.NewResourceGroupID(subscriptionId, resourceGroupName) images, err := client.ImagesClient.ListByResourceGroupComplete(context.TODO(), id) @@ -67,6 +59,5 @@ func findManagedImageByName(client *AzureClient, name, subscriptionId, resourceG return &image, nil } } - return nil, fmt.Errorf("Cannot find an image named '%s' in the resource group '%s'", name, resourceGroupName) } From e18282093e54dad8f446a4a94891104ca475c368 Mon Sep 17 00:00:00 2001 From: Jenna Goldstrich Date: Fri, 7 Jul 2023 14:05:35 -0700 Subject: [PATCH 07/10] DTL never supported VHDs, it just had all the code of it, so I didn't need to port some of this --- builder/azure/arm/capture_template.go | 87 ------------ builder/azure/common/constants/stateBag.go | 1 - builder/azure/dtl/artifact.go | 150 +++------------------ builder/azure/dtl/azure_client.go | 25 +--- builder/azure/dtl/builder.go | 26 +++- builder/azure/dtl/builder_acc_test.go | 4 +- builder/azure/dtl/config.go | 4 + builder/azure/dtl/step_capture_image.go | 12 -- builder/azure/dtl/step_deploy_template.go | 93 ++----------- 9 files changed, 66 insertions(+), 336 deletions(-) delete mode 100644 builder/azure/arm/capture_template.go diff --git a/builder/azure/arm/capture_template.go b/builder/azure/arm/capture_template.go deleted file mode 100644 index 85375513..00000000 --- a/builder/azure/arm/capture_template.go +++ /dev/null @@ -1,87 +0,0 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.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/common/constants/stateBag.go b/builder/azure/common/constants/stateBag.go index 30ea5760..20125ae7 100644 --- a/builder/azure/common/constants/stateBag.go +++ b/builder/azure/common/constants/stateBag.go @@ -20,7 +20,6 @@ const ( ) const ( - ArmCaptureTemplate string = "arm.CaptureTemplate" ArmComputeName string = "arm.ComputeName" ArmImageParameters string = "arm.ImageParameters" ArmCertificateUrl string = "arm.CertificateUrl" diff --git a/builder/azure/dtl/artifact.go b/builder/azure/dtl/artifact.go index 7b0feabf..a336b9e8 100644 --- a/builder/azure/dtl/artifact.go +++ b/builder/azure/dtl/artifact.go @@ -6,9 +6,6 @@ package dtl import ( "bytes" "fmt" - "net/url" - "path" - "strings" ) const ( @@ -24,20 +21,16 @@ 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 + ManagedImageResourceGroupName string + ManagedImageName string + ManagedImageLocation string + ManagedImageId string + + // Shared Image Gallery + // ARM resource id for Shared Image Gallery + ManagedImageSharedImageGalleryId string + SharedImageGalleryLocation string // Additional Disks AdditionalDisks *[]AdditionalDiskArtifact @@ -53,82 +46,17 @@ func NewManagedImageArtifact(osType, resourceGroup, name, location, id string) ( }, 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 - } - +func NewManagedImageArtifactWithSIGAsDestination(osType, resourceGroup, name, location, id, destinationSharedImageGalleryId string) (*Artifact, error) { 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, + ManagedImageResourceGroupName: resourceGroup, + ManagedImageName: name, + ManagedImageLocation: location, + ManagedImageId: id, + OSType: osType, + ManagedImageSharedImageGalleryId: destinationSharedImageGalleryId, }, 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 } @@ -138,16 +66,11 @@ func (*Artifact) Files() []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 } @@ -158,45 +81,16 @@ func (a *Artifact) String() string { 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)) - } - } + 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.ManagedImageSharedImageGalleryId != "" { + buf.WriteString(fmt.Sprintf("ManagedImageSharedImageGalleryId: %s\n", a.ManagedImageSharedImageGalleryId)) } - 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 index 00739cc8..b616cab6 100644 --- a/builder/azure/dtl/azure_client.go +++ b/builder/azure/dtl/azure_client.go @@ -17,7 +17,6 @@ import ( "github.com/Azure/go-autorest/autorest" hashiImagesSDK "github.com/hashicorp/go-azure-sdk/resource-manager/compute/2022-03-01/images" hashiVMSDK "github.com/hashicorp/go-azure-sdk/resource-manager/compute/2022-03-01/virtualmachines" - hashiDisksSDK "github.com/hashicorp/go-azure-sdk/resource-manager/compute/2022-03-02/disks" hashiGalleryImagesSDK "github.com/hashicorp/go-azure-sdk/resource-manager/compute/2022-03-03/galleryimages" hashiGalleryImageVersionsSDK "github.com/hashicorp/go-azure-sdk/resource-manager/compute/2022-03-03/galleryimageversions" hashiDTLSDK "github.com/hashicorp/go-azure-sdk/resource-manager/devtestlab/2018-09-15" @@ -29,7 +28,6 @@ import ( "github.com/hashicorp/go-azure-sdk/sdk/environments" "github.com/hashicorp/packer-plugin-azure/version" "github.com/hashicorp/packer-plugin-sdk/useragent" - giovanniBlobStorageSDK "github.com/tombuildsstuff/giovanni/storage/2020-08-04/blob/blobs" ) const ( @@ -40,8 +38,6 @@ type AzureClient struct { InspectorMaxLength int LastError azureErrorResponse - GiovanniBlobClient giovanniBlobStorageSDK.Client - hashiDisksSDK.DisksClient hashiVMSDK.VirtualMachinesClient hashiImagesSDK.ImagesClient hashiVaultsSDK.VaultsClient @@ -104,13 +100,11 @@ func NewAzureClient(ctx context.Context, subscriptionID string, if err != nil { return nil, nil, err } - storageAccountAuthorizer, err := buildStorageAuthorizer(ctx, newSdkAuthOptions, *cloud) - if err != nil { - return nil, nil, err - } dtlMetaClient := hashiDTLSDK.NewClientWithBaseURI(*resourceManagerEndpoint, func(c *autorest.Client) { c.Authorizer = authWrapper.AutorestAuthorizer(resourceManagerAuthorizer) - c.UserAgent = "some-user-agent" + c.UserAgent = fmt.Sprintf("%s %s", useragent.String(version.AzurePluginVersion.FormattedVersion()), "go-azure-sdk Meta Client") + c.RequestInspector = withInspection(maxlen) + c.ResponseInspector = byConcatDecorators(byInspecting(maxlen), errorCapture(azureClient)) }) azureClient.DtlMetaClient = dtlMetaClient @@ -144,11 +138,6 @@ func NewAzureClient(ctx context.Context, subscriptionID string, return nil, nil, err } azureClient.NetworkMetaClient = *networkMetaClient - blobClient := giovanniBlobStorageSDK.New() - azureClient.GiovanniBlobClient = blobClient - azureClient.GiovanniBlobClient.Authorizer = authWrapper.AutorestAuthorizer(storageAccountAuthorizer) - azureClient.GiovanniBlobClient.Client.RequestInspector = withInspection(maxlen) - azureClient.GiovanniBlobClient.Client.ResponseInspector = byConcatDecorators(byInspecting(maxlen), errorCapture(azureClient)) token, err := resourceManagerAuthorizer.Token(ctx, &http.Request{}) if err != nil { return nil, nil, err @@ -177,14 +166,6 @@ func buildResourceManagerAuthorizer(ctx context.Context, authOpts NewSDKAuthOpti return authorizer, nil } -func buildStorageAuthorizer(ctx context.Context, authOpts NewSDKAuthOptions, env environments.Environment) (auth.Authorizer, error) { - authorizer, err := buildAuthorizer(ctx, authOpts, env, env.Storage) - if err != nil { - return nil, fmt.Errorf("building Storage authorizer from credentials: %+v", err) - } - return authorizer, nil -} - func buildAuthorizer(ctx context.Context, authOpts NewSDKAuthOptions, env environments.Environment, api environments.Api) (auth.Authorizer, error) { var authConfig auth.Credentials switch authOpts.AuthType { diff --git a/builder/azure/dtl/builder.go b/builder/azure/dtl/builder.go index b38bfffd..1d7096f7 100644 --- a/builder/azure/dtl/builder.go +++ b/builder/azure/dtl/builder.go @@ -32,6 +32,8 @@ type Builder struct { runner multistep.Runner } +var ErrNoImage = errors.New("failed to find shared image gallery id in state") + const ( DefaultSasBlobContainer = "system/Microsoft.Compute" DefaultSecretName = "packerKeyVaultSecret" @@ -266,11 +268,11 @@ func (b *Builder) Run(ctx context.Context, ui packersdk.Ui, hook packersdk.Hook) 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) + 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.isPublishToSIG() { + return b.managedImageArtifactWithSIGAsDestination(managedImageID) } - return &Artifact{}, nil + return NewManagedImageArtifact(b.config.OSType, b.config.ManagedImageResourceGroupName, b.config.ManagedImageName, b.config.Location, managedImageID) } func (b *Builder) writeSSHPrivateKey(ui packersdk.Ui, debugKeyPath string) { @@ -362,3 +364,19 @@ func (b *Builder) getSubnetInformation(ctx context.Context, ui packersdk.Ui, azC func normalizeAzureRegion(name string) string { return strings.ToLower(strings.Replace(name, " ", "", -1)) } + +func (b *Builder) managedImageArtifactWithSIGAsDestination(managedImageID string) (*Artifact, error) { + destinationSharedImageGalleryId := "" + if galleryID, ok := b.stateBag.GetOk(constants.ArmManagedImageSharedGalleryId); ok { + destinationSharedImageGalleryId = galleryID.(string) + } else { + return nil, ErrNoImage + } + + return NewManagedImageArtifactWithSIGAsDestination(b.config.OSType, + b.config.ManagedImageResourceGroupName, + b.config.ManagedImageName, + b.config.Location, + managedImageID, + destinationSharedImageGalleryId) +} diff --git a/builder/azure/dtl/builder_acc_test.go b/builder/azure/dtl/builder_acc_test.go index adf171dd..0cad0f03 100644 --- a/builder/azure/dtl/builder_acc_test.go +++ b/builder/azure/dtl/builder_acc_test.go @@ -36,7 +36,7 @@ import ( "github.com/hashicorp/packer-plugin-sdk/acctest" ) -func TestBuilderAcc_ManagedDisk_Windows(t *testing.T) { +func TestDTLBuilderAcc_ManagedDisk_Windows(t *testing.T) { t.Parallel() acctest.TestPlugin(t, &acctest.PluginTestCase{ Name: "test-azure-managedisk-windows", @@ -52,7 +52,7 @@ func TestBuilderAcc_ManagedDisk_Windows(t *testing.T) { }, }) } -func TestBuilderAcc_ManagedDisk_Linux_Artifacts(t *testing.T) { +func TestDTLBuilderAcc_ManagedDisk_Linux_Artifacts(t *testing.T) { t.Parallel() acctest.TestPlugin(t, &acctest.PluginTestCase{ Name: "test-azure-managedisk-linux", diff --git a/builder/azure/dtl/config.go b/builder/azure/dtl/config.go index c56f305a..d4968045 100644 --- a/builder/azure/dtl/config.go +++ b/builder/azure/dtl/config.go @@ -325,6 +325,10 @@ func (c *Config) isManagedImage() bool { return c.ManagedImageName != "" } +func (c *Config) isPublishToSIG() bool { + return c.SharedGalleryDestination.SigDestinationGalleryName != "" +} + func (c *Config) toVirtualMachineCaptureParameters() *compute.VirtualMachineCaptureParameters { return &compute.VirtualMachineCaptureParameters{ DestinationContainerName: &c.CaptureContainerName, diff --git a/builder/azure/dtl/step_capture_image.go b/builder/azure/dtl/step_capture_image.go index a0c8939d..be575506 100644 --- a/builder/azure/dtl/step_capture_image.go +++ b/builder/azure/dtl/step_capture_image.go @@ -16,7 +16,6 @@ import ( 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) @@ -112,17 +111,6 @@ func (s *StepCaptureImage) Run(ctx context.Context, state multistep.StateBag) mu 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 } diff --git a/builder/azure/dtl/step_deploy_template.go b/builder/azure/dtl/step_deploy_template.go index ceca4e92..b53895c3 100644 --- a/builder/azure/dtl/step_deploy_template.go +++ b/builder/azure/dtl/step_deploy_template.go @@ -7,16 +7,11 @@ import ( "context" "errors" "fmt" - "net/url" "strings" "time" "github.com/hashicorp/go-azure-helpers/resourcemanager/commonids" hashiVMSDK "github.com/hashicorp/go-azure-sdk/resource-manager/compute/2022-03-01/virtualmachines" - hashiDisksSDK "github.com/hashicorp/go-azure-sdk/resource-manager/compute/2022-03-02/disks" - hashiNetworkSecurityGroupsSDK "github.com/hashicorp/go-azure-sdk/resource-manager/network/2022-09-01/networksecuritygroups" - hashiVirtualNetworksSDK "github.com/hashicorp/go-azure-sdk/resource-manager/network/2022-09-01/virtualnetworks" - giovanniBlobStorageSDK "github.com/tombuildsstuff/giovanni/storage/2020-08-04/blob/blobs" hashiLabsSDK "github.com/hashicorp/go-azure-sdk/resource-manager/devtestlab/2018-09-15/labs" hashiDTLVMSDK "github.com/hashicorp/go-azure-sdk/resource-manager/devtestlab/2018-09-15/virtualmachines" @@ -27,16 +22,14 @@ import ( ) 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, subscriptionID, resourceType string, resourceName string, resourceGroupName string) error - disk func(ctx context.Context, subscriptionId string, resourceGroupName string, computeName string) (string, string, error) - deleteDisk func(ctx context.Context, imageName string, resourceGroupName string, isManagedDisk bool, subscriptionId string, storageAccountName string) error - say func(message string) - error func(e error) - config *Config - factory templateFactoryFuncDtl - name string + client *AzureClient + deploy func(ctx context.Context, resourceGroupName string, deploymentName string, state multistep.StateBag) error + disk func(ctx context.Context, subscriptionId string, resourceGroupName string, computeName string) (string, 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 { @@ -50,9 +43,7 @@ func NewStepDeployTemplate(client *AzureClient, ui packersdk.Ui, config *Config, } step.deploy = step.deployTemplate - step.delete = deleteResource step.disk = step.getImageDetails - step.deleteDisk = step.deleteImage return step } @@ -143,9 +134,10 @@ func (s *StepDeployTemplate) deployTemplate(ctx context.Context, resourceGroupNa for { err := s.client.DtlMetaClient.VirtualMachines.ApplyArtifactsThenPoll(ctx, vmResourceId, dtlArtifactsRequest) if err != nil { - s.say("WinRM artifact deployment failed, sleeping a minute and retrying") - time.Sleep(60 * time.Second) + s.say(fmt.Sprintf("WinRM artifact deployment failed, sleeping 5 seconds and retrying %s", err.Error())) + time.Sleep(5 * time.Second) } + break } } @@ -203,66 +195,7 @@ func (s *StepDeployTemplate) getImageDetails(ctx context.Context, subscriptionId return imageType, imageName, nil } -func deleteResource(ctx context.Context, client *AzureClient, subscriptionId string, resourceType string, resourceName string, resourceGroupName string) error { - switch resourceType { - case "Microsoft.Compute/virtualMachines": - vmID := hashiVMSDK.NewVirtualMachineID(subscriptionId, resourceGroupName, resourceName) - if err := client.VirtualMachinesClient.DeleteThenPoll(ctx, vmID, hashiVMSDK.DefaultDeleteOperationOptions()); err != nil { - return err - } - case "Microsoft.KeyVault/vaults": - id := commonids.NewKeyVaultID(subscriptionId, resourceGroupName, resourceName) - _, err := client.VaultsClient.Delete(ctx, id) - return err - case "Microsoft.Network/networkInterfaces": - interfaceID := commonids.NewNetworkInterfaceID(subscriptionId, resourceGroupName, resourceName) - err := client.NetworkMetaClient.NetworkInterfaces.DeleteThenPoll(ctx, interfaceID) - return err - case "Microsoft.Network/virtualNetworks": - vnetID := hashiVirtualNetworksSDK.NewVirtualNetworkID(subscriptionId, resourceGroupName, resourceName) - err := client.NetworkMetaClient.VirtualNetworks.DeleteThenPoll(ctx, vnetID) - return err - case "Microsoft.Network/networkSecurityGroups": - secGroupId := hashiNetworkSecurityGroupsSDK.NewNetworkSecurityGroupID(subscriptionId, resourceGroupName, resourceName) - err := client.NetworkMetaClient.NetworkSecurityGroups.DeleteThenPoll(ctx, secGroupId) - return err - case "Microsoft.Network/publicIPAddresses": - ipID := commonids.NewPublicIPAddressID(subscriptionId, resourceGroupName, resourceName) - err := client.NetworkMetaClient.PublicIPAddresses.DeleteThenPoll(ctx, ipID) - return err - } - return nil -} - -func (s *StepDeployTemplate) deleteImage(ctx context.Context, imageName string, resourceGroupName string, isManagedDisk bool, subscriptionId string, storageAccountName string) error { - // Managed disk - if isManagedDisk { - xs := strings.Split(imageName, "/") - diskName := xs[len(xs)-1] - diskId := hashiDisksSDK.NewDiskID(subscriptionId, resourceGroupName, diskName) - - if err := s.client.DisksClient.DeleteThenPoll(ctx, diskId); err != nil { - return err - } - return nil - } - - // VHD image - u, err := url.Parse(imageName) - if err != nil { - return err - } - xs := strings.Split(u.Path, "/") - var blobName = strings.Join(xs[2:], "/") - if len(xs) < 3 { - return errors.New("Unable to parse path of image " + imageName) - } - _, err = s.client.GiovanniBlobClient.Delete(ctx, storageAccountName, "images", blobName, giovanniBlobStorageSDK.DeleteInput{}) - 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 + // TODO are there any resources created in DTL builds we should tear down? + // There was teardown code from the ARM builder copy pasted in but it was never called } From 2a592be8ac7b016507b3255e59dc48c9cdb647b1 Mon Sep 17 00:00:00 2001 From: Jenna Goldstrich Date: Fri, 7 Jul 2023 16:10:44 -0700 Subject: [PATCH 08/10] Use retry config instead of an infinite loop --- builder/azure/dtl/step_deploy_template.go | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/builder/azure/dtl/step_deploy_template.go b/builder/azure/dtl/step_deploy_template.go index b53895c3..fcd7f1a3 100644 --- a/builder/azure/dtl/step_deploy_template.go +++ b/builder/azure/dtl/step_deploy_template.go @@ -19,6 +19,7 @@ import ( "github.com/hashicorp/packer-plugin-azure/builder/azure/common/constants" "github.com/hashicorp/packer-plugin-sdk/multistep" packersdk "github.com/hashicorp/packer-plugin-sdk/packer" + "github.com/hashicorp/packer-plugin-sdk/retry" ) type StepDeployTemplate struct { @@ -130,14 +131,24 @@ func (s *StepDeployTemplate) deployTemplate(ctx context.Context, resourceGroupNa dtlArtifacts := []hashiDTLVMSDK.ArtifactInstallProperties{*winrmArtifact} dtlArtifactsRequest := hashiDTLVMSDK.ApplyArtifactsRequest{Artifacts: &dtlArtifacts} - // TODO replaced infinite loop with one time try, this should not fail imo, maybe they were actually running into failures after polling? - for { + // TODO this was an infinite loop, I have seen apply artifacts fail + // But this needs a bit further validation into why it fails and + // How we can avoid the need for a retry backoff + // But a retry backoff is much more preferable to an infinite loop + + retryConfig := retry.Config{ + Tries: 5, + RetryDelay: (&retry.Backoff{InitialBackoff: 5 * time.Second, MaxBackoff: 60 * time.Second, Multiplier: 1.5}).Linear, + } + err = retryConfig.Run(ctx, func(ctx context.Context) error { err := s.client.DtlMetaClient.VirtualMachines.ApplyArtifactsThenPoll(ctx, vmResourceId, dtlArtifactsRequest) if err != nil { - s.say(fmt.Sprintf("WinRM artifact deployment failed, sleeping 5 seconds and retrying %s", err.Error())) - time.Sleep(5 * time.Second) + s.say("WinRM artifact deployment failed, retrying") } - break + return nil + }) + if err != nil { + return err } } From 936a190e1e89349ae0b084015e8f1ca7e633242b Mon Sep 17 00:00:00 2001 From: Jenna Goldstrich Date: Fri, 7 Jul 2023 16:26:45 -0700 Subject: [PATCH 09/10] Delete more unused code --- builder/azure/dtl/step_deploy_template.go | 35 ----------------------- 1 file changed, 35 deletions(-) diff --git a/builder/azure/dtl/step_deploy_template.go b/builder/azure/dtl/step_deploy_template.go index fcd7f1a3..b0e13747 100644 --- a/builder/azure/dtl/step_deploy_template.go +++ b/builder/azure/dtl/step_deploy_template.go @@ -5,13 +5,11 @@ package dtl import ( "context" - "errors" "fmt" "strings" "time" "github.com/hashicorp/go-azure-helpers/resourcemanager/commonids" - hashiVMSDK "github.com/hashicorp/go-azure-sdk/resource-manager/compute/2022-03-01/virtualmachines" hashiLabsSDK "github.com/hashicorp/go-azure-sdk/resource-manager/devtestlab/2018-09-15/labs" hashiDTLVMSDK "github.com/hashicorp/go-azure-sdk/resource-manager/devtestlab/2018-09-15/virtualmachines" @@ -25,7 +23,6 @@ import ( type StepDeployTemplate struct { client *AzureClient deploy func(ctx context.Context, resourceGroupName string, deploymentName string, state multistep.StateBag) error - disk func(ctx context.Context, subscriptionId string, resourceGroupName string, computeName string) (string, string, error) say func(message string) error func(e error) config *Config @@ -44,7 +41,6 @@ func NewStepDeployTemplate(client *AzureClient, ui packersdk.Ui, config *Config, } step.deploy = step.deployTemplate - step.disk = step.getImageDetails return step } @@ -175,37 +171,6 @@ func (s *StepDeployTemplate) Run(ctx context.Context, state multistep.StateBag) s.error, state) } -func (s *StepDeployTemplate) getImageDetails(ctx context.Context, subscriptionId string, resourceGroupName string, computeName string) (string, string, error) { - //We can't depend on constants.ArmOSDiskVhd being set - var imageName, imageType string - vmID := hashiVMSDK.NewVirtualMachineID(subscriptionId, resourceGroupName, computeName) - vm, err := s.client.VirtualMachinesClient.Get(ctx, vmID, hashiVMSDK.DefaultGetOperationOptions()) - if err != nil { - return imageName, imageType, err - } - if err != nil { - s.say(s.client.LastError.Error()) - return "", "", err - } - if model := vm.Model; model == nil { - return "", "", errors.New("TODO") - } - if vm.Model.Properties.StorageProfile.OsDisk.Vhd != nil { - imageType = "image" - imageName = *vm.Model.Properties.StorageProfile.OsDisk.Vhd.Uri - return imageType, imageName, nil - } - - if vm.Model.Properties.StorageProfile.OsDisk.ManagedDisk.Id == nil { - return "", "", fmt.Errorf("unable to obtain a OS disk for %q, please check that the instance has been created", computeName) - } - - imageType = "Microsoft.Compute/disks" - imageName = *vm.Model.Properties.StorageProfile.OsDisk.ManagedDisk.Id - - return imageType, imageName, nil -} - func (s *StepDeployTemplate) Cleanup(state multistep.StateBag) { // TODO are there any resources created in DTL builds we should tear down? // There was teardown code from the ARM builder copy pasted in but it was never called From dff36833cf08ad7e9ec3d8cf2f4a6996b73a9057 Mon Sep 17 00:00:00 2001 From: Jenna Goldstrich Date: Fri, 7 Jul 2023 16:51:14 -0700 Subject: [PATCH 10/10] Update comments --- builder/azure/arm/azure_client.go | 2 +- builder/azure/dtl/azure_client.go | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/builder/azure/arm/azure_client.go b/builder/azure/arm/azure_client.go index d87237e9..70e735dd 100644 --- a/builder/azure/arm/azure_client.go +++ b/builder/azure/arm/azure_client.go @@ -176,7 +176,6 @@ func NewAzureClient(ctx context.Context, isVHDBuild bool, cloud *environments.En azureClient.ImagesClient.Client.UserAgent = fmt.Sprintf("%s %s", useragent.String(version.AzurePluginVersion.FormattedVersion()), azureClient.ImagesClient.Client.UserAgent) azureClient.ImagesClient.Client.PollingDuration = pollingDuration - // Clients that are using the existing SDK/auth logic azureClient.StorageAccountsClient = hashiStorageAccountsSDK.NewStorageAccountsClientWithBaseURI(*resourceManagerEndpoint) azureClient.StorageAccountsClient.Client.Authorizer = authWrapper.AutorestAuthorizer(resourceManagerAuthorizer) azureClient.StorageAccountsClient.Client.RequestInspector = withInspection(maxlen) @@ -184,6 +183,7 @@ func NewAzureClient(ctx context.Context, isVHDBuild bool, cloud *environments.En azureClient.StorageAccountsClient.Client.UserAgent = fmt.Sprintf("%s %s", useragent.String(version.AzurePluginVersion.FormattedVersion()), azureClient.StorageAccountsClient.Client.UserAgent) azureClient.StorageAccountsClient.Client.PollingDuration = pollingDuration + // TODO Request/Response inpectors for Track 2 networkMetaClient, err := hashiNetworkMetaSDK.NewClientWithBaseURI(cloud.ResourceManager, func(c *resourcemanager.Client) { c.Client.Authorizer = resourceManagerAuthorizer c.Client.UserAgent = "some-user-agent" diff --git a/builder/azure/dtl/azure_client.go b/builder/azure/dtl/azure_client.go index b616cab6..31460f34 100644 --- a/builder/azure/dtl/azure_client.go +++ b/builder/azure/dtl/azure_client.go @@ -129,6 +129,7 @@ func NewAzureClient(ctx context.Context, subscriptionID string, azureClient.ImagesClient.Client.UserAgent = fmt.Sprintf("%s %s", useragent.String(version.AzurePluginVersion.FormattedVersion()), azureClient.ImagesClient.Client.UserAgent) azureClient.ImagesClient.Client.PollingDuration = PollingDuration + // TODO Request/Response inpectors for Track 2 networkMetaClient, err := hashiNetworkSDK.NewClientWithBaseURI(cloud.ResourceManager, func(c *resourcemanager.Client) { c.Client.Authorizer = resourceManagerAuthorizer c.Client.UserAgent = "some-user-agent"