//go:generate mapstructure-to-hcl2 -type Config,DtlArtifact,ArtifactParameter package devtestlabsartifacts import ( "context" "fmt" "time" "github.com/Azure/azure-sdk-for-go/services/devtestlabs/mgmt/2018-09-15/dtl" "github.com/hashicorp/hcl/v2/hcldec" "github.com/hashicorp/packer/builder/azure/common/client" dtlBuilder "github.com/hashicorp/packer/builder/azure/dtl" packersdk "github.com/hashicorp/packer-plugin-sdk/packer" "github.com/hashicorp/packer-plugin-sdk/common" "github.com/hashicorp/packer-plugin-sdk/template/config" "github.com/hashicorp/packer-plugin-sdk/template/interpolate" ) type DtlArtifact struct { ArtifactName string `mapstructure:"artifact_name"` ArtifactId string `mapstructure:"artifact_id"` Parameters []ArtifactParameter `mapstructure:"parameters"` } type ArtifactParameter struct { Name string `mapstructure:"name"` Value string `mapstructure:"value"` Type string `mapstructure:"type"` } type Config struct { common.PackerConfig `mapstructure:",squash"` // Authentication via OAUTH ClientConfig client.Config `mapstructure:",squash"` DtlArtifacts []DtlArtifact `mapstructure:"dtl_artifacts"` LabName string `mapstructure:"lab_name"` ResourceGroupName string `mapstructure:"lab_resource_group_name"` VMName string `mapstructure:"vm_name"` // The default PollingDuration for azure is 15mins, this property will override // that value. See [Azure DefaultPollingDuration](https://godoc.org/github.com/Azure/go-autorest/autorest#pkg-constants) // If your Packer build is failing on the // ARM deployment step with the error `Original Error: // context deadline exceeded`, then you probably need to increase this timeout from // its default of "15m" (valid time units include `s` for seconds, `m` for // minutes, and `h` for hours.) PollingDurationTimeout time.Duration `mapstructure:"polling_duration_timeout" required:"false"` AzureTags map[string]*string `mapstructure:"azure_tags"` Json map[string]interface{} ctx interpolate.Context } type Provisioner struct { config Config communicator packersdk.Communicator } func (p *Provisioner) ConfigSpec() hcldec.ObjectSpec { return p.config.FlatMapstructure().HCL2Spec() } func (p *Provisioner) Prepare(raws ...interface{}) error { // // Create passthrough for winrm password so we can fill it in once we know // // it // p.config.ctx.Data = &EnvVarsTemplate{ // WinRMPassword: `{{.WinRMPassword}}`, // } err := config.Decode(&p.config, &config.DecodeOpts{ PluginType: "azure-dtlartifact", Interpolate: true, InterpolateContext: &p.config.ctx, InterpolateFilter: &interpolate.RenderFilter{ Exclude: []string{ "execute_command", }, }, }, raws...) if err != nil { return err } p.config.ClientConfig.CloudEnvironmentName = "Public" return nil } func (p *Provisioner) Communicator() packersdk.Communicator { return p.communicator } func (p *Provisioner) Provision(ctx context.Context, ui packersdk.Ui, comm packersdk.Communicator, _ map[string]interface{}) error { p.communicator = comm err := p.config.ClientConfig.SetDefaultValues() if err != nil { ui.Say(fmt.Sprintf("Error saving debug key: %s", err)) return nil } ///////////////////////////////////////////// // Polling Duration Timeout if p.config.PollingDurationTimeout == 0 { // In the sdk, the default is 15 m. p.config.PollingDurationTimeout = 15 * time.Minute } // FillParameters function captures authType and sets defaults. err = p.config.ClientConfig.FillParameters() if err != nil { return err } spnCloud, err := p.config.ClientConfig.GetServicePrincipalToken(ui.Say, p.config.ClientConfig.CloudEnvironment().ResourceManagerEndpoint) if err != nil { return err } ui.Message("Creating Azure Resource Manager (ARM) client ...") azureClient, err := dtlBuilder.NewAzureClient( p.config.ClientConfig.SubscriptionID, "", p.config.ClientConfig.CloudEnvironment(), p.config.PollingDurationTimeout, p.config.PollingDurationTimeout, spnCloud) if err != nil { ui.Say(fmt.Sprintf("Error saving debug key: %s", err)) return err } ui.Say("Installing Artifact DTL") dtlArtifacts := []dtl.ArtifactInstallProperties{} if p.config.DtlArtifacts != nil { for i := range p.config.DtlArtifacts { p.config.DtlArtifacts[i].ArtifactId = fmt.Sprintf("/subscriptions/%s/resourceGroups/%s/providers/Microsoft.DevTestLab/labs/%s/artifactSources/public repo/artifacts/%s", p.config.ClientConfig.SubscriptionID, p.config.ResourceGroupName, p.config.LabName, p.config.DtlArtifacts[i].ArtifactName) dparams := []dtl.ArtifactParameterProperties{} for j := range p.config.DtlArtifacts[i].Parameters { dp := &dtl.ArtifactParameterProperties{} dp.Name = &p.config.DtlArtifacts[i].Parameters[j].Name dp.Value = &p.config.DtlArtifacts[i].Parameters[j].Value dparams = append(dparams, *dp) } Aip := dtl.ArtifactInstallProperties{ ArtifactID: &p.config.DtlArtifacts[i].ArtifactId, Parameters: &dparams, ArtifactTitle: &p.config.DtlArtifacts[i].ArtifactName, } dtlArtifacts = append(dtlArtifacts, Aip) } } dtlApplyArifactRequest := dtl.ApplyArtifactsRequest{ Artifacts: &dtlArtifacts, } ui.Say("Applying artifact ") f, err := azureClient.DtlVirtualMachineClient.ApplyArtifacts(ctx, p.config.ResourceGroupName, p.config.LabName, p.config.VMName, dtlApplyArifactRequest) if err == nil { err = f.WaitForCompletionRef(ctx, azureClient.DtlVirtualMachineClient.Client) } if err != nil { ui.Say(fmt.Sprintf("Error Applying artifact: %s", err)) } ui.Say("Aftifact installed") return err }