github.com/bradfeehan/terraform@v0.7.0-rc3.0.20170529055808-34b45c5ad841/builtin/providers/scaleway/resource_scaleway_server.go (about) 1 package scaleway 2 3 import ( 4 "fmt" 5 "log" 6 7 "github.com/hashicorp/terraform/helper/schema" 8 "github.com/scaleway/scaleway-cli/pkg/api" 9 ) 10 11 func resourceScalewayServer() *schema.Resource { 12 return &schema.Resource{ 13 Create: resourceScalewayServerCreate, 14 Read: resourceScalewayServerRead, 15 Update: resourceScalewayServerUpdate, 16 Delete: resourceScalewayServerDelete, 17 Importer: &schema.ResourceImporter{ 18 State: schema.ImportStatePassthrough, 19 }, 20 21 Schema: map[string]*schema.Schema{ 22 "name": { 23 Type: schema.TypeString, 24 Required: true, 25 }, 26 "image": { 27 Type: schema.TypeString, 28 Required: true, 29 ForceNew: true, 30 }, 31 "type": { 32 Type: schema.TypeString, 33 Required: true, 34 ForceNew: true, 35 }, 36 "bootscript": { 37 Type: schema.TypeString, 38 Optional: true, 39 }, 40 "tags": { 41 Type: schema.TypeList, 42 Elem: &schema.Schema{ 43 Type: schema.TypeString, 44 }, 45 Optional: true, 46 }, 47 "security_group": { 48 Type: schema.TypeString, 49 Optional: true, 50 }, 51 "volume": { 52 Type: schema.TypeList, 53 Optional: true, 54 ForceNew: true, 55 Elem: &schema.Resource{ 56 Schema: map[string]*schema.Schema{ 57 "size_in_gb": { 58 Type: schema.TypeInt, 59 Required: true, 60 ValidateFunc: validateVolumeSize, 61 }, 62 "type": { 63 Type: schema.TypeString, 64 Required: true, 65 ValidateFunc: validateVolumeType, 66 }, 67 "volume_id": { 68 Type: schema.TypeString, 69 Computed: true, 70 }, 71 }, 72 }, 73 }, 74 "enable_ipv6": { 75 Type: schema.TypeBool, 76 Optional: true, 77 Default: false, 78 }, 79 "dynamic_ip_required": { 80 Type: schema.TypeBool, 81 Optional: true, 82 }, 83 "private_ip": { 84 Type: schema.TypeString, 85 Computed: true, 86 }, 87 "public_ip": { 88 Type: schema.TypeString, 89 Optional: true, 90 Computed: true, 91 }, 92 "public_ipv6": { 93 Type: schema.TypeString, 94 Computed: true, 95 }, 96 "state": { 97 Type: schema.TypeString, 98 Optional: true, 99 Computed: true, 100 }, 101 "state_detail": { 102 Type: schema.TypeString, 103 Computed: true, 104 }, 105 }, 106 } 107 } 108 109 func resourceScalewayServerCreate(d *schema.ResourceData, m interface{}) error { 110 scaleway := m.(*Client).scaleway 111 112 mu.Lock() 113 defer mu.Unlock() 114 115 image := d.Get("image").(string) 116 var server = api.ScalewayServerDefinition{ 117 Name: d.Get("name").(string), 118 Image: String(image), 119 Organization: scaleway.Organization, 120 EnableIPV6: d.Get("enable_ipv6").(bool), 121 SecurityGroup: d.Get("security_group").(string), 122 } 123 124 server.DynamicIPRequired = Bool(d.Get("dynamic_ip_required").(bool)) 125 server.CommercialType = d.Get("type").(string) 126 127 if bootscript, ok := d.GetOk("bootscript"); ok { 128 server.Bootscript = String(bootscript.(string)) 129 } 130 131 if vs, ok := d.GetOk("volume"); ok { 132 server.Volumes = make(map[string]string) 133 134 volumes := vs.([]interface{}) 135 for i, v := range volumes { 136 volume := v.(map[string]interface{}) 137 138 volumeID, err := scaleway.PostVolume(api.ScalewayVolumeDefinition{ 139 Size: uint64(volume["size_in_gb"].(int)) * gb, 140 Type: volume["type"].(string), 141 Name: fmt.Sprintf("%s-%d", server.Name, volume["size_in_gb"].(int)), 142 }) 143 if err != nil { 144 return err 145 } 146 volume["volume_id"] = volumeID 147 volumes[i] = volume 148 server.Volumes[fmt.Sprintf("%d", i+1)] = volumeID 149 } 150 d.Set("volume", volumes) 151 } 152 153 if raw, ok := d.GetOk("tags"); ok { 154 for _, tag := range raw.([]interface{}) { 155 server.Tags = append(server.Tags, tag.(string)) 156 } 157 } 158 159 id, err := scaleway.PostServer(server) 160 if err != nil { 161 return err 162 } 163 164 d.SetId(id) 165 if d.Get("state").(string) != "stopped" { 166 err = scaleway.PostServerAction(id, "poweron") 167 if err != nil { 168 return err 169 } 170 171 err = waitForServerState(scaleway, id, "running") 172 173 if v, ok := d.GetOk("public_ip"); ok { 174 if ips, err := scaleway.GetIPS(); err != nil { 175 return err 176 } else { 177 for _, ip := range ips.IPS { 178 if ip.Address == v.(string) { 179 log.Printf("[DEBUG] Attaching IP %q to server %q\n", ip.ID, d.Id()) 180 if err := scaleway.AttachIP(ip.ID, d.Id()); err != nil { 181 return err 182 } 183 break 184 } 185 } 186 } 187 } 188 } 189 190 if err != nil { 191 return err 192 } 193 194 return resourceScalewayServerRead(d, m) 195 } 196 197 func resourceScalewayServerRead(d *schema.ResourceData, m interface{}) error { 198 scaleway := m.(*Client).scaleway 199 server, err := scaleway.GetServer(d.Id()) 200 201 if err != nil { 202 if serr, ok := err.(api.ScalewayAPIError); ok { 203 log.Printf("[DEBUG] Error reading server: %q\n", serr.APIMessage) 204 205 if serr.StatusCode == 404 { 206 d.SetId("") 207 return nil 208 } 209 } 210 211 return err 212 } 213 214 d.Set("name", server.Name) 215 d.Set("image", server.Image.Identifier) 216 d.Set("type", server.CommercialType) 217 d.Set("enable_ipv6", server.EnableIPV6) 218 d.Set("private_ip", server.PrivateIP) 219 d.Set("public_ip", server.PublicAddress.IP) 220 221 if server.EnableIPV6 { 222 d.Set("public_ipv6", server.IPV6.Address) 223 } 224 225 d.Set("state", server.State) 226 d.Set("state_detail", server.StateDetail) 227 d.Set("tags", server.Tags) 228 229 d.SetConnInfo(map[string]string{ 230 "type": "ssh", 231 "host": server.PublicAddress.IP, 232 }) 233 234 return nil 235 } 236 237 func resourceScalewayServerUpdate(d *schema.ResourceData, m interface{}) error { 238 scaleway := m.(*Client).scaleway 239 240 mu.Lock() 241 defer mu.Unlock() 242 243 var req api.ScalewayServerPatchDefinition 244 if d.HasChange("name") { 245 name := d.Get("name").(string) 246 req.Name = &name 247 } 248 249 if d.HasChange("tags") { 250 if raw, ok := d.GetOk("tags"); ok { 251 var tags []string 252 for _, tag := range raw.([]interface{}) { 253 tags = append(tags, tag.(string)) 254 } 255 req.Tags = &tags 256 } 257 } 258 259 if d.HasChange("enable_ipv6") { 260 req.EnableIPV6 = Bool(d.Get("enable_ipv6").(bool)) 261 } 262 263 if d.HasChange("dynamic_ip_required") { 264 req.DynamicIPRequired = Bool(d.Get("dynamic_ip_required").(bool)) 265 } 266 267 if d.HasChange("security_group") { 268 req.SecurityGroup = &api.ScalewaySecurityGroup{ 269 Identifier: d.Get("security_group").(string), 270 } 271 } 272 273 if err := scaleway.PatchServer(d.Id(), req); err != nil { 274 return fmt.Errorf("Failed patching scaleway server: %q", err) 275 } 276 277 if d.HasChange("public_ip") { 278 ips, err := scaleway.GetIPS() 279 if err != nil { 280 return err 281 } 282 if v, ok := d.GetOk("public_ip"); ok { 283 for _, ip := range ips.IPS { 284 if ip.Address == v.(string) { 285 log.Printf("[DEBUG] Attaching IP %q to server %q\n", ip.ID, d.Id()) 286 if err := scaleway.AttachIP(ip.ID, d.Id()); err != nil { 287 return err 288 } 289 break 290 } 291 } 292 } else { 293 for _, ip := range ips.IPS { 294 if ip.Server != nil && ip.Server.Identifier == d.Id() { 295 log.Printf("[DEBUG] Detaching IP %q to server %q\n", ip.ID, d.Id()) 296 if err := scaleway.DetachIP(ip.ID); err != nil { 297 return err 298 } 299 break 300 } 301 } 302 } 303 } 304 305 return resourceScalewayServerRead(d, m) 306 } 307 308 func resourceScalewayServerDelete(d *schema.ResourceData, m interface{}) error { 309 scaleway := m.(*Client).scaleway 310 311 mu.Lock() 312 defer mu.Unlock() 313 314 s, err := scaleway.GetServer(d.Id()) 315 if err != nil { 316 return err 317 } 318 319 if s.State == "stopped" { 320 return deleteStoppedServer(scaleway, s) 321 } 322 323 err = deleteRunningServer(scaleway, s) 324 325 if err == nil { 326 d.SetId("") 327 } 328 329 return err 330 }