packer-cn/builder/osc/common/state.go

268 lines
6.8 KiB
Go

package common
import (
"context"
"fmt"
"log"
"github.com/antihax/optional"
"github.com/hashicorp/packer/builder/osc/common/retry"
"github.com/outscale/osc-sdk-go/osc"
)
type stateRefreshFunc func() (string, error)
func waitUntilForOscVmRunning(conn *osc.APIClient, vmID string) error {
errCh := make(chan error, 1)
go waitForState(errCh, "running", waitUntilOscVmStateFunc(conn, vmID))
err := <-errCh
return err
}
func waitUntilOscVmDeleted(conn *osc.APIClient, vmID string) error {
errCh := make(chan error, 1)
go waitForState(errCh, "terminated", waitUntilOscVmStateFunc(conn, vmID))
return <-errCh
}
func waitUntilOscVmStopped(conn *osc.APIClient, vmID string) error {
errCh := make(chan error, 1)
go waitForState(errCh, "stopped", waitUntilOscVmStateFunc(conn, vmID))
return <-errCh
}
func WaitUntilOscSnapshotCompleted(conn *osc.APIClient, id string) error {
errCh := make(chan error, 1)
go waitForState(errCh, "completed", waitUntilOscSnapshotStateFunc(conn, id))
return <-errCh
}
func WaitUntilOscImageAvailable(conn *osc.APIClient, imageID string) error {
errCh := make(chan error, 1)
go waitForState(errCh, "available", waitUntilOscImageStateFunc(conn, imageID))
return <-errCh
}
func WaitUntilOscVolumeAvailable(conn *osc.APIClient, volumeID string) error {
errCh := make(chan error, 1)
go waitForState(errCh, "available", volumeOscWaitFunc(conn, volumeID))
return <-errCh
}
func WaitUntilOscVolumeIsLinked(conn *osc.APIClient, volumeID string) error {
errCh := make(chan error, 1)
go waitForState(errCh, "attached", waitUntilOscVolumeLinkedStateFunc(conn, volumeID))
return <-errCh
}
func WaitUntilOscVolumeIsUnlinked(conn *osc.APIClient, volumeID string) error {
errCh := make(chan error, 1)
go waitForState(errCh, "dettached", waitUntilOscVolumeUnLinkedStateFunc(conn, volumeID))
return <-errCh
}
func WaitUntilOscSnapshotDone(conn *osc.APIClient, snapshotID string) error {
errCh := make(chan error, 1)
go waitForState(errCh, "completed", waitUntilOscSnapshotDoneStateFunc(conn, snapshotID))
return <-errCh
}
func waitForState(errCh chan<- error, target string, refresh stateRefreshFunc) {
err := retry.Run(2, 2, 0, func(_ uint) (bool, error) {
state, err := refresh()
if err != nil {
return false, err
} else if state == target {
return true, nil
}
return false, nil
})
errCh <- err
}
func waitUntilOscVmStateFunc(conn *osc.APIClient, id string) stateRefreshFunc {
return func() (string, error) {
log.Printf("[Debug] Retrieving state for VM with id %s", id)
resp, _, err := conn.VmApi.ReadVms(context.Background(), &osc.ReadVmsOpts{
ReadVmsRequest: optional.NewInterface(osc.ReadVmsRequest{
Filters: osc.FiltersVm{
VmIds: []string{id},
},
}),
})
if err != nil {
return "", err
}
//TODO: check if needed
// if resp == nil {
// return "", fmt.Errorf("Vm with ID %s not Found", id)
// }
if len(resp.Vms) == 0 {
return "pending", nil
}
return resp.Vms[0].State, nil
}
}
func waitUntilOscVolumeLinkedStateFunc(conn *osc.APIClient, id string) stateRefreshFunc {
return func() (string, error) {
log.Printf("[Debug] Check if volume with id %s exists", id)
resp, _, err := conn.VolumeApi.ReadVolumes(context.Background(), &osc.ReadVolumesOpts{
ReadVolumesRequest: optional.NewInterface(osc.ReadVolumesRequest{
Filters: osc.FiltersVolume{
VolumeIds: []string{id},
},
}),
})
if err != nil {
return "", err
}
if len(resp.Volumes) == 0 {
return "pending", nil
}
if len(resp.Volumes[0].LinkedVolumes) == 0 {
return "pending", nil
}
return resp.Volumes[0].LinkedVolumes[0].State, nil
}
}
func waitUntilOscVolumeUnLinkedStateFunc(conn *osc.APIClient, id string) stateRefreshFunc {
return func() (string, error) {
log.Printf("[Debug] Check if volume with id %s exists", id)
resp, _, err := conn.VolumeApi.ReadVolumes(context.Background(), &osc.ReadVolumesOpts{
ReadVolumesRequest: optional.NewInterface(osc.ReadVolumesRequest{
Filters: osc.FiltersVolume{
VolumeIds: []string{id},
},
}),
})
if err != nil {
return "", err
}
if len(resp.Volumes) == 0 {
return "pending", nil
}
if len(resp.Volumes[0].LinkedVolumes) == 0 {
return "dettached", nil
}
return "failed", nil
}
}
func waitUntilOscSnapshotStateFunc(conn *osc.APIClient, id string) stateRefreshFunc {
return func() (string, error) {
log.Printf("[Debug] Check if Snapshot with id %s exists", id)
resp, _, err := conn.SnapshotApi.ReadSnapshots(context.Background(), &osc.ReadSnapshotsOpts{
ReadSnapshotsRequest: optional.NewInterface(osc.ReadSnapshotsRequest{
Filters: osc.FiltersSnapshot{
SnapshotIds: []string{id},
},
}),
})
if err != nil {
return "", err
}
if len(resp.Snapshots) == 0 {
return "pending", nil
}
return resp.Snapshots[0].State, nil
}
}
func waitUntilOscImageStateFunc(conn *osc.APIClient, id string) stateRefreshFunc {
return func() (string, error) {
log.Printf("[Debug] Check if Image with id %s exists", id)
resp, _, err := conn.ImageApi.ReadImages(context.Background(), &osc.ReadImagesOpts{
ReadImagesRequest: optional.NewInterface(osc.ReadImagesRequest{
Filters: osc.FiltersImage{
ImageIds: []string{id},
},
}),
})
if err != nil {
return "", err
}
if len(resp.Images) == 0 {
return "pending", nil
}
if resp.Images[0].State == "failed" {
return resp.Images[0].State, fmt.Errorf("Image (%s) creation is failed", id)
}
return resp.Images[0].State, nil
}
}
func waitUntilOscSnapshotDoneStateFunc(conn *osc.APIClient, id string) stateRefreshFunc {
return func() (string, error) {
log.Printf("[Debug] Check if Snapshot with id %s exists", id)
resp, _, err := conn.SnapshotApi.ReadSnapshots(context.Background(), &osc.ReadSnapshotsOpts{
ReadSnapshotsRequest: optional.NewInterface(osc.ReadSnapshotsRequest{
Filters: osc.FiltersSnapshot{
SnapshotIds: []string{id},
},
}),
})
if err != nil {
return "", err
}
if len(resp.Snapshots) == 0 {
return "", fmt.Errorf("Snapshot with ID %s. Not Found", id)
}
if resp.Snapshots[0].State == "error" {
return resp.Snapshots[0].State, fmt.Errorf("Snapshot (%s) creation is failed", id)
}
return resp.Snapshots[0].State, nil
}
}
func volumeOscWaitFunc(conn *osc.APIClient, id string) stateRefreshFunc {
return func() (string, error) {
log.Printf("[Debug] Check if SvolumeG with id %s exists", id)
resp, _, err := conn.VolumeApi.ReadVolumes(context.Background(), &osc.ReadVolumesOpts{
ReadVolumesRequest: optional.NewInterface(osc.ReadVolumesRequest{
Filters: osc.FiltersVolume{
VolumeIds: []string{id},
},
}),
})
if err != nil {
return "", err
}
if len(resp.Volumes) == 0 {
return "waiting", nil
}
if resp.Volumes[0].State == "error" {
return resp.Volumes[0].State, fmt.Errorf("Volume (%s) creation is failed", id)
}
return resp.Volumes[0].State, nil
}
}