github.com/danp/terraform@v0.9.5-0.20170426144147-39d740081351/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": {
    20  				Type:     schema.TypeString,
    21  				Required: true,
    22  				ForceNew: true,
    23  			},
    24  			"volume": {
    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  		mu.Lock()
    99  		err := scaleway.PatchServer(serverID, req)
   100  		mu.Unlock()
   101  
   102  		if err == nil {
   103  			return nil
   104  		}
   105  
   106  		if serr, ok := err.(api.ScalewayAPIError); ok {
   107  			log.Printf("[DEBUG] Error patching server: %q\n", serr.APIMessage)
   108  
   109  			if serr.StatusCode == 400 {
   110  				return resource.RetryableError(fmt.Errorf("Waiting for server update to succeed: %q", serr.APIMessage))
   111  			}
   112  		}
   113  
   114  		return resource.NonRetryableError(err)
   115  	}); err != nil {
   116  		return err
   117  	}
   118  
   119  	if startServerAgain {
   120  		if err := scaleway.PostServerAction(serverID, "poweron"); err != nil {
   121  			return err
   122  		}
   123  		if err := waitForServerState(scaleway, serverID, "running"); err != nil {
   124  			return err
   125  		}
   126  	}
   127  
   128  	d.SetId(fmt.Sprintf("scaleway-server:%s/volume/%s", serverID, d.Get("volume").(string)))
   129  
   130  	return resourceScalewayVolumeAttachmentRead(d, m)
   131  }
   132  
   133  func resourceScalewayVolumeAttachmentRead(d *schema.ResourceData, m interface{}) error {
   134  	scaleway := m.(*Client).scaleway
   135  	scaleway.ClearCache()
   136  
   137  	server, err := scaleway.GetServer(d.Get("server").(string))
   138  	if err != nil {
   139  		if serr, ok := err.(api.ScalewayAPIError); ok {
   140  			log.Printf("[DEBUG] Error reading server: %q\n", serr.APIMessage)
   141  
   142  			if serr.StatusCode == 404 {
   143  				d.SetId("")
   144  				return nil
   145  			}
   146  		}
   147  		return err
   148  	}
   149  
   150  	if _, err := scaleway.GetVolume(d.Get("volume").(string)); err != nil {
   151  		if serr, ok := err.(api.ScalewayAPIError); ok {
   152  			log.Printf("[DEBUG] Error reading volume: %q\n", serr.APIMessage)
   153  
   154  			if serr.StatusCode == 404 {
   155  				d.SetId("")
   156  				return nil
   157  			}
   158  		}
   159  		return err
   160  	}
   161  
   162  	for _, volume := range server.Volumes {
   163  		if volume.Identifier == d.Get("volume").(string) {
   164  			return nil
   165  		}
   166  	}
   167  
   168  	log.Printf("[DEBUG] Volume %q not attached to server %q\n", d.Get("volume").(string), d.Get("server").(string))
   169  	d.SetId("")
   170  	return nil
   171  }
   172  
   173  func resourceScalewayVolumeAttachmentDelete(d *schema.ResourceData, m interface{}) error {
   174  	scaleway := m.(*Client).scaleway
   175  	scaleway.ClearCache()
   176  
   177  	mu.Lock()
   178  	defer mu.Unlock()
   179  
   180  	var startServerAgain = false
   181  
   182  	// guard against server shutdown/ startup race conditiond
   183  	serverID := d.Get("server").(string)
   184  	scalewayMutexKV.Lock(serverID)
   185  	defer scalewayMutexKV.Unlock(serverID)
   186  
   187  	server, err := scaleway.GetServer(serverID)
   188  	if err != nil {
   189  		return err
   190  	}
   191  
   192  	// volumes can only be modified when the server is powered off
   193  	if server.State != "stopped" {
   194  		startServerAgain = true
   195  		if err := scaleway.PostServerAction(server.Identifier, "poweroff"); err != nil {
   196  			return err
   197  		}
   198  	}
   199  	if err := waitForServerState(scaleway, server.Identifier, "stopped"); err != nil {
   200  		return err
   201  	}
   202  
   203  	volumes := make(map[string]api.ScalewayVolume)
   204  	for _, volume := range server.Volumes {
   205  		if volume.Identifier != d.Get("volume").(string) {
   206  			volumes[fmt.Sprintf("%d", len(volumes))] = volume
   207  		}
   208  	}
   209  
   210  	// the API request requires most volume attributes to be unset to succeed
   211  	for k, v := range volumes {
   212  		v.Size = 0
   213  		v.CreationDate = ""
   214  		v.Organization = ""
   215  		v.ModificationDate = ""
   216  		v.VolumeType = ""
   217  		v.Server = nil
   218  		v.ExportURI = ""
   219  
   220  		volumes[k] = v
   221  	}
   222  
   223  	if err := resource.Retry(5*time.Minute, func() *resource.RetryError {
   224  		scaleway.ClearCache()
   225  
   226  		var req = api.ScalewayServerPatchDefinition{
   227  			Volumes: &volumes,
   228  		}
   229  		mu.Lock()
   230  		err := scaleway.PatchServer(serverID, req)
   231  		mu.Unlock()
   232  
   233  		if err == nil {
   234  			return nil
   235  		}
   236  
   237  		if serr, ok := err.(api.ScalewayAPIError); ok {
   238  			log.Printf("[DEBUG] Error patching server: %q\n", serr.APIMessage)
   239  
   240  			if serr.StatusCode == 400 {
   241  				return resource.RetryableError(fmt.Errorf("Waiting for server update to succeed: %q", serr.APIMessage))
   242  			}
   243  		}
   244  
   245  		return resource.NonRetryableError(err)
   246  	}); err != nil {
   247  		return err
   248  	}
   249  
   250  	if startServerAgain {
   251  		if err := scaleway.PostServerAction(serverID, "poweron"); err != nil {
   252  			return err
   253  		}
   254  		if err := waitForServerState(scaleway, serverID, "running"); err != nil {
   255  			return err
   256  		}
   257  	}
   258  
   259  	d.SetId("")
   260  
   261  	return nil
   262  }