github.com/turtlemonvh/terraform@v0.6.9-0.20151204001754-8e40b6b855e8/builtin/providers/packet/resource_packet_device.go (about) 1 package packet 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/packethost/packngo" 11 ) 12 13 func resourcePacketDevice() *schema.Resource { 14 return &schema.Resource{ 15 Create: resourcePacketDeviceCreate, 16 Read: resourcePacketDeviceRead, 17 Update: resourcePacketDeviceUpdate, 18 Delete: resourcePacketDeviceDelete, 19 20 Schema: map[string]*schema.Schema{ 21 "project_id": &schema.Schema{ 22 Type: schema.TypeString, 23 Required: true, 24 ForceNew: true, 25 }, 26 27 "hostname": &schema.Schema{ 28 Type: schema.TypeString, 29 Required: true, 30 ForceNew: true, 31 }, 32 33 "operating_system": &schema.Schema{ 34 Type: schema.TypeString, 35 Required: true, 36 ForceNew: true, 37 }, 38 39 "facility": &schema.Schema{ 40 Type: schema.TypeString, 41 Required: true, 42 ForceNew: true, 43 }, 44 45 "plan": &schema.Schema{ 46 Type: schema.TypeString, 47 Required: true, 48 ForceNew: true, 49 }, 50 51 "billing_cycle": &schema.Schema{ 52 Type: schema.TypeString, 53 Required: true, 54 ForceNew: true, 55 }, 56 57 "state": &schema.Schema{ 58 Type: schema.TypeString, 59 Computed: true, 60 }, 61 62 "locked": &schema.Schema{ 63 Type: schema.TypeBool, 64 Computed: true, 65 }, 66 67 "network": &schema.Schema{ 68 Type: schema.TypeList, 69 Computed: true, 70 Elem: &schema.Resource{ 71 Schema: map[string]*schema.Schema{ 72 "address": &schema.Schema{ 73 Type: schema.TypeString, 74 Computed: true, 75 }, 76 77 "gateway": &schema.Schema{ 78 Type: schema.TypeString, 79 Computed: true, 80 }, 81 82 "family": &schema.Schema{ 83 Type: schema.TypeInt, 84 Computed: true, 85 }, 86 87 "cidr": &schema.Schema{ 88 Type: schema.TypeInt, 89 Computed: true, 90 }, 91 92 "public": &schema.Schema{ 93 Type: schema.TypeBool, 94 Computed: true, 95 }, 96 }, 97 }, 98 }, 99 100 "created": &schema.Schema{ 101 Type: schema.TypeString, 102 Computed: true, 103 }, 104 105 "updated": &schema.Schema{ 106 Type: schema.TypeString, 107 Computed: true, 108 }, 109 110 "user_data": &schema.Schema{ 111 Type: schema.TypeString, 112 Optional: true, 113 }, 114 115 "tags": &schema.Schema{ 116 Type: schema.TypeList, 117 Optional: true, 118 Elem: &schema.Schema{Type: schema.TypeString}, 119 }, 120 }, 121 } 122 } 123 124 func resourcePacketDeviceCreate(d *schema.ResourceData, meta interface{}) error { 125 client := meta.(*packngo.Client) 126 127 createRequest := &packngo.DeviceCreateRequest{ 128 HostName: d.Get("hostname").(string), 129 Plan: d.Get("plan").(string), 130 Facility: d.Get("facility").(string), 131 OS: d.Get("operating_system").(string), 132 BillingCycle: d.Get("billing_cycle").(string), 133 ProjectID: d.Get("project_id").(string), 134 } 135 136 if attr, ok := d.GetOk("user_data"); ok { 137 createRequest.UserData = attr.(string) 138 } 139 140 tags := d.Get("tags.#").(int) 141 if tags > 0 { 142 createRequest.Tags = make([]string, 0, tags) 143 for i := 0; i < tags; i++ { 144 key := fmt.Sprintf("tags.%d", i) 145 createRequest.Tags = append(createRequest.Tags, d.Get(key).(string)) 146 } 147 } 148 149 log.Printf("[DEBUG] Device create configuration: %#v", createRequest) 150 151 newDevice, _, err := client.Devices.Create(createRequest) 152 if err != nil { 153 return fmt.Errorf("Error creating device: %s", err) 154 } 155 156 // Assign the device id 157 d.SetId(newDevice.ID) 158 159 log.Printf("[INFO] Device ID: %s", d.Id()) 160 161 _, err = WaitForDeviceAttribute(d, "active", []string{"queued", "provisioning"}, "state", meta) 162 if err != nil { 163 return fmt.Errorf( 164 "Error waiting for device (%s) to become ready: %s", d.Id(), err) 165 } 166 167 return resourcePacketDeviceRead(d, meta) 168 } 169 170 func resourcePacketDeviceRead(d *schema.ResourceData, meta interface{}) error { 171 client := meta.(*packngo.Client) 172 173 // Retrieve the device properties for updating the state 174 device, _, err := client.Devices.Get(d.Id()) 175 if err != nil { 176 return fmt.Errorf("Error retrieving device: %s", err) 177 } 178 179 d.Set("name", device.Hostname) 180 d.Set("plan", device.Plan.Slug) 181 d.Set("facility", device.Facility.Code) 182 d.Set("operating_system", device.OS.Slug) 183 d.Set("state", device.State) 184 d.Set("billing_cycle", device.BillingCycle) 185 d.Set("locked", device.Locked) 186 d.Set("created", device.Created) 187 d.Set("updated", device.Updated) 188 189 tags := make([]string, 0) 190 for _, tag := range device.Tags { 191 tags = append(tags, tag) 192 } 193 d.Set("tags", tags) 194 195 provisionerAddress := "" 196 197 networks := make([]map[string]interface{}, 0, 1) 198 for _, ip := range device.Network { 199 network := make(map[string]interface{}) 200 network["address"] = ip.Address 201 network["gateway"] = ip.Gateway 202 network["family"] = ip.Family 203 network["cidr"] = ip.Cidr 204 network["public"] = ip.Public 205 networks = append(networks, network) 206 if ip.Family == 4 && ip.Public == true { 207 provisionerAddress = ip.Address 208 } 209 } 210 d.Set("network", networks) 211 212 log.Printf("[DEBUG] Provisioner Address set to %v", provisionerAddress) 213 214 if provisionerAddress != "" { 215 d.SetConnInfo(map[string]string{ 216 "type": "ssh", 217 "host": provisionerAddress, 218 }) 219 } 220 221 return nil 222 } 223 224 func resourcePacketDeviceUpdate(d *schema.ResourceData, meta interface{}) error { 225 client := meta.(*packngo.Client) 226 227 if d.HasChange("locked") && d.Get("locked").(bool) { 228 _, err := client.Devices.Lock(d.Id()) 229 230 if err != nil { 231 return fmt.Errorf( 232 "Error locking device (%s): %s", d.Id(), err) 233 } 234 } else if d.HasChange("locked") { 235 _, err := client.Devices.Unlock(d.Id()) 236 237 if err != nil { 238 return fmt.Errorf( 239 "Error unlocking device (%s): %s", d.Id(), err) 240 } 241 } 242 243 return resourcePacketDeviceRead(d, meta) 244 } 245 246 func resourcePacketDeviceDelete(d *schema.ResourceData, meta interface{}) error { 247 client := meta.(*packngo.Client) 248 249 log.Printf("[INFO] Deleting device: %s", d.Id()) 250 if _, err := client.Devices.Delete(d.Id()); err != nil { 251 return fmt.Errorf("Error deleting device: %s", err) 252 } 253 254 return nil 255 } 256 257 func WaitForDeviceAttribute( 258 d *schema.ResourceData, target string, pending []string, attribute string, meta interface{}) (interface{}, error) { 259 // Wait for the device so we can get the networking attributes 260 // that show up after a while 261 log.Printf( 262 "[INFO] Waiting for device (%s) to have %s of %s", 263 d.Id(), attribute, target) 264 265 stateConf := &resource.StateChangeConf{ 266 Pending: pending, 267 Target: target, 268 Refresh: newDeviceStateRefreshFunc(d, attribute, meta), 269 Timeout: 60 * time.Minute, 270 Delay: 10 * time.Second, 271 MinTimeout: 3 * time.Second, 272 } 273 274 return stateConf.WaitForState() 275 } 276 277 func newDeviceStateRefreshFunc( 278 d *schema.ResourceData, attribute string, meta interface{}) resource.StateRefreshFunc { 279 client := meta.(*packngo.Client) 280 return func() (interface{}, string, error) { 281 err := resourcePacketDeviceRead(d, meta) 282 if err != nil { 283 return nil, "", err 284 } 285 286 // See if we can access our attribute 287 if attr, ok := d.GetOk(attribute); ok { 288 // Retrieve the device properties 289 device, _, err := client.Devices.Get(d.Id()) 290 if err != nil { 291 return nil, "", fmt.Errorf("Error retrieving device: %s", err) 292 } 293 294 return &device, attr.(string), nil 295 } 296 297 return nil, "", nil 298 } 299 } 300 301 // Powers on the device and waits for it to be active 302 func powerOnAndWait(d *schema.ResourceData, meta interface{}) error { 303 client := meta.(*packngo.Client) 304 _, err := client.Devices.PowerOn(d.Id()) 305 if err != nil { 306 return err 307 } 308 309 // Wait for power on 310 _, err = WaitForDeviceAttribute(d, "active", []string{"off"}, "state", client) 311 if err != nil { 312 return err 313 } 314 315 return nil 316 }