github.com/jsoriano/terraform@v0.6.7-0.20151026070445-8b70867fdd95/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{"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("udpated", 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 networks := make([]map[string]interface{}, 0, 1) 196 for _, ip := range device.Network { 197 network := make(map[string]interface{}) 198 network["address"] = ip.Address 199 network["gateway"] = ip.Gateway 200 network["family"] = ip.Family 201 network["cidr"] = ip.Cidr 202 network["public"] = ip.Public 203 networks = append(networks, network) 204 } 205 d.Set("network", networks) 206 207 return nil 208 } 209 210 func resourcePacketDeviceUpdate(d *schema.ResourceData, meta interface{}) error { 211 client := meta.(*packngo.Client) 212 213 if d.HasChange("locked") && d.Get("locked").(bool) { 214 _, err := client.Devices.Lock(d.Id()) 215 216 if err != nil { 217 return fmt.Errorf( 218 "Error locking device (%s): %s", d.Id(), err) 219 } 220 } else if d.HasChange("locked") { 221 _, err := client.Devices.Unlock(d.Id()) 222 223 if err != nil { 224 return fmt.Errorf( 225 "Error unlocking device (%s): %s", d.Id(), err) 226 } 227 } 228 229 return resourcePacketDeviceRead(d, meta) 230 } 231 232 func resourcePacketDeviceDelete(d *schema.ResourceData, meta interface{}) error { 233 client := meta.(*packngo.Client) 234 235 log.Printf("[INFO] Deleting device: %s", d.Id()) 236 if _, err := client.Devices.Delete(d.Id()); err != nil { 237 return fmt.Errorf("Error deleting device: %s", err) 238 } 239 240 return nil 241 } 242 243 func WaitForDeviceAttribute( 244 d *schema.ResourceData, target string, pending []string, attribute string, meta interface{}) (interface{}, error) { 245 // Wait for the device so we can get the networking attributes 246 // that show up after a while 247 log.Printf( 248 "[INFO] Waiting for device (%s) to have %s of %s", 249 d.Id(), attribute, target) 250 251 stateConf := &resource.StateChangeConf{ 252 Pending: pending, 253 Target: target, 254 Refresh: newDeviceStateRefreshFunc(d, attribute, meta), 255 Timeout: 60 * time.Minute, 256 Delay: 10 * time.Second, 257 MinTimeout: 3 * time.Second, 258 } 259 260 return stateConf.WaitForState() 261 } 262 263 func newDeviceStateRefreshFunc( 264 d *schema.ResourceData, attribute string, meta interface{}) resource.StateRefreshFunc { 265 client := meta.(*packngo.Client) 266 return func() (interface{}, string, error) { 267 err := resourcePacketDeviceRead(d, meta) 268 if err != nil { 269 return nil, "", err 270 } 271 272 // See if we can access our attribute 273 if attr, ok := d.GetOk(attribute); ok { 274 // Retrieve the device properties 275 device, _, err := client.Devices.Get(d.Id()) 276 if err != nil { 277 return nil, "", fmt.Errorf("Error retrieving device: %s", err) 278 } 279 280 return &device, attr.(string), nil 281 } 282 283 return nil, "", nil 284 } 285 } 286 287 // Powers on the device and waits for it to be active 288 func powerOnAndWait(d *schema.ResourceData, meta interface{}) error { 289 client := meta.(*packngo.Client) 290 _, err := client.Devices.PowerOn(d.Id()) 291 if err != nil { 292 return err 293 } 294 295 // Wait for power on 296 _, err = WaitForDeviceAttribute(d, "active", []string{"off"}, "state", client) 297 if err != nil { 298 return err 299 } 300 301 return nil 302 }