Skip to content

Commit

Permalink
Merge pull request #55 from terraform-providers/use-task-api
Browse files Browse the repository at this point in the history
replace waiting on server results with task api
  • Loading branch information
nicolai86 authored Mar 31, 2018
2 parents 492a5f3 + 8c44821 commit c73f6ff
Show file tree
Hide file tree
Showing 3 changed files with 111 additions and 155 deletions.
78 changes: 45 additions & 33 deletions scaleway/helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ func validateVolumeType(v interface{}, k string) (ws []string, errors []error) {

// deleteRunningServer terminates the server and waits until it is removed.
func deleteRunningServer(scaleway *api.API, server *api.Server) error {
_, err := scaleway.PostServerAction(server.Identifier, "terminate")
task, err := scaleway.PostServerAction(server.Identifier, "terminate")

if err != nil {
if serr, ok := err.(api.APIError); ok {
Expand All @@ -59,7 +59,7 @@ func deleteRunningServer(scaleway *api.API, server *api.Server) error {
return err
}

return waitForServerShutdown(scaleway, server.Identifier)
return waitForTaskCompletion(scaleway, task.Identifier)
}

// deleteStoppedServer needs to cleanup attached root volumes. this is not done
Expand All @@ -77,40 +77,16 @@ func deleteStoppedServer(scaleway *api.API, server *api.Server) error {
return nil
}

// NOTE copied from github.com/scaleway/scaleway-cli/pkg/api/helpers.go
// the helpers.go file pulls in quite a lot dependencies, and they're just convenience wrappers anyway

var allStates = []string{"starting", "running", "stopping", "stopped"}

func waitForServerStartup(scaleway *api.API, serverID string) error {
return waitForServerState(scaleway, serverID, "running", []string{"running", "starting"})
}

func waitForServerShutdown(scaleway *api.API, serverID string) error {
return waitForServerState(scaleway, serverID, "stopped", []string{"stopped", "stopping"})
}

func waitForServerState(scaleway *api.API, serverID, targetState string, pendingStates []string) error {
func waitForTaskCompletion(scaleway *api.API, taskID string) error {
stateConf := &resource.StateChangeConf{
Pending: pendingStates,
Target: []string{targetState},
Pending: []string{"pending", "started"},
Target: []string{"success"},
Refresh: func() (interface{}, string, error) {
s, err := scaleway.GetServer(serverID)

if err == nil {
return 42, s.State, nil
}

if serr, ok := err.(api.APIError); ok {
if serr.StatusCode == 404 {
return 42, "stopped", nil
}
task, err := scaleway.GetTask(taskID)
if err != nil {
return 42, "error", err
}

if s != nil {
return 42, s.State, err
}
return 42, "error", err
return 42, task.Status, nil
},
Timeout: 60 * time.Minute,
MinTimeout: 10 * time.Second,
Expand All @@ -119,3 +95,39 @@ func waitForServerState(scaleway *api.API, serverID, targetState string, pending
_, err := stateConf.WaitForState()
return err
}

func withStoppedServer(scaleway *api.API, serverID string, run func(*api.Server) error) error {
server, err := scaleway.GetServer(serverID)
if err != nil {
return err
}

var startServerAgain = false

if server.State != "stopped" {
startServerAgain = true

task, err := scaleway.PostServerAction(server.Identifier, "poweroff")
if err != nil {
return err
}
if err := waitForTaskCompletion(scaleway, task.Identifier); err != nil {
return err
}
}

if err := run(server); err != nil {
return err
}

if startServerAgain {
task, err := scaleway.PostServerAction(serverID, "poweron")
if err != nil {
return err
}
if err := waitForTaskCompletion(scaleway, task.Identifier); err != nil {
return err
}
}
return nil
}
4 changes: 2 additions & 2 deletions scaleway/resource_server.go
Original file line number Diff line number Diff line change
Expand Up @@ -203,12 +203,12 @@ func resourceScalewayServerCreate(d *schema.ResourceData, m interface{}) error {

d.SetId(server.Identifier)
if d.Get("state").(string) != "stopped" {
_, err = scaleway.PostServerAction(server.Identifier, "poweron")
task, err := scaleway.PostServerAction(server.Identifier, "poweron")
if err != nil {
return err
}

err = waitForServerStartup(scaleway, server.Identifier)
err = waitForTaskCompletion(scaleway, task.Identifier)

if v, ok := d.GetOk("public_ip"); ok {
if err := attachIP(scaleway, d.Id(), v.(string)); err != nil {
Expand Down
184 changes: 64 additions & 120 deletions scaleway/resource_volume_attachment.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,81 +49,52 @@ func resourceScalewayVolumeAttachmentCreate(d *schema.ResourceData, m interface{
return errVolumeAlreadyAttached
}

serverID := d.Get("server").(string)

server, err := scaleway.GetServer(serverID)
if err != nil {
fmt.Printf("Failed getting server: %q", err)
return err
}

var startServerAgain = false
// volumes can only be modified when the server is powered off
if server.State != "stopped" {
startServerAgain = true

if _, err := scaleway.PostServerAction(server.Identifier, "poweroff"); err != nil {
return err
if err := withStoppedServer(scaleway, d.Get("server").(string), func(server *api.Server) error {
volumes := make(map[string]api.Volume)
for i, volume := range server.Volumes {
volumes[i] = volume
}
}

if err := waitForServerShutdown(scaleway, server.Identifier); err != nil {
return err
}

volumes := make(map[string]api.Volume)
for i, volume := range server.Volumes {
volumes[i] = volume
}
volumes[fmt.Sprintf("%d", len(volumes)+1)] = *vol

volumes[fmt.Sprintf("%d", len(volumes)+1)] = *vol

// the API request requires most volume attributes to be unset to succeed
for k, v := range volumes {
v.Size = 0
v.CreationDate = ""
v.Organization = ""
v.ModificationDate = ""
v.VolumeType = ""
v.Server = nil
v.ExportURI = ""

volumes[k] = v
}
// the API request requires most volume attributes to be unset to succeed
for k, v := range volumes {
v.Size = 0
v.CreationDate = ""
v.Organization = ""
v.ModificationDate = ""
v.VolumeType = ""
v.Server = nil
v.ExportURI = ""

if err := resource.Retry(serverWaitTimeout, func() *resource.RetryError {
var req = api.ServerPatchDefinition{
Volumes: &volumes,
volumes[k] = v
}
err := scaleway.PatchServer(serverID, req)

if err == nil {
return nil
}
return resource.Retry(serverWaitTimeout, func() *resource.RetryError {
var req = api.ServerPatchDefinition{
Volumes: &volumes,
}
err := scaleway.PatchServer(server.Identifier, req)

if serr, ok := err.(api.APIError); ok {
log.Printf("[DEBUG] Error patching server: %q\n", serr.APIMessage)
if err == nil {
return nil
}

if serr, ok := err.(api.APIError); ok {
log.Printf("[DEBUG] Error patching server: %q\n", serr.APIMessage)

if serr.StatusCode == 400 {
return resource.RetryableError(fmt.Errorf("Waiting for server update to succeed: %q", serr.APIMessage))
if serr.StatusCode == 400 {
return resource.RetryableError(fmt.Errorf("Waiting for server update to succeed: %q", serr.APIMessage))
}
}
}

return resource.NonRetryableError(err)
return resource.NonRetryableError(err)
})
}); err != nil {
return err
}

if startServerAgain {
if _, err := scaleway.PostServerAction(serverID, "poweron"); err != nil {
return err
}
if err := waitForServerStartup(scaleway, serverID); err != nil {
return err
}
}

d.SetId(fmt.Sprintf("scaleway-server:%s/volume/%s", serverID, d.Get("volume").(string)))
d.SetId(fmt.Sprintf("scaleway-server:%s/volume/%s", d.Get("server").(string), d.Get("volume").(string)))

return resourceScalewayVolumeAttachmentRead(d, m)
}
Expand Down Expand Up @@ -175,78 +146,51 @@ func resourceScalewayVolumeAttachmentDelete(d *schema.ResourceData, m interface{

scaleway := m.(*Client).scaleway

var startServerAgain = false

serverID := d.Get("server").(string)

server, err := scaleway.GetServer(serverID)
if err != nil {
return err
}

// volumes can only be modified when the server is powered off
if server.State != "stopped" {
startServerAgain = true
if _, err := scaleway.PostServerAction(server.Identifier, "poweroff"); err != nil {
return err
}
}
if err := waitForServerShutdown(scaleway, server.Identifier); err != nil {
return err
}

volumes := make(map[string]api.Volume)
for _, volume := range server.Volumes {
if volume.Identifier != d.Get("volume").(string) {
volumes[fmt.Sprintf("%d", len(volumes))] = volume
if err := withStoppedServer(scaleway, d.Get("server").(string), func(server *api.Server) error {
volumes := make(map[string]api.Volume)
for _, volume := range server.Volumes {
if volume.Identifier != d.Get("volume").(string) {
volumes[fmt.Sprintf("%d", len(volumes))] = volume
}
}
}

// the API request requires most volume attributes to be unset to succeed
for k, v := range volumes {
v.Size = 0
v.CreationDate = ""
v.Organization = ""
v.ModificationDate = ""
v.VolumeType = ""
v.Server = nil
v.ExportURI = ""

volumes[k] = v
}
// the API request requires most volume attributes to be unset to succeed
for k, v := range volumes {
v.Size = 0
v.CreationDate = ""
v.Organization = ""
v.ModificationDate = ""
v.VolumeType = ""
v.Server = nil
v.ExportURI = ""

if err := resource.Retry(serverWaitTimeout, func() *resource.RetryError {
var req = api.ServerPatchDefinition{
Volumes: &volumes,
volumes[k] = v
}
err := scaleway.PatchServer(serverID, req)

if err == nil {
return nil
}
return resource.Retry(serverWaitTimeout, func() *resource.RetryError {
var req = api.ServerPatchDefinition{
Volumes: &volumes,
}
err := scaleway.PatchServer(server.Identifier, req)

if serr, ok := err.(api.APIError); ok {
log.Printf("[DEBUG] Error patching server: %q\n", serr.APIMessage)
if err == nil {
return nil
}

if serr.StatusCode == 400 {
return resource.RetryableError(fmt.Errorf("Waiting for server update to succeed: %q", serr.APIMessage))
if serr, ok := err.(api.APIError); ok {
log.Printf("[DEBUG] Error patching server: %q\n", serr.APIMessage)

if serr.StatusCode == 400 {
return resource.RetryableError(fmt.Errorf("Waiting for server update to succeed: %q", serr.APIMessage))
}
}
}

return resource.NonRetryableError(err)
return resource.NonRetryableError(err)
})
}); err != nil {
return err
}

if startServerAgain {
if _, err := scaleway.PostServerAction(serverID, "poweron"); err != nil {
return err
}
if err := waitForServerStartup(scaleway, serverID); err != nil {
return err
}
}

d.SetId("")

return nil
Expand Down

0 comments on commit c73f6ff

Please sign in to comment.