github.com/vtorhonen/terraform@v0.9.0-beta2.0.20170307220345-5d894e4ffda7/builtin/providers/scaleway/resource_scaleway_volume_attachment.go (about)

     1  package scaleway
     2  
     3  import (
     4  	"fmt"
     5  	"log"
     6  	"time"
     7  
     8  	"github.com/hashicorp/terraform/helper/resource"
     9  	"github.com/hashicorp/terraform/helper/schema"
    10  	"github.com/scaleway/scaleway-cli/pkg/api"
    11  )
    12  
    13  func resourceScalewayVolumeAttachment() *schema.Resource {
    14  	return &schema.Resource{
    15  		Create: resourceScalewayVolumeAttachmentCreate,
    16  		Read:   resourceScalewayVolumeAttachmentRead,
    17  		Delete: resourceScalewayVolumeAttachmentDelete,
    18  		Schema: map[string]*schema.Schema{
    19  			"server": &schema.Schema{
    20  				Type:     schema.TypeString,
    21  				Required: true,
    22  				ForceNew: true,
    23  			},
    24  			"volume": &schema.Schema{
    25  				Type:     schema.TypeString,
    26  				Required: true,
    27  				ForceNew: true,
    28  			},
    29  		},
    30  	}
    31  }
    32  
    33  var errVolumeAlreadyAttached = fmt.Errorf("Scaleway volume already attached")
    34  
    35  func resourceScalewayVolumeAttachmentCreate(d *schema.ResourceData, m interface{}) error {
    36  	scaleway := m.(*Client).scaleway
    37  	scaleway.ClearCache()
    38  
    39  	vol, err := scaleway.GetVolume(d.Get("volume").(string))
    40  	if err != nil {
    41  		return err
    42  	}
    43  	if vol.Server != nil {
    44  		log.Printf("[DEBUG] Scaleway volume %q already attached to %q.", vol.Identifier, vol.Server.Identifier)
    45  		return errVolumeAlreadyAttached
    46  	}
    47  
    48  	// guard against server shutdown/ startup race conditiond
    49  	serverID := d.Get("server").(string)
    50  	scalewayMutexKV.Lock(serverID)
    51  	defer scalewayMutexKV.Unlock(serverID)
    52  
    53  	server, err := scaleway.GetServer(serverID)
    54  	if err != nil {
    55  		fmt.Printf("Failed getting server: %q", err)
    56  		return err
    57  	}
    58  
    59  	var startServerAgain = false
    60  	// volumes can only be modified when the server is powered off
    61  	if server.State != "stopped" {
    62  		startServerAgain = true
    63  
    64  		if err := scaleway.PostServerAction(server.Identifier, "poweroff"); err != nil {
    65  			return err
    66  		}
    67  	}
    68  	if err := waitForServerState(scaleway, server.Identifier, "stopped"); err != nil {
    69  		return err
    70  	}
    71  
    72  	volumes := make(map[string]api.ScalewayVolume)
    73  	for i, volume := range server.Volumes {
    74  		volumes[i] = volume
    75  	}
    76  
    77  	volumes[fmt.Sprintf("%d", len(volumes)+1)] = *vol
    78  
    79  	// the API request requires most volume attributes to be unset to succeed
    80  	for k, v := range volumes {
    81  		v.Size = 0
    82  		v.CreationDate = ""
    83  		v.Organization = ""
    84  		v.ModificationDate = ""
    85  		v.VolumeType = ""
    86  		v.Server = nil
    87  		v.ExportURI = ""
    88  
    89  		volumes[k] = v
    90  	}
    91  
    92  	if err := resource.Retry(5*time.Minute, func() *resource.RetryError {
    93  		scaleway.ClearCache()
    94  
    95  		var req = api.ScalewayServerPatchDefinition{
    96  			Volumes: &volumes,
    97  		}
    98  		err := scaleway.PatchServer(serverID, req)
    99  
   100  		if err == nil {
   101  			return nil
   102  		}
   103  
   104  		if serr, ok := err.(api.ScalewayAPIError); ok {
   105  			log.Printf("[DEBUG] Error patching server: %q\n", serr.APIMessage)
   106  
   107  			if serr.StatusCode == 400 {
   108  				return resource.RetryableError(fmt.Errorf("Waiting for server update to succeed: %q", serr.APIMessage))
   109  			}
   110  		}
   111  
   112  		return resource.NonRetryableError(err)
   113  	}); err != nil {
   114  		return err
   115  	}
   116  
   117  	if startServerAgain {
   118  		if err := scaleway.PostServerAction(serverID, "poweron"); err != nil {
   119  			return err
   120  		}
   121  		if err := waitForServerState(scaleway, serverID, "running"); err != nil {
   122  			return err
   123  		}
   124  	}
   125  
   126  	d.SetId(fmt.Sprintf("scaleway-server:%s/volume/%s", serverID, d.Get("volume").(string)))
   127  
   128  	return resourceScalewayVolumeAttachmentRead(d, m)
   129  }
   130  
   131  func resourceScalewayVolumeAttachmentRead(d *schema.ResourceData, m interface{}) error {
   132  	scaleway := m.(*Client).scaleway
   133  	scaleway.ClearCache()
   134  
   135  	server, err := scaleway.GetServer(d.Get("server").(string))
   136  	if err != nil {
   137  		if serr, ok := err.(api.ScalewayAPIError); ok {
   138  			log.Printf("[DEBUG] Error reading server: %q\n", serr.APIMessage)
   139  
   140  			if serr.StatusCode == 404 {
   141  				d.SetId("")
   142  				return nil
   143  			}
   144  		}
   145  		return err
   146  	}
   147  
   148  	if _, err := scaleway.GetVolume(d.Get("volume").(string)); err != nil {
   149  		if serr, ok := err.(api.ScalewayAPIError); ok {
   150  			log.Printf("[DEBUG] Error reading volume: %q\n", serr.APIMessage)
   151  
   152  			if serr.StatusCode == 404 {
   153  				d.SetId("")
   154  				return nil
   155  			}
   156  		}
   157  		return err
   158  	}
   159  
   160  	for _, volume := range server.Volumes {
   161  		if volume.Identifier == d.Get("volume").(string) {
   162  			return nil
   163  		}
   164  	}
   165  
   166  	log.Printf("[DEBUG] Volume %q not attached to server %q\n", d.Get("volume").(string), d.Get("server").(string))
   167  	d.SetId("")
   168  	return nil
   169  }
   170  
   171  func resourceScalewayVolumeAttachmentDelete(d *schema.ResourceData, m interface{}) error {
   172  	scaleway := m.(*Client).scaleway
   173  	scaleway.ClearCache()
   174  
   175  	var startServerAgain = false
   176  
   177  	// guard against server shutdown/ startup race conditiond
   178  	serverID := d.Get("server").(string)
   179  	scalewayMutexKV.Lock(serverID)
   180  	defer scalewayMutexKV.Unlock(serverID)
   181  
   182  	server, err := scaleway.GetServer(serverID)
   183  	if err != nil {
   184  		return err
   185  	}
   186  
   187  	// volumes can only be modified when the server is powered off
   188  	if server.State != "stopped" {
   189  		startServerAgain = true
   190  		if err := scaleway.PostServerAction(server.Identifier, "poweroff"); err != nil {
   191  			return err
   192  		}
   193  	}
   194  	if err := waitForServerState(scaleway, server.Identifier, "stopped"); err != nil {
   195  		return err
   196  	}
   197  
   198  	volumes := make(map[string]api.ScalewayVolume)
   199  	for _, volume := range server.Volumes {
   200  		if volume.Identifier != d.Get("volume").(string) {
   201  			volumes[fmt.Sprintf("%d", len(volumes))] = volume
   202  		}
   203  	}
   204  
   205  	// the API request requires most volume attributes to be unset to succeed
   206  	for k, v := range volumes {
   207  		v.Size = 0
   208  		v.CreationDate = ""
   209  		v.Organization = ""
   210  		v.ModificationDate = ""
   211  		v.VolumeType = ""
   212  		v.Server = nil
   213  		v.ExportURI = ""
   214  
   215  		volumes[k] = v
   216  	}
   217  
   218  	if err := resource.Retry(5*time.Minute, func() *resource.RetryError {
   219  		scaleway.ClearCache()
   220  
   221  		var req = api.ScalewayServerPatchDefinition{
   222  			Volumes: &volumes,
   223  		}
   224  		err := scaleway.PatchServer(serverID, req)
   225  
   226  		if err == nil {
   227  			return nil
   228  		}
   229  
   230  		if serr, ok := err.(api.ScalewayAPIError); ok {
   231  			log.Printf("[DEBUG] Error patching server: %q\n", serr.APIMessage)
   232  
   233  			if serr.StatusCode == 400 {
   234  				return resource.RetryableError(fmt.Errorf("Waiting for server update to succeed: %q", serr.APIMessage))
   235  			}
   236  		}
   237  
   238  		return resource.NonRetryableError(err)
   239  	}); err != nil {
   240  		return err
   241  	}
   242  
   243  	if startServerAgain {
   244  		if err := scaleway.PostServerAction(serverID, "poweron"); err != nil {
   245  			return err
   246  		}
   247  		if err := waitForServerState(scaleway, serverID, "running"); err != nil {
   248  			return err
   249  		}
   250  	}
   251  
   252  	d.SetId("")
   253  
   254  	return nil
   255  }