package chroot import ( "context" "fmt" "log" "strings" "github.com/Azure/azure-sdk-for-go/services/compute/mgmt/2019-12-01/compute" "github.com/Azure/go-autorest/autorest/to" "github.com/hashicorp/packer/builder/azure/common/client" "github.com/hashicorp/packer/helper/multistep" "github.com/hashicorp/packer/packer" ) var _ multistep.Step = &StepVerifySharedImageDestination{} // StepVerifySharedImageDestination verifies that the shared image location matches the Location field in the step. // Also verifies that the OS Type is Linux. type StepVerifySharedImageDestination struct { Image SharedImageGalleryDestination Location string } // Run retrieves the image metadata from Azure and compares the location to Location. Verifies the OS Type. func (s *StepVerifySharedImageDestination) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction { azcli := state.Get("azureclient").(client.AzureClientSet) ui := state.Get("ui").(packer.Ui) errorMessage := func(message string, parameters ...interface{}) multistep.StepAction { err := fmt.Errorf(message, parameters...) log.Printf("StepVerifySharedImageDestination.Run: error: %+v", err) state.Put("error", err) ui.Error(err.Error()) return multistep.ActionHalt } imageURI := fmt.Sprintf("/subscriptions/%s/resourcegroup/%s/providers/Microsoft.Compute/galleries/%s/images/%s", azcli.SubscriptionID(), s.Image.ResourceGroup, s.Image.GalleryName, s.Image.ImageName, ) ui.Say(fmt.Sprintf("Validating that shared image %s exists", imageURI)) image, err := azcli.GalleryImagesClient().Get(ctx, s.Image.ResourceGroup, s.Image.GalleryName, s.Image.ImageName) if err != nil { return errorMessage("Error retrieving shared image %q: %+v ", imageURI, err) } if image.ID == nil || *image.ID == "" { return errorMessage("Error retrieving shared image %q: ID field in response is empty", imageURI) } if image.GalleryImageProperties == nil { return errorMessage("Could not retrieve shared image properties for image %q.", to.String(image.ID)) } location := to.String(image.Location) log.Printf("StepVerifySharedImageDestination:Run: Image %q, Location: %q, HvGen: %q, osState: %q", to.String(image.ID), location, image.GalleryImageProperties.HyperVGeneration, image.GalleryImageProperties.OsState) if !strings.EqualFold(location, s.Location) { return errorMessage("Destination shared image resource %q is in a different location (%q) than this VM (%q). "+ "Packer does not know how to handle that.", to.String(image.ID), location, s.Location) } if image.GalleryImageProperties.OsType != compute.Linux { return errorMessage("The shared image (%q) is not a Linux image (found %q). Currently only Linux images are supported.", to.String(image.ID), image.GalleryImageProperties.OsType) } ui.Say(fmt.Sprintf("Found image %s in location %s", to.String(image.ID), to.String(image.Location))) versions, err := azcli.GalleryImageVersionsClient().ListByGalleryImageComplete(ctx, s.Image.ResourceGroup, s.Image.GalleryName, s.Image.ImageName) if err != nil { return errorMessage("Could not ListByGalleryImageComplete group:%v gallery:%v image:%v", s.Image.ResourceGroup, s.Image.GalleryName, s.Image.ImageName) } for versions.NotDone() { version := versions.Value() if version.Name == nil { return errorMessage("Could not retrieve versions for image %q: unexpected nil name", to.String(image.ID)) } if *version.Name == s.Image.ImageVersion { return errorMessage("Shared image version %q already exists for image %q.", s.Image.ImageVersion, to.String(image.ID)) } err := versions.NextWithContext(ctx) if err != nil { return errorMessage("Could not retrieve versions for image %q: %+v", to.String(image.ID), err) } } return multistep.ActionContinue } func (*StepVerifySharedImageDestination) Cleanup(multistep.StateBag) {}