Profitbricks builder fixes (#10549)
This commit is contained in:
parent
f5006d0842
commit
9afaa5a21f
|
@ -22,8 +22,11 @@ func (s *stepCreateServer) Run(ctx context.Context, state multistep.StateBag) mu
|
||||||
|
|
||||||
profitbricks.SetAuth(c.PBUsername, c.PBPassword)
|
profitbricks.SetAuth(c.PBUsername, c.PBPassword)
|
||||||
profitbricks.SetDepth("5")
|
profitbricks.SetDepth("5")
|
||||||
if sshkey, ok := state.GetOk("publicKey"); ok {
|
if c.Comm.SSHPublicKey != nil {
|
||||||
c.SSHKey = sshkey.(string)
|
c.SSHKey = string(c.Comm.SSHPublicKey)
|
||||||
|
} else {
|
||||||
|
ui.Error("No ssh private key set; ssh authentication won't be possible. Please specify your private key in the ssh_private_key_file configuration key.")
|
||||||
|
return multistep.ActionHalt
|
||||||
}
|
}
|
||||||
ui.Say("Creating Virtual Data Center...")
|
ui.Say("Creating Virtual Data Center...")
|
||||||
img := s.getImageId(c.Image, c)
|
img := s.getImageId(c.Image, c)
|
||||||
|
@ -204,7 +207,7 @@ func (d *stepCreateServer) setPB(username string, password string, url string) {
|
||||||
|
|
||||||
func (d *stepCreateServer) checkForErrors(instance profitbricks.Resp) error {
|
func (d *stepCreateServer) checkForErrors(instance profitbricks.Resp) error {
|
||||||
if instance.StatusCode > 299 {
|
if instance.StatusCode > 299 {
|
||||||
return errors.New(fmt.Sprintf("Error occurred %s", string(instance.Body)))
|
return fmt.Errorf("Error occurred %s", string(instance.Body))
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -261,7 +264,9 @@ func (d *stepCreateServer) getImageAlias(imageAlias string, location string, ui
|
||||||
|
|
||||||
func parseErrorMessage(raw string) (toreturn string) {
|
func parseErrorMessage(raw string) (toreturn string) {
|
||||||
var tmp map[string]interface{}
|
var tmp map[string]interface{}
|
||||||
json.Unmarshal([]byte(raw), &tmp)
|
if json.Unmarshal([]byte(raw), &tmp) != nil {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
for _, v := range tmp["messages"].([]interface{}) {
|
for _, v := range tmp["messages"].([]interface{}) {
|
||||||
for index, i := range v.(map[string]interface{}) {
|
for index, i := range v.(map[string]interface{}) {
|
||||||
|
|
|
@ -3,6 +3,9 @@ package profitbricks
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/hashicorp/packer-plugin-sdk/multistep"
|
"github.com/hashicorp/packer-plugin-sdk/multistep"
|
||||||
|
@ -22,9 +25,32 @@ func (s *stepTakeSnapshot) Run(ctx context.Context, state multistep.StateBag) mu
|
||||||
|
|
||||||
dcId := state.Get("datacenter_id").(string)
|
dcId := state.Get("datacenter_id").(string)
|
||||||
volumeId := state.Get("volume_id").(string)
|
volumeId := state.Get("volume_id").(string)
|
||||||
|
serverId := state.Get("instance_id").(string)
|
||||||
|
|
||||||
|
comm, _ := state.Get("communicator").(packersdk.Communicator)
|
||||||
|
if comm == nil {
|
||||||
|
ui.Error("no communicator found")
|
||||||
|
return multistep.ActionHalt
|
||||||
|
}
|
||||||
|
|
||||||
|
/* sync fs changes from the provisioning step */
|
||||||
|
os, err := s.getOs(dcId, serverId)
|
||||||
|
if err != nil {
|
||||||
|
ui.Error(fmt.Sprintf("an error occurred while getting the server os: %s", err.Error()))
|
||||||
|
return multistep.ActionHalt
|
||||||
|
}
|
||||||
|
ui.Say(fmt.Sprintf("Server OS is %s", os))
|
||||||
|
|
||||||
|
switch strings.ToLower(os) {
|
||||||
|
case "linux":
|
||||||
|
ui.Say("syncing file system changes")
|
||||||
|
if err := s.syncFs(ctx, comm); err != nil {
|
||||||
|
ui.Error(fmt.Sprintf("error syncing fs changes: %s", err.Error()))
|
||||||
|
return multistep.ActionHalt
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
snapshot := profitbricks.CreateSnapshot(dcId, volumeId, c.SnapshotName, "")
|
snapshot := profitbricks.CreateSnapshot(dcId, volumeId, c.SnapshotName, "")
|
||||||
|
|
||||||
state.Put("snapshotname", c.SnapshotName)
|
state.Put("snapshotname", c.SnapshotName)
|
||||||
|
|
||||||
if snapshot.StatusCode > 299 {
|
if snapshot.StatusCode > 299 {
|
||||||
|
@ -42,31 +68,123 @@ func (s *stepTakeSnapshot) Run(ctx context.Context, state multistep.StateBag) mu
|
||||||
return multistep.ActionHalt
|
return multistep.ActionHalt
|
||||||
}
|
}
|
||||||
|
|
||||||
s.waitTillProvisioned(snapshot.Headers.Get("Location"), *c)
|
ui.Say(fmt.Sprintf("Creating a snapshot for %s/volumes/%s", dcId, volumeId))
|
||||||
|
|
||||||
|
err = s.waitForRequest(snapshot.Headers.Get("Location"), *c, ui)
|
||||||
|
if err != nil {
|
||||||
|
ui.Error(fmt.Sprintf("An error occurred while waiting for the request to be done: %s", err.Error()))
|
||||||
|
return multistep.ActionHalt
|
||||||
|
}
|
||||||
|
|
||||||
|
err = s.waitTillSnapshotAvailable(snapshot.Id, *c, ui)
|
||||||
|
if err != nil {
|
||||||
|
ui.Error(fmt.Sprintf("An error occurred while waiting for the snapshot to be created: %s", err.Error()))
|
||||||
|
return multistep.ActionHalt
|
||||||
|
}
|
||||||
|
|
||||||
return multistep.ActionContinue
|
return multistep.ActionContinue
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *stepTakeSnapshot) Cleanup(state multistep.StateBag) {
|
func (s *stepTakeSnapshot) Cleanup(_ multistep.StateBag) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *stepTakeSnapshot) waitTillProvisioned(path string, config Config) {
|
func (s *stepTakeSnapshot) waitForRequest(path string, config Config, ui packersdk.Ui) error {
|
||||||
d.setPB(config.PBUsername, config.PBPassword, config.PBUrl)
|
|
||||||
|
ui.Say(fmt.Sprintf("Watching request %s", path))
|
||||||
|
s.setPB(config.PBUsername, config.PBPassword, config.PBUrl)
|
||||||
waitCount := 50
|
waitCount := 50
|
||||||
|
var waitInterval = 10 * time.Second
|
||||||
if config.Retries > 0 {
|
if config.Retries > 0 {
|
||||||
waitCount = config.Retries
|
waitCount = config.Retries
|
||||||
}
|
}
|
||||||
|
done := false
|
||||||
for i := 0; i < waitCount; i++ {
|
for i := 0; i < waitCount; i++ {
|
||||||
request := profitbricks.GetRequestStatus(path)
|
request := profitbricks.GetRequestStatus(path)
|
||||||
|
ui.Say(fmt.Sprintf("request status = %s", request.Metadata.Status))
|
||||||
if request.Metadata.Status == "DONE" {
|
if request.Metadata.Status == "DONE" {
|
||||||
|
done = true
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
time.Sleep(10 * time.Second)
|
if request.Metadata.Status == "FAILED" {
|
||||||
|
return fmt.Errorf("Request failed: %s", request.Response)
|
||||||
|
}
|
||||||
|
time.Sleep(waitInterval)
|
||||||
i++
|
i++
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if done == false {
|
||||||
|
return fmt.Errorf("request not fulfilled after waiting %d seconds",
|
||||||
|
int64(waitCount)*int64(waitInterval)/int64(time.Second))
|
||||||
|
}
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *stepTakeSnapshot) setPB(username string, password string, url string) {
|
func (s *stepTakeSnapshot) waitTillSnapshotAvailable(id string, config Config, ui packersdk.Ui) error {
|
||||||
|
s.setPB(config.PBUsername, config.PBPassword, config.PBUrl)
|
||||||
|
waitCount := 50
|
||||||
|
var waitInterval = 10 * time.Second
|
||||||
|
if config.Retries > 0 {
|
||||||
|
waitCount = config.Retries
|
||||||
|
}
|
||||||
|
done := false
|
||||||
|
ui.Say(fmt.Sprintf("waiting for snapshot %s to become available", id))
|
||||||
|
for i := 0; i < waitCount; i++ {
|
||||||
|
snap := profitbricks.GetSnapshot(id)
|
||||||
|
ui.Say(fmt.Sprintf("snapshot status = %s", snap.Metadata.State))
|
||||||
|
if snap.StatusCode != 200 {
|
||||||
|
return fmt.Errorf("%s", snap.Response)
|
||||||
|
}
|
||||||
|
if snap.Metadata.State == "AVAILABLE" {
|
||||||
|
done = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
time.Sleep(waitInterval)
|
||||||
|
i++
|
||||||
|
ui.Say(fmt.Sprintf("... still waiting, %d seconds have passed", int64(waitInterval)*int64(i)))
|
||||||
|
}
|
||||||
|
|
||||||
|
if done == false {
|
||||||
|
return fmt.Errorf("snapshot not created after waiting %d seconds",
|
||||||
|
int64(waitCount)*int64(waitInterval)/int64(time.Second))
|
||||||
|
}
|
||||||
|
|
||||||
|
ui.Say("snapshot created")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *stepTakeSnapshot) syncFs(ctx context.Context, comm packersdk.Communicator) error {
|
||||||
|
cmd := &packersdk.RemoteCmd{
|
||||||
|
Command: "sync",
|
||||||
|
}
|
||||||
|
if err := comm.Start(ctx, cmd); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if cmd.Wait() != 0 {
|
||||||
|
return fmt.Errorf("sync command exited with code %d", cmd.ExitStatus())
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *stepTakeSnapshot) getOs(dcId string, serverId string) (string, error) {
|
||||||
|
server := profitbricks.GetServer(dcId, serverId)
|
||||||
|
if server.StatusCode != 200 {
|
||||||
|
return "", errors.New(server.Response)
|
||||||
|
}
|
||||||
|
|
||||||
|
if server.Properties.BootVolume == nil {
|
||||||
|
return "", errors.New("no boot volume found on server")
|
||||||
|
}
|
||||||
|
|
||||||
|
volumeId := server.Properties.BootVolume.Id
|
||||||
|
volume := profitbricks.GetVolume(dcId, volumeId)
|
||||||
|
if volume.StatusCode != 200 {
|
||||||
|
return "", errors.New(volume.Response)
|
||||||
|
}
|
||||||
|
|
||||||
|
return volume.Properties.LicenceType, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *stepTakeSnapshot) setPB(username string, password string, url string) {
|
||||||
profitbricks.SetAuth(username, password)
|
profitbricks.SetAuth(username, password)
|
||||||
profitbricks.SetEndpoint(url)
|
profitbricks.SetEndpoint(url)
|
||||||
}
|
}
|
||||||
|
|
1
go.sum
1
go.sum
|
@ -530,6 +530,7 @@ github.com/mitchellh/go-wordwrap v0.0.0-20150314170334-ad45545899c7/go.mod h1:ZX
|
||||||
github.com/mitchellh/go-wordwrap v1.0.0 h1:6GlHJ/LTGMrIJbwgdqdl2eEH8o+Exx/0m8ir9Gns0u4=
|
github.com/mitchellh/go-wordwrap v1.0.0 h1:6GlHJ/LTGMrIJbwgdqdl2eEH8o+Exx/0m8ir9Gns0u4=
|
||||||
github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo=
|
github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo=
|
||||||
github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg=
|
github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg=
|
||||||
|
github.com/mitchellh/gox v1.0.1 h1:x0jD3dcHk9a9xPSDN6YEL4xL6Qz0dvNYm8yZqui5chI=
|
||||||
github.com/mitchellh/gox v1.0.1/go.mod h1:ED6BioOGXMswlXa2zxfh/xdd5QhwYliBFn9V18Ap4z4=
|
github.com/mitchellh/gox v1.0.1/go.mod h1:ED6BioOGXMswlXa2zxfh/xdd5QhwYliBFn9V18Ap4z4=
|
||||||
github.com/mitchellh/iochan v1.0.0 h1:C+X3KsSTLFVBr/tK1eYN/vs4rJcvsiLU338UhYPJWeY=
|
github.com/mitchellh/iochan v1.0.0 h1:C+X3KsSTLFVBr/tK1eYN/vs4rJcvsiLU338UhYPJWeY=
|
||||||
github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY=
|
github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY=
|
||||||
|
|
Loading…
Reference in New Issue