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 }