packer-cn/provisioner/azure-dtlartifact/provisioner.go

184 lines
5.6 KiB
Go

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