Skip to content
This repository has been archived by the owner on Oct 4, 2021. It is now read-only.

Commit

Permalink
Added builds teardown and create image steps
Browse files Browse the repository at this point in the history
  • Loading branch information
maxfrei committed Feb 5, 2021
1 parent 1563f6a commit 9113161
Show file tree
Hide file tree
Showing 9 changed files with 190 additions and 13 deletions.
4 changes: 2 additions & 2 deletions builder/upcloud/builder.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,8 +66,8 @@ func (b *Builder) Run(ctx context.Context, ui packersdk.Ui, hook packersdk.Hook)
&commonsteps.StepCleanupTempKeys{
Comm: &b.config.Communicator,
},
// &StepTeardownInstance{},
// &StepCreateImage{},
&StepTeardownInstance{},
&StepCreateImage{},
}

// Run
Expand Down
10 changes: 6 additions & 4 deletions builder/upcloud/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,10 @@ type Config struct {
TemplatePrefix string `mapstructure:"template_prefix"`

// Optional configuration values
StorageSize int `mapstructure:"storage_size"`
RawStateTimeoutDuration string `mapstructure:"state_timeout_duration"`
StorageSize int `mapstructure:"storage_size"`

StateTimeoutDuration time.Duration
ctx interpolate.Context
Timeout time.Duration
ctx interpolate.Context
}

func (c *Config) Prepare(raws ...interface{}) ([]string, error) {
Expand All @@ -40,6 +39,7 @@ func (c *Config) Prepare(raws ...interface{}) ([]string, error) {
return nil, err
}
// defaults

// later

// validate
Expand Down Expand Up @@ -67,5 +67,7 @@ func (c *Config) Prepare(raws ...interface{}) ([]string, error) {
errs = packer.MultiErrorAppend(
errs, errors.New("\"storage_uuid\" must be specified"))
}

c.Timeout = 5 * time.Minute
return nil, nil
}
3 changes: 1 addition & 2 deletions builder/upcloud/config.hcl2spec.go
Original file line number Diff line number Diff line change
Expand Up @@ -73,8 +73,7 @@ type FlatConfig struct {
TemplatePrefix string `mapstructure:"template_prefix" cty:"template_prefix"`

// Optional configuration values
StorageSize int `mapstructure:"storage_size" cty:"storage_size"`
RawStateTimeoutDuration string `mapstructure:"state_timeout_duration" cty:"state_timeout_duration"`
StorageSize int `mapstructure:"storage_size" cty:"storage_size"`
}

// FlatMapstructure returns a new FlatConfig.
Expand Down
2 changes: 0 additions & 2 deletions builder/upcloud/set_teardown_instance.go

This file was deleted.

122 changes: 122 additions & 0 deletions builder/upcloud/step_create_image.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
package upcloud

import (
"context"
"errors"
"fmt"
"time"

"github.com/UpCloudLtd/upcloud-go-api/upcloud"
"github.com/UpCloudLtd/upcloud-go-api/upcloud/request"
"github.com/UpCloudLtd/upcloud-go-api/upcloud/service"
"github.com/hashicorp/packer-plugin-sdk/multistep"
"github.com/hashicorp/packer-plugin-sdk/packer"
)

// StepCreateImage represents the step that creates a storage template from the newly created server
type StepCreateImage struct{}

// Run runs the actual step
func (s *StepCreateImage) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction {
// Store a success indicator in the state
state.Put("step_templatize_storage_success", false)

// Extract state
ui := state.Get("ui").(packer.Ui)
api := state.Get("api").(service.Service)
config := state.Get("config").(Config)
serverDetails := state.Get("server_details").(*upcloud.ServerDetails)

// Stop the server and wait until it has stopped
ui.Say(fmt.Sprintf("Stopping server \"%s\" ...", serverDetails.Title))
serverDetails, err := api.StopServer(&request.StopServerRequest{
UUID: serverDetails.UUID,
})

if err != nil {
return StepHaltWithError(state, fmt.Errorf("Error teardown server: %s", err))
}

ui.Say(fmt.Sprintf("Waiting for server %q to enter the 'stopped' state...", serverDetails.Title))
serverDetails, err = api.WaitForServerState(&request.WaitForServerStateRequest{
UUID: serverDetails.UUID,
DesiredState: upcloud.ServerStateStopped,
Timeout: config.Timeout,
})

if err != nil {
return StepHaltWithError(state, fmt.Errorf("Error waiting for server: %s", err))
}

ui.Say(fmt.Sprintf("Server %q is now in 'stopped' state", serverDetails.Title))

// Templatize the first disk device in the server
for _, storage := range serverDetails.StorageDevices {
if storage.Type == upcloud.StorageTypeDisk {
ui.Say(fmt.Sprintf("Creating storage image %q ...", storage.Title))

// Determine the prefix to use for the template title
prefix := storage.Title
if config.TemplatePrefix != "" {
prefix = config.TemplatePrefix
}

storageDetails, err := api.TemplatizeStorage(&request.TemplatizeStorageRequest{
UUID: storage.UUID,
Title: fmt.Sprintf("%s-template-%d", prefix, time.Now().Unix()),
})

if err != nil {
return StepHaltWithError(state, fmt.Errorf("Error creating image: %s", err))
}

// Wait for the newly templatized storage to enter the "online" state
ui.Say(fmt.Sprintf("Waiting for storage %q to enter the 'online' state", storageDetails.Title))
storageDetails, err = api.WaitForStorageState(&request.WaitForStorageStateRequest{
UUID: storageDetails.UUID,
DesiredState: upcloud.StorageStateOnline,
Timeout: config.Timeout,
})

if err != nil {
return StepHaltWithError(state, fmt.Errorf("Error creating image: %s", err))
}

// Storage the details about the templatized storage in the state. Also update our success
// boolean
state.Put("storage_details", storageDetails)
state.Put("step_templatize_storage_success", true)

return multistep.ActionContinue
}
}

// No storage found, we'll have to abort
return StepHaltWithError(state, errors.New("Unable to find the storage device to templatize"))
}

// Cleanup cleans up after the step
func (s *StepCreateImage) Cleanup(state multistep.StateBag) {
// Don't perform any cleanup if the step executed successfully
if state.Get("step_templatize_storage_success").(bool) {
return
}

// Extract state, return if no state has been stored
if rawDetails, ok := state.GetOk("storage_details"); ok {
storageDetails := rawDetails.(*upcloud.StorageDetails)

api := state.Get("api").(service.Service)
ui := state.Get("ui").(packer.Ui)

// Delete the storage device
err := api.DeleteStorage(&request.DeleteStorageRequest{
UUID: storageDetails.UUID,
})

if err != nil {
ui.Error(fmt.Sprintf("%s", err))
return
}
}
}
6 changes: 3 additions & 3 deletions builder/upcloud/step_create_instance.go
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ func (s *StepCreateInstance) Run(ctx context.Context, state multistep.StateBag)
serverDetails, err = api.WaitForServerState(&request.WaitForServerStateRequest{
UUID: serverDetails.UUID,
DesiredState: upcloud.ServerStateStarted,
Timeout: config.StateTimeoutDuration,
Timeout: config.Timeout,
})

if err != nil {
Expand Down Expand Up @@ -130,7 +130,7 @@ func (s *StepCreateInstance) Cleanup(state multistep.StateBag) {
_, err := api.WaitForServerState(&request.WaitForServerStateRequest{
UUID: uuid,
UndesiredState: upcloud.ServerStateMaintenance,
Timeout: config.StateTimeoutDuration,
Timeout: config.Timeout,
})

if err != nil {
Expand Down Expand Up @@ -164,7 +164,7 @@ func (s *StepCreateInstance) Cleanup(state multistep.StateBag) {
_, err = api.WaitForServerState(&request.WaitForServerStateRequest{
UUID: serverDetails.UUID,
DesiredState: upcloud.ServerStateStopped,
Timeout: config.StateTimeoutDuration,
Timeout: config.Timeout,
})

if err != nil {
Expand Down
54 changes: 54 additions & 0 deletions builder/upcloud/step_teardown_instance.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
package upcloud

import (
"context"
"fmt"

"github.com/UpCloudLtd/upcloud-go-api/upcloud"
"github.com/UpCloudLtd/upcloud-go-api/upcloud/request"
"github.com/UpCloudLtd/upcloud-go-api/upcloud/service"
"github.com/hashicorp/packer-plugin-sdk/multistep"
"github.com/hashicorp/packer-plugin-sdk/packer"
)

type StepTeardownInstance struct{}

func (s *StepTeardownInstance) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction {
// Store a success indicator in the state
state.Put("step_templatize_storage_success", false)

// Extract state
ui := state.Get("ui").(packer.Ui)
api := state.Get("api").(service.Service)
config := state.Get("config").(Config)
serverDetails := state.Get("server_details").(*upcloud.ServerDetails)

// Stop the server and wait until it has stopped
ui.Say(fmt.Sprintf("Stopping server \"%s\" ...", serverDetails.Title))
serverDetails, err := api.StopServer(&request.StopServerRequest{
UUID: serverDetails.UUID,
})

if err != nil {
return StepHaltWithError(state, fmt.Errorf("Error teardown server: %s", err))
}

ui.Say(fmt.Sprintf("Waiting for server %q to enter the 'stopped' state...", serverDetails.Title))
serverDetails, err = api.WaitForServerState(&request.WaitForServerStateRequest{
UUID: serverDetails.UUID,
DesiredState: upcloud.ServerStateStopped,
Timeout: config.Timeout,
})

if err != nil {
return StepHaltWithError(state, fmt.Errorf("Error waiting for server: %s", err))
}

ui.Say(fmt.Sprintf("Server %q is now in 'stopped' state", serverDetails.Title))

return multistep.ActionContinue
}

func (s *StepTeardownInstance) Cleanup(state multistep.StateBag) {
// no cleanup
}
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ go 1.15
require (
github.com/UpCloudLtd/upcloud-go-api v0.0.0-20210127073406-2964ed7e5972
github.com/hashicorp/hcl/v2 v2.8.0
github.com/hashicorp/packer v1.6.7-0.20210107234516-6564ee76e807 // indirect
github.com/hashicorp/packer-plugin-sdk v0.0.10
github.com/zclconf/go-cty v1.7.0
golang.org/x/crypto v0.0.0-20201208171446-5f87f3452ae9
Expand Down
1 change: 1 addition & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,7 @@ github.com/digitalocean/godo v1.11.1 h1:OsTh37YFKk+g6DnAOrkXJ9oDArTkRx5UTkBJ2EWA
github.com/digitalocean/godo v1.11.1/go.mod h1:h6faOIcZ8lWIwNQ+DN7b3CgX4Kwby5T+nbpNqkUIozU=
github.com/dimchansky/utfbom v1.1.0 h1:FcM3g+nofKgUteL8dm/UpdRXNC9KmADgTpLKsu0TRo4=
github.com/dimchansky/utfbom v1.1.0/go.mod h1:rO41eb7gLfo8SF1jd9F8HplJm1Fewwi4mQvIirEdv+8=
github.com/dnaeon/go-vcr v1.0.1 h1:r8L/HqC0Hje5AXMu1ooW8oyQyOFv4GxqpL0nRP7SLLY=
github.com/dnaeon/go-vcr v1.0.1/go.mod h1:aBB1+wY4s93YsC3HHjMBMrwTj2R9FHDzUr9KyGc8n1E=
github.com/dylanmei/iso8601 v0.1.0 h1:812NGQDBcqquTfH5Yeo7lwR0nzx/cKdsmf3qMjPURUI=
github.com/dylanmei/iso8601 v0.1.0/go.mod h1:w9KhXSgIyROl1DefbMYIE7UVSIvELTbMrCfx+QkYnoQ=
Expand Down

0 comments on commit 9113161

Please sign in to comment.