Make PIR images work

This commit is contained in:
Paul Meyer 2019-06-03 08:33:31 +00:00
parent b5401d552a
commit bbac79f0a4
3 changed files with 65 additions and 13 deletions

View File

@ -5,6 +5,7 @@ import (
"errors" "errors"
"fmt" "fmt"
"github.com/Azure/go-autorest/autorest/azure" "github.com/Azure/go-autorest/autorest/azure"
"github.com/Azure/go-autorest/autorest/to"
"log" "log"
"runtime" "runtime"
"strings" "strings"
@ -26,7 +27,8 @@ type Config struct {
ClientConfig client.Config `mapstructure:",squash"` ClientConfig client.Config `mapstructure:",squash"`
FromScratch bool `mapstructure:"from_scratch"` FromScratch bool `mapstructure:"from_scratch"`
Source string `mapstructure:"source"`
CommandWrapper string `mapstructure:"command_wrapper"` CommandWrapper string `mapstructure:"command_wrapper"`
PreMountCommands []string `mapstructure:"pre_mount_commands"` PreMountCommands []string `mapstructure:"pre_mount_commands"`
@ -75,6 +77,9 @@ func (b *Builder) Prepare(raws ...interface{}) ([]string, error) {
}, },
}, raws...) }, raws...)
var errs *packer.MultiError
var warns []string
// Defaults // Defaults
err = b.config.ClientConfig.SetDefaultValues() err = b.config.ClientConfig.SetDefaultValues()
if err != nil { if err != nil {
@ -115,7 +120,12 @@ func (b *Builder) Prepare(raws ...interface{}) ([]string, error) {
} }
if b.config.TemporaryOSDiskName == "" { if b.config.TemporaryOSDiskName == "" {
b.config.TemporaryOSDiskName = "PackerTemp-{{timestamp}}"
if def, err := interpolate.Render("PackerTemp-{{timestamp}}", &b.config.ctx); err == nil {
b.config.TemporaryOSDiskName = def
} else {
errs = packer.MultiErrorAppend(errs, fmt.Errorf("unable to render temporary disk name: %s", err))
}
} }
if b.config.OSDiskStorageAccountType == "" { if b.config.OSDiskStorageAccountType == "" {
@ -135,10 +145,12 @@ func (b *Builder) Prepare(raws ...interface{}) ([]string, error) {
} }
// checks, accumulate any errors or warnings // checks, accumulate any errors or warnings
var errs *packer.MultiError
var warns []string
if b.config.FromScratch { if b.config.FromScratch {
if b.config.Source != "" {
errs = packer.MultiErrorAppend(
errs, errors.New("source cannot be specified when building from_scratch"))
}
if b.config.OSDiskSizeGB == 0 { if b.config.OSDiskSizeGB == 0 {
errs = packer.MultiErrorAppend( errs = packer.MultiErrorAppend(
errs, errors.New("os_disk_size_gb is required with from_scratch")) errs, errors.New("os_disk_size_gb is required with from_scratch"))
@ -148,7 +160,12 @@ func (b *Builder) Prepare(raws ...interface{}) ([]string, error) {
errs, errors.New("pre_mount_commands is required with from_scratch")) errs, errors.New("pre_mount_commands is required with from_scratch"))
} }
} else { } else {
errs = packer.MultiErrorAppend(errors.New("only 'from_scratch'=true is supported right now")) if _, err := client.ParsePlatformImageURN(b.config.Source); err == nil {
log.Println("Source is platform image:", b.config.Source)
} else {
errs = packer.MultiErrorAppend(
errs, fmt.Errorf("source: %q is not a valid platform image specifier", b.config.Source))
}
} }
if err := checkDiskCacheType(b.config.OSDiskCacheType); err != nil { if err := checkDiskCacheType(b.config.OSDiskCacheType); err != nil {
@ -271,10 +288,7 @@ func (b *Builder) Run(ctx context.Context, ui packer.Ui, hook packer.Hook) (pack
// Build the steps // Build the steps
var steps []multistep.Step var steps []multistep.Step
if !b.config.FromScratch { if b.config.FromScratch {
panic("Only from_scratch is currently implemented")
// create disk from PIR / managed image (warn on non-linux images)
} else {
steps = append(steps, steps = append(steps,
&StepCreateNewDisk{ &StepCreateNewDisk{
SubscriptionID: info.SubscriptionID, SubscriptionID: info.SubscriptionID,
@ -285,6 +299,31 @@ func (b *Builder) Run(ctx context.Context, ui packer.Ui, hook packer.Hook) (pack
HyperVGeneration: b.config.ImageHyperVGeneration, HyperVGeneration: b.config.ImageHyperVGeneration,
Location: info.Location, Location: info.Location,
}) })
} else {
if pi, err := client.ParsePlatformImageURN(b.config.Source); err == nil {
if strings.EqualFold(pi.Version, "latest") {
vmi, err := azcli.VirtualMachineImagesClient().GetLatest(ctx, pi.Publisher, pi.Offer, pi.Sku, info.Location)
if err != nil {
return nil, fmt.Errorf("error retieving latest version of %q: %v", b.config.Source, err)
}
pi.Version = to.String(vmi.Name)
log.Println("Resolved latest version of source image:", pi.Version)
}
steps = append(steps,
&StepCreateNewDisk{
SubscriptionID: info.SubscriptionID,
ResourceGroup: info.ResourceGroupName,
DiskName: b.config.TemporaryOSDiskName,
DiskSizeGB: b.config.OSDiskSizeGB,
DiskStorageAccountType: b.config.OSDiskStorageAccountType,
HyperVGeneration: b.config.ImageHyperVGeneration,
Location: info.Location,
PlatformImage: pi,
})
} else {
panic("Unknown image source: " + b.config.Source)
}
} }
steps = append(steps, steps = append(steps,

View File

@ -51,9 +51,12 @@ func (s *StepCreateImage) Run(ctx context.Context, state multistep.StateBag) mul
StorageProfile: &compute.ImageStorageProfile{ StorageProfile: &compute.ImageStorageProfile{
OsDisk: &compute.ImageOSDisk{ OsDisk: &compute.ImageOSDisk{
OsState: compute.OperatingSystemStateTypes(s.ImageOSState), OsState: compute.OperatingSystemStateTypes(s.ImageOSState),
OsType: compute.Linux,
ManagedDisk: &compute.SubResource{ ManagedDisk: &compute.SubResource{
ID: &diskResourceID, ID: &diskResourceID,
}, },
StorageAccountType: compute.StorageAccountTypes(s.OSDiskStorageAccountType),
Caching: compute.CachingTypes(s.OSDiskCacheType),
}, },
// DataDisks: nil, // DataDisks: nil,
// ZoneResilient: nil, // ZoneResilient: nil,

View File

@ -20,6 +20,7 @@ type StepCreateNewDisk struct {
DiskStorageAccountType string // from compute.DiskStorageAccountTypes DiskStorageAccountType string // from compute.DiskStorageAccountTypes
HyperVGeneration string HyperVGeneration string
Location string Location string
PlatformImage *client.PlatformImage
} }
func (s StepCreateNewDisk) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction { func (s StepCreateNewDisk) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction {
@ -42,10 +43,8 @@ func (s StepCreateNewDisk) Run(ctx context.Context, state multistep.StateBag) mu
DiskProperties: &compute.DiskProperties{ DiskProperties: &compute.DiskProperties{
OsType: "Linux", OsType: "Linux",
HyperVGeneration: compute.HyperVGeneration(s.HyperVGeneration), HyperVGeneration: compute.HyperVGeneration(s.HyperVGeneration),
CreationData: &compute.CreationData{ CreationData: &compute.CreationData{},
CreateOption: compute.Empty, DiskSizeGB: to.Int32Ptr(s.DiskSizeGB),
},
DiskSizeGB: to.Int32Ptr(s.DiskSizeGB),
}, },
//Tags: map[string]*string{ //Tags: map[string]*string{
} }
@ -54,6 +53,17 @@ func (s StepCreateNewDisk) Run(ctx context.Context, state multistep.StateBag) mu
disk.DiskProperties.DiskSizeGB = to.Int32Ptr(s.DiskSizeGB) disk.DiskProperties.DiskSizeGB = to.Int32Ptr(s.DiskSizeGB)
} }
if s.PlatformImage == nil {
disk.CreationData.CreateOption = compute.Empty
} else {
disk.CreationData.CreateOption = compute.FromImage
disk.CreationData.ImageReference = &compute.ImageDiskReference{
ID: to.StringPtr(fmt.Sprintf(
"/subscriptions/%s/providers/Microsoft.Compute/locations/%s/publishers/%s/artifacttypes/vmimage/offers/%s/skus/%s/versions/%s",
s.SubscriptionID, s.Location, s.PlatformImage.Publisher, s.PlatformImage.Offer, s.PlatformImage.Sku, s.PlatformImage.Version)),
}
}
f, err := azcli.DisksClient().CreateOrUpdate(ctx, s.ResourceGroup, s.DiskName, disk) f, err := azcli.DisksClient().CreateOrUpdate(ctx, s.ResourceGroup, s.DiskName, disk)
if err == nil { if err == nil {
err = f.WaitForCompletionRef(ctx, azcli.PollClient()) err = f.WaitForCompletionRef(ctx, azcli.PollClient())