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