From e8783873d0591b95def8305544c895793e6a8249 Mon Sep 17 00:00:00 2001 From: Andrew Starr-Bochicchio Date: Tue, 12 May 2020 11:37:07 -0400 Subject: [PATCH 1/7] builder/digitalocean: Fix failing acceptance test. --- builder/digitalocean/builder_acc_test.go | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/builder/digitalocean/builder_acc_test.go b/builder/digitalocean/builder_acc_test.go index 3a091697e..63d4a425b 100644 --- a/builder/digitalocean/builder_acc_test.go +++ b/builder/digitalocean/builder_acc_test.go @@ -26,10 +26,11 @@ const testBuilderAccBasic = ` "builders": [{ "type": "test", "region": "nyc2", - "size": "512mb", - "image": "ubuntu-12-04-x64", - "user_date": "", - "user_date_file": "" + "size": "s-1vcpu-1gb", + "image": "ubuntu-20-04-x64", + "ssh_username": "root", + "user_data": "", + "user_data_file": "" }] } ` From 80b4e0425ef36775ba4c4a9779de9e9fa5ae139f Mon Sep 17 00:00:00 2001 From: Andrew Starr-Bochicchio Date: Tue, 12 May 2020 11:46:58 -0400 Subject: [PATCH 2/7] builder/digitalocean: Use correct type for image for Droplet creates. --- builder/digitalocean/step_create_droplet.go | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/builder/digitalocean/step_create_droplet.go b/builder/digitalocean/step_create_droplet.go index d3a54c955..318426425 100644 --- a/builder/digitalocean/step_create_droplet.go +++ b/builder/digitalocean/step_create_droplet.go @@ -3,6 +3,7 @@ package digitalocean import ( "context" "fmt" + "strconv" "io/ioutil" @@ -35,13 +36,18 @@ func (s *stepCreateDroplet) Run(ctx context.Context, state multistep.StateBag) m userData = string(contents) } + createImage := godo.DropletCreateImage{Slug: c.Image} + + imageId, err := strconv.Atoi(c.Image) + if err == nil { + createImage = godo.DropletCreateImage{ID: imageId} + } + droplet, _, err := client.Droplets.Create(context.TODO(), &godo.DropletCreateRequest{ Name: c.DropletName, Region: c.Region, Size: c.Size, - Image: godo.DropletCreateImage{ - Slug: c.Image, - }, + Image: createImage, SSHKeys: []godo.DropletCreateSSHKey{ {ID: sshKeyId}, }, From 374a29d75c22d98dc9b3a8329ee862786839d4dd Mon Sep 17 00:00:00 2001 From: Andrew Starr-Bochicchio Date: Tue, 12 May 2020 12:38:51 -0400 Subject: [PATCH 3/7] builder/digitalocean: Add logging of Droplet create attributes. --- builder/digitalocean/step_create_droplet.go | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/builder/digitalocean/step_create_droplet.go b/builder/digitalocean/step_create_droplet.go index 318426425..e62a9ecb8 100644 --- a/builder/digitalocean/step_create_droplet.go +++ b/builder/digitalocean/step_create_droplet.go @@ -3,6 +3,7 @@ package digitalocean import ( "context" "fmt" + "log" "strconv" "io/ioutil" @@ -43,7 +44,7 @@ func (s *stepCreateDroplet) Run(ctx context.Context, state multistep.StateBag) m createImage = godo.DropletCreateImage{ID: imageId} } - droplet, _, err := client.Droplets.Create(context.TODO(), &godo.DropletCreateRequest{ + dropletCreateReq := &godo.DropletCreateRequest{ Name: c.DropletName, Region: c.Region, Size: c.Size, @@ -56,7 +57,11 @@ func (s *stepCreateDroplet) Run(ctx context.Context, state multistep.StateBag) m IPv6: c.IPv6, UserData: userData, Tags: c.Tags, - }) + } + + log.Printf("[DEBUG] Droplet create paramaters: %s", godo.Stringify(dropletCreateReq)) + + droplet, _, err := client.Droplets.Create(context.TODO(), dropletCreateReq) if err != nil { err := fmt.Errorf("Error creating droplet: %s", err) state.Put("error", err) From 05d56034dd77fbd016b17c23189da050863c6510 Mon Sep 17 00:00:00 2001 From: Andrew Starr-Bochicchio Date: Tue, 12 May 2020 13:38:15 -0400 Subject: [PATCH 4/7] builder/digitalocean: Add acceptance test for creating Droplet using image ID. --- builder/digitalocean/builder_acc_test.go | 29 ++++++++++++++++++++++-- 1 file changed, 27 insertions(+), 2 deletions(-) diff --git a/builder/digitalocean/builder_acc_test.go b/builder/digitalocean/builder_acc_test.go index 63d4a425b..ee9451c9a 100644 --- a/builder/digitalocean/builder_acc_test.go +++ b/builder/digitalocean/builder_acc_test.go @@ -1,17 +1,29 @@ package digitalocean import ( + "context" + "fmt" "os" "testing" + "github.com/digitalocean/godo" builderT "github.com/hashicorp/packer/helper/builder/testing" + "golang.org/x/oauth2" ) func TestBuilderAcc_basic(t *testing.T) { builderT.Test(t, builderT.TestCase{ PreCheck: func() { testAccPreCheck(t) }, Builder: &Builder{}, - Template: testBuilderAccBasic, + Template: fmt.Sprintf(testBuilderAccBasic, "ubuntu-20-04-x64"), + }) +} + +func TestBuilderAcc_imageId(t *testing.T) { + builderT.Test(t, builderT.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Builder: &Builder{}, + Template: makeTemplateWithImageId(t), }) } @@ -21,13 +33,26 @@ func testAccPreCheck(t *testing.T) { } } +func makeTemplateWithImageId(t *testing.T) string { + token := os.Getenv("DIGITALOCEAN_API_TOKEN") + client := godo.NewClient(oauth2.NewClient(context.TODO(), &apiTokenSource{ + AccessToken: token, + })) + image, _, err := client.Images.GetBySlug(context.TODO(), "ubuntu-20-04-x64") + if err != nil { + t.Fatalf("failed to retrieve image ID: %s", err) + } + + return fmt.Sprintf(testBuilderAccBasic, image.ID) +} + const testBuilderAccBasic = ` { "builders": [{ "type": "test", "region": "nyc2", "size": "s-1vcpu-1gb", - "image": "ubuntu-20-04-x64", + "image": "%v", "ssh_username": "root", "user_data": "", "user_data_file": "" From bf0ab6b722613d69f9a8073ab8644c1a22a4a56d Mon Sep 17 00:00:00 2001 From: Andrew Starr-Bochicchio Date: Wed, 13 May 2020 11:38:03 -0400 Subject: [PATCH 5/7] Force test to be skipped unless PACKER_ACC set. --- builder/digitalocean/builder_acc_test.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/builder/digitalocean/builder_acc_test.go b/builder/digitalocean/builder_acc_test.go index ee9451c9a..588331b04 100644 --- a/builder/digitalocean/builder_acc_test.go +++ b/builder/digitalocean/builder_acc_test.go @@ -20,6 +20,10 @@ func TestBuilderAcc_basic(t *testing.T) { } func TestBuilderAcc_imageId(t *testing.T) { + if os.Getenv("PACKER_ACC") == "" { + t.Skip("Acceptance tests skipped unless env 'PACKER_ACC' set") + } + builderT.Test(t, builderT.TestCase{ PreCheck: func() { testAccPreCheck(t) }, Builder: &Builder{}, From a1f334daff289957b92fceb8651b9dcb143f7f24 Mon Sep 17 00:00:00 2001 From: Andrew Starr-Bochicchio Date: Wed, 13 May 2020 13:28:44 -0400 Subject: [PATCH 6/7] Use constant and move check to template generator. --- builder/digitalocean/builder_acc_test.go | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/builder/digitalocean/builder_acc_test.go b/builder/digitalocean/builder_acc_test.go index 588331b04..183058d95 100644 --- a/builder/digitalocean/builder_acc_test.go +++ b/builder/digitalocean/builder_acc_test.go @@ -20,10 +20,6 @@ func TestBuilderAcc_basic(t *testing.T) { } func TestBuilderAcc_imageId(t *testing.T) { - if os.Getenv("PACKER_ACC") == "" { - t.Skip("Acceptance tests skipped unless env 'PACKER_ACC' set") - } - builderT.Test(t, builderT.TestCase{ PreCheck: func() { testAccPreCheck(t) }, Builder: &Builder{}, @@ -38,16 +34,20 @@ func testAccPreCheck(t *testing.T) { } func makeTemplateWithImageId(t *testing.T) string { - token := os.Getenv("DIGITALOCEAN_API_TOKEN") - client := godo.NewClient(oauth2.NewClient(context.TODO(), &apiTokenSource{ - AccessToken: token, - })) - image, _, err := client.Images.GetBySlug(context.TODO(), "ubuntu-20-04-x64") - if err != nil { - t.Fatalf("failed to retrieve image ID: %s", err) + if os.Getenv(builderT.TestEnvVar) != "" { + token := os.Getenv("DIGITALOCEAN_API_TOKEN") + client := godo.NewClient(oauth2.NewClient(context.TODO(), &apiTokenSource{ + AccessToken: token, + })) + image, _, err := client.Images.GetBySlug(context.TODO(), "ubuntu-20-04-x64") + if err != nil { + t.Fatalf("failed to retrieve image ID: %s", err) + } + + return fmt.Sprintf(testBuilderAccBasic, image.ID) } - return fmt.Sprintf(testBuilderAccBasic, image.ID) + return "" } const testBuilderAccBasic = ` From 84f0079c3a2105c36f4e20ebb17f92e48f0b5bfb Mon Sep 17 00:00:00 2001 From: Andrew Starr-Bochicchio Date: Wed, 13 May 2020 13:29:22 -0400 Subject: [PATCH 7/7] Move to a new func to make testable. --- builder/digitalocean/step_create_droplet.go | 18 ++++++++----- .../digitalocean/step_create_droplet_test.go | 26 +++++++++++++++++++ 2 files changed, 38 insertions(+), 6 deletions(-) create mode 100644 builder/digitalocean/step_create_droplet_test.go diff --git a/builder/digitalocean/step_create_droplet.go b/builder/digitalocean/step_create_droplet.go index e62a9ecb8..e246abf5e 100644 --- a/builder/digitalocean/step_create_droplet.go +++ b/builder/digitalocean/step_create_droplet.go @@ -37,12 +37,7 @@ func (s *stepCreateDroplet) Run(ctx context.Context, state multistep.StateBag) m userData = string(contents) } - createImage := godo.DropletCreateImage{Slug: c.Image} - - imageId, err := strconv.Atoi(c.Image) - if err == nil { - createImage = godo.DropletCreateImage{ID: imageId} - } + createImage := getImageType(c.Image) dropletCreateReq := &godo.DropletCreateRequest{ Name: c.DropletName, @@ -98,3 +93,14 @@ func (s *stepCreateDroplet) Cleanup(state multistep.StateBag) { "Error destroying droplet. Please destroy it manually: %s", err)) } } + +func getImageType(image string) godo.DropletCreateImage { + createImage := godo.DropletCreateImage{Slug: image} + + imageId, err := strconv.Atoi(image) + if err == nil { + createImage = godo.DropletCreateImage{ID: imageId} + } + + return createImage +} diff --git a/builder/digitalocean/step_create_droplet_test.go b/builder/digitalocean/step_create_droplet_test.go new file mode 100644 index 000000000..507d77d61 --- /dev/null +++ b/builder/digitalocean/step_create_droplet_test.go @@ -0,0 +1,26 @@ +package digitalocean + +import ( + "testing" + + "github.com/digitalocean/godo" +) + +func TestBuilder_GetImageType(t *testing.T) { + imageTypeTests := []struct { + in string + out godo.DropletCreateImage + }{ + {"ubuntu-20-04-x64", godo.DropletCreateImage{Slug: "ubuntu-20-04-x64"}}, + {"123456", godo.DropletCreateImage{ID: 123456}}, + } + + for _, tt := range imageTypeTests { + t.Run(tt.in, func(t *testing.T) { + i := getImageType(tt.in) + if i != tt.out { + t.Errorf("got %q, want %q", godo.Stringify(i), godo.Stringify(tt.out)) + } + }) + } +}