1package vultr 2 3import ( 4 "errors" 5 "fmt" 6 "log" 7 "strings" 8 9 "github.com/JamesClonk/vultr/lib" 10 "github.com/hashicorp/terraform/helper/schema" 11) 12 13func resourceIPV4() *schema.Resource { 14 return &schema.Resource{ 15 Create: resourceIPV4Create, 16 Read: resourceIPV4Read, 17 Update: resourceIPV4Update, 18 Delete: resourceIPV4Delete, 19 Importer: &schema.ResourceImporter{ 20 State: schema.ImportStatePassthrough, 21 }, 22 23 Schema: map[string]*schema.Schema{ 24 "gateway": { 25 Type: schema.TypeString, 26 Computed: true, 27 }, 28 29 "ipv4_address": { 30 Type: schema.TypeString, 31 Computed: true, 32 }, 33 34 "instance_id": { 35 Type: schema.TypeString, 36 Required: true, 37 ForceNew: true, 38 }, 39 40 "netmask": { 41 Type: schema.TypeString, 42 Computed: true, 43 }, 44 45 "reboot": { 46 Type: schema.TypeBool, 47 Optional: true, 48 Default: true, 49 }, 50 51 "reverse_dns": { 52 Type: schema.TypeString, 53 Computed: true, 54 }, 55 }, 56 } 57} 58 59func resourceIPV4Create(d *schema.ResourceData, meta interface{}) error { 60 client := meta.(*Client) 61 62 instance := d.Get("instance_id").(string) 63 reboot := d.Get("reboot").(bool) 64 65 log.Printf("[INFO] Creating new IPv4 address") 66 67 vultrMutexKV.Lock(instance) 68 ips, err := client.ListIPv4(instance) 69 if err != nil { 70 return fmt.Errorf("Error listing IPv4 addresses: %v", err) 71 } 72 if err := client.CreateIPv4(instance, reboot); err != nil { 73 return fmt.Errorf("Error creating IPv4 address: %v", err) 74 } 75 newIPs, err := client.ListIPv4(instance) 76 if err != nil { 77 return fmt.Errorf("Error re-listing IPv4 addresses: %v", err) 78 } 79 vultrMutexKV.Unlock(instance) 80 81 var ip *lib.IPv4 82 for i := range newIPs { 83 var found bool 84 for j := range ips { 85 if newIPs[i] == ips[j] { 86 found = true 87 break 88 } 89 } 90 if !found { 91 ip = &newIPs[i] 92 break 93 } 94 } 95 if ip == nil { 96 return errors.New("Error finding created IPv4 address") 97 } 98 99 d.SetId(fmt.Sprintf("%s/%s", instance, ip.IP)) 100 101 return resourceIPV4Read(d, meta) 102} 103 104func resourceIPV4Read(d *schema.ResourceData, meta interface{}) error { 105 client := meta.(*Client) 106 107 instance, id, err := parseStringSlashString(d.Id(), "IPv4 ID", "instance-id", "ip-address") 108 if err != nil { 109 return err 110 } 111 112 ips, err := client.ListIPv4(instance) 113 if err != nil { 114 if strings.HasPrefix(err.Error(), "Invalid server") { 115 log.Printf("[WARN] Removing IPv4 address (%s) because the attached instance (%s) is gone", d.Id(), instance) 116 d.SetId("") 117 return nil 118 } 119 return fmt.Errorf("Error getting IPv4 addresses: %v", err) 120 } 121 var ip *lib.IPv4 122 for i := range ips { 123 if ips[i].IP == id { 124 ip = &ips[i] 125 break 126 } 127 } 128 if ip == nil { 129 log.Printf("[WARN] Removing IPv4 address (%s) because it is gone", d.Id()) 130 d.SetId("") 131 return nil 132 } 133 134 d.Set("gateway", ip.Gateway) 135 d.Set("ipv4_address", ip.IP) 136 d.Set("netmask", ip.Netmask) 137 d.Set("reverse_dns", ip.ReverseDNS) 138 139 return nil 140} 141 142func resourceIPV4Update(d *schema.ResourceData, meta interface{}) error { 143 return resourceIPV4Read(d, meta) 144} 145 146func resourceIPV4Delete(d *schema.ResourceData, meta interface{}) error { 147 client := meta.(*Client) 148 149 instance, id, err := parseStringSlashString(d.Id(), "IPv4 ID", "instance-id", "ip-address") 150 if err != nil { 151 return err 152 } 153 154 log.Printf("[INFO] Destroying IPv4 address (%s)", d.Id()) 155 156 if err := client.DeleteIPv4(instance, id); err != nil { 157 return fmt.Errorf("Error destroying IPv4 address (%s): %v", d.Id(), err) 158 } 159 160 return nil 161} 162