diff --git a/builder/oracle/classic/artifact.go b/builder/oracle/classic/artifact.go index fb7861b04..82987be1a 100644 --- a/builder/oracle/classic/artifact.go +++ b/builder/oracle/classic/artifact.go @@ -6,10 +6,13 @@ import ( "github.com/hashicorp/go-oracle-terraform/compute" ) -// Artifact is an artifact implementation that contains a Snapshot. +// Artifact is an artifact implementation that contains Image List +// and Machine Image info. type Artifact struct { - Snapshot *compute.Snapshot - driver *compute.ComputeClient + MachineImageName string + MachineImageFile string + ImageListVersion int + driver *compute.ComputeClient } // BuilderId uniquely identifies the builder. @@ -24,16 +27,15 @@ func (a *Artifact) Files() []string { } func (a *Artifact) Id() string { - return a.Snapshot.Name + return a.MachineImageName } func (a *Artifact) String() string { - return fmt.Sprintf("A Snapshot was created: \n"+ + return fmt.Sprintf("An image list entry was created: \n"+ "Name: %s\n"+ - "Instance: %s\n"+ - "MachineImage: %s\n"+ - "URI: %s", - a.Snapshot.Name, a.Snapshot.Instance, a.Snapshot.MachineImage, a.Snapshot.URI) + "File: %s\n"+ + "Version: %d", + a.MachineImageName, a.MachineImageFile, a.ImageListVersion) } func (a *Artifact) State(name string) interface{} { diff --git a/builder/oracle/classic/builder.go b/builder/oracle/classic/builder.go index 088ff4dbc..1e90439be 100644 --- a/builder/oracle/classic/builder.go +++ b/builder/oracle/classic/builder.go @@ -99,8 +99,10 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe // Build the artifact and return it artifact := &Artifact{ - Snapshot: state.Get("snapshot").(*compute.Snapshot), - driver: client, + ImageListVersion: state.Get("image_list_version").(int), + MachineImageName: state.Get("machine_image_name").(string), + MachineImageFile: state.Get("machine_image_file").(string), + driver: client, } return artifact, nil diff --git a/builder/oracle/classic/config.go b/builder/oracle/classic/config.go index e0c82beb2..c04235da9 100644 --- a/builder/oracle/classic/config.go +++ b/builder/oracle/classic/config.go @@ -29,7 +29,7 @@ type Config struct { DestImageList string `mapstructure:"dest_image_list"` // Optional; if you don't enter anything, the image list description // will read "Packer-built image list" - DestImageListDescription string `mapstructure:"dest_image_list_description` + DestImageListDescription string `mapstructure:"dest_image_list_description"` // Optional. Describes what computers are allowed to reach your instance // via SSH. This whitelist must contain the computer you're running Packer // from. It defaults to public-internet, meaning that you can SSH into your @@ -72,6 +72,7 @@ func NewConfig(raws ...interface{}) (*Config, error) { "api_endpoint": c.APIEndpoint, "identity_domain": c.IdentityDomain, "source_image_list": c.SourceImageList, + "dest_image_list": c.DestImageList, "shape": c.Shape, } for k, v := range required { diff --git a/builder/oracle/classic/config_test.go b/builder/oracle/classic/config_test.go index 81b8f0344..214365731 100644 --- a/builder/oracle/classic/config_test.go +++ b/builder/oracle/classic/config_test.go @@ -6,14 +6,15 @@ import ( func testConfig() map[string]interface{} { return map[string]interface{}{ - "identity_domain": "abc12345", - "username": "test@hashicorp.com", - "password": "testpassword123", - "api_endpoint": "https://api-test.compute.test.oraclecloud.com/", - "image_list": "/oracle/public/myimage", - "shape": "oc3", - "image_name": "TestImageName", - "ssh_username": "opc", + "identity_domain": "abc12345", + "username": "test@hashicorp.com", + "password": "testpassword123", + "api_endpoint": "https://api-test.compute.test.oraclecloud.com/", + "dest_image_list": "/Config-thing/myuser/myimage", + "source_image_list": "/oracle/public/whatever", + "shape": "oc3", + "image_name": "TestImageName", + "ssh_username": "opc", } } @@ -36,7 +37,8 @@ func TestConfigValidationCatchesMissing(t *testing.T) { "password", "api_endpoint", "identity_domain", - "image_list", + "dest_image_list", + "source_image_list", "shape", } for _, key := range required { diff --git a/builder/oracle/classic/step_create_instance.go b/builder/oracle/classic/step_create_instance.go index 891fda33e..041889ab1 100644 --- a/builder/oracle/classic/step_create_instance.go +++ b/builder/oracle/classic/step_create_instance.go @@ -3,7 +3,6 @@ package classic import ( "context" "fmt" - "log" "github.com/hashicorp/go-oracle-terraform/compute" "github.com/hashicorp/packer/helper/multistep" @@ -67,7 +66,6 @@ func (s *stepCreateInstance) Cleanup(state multistep.StateBag) { Name: config.ImageName, ID: imID, } - log.Printf("instance destroy input is %#v", input) err := instanceClient.DeleteInstance(input) if err != nil { diff --git a/builder/oracle/classic/step_list_images.go b/builder/oracle/classic/step_list_images.go index 8d0c5ee12..a32355e79 100644 --- a/builder/oracle/classic/step_list_images.go +++ b/builder/oracle/classic/step_list_images.go @@ -18,7 +18,6 @@ func (s *stepListImages) Run(_ context.Context, state multistep.StateBag) multis client := state.Get("client").(*compute.ComputeClient) ui.Say("Adding image to image list...") - // TODO: Try to get image list imageListClient := client.ImageList() getInput := compute.GetImageListInput{ Name: config.DestImageList, @@ -27,7 +26,8 @@ func (s *stepListImages) Run(_ context.Context, state multistep.StateBag) multis if err != nil { ui.Say(fmt.Sprintf(err.Error())) // If the list didn't exist, create it. - ui.Say(fmt.Sprintf("Creating image list: %s", config.DestImageList)) + ui.Say(fmt.Sprintf("Destination image list %s does not exist; Creating it...", + config.DestImageList)) ilInput := compute.CreateImageListInput{ Name: config.DestImageList, @@ -37,7 +37,7 @@ func (s *stepListImages) Run(_ context.Context, state multistep.StateBag) multis // Load the packer-generated SSH key into the Oracle Compute cloud. imList, err = imageListClient.CreateImageList(&ilInput) if err != nil { - err = fmt.Errorf("Problem creating an image list through Oracle's API: %s", err) + err = fmt.Errorf("Problem creating image list: %s", err) ui.Error(err.Error()) state.Put("error", err) return multistep.ActionHalt @@ -47,11 +47,12 @@ func (s *stepListImages) Run(_ context.Context, state multistep.StateBag) multis // Now create and image list entry for the image into that list. snap := state.Get("snapshot").(*compute.Snapshot) + version := len(imList.Entries) + 1 entriesClient := client.ImageListEntries() entriesInput := compute.CreateImageListEntryInput{ Name: config.DestImageList, MachineImages: []string{fmt.Sprintf("Compute-%s/%s/%s", config.IdentityDomain, config.Username, snap.MachineImage)}, - Version: 1, + Version: version, } entryInfo, err := entriesClient.CreateImageListEntry(&entriesInput) if err != nil { @@ -60,7 +61,28 @@ func (s *stepListImages) Run(_ context.Context, state multistep.StateBag) multis state.Put("error", err) return multistep.ActionHalt } + state.Put("image_list_entry", entryInfo) ui.Message(fmt.Sprintf("created image list entry %s", entryInfo.Name)) + + imList, err = imageListClient.GetImageList(&getInput) + + machineImagesClient := client.MachineImages() + getImagesInput := compute.GetMachineImageInput{ + Name: config.ImageName, + } + + // Grab info about the machine image to return with the artifact + imInfo, err := machineImagesClient.GetMachineImage(&getImagesInput) + if err != nil { + err = fmt.Errorf("Problem getting machine image info: %s", err) + ui.Error(err.Error()) + state.Put("error", err) + return multistep.ActionHalt + } + state.Put("machine_image_file", imInfo.File) + state.Put("machine_image_name", imInfo.Name) + state.Put("image_list_version", version) + return multistep.ActionContinue } diff --git a/builder/oracle/classic/step_snapshot.go b/builder/oracle/classic/step_snapshot.go index b98530691..452fb56eb 100644 --- a/builder/oracle/classic/step_snapshot.go +++ b/builder/oracle/classic/step_snapshot.go @@ -52,8 +52,8 @@ func (s *stepSnapshot) Cleanup(state multistep.StateBag) { Snapshot: snap.Name, MachineImage: snap.MachineImage, } - machineClient := client.MachineImages() - err := snapClient.DeleteSnapshot(machineClient, &snapInput) + + err := snapClient.DeleteSnapshotResourceOnly(&snapInput) if err != nil { err = fmt.Errorf("Problem deleting snapshot: %s", err) ui.Error(err.Error()) diff --git a/vendor/github.com/hashicorp/go-oracle-terraform/compute/snapshots.go b/vendor/github.com/hashicorp/go-oracle-terraform/compute/snapshots.go index d2a9616e9..370fd0c97 100644 --- a/vendor/github.com/hashicorp/go-oracle-terraform/compute/snapshots.go +++ b/vendor/github.com/hashicorp/go-oracle-terraform/compute/snapshots.go @@ -176,6 +176,31 @@ func (c *SnapshotsClient) DeleteSnapshot(machineImagesClient *MachineImagesClien return nil } +// DeleteSnapshot deletes the Snapshot with the given name. +// A machine image gets created with the associated snapshot is not deleted +// by this method. +func (c *SnapshotsClient) DeleteSnapshotResourceOnly(input *DeleteSnapshotInput) error { + // Wait for snapshot complete in case delay is active and the corresponding + // instance needs to be deleted first + getInput := &GetSnapshotInput{ + Name: input.Snapshot, + } + + if input.Timeout == 0 { + input.Timeout = WaitForSnapshotCompleteTimeout + } + + if _, err := c.WaitForSnapshotComplete(getInput, input.Timeout); err != nil { + return fmt.Errorf("Could not delete snapshot: %s", err) + } + + if err := c.deleteResource(input.Snapshot); err != nil { + return fmt.Errorf("Could not delete snapshot: %s", err) + } + + return nil +} + // WaitForSnapshotComplete waits for an snapshot to be completely initialized and available. func (c *SnapshotsClient) WaitForSnapshotComplete(input *GetSnapshotInput, timeout time.Duration) (*Snapshot, error) { var info *Snapshot diff --git a/vendor/vendor.json b/vendor/vendor.json index 6172b8c33..421c8710a 100644 --- a/vendor/vendor.json +++ b/vendor/vendor.json @@ -803,7 +803,7 @@ "revisionTime": "2018-01-11T20:31:13Z" }, { - "checksumSHA1": "RhoE7zmHsn5zoXbx5AsAUUQI72E=", + "checksumSHA1": "wce86V0j11J6xRSvJEanprjK7so=", "path": "github.com/hashicorp/go-oracle-terraform/compute", "revision": "5a9a298c54339d2296d2f1135eae55a3a8f5e8c2", "revisionTime": "2018-01-11T20:31:13Z" diff --git a/website/source/docs/builders/oracle-classic.html.md b/website/source/docs/builders/oracle-classic.html.md index 08d3d10b1..83169fcee 100644 --- a/website/source/docs/builders/oracle-classic.html.md +++ b/website/source/docs/builders/oracle-classic.html.md @@ -40,14 +40,17 @@ This builder currently only works with the SSH communicator. requests. Instructions for determining your API endpoint can be found [here](https://docs.oracle.com/en/cloud/iaas/compute-iaas-cloud/stcsa/SendRequests.html) + - `dest_image_list` (string) - Where to save the machine image to once you've + provisioned it. If the provided image list does not exist, Packer will create it. + - `identity_domain` (string) - This is your customer-specific identity domain as generated by Oracle. If you don't know what your identity domain is, ask your account administrator. For a little more information, see the Oracle [documentation](https://docs.oracle.com/en/cloud/get-started/subscriptions-cloud/ocuid/identity-domain-overview.html#GUID-7969F881-5F4D-443E-B86C-9044C8085B8A). - - `image_list` (string) - This is what image you want to use as your base image. + - `source_image_list` (string) - This is what image you want to use as your base image. See the [documentation](https://docs.oracle.com/en/cloud/iaas/compute-iaas-cloud/stcsg/listing-machine-images.html) - for more details. To see what public image lists are available, you can use + for more details. You may use either a public image list, or a private image list. To see what public image lists are available, you can use the CLI, as described [here](https://docs.oracle.com/en/cloud/iaas/compute-iaas-cloud/stopc/image-lists-stclr-and-nmcli.html#GUID-DB7E75FE-F752-4FF7-AB70-3C8DCDFCA0FA) - `password` (string) - Your account password. @@ -60,6 +63,9 @@ This builder currently only works with the SSH communicator. ### Optional + - `dest_image_list_description` (string) - a description for your destination + image list. If you don't provide one, Packer will provide a generic description. + - `ssh_username` (string) - The username that Packer will use to SSH into the instance; defaults to `opc`, the default oracle user, which has sudo priveliges. If you have already configured users on your machine, you may