Skip to content

Commit

Permalink
vultr: add reserved IP
Browse files Browse the repository at this point in the history
  • Loading branch information
squat committed Apr 20, 2018
1 parent 78a4f96 commit c8cc3a1
Show file tree
Hide file tree
Showing 4 changed files with 219 additions and 0 deletions.
56 changes: 56 additions & 0 deletions examples/reserved_ip/example.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
// Configure the Vultr provider.
// Alternatively, export the API key as an environment variable: `export VULTR_API_KEY=<your-vultr-api-key>`.
#provider "vultr" {
#api_key = "<your-vultr-api-key>"
#}

// Find the ID of the Silicon Valley region.
data "vultr_region" "silicon_valley" {
filter {
name = "name"
values = ["Silicon Valley"]
}
}

// Find the ID for CoreOS Container Linux.
data "vultr_os" "container_linux" {
filter {
name = "family"
values = ["coreos"]
}
}

// Find the ID for a starter plan.
data "vultr_plan" "starter" {
filter {
name = "price_per_month"
values = ["5.00"]
}

filter {
name = "ram"
values = ["1024"]
}
}

// Create a Vultr virtual machine.
resource "vultr_instance" "example" {
name = "example"
region_id = "${data.vultr_region.silicon_valley.id}"
plan_id = "${data.vultr_plan.starter.id}"
os_id = "${data.vultr_os.container_linux.id}"
ssh_key_ids = ["${vultr_ssh_key.squat.id}"]
}

// Create a new SSH key.
resource "vultr_ssh_key" "squat" {
name = "squat"
public_key = "${file("~/lserven.ssh")}"
}

// Create a reserved IP.
resource "vultr_reserved_ip" "example" {
name = "example"
attached_id = "${vultr_instance.example.id}"
region_id = "${data.vultr_region.silicon_valley.id}"
}
1 change: 1 addition & 0 deletions vultr/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ func Provider() terraform.ResourceProvider {
"vultr_firewall_rule": resourceFirewallRule(),
"vultr_instance": resourceInstance(),
"vultr_ipv4": resourceIPV4(),
"vultr_reserved_ip": resourceReservedIP(),
"vultr_startup_script": resourceStartupScript(),
"vultr_ssh_key": resourceSSHKey(),
},
Expand Down
152 changes: 152 additions & 0 deletions vultr/resource_reserved_ip.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
package vultr

import (
"fmt"
"log"

"github.com/JamesClonk/vultr/lib"
"github.com/hashicorp/terraform/helper/schema"
)

func resourceReservedIP() *schema.Resource {
return &schema.Resource{
Create: resourceReservedIPCreate,
Read: resourceReservedIPRead,
Update: resourceReservedIPUpdate,
Delete: resourceReservedIPDelete,
Importer: &schema.ResourceImporter{
State: schema.ImportStatePassthrough,
},

Schema: map[string]*schema.Schema{
"attached_id": {
Type: schema.TypeString,
Optional: true,
},

"cidr": {
Type: schema.TypeString,
Computed: true,
},

"name": {
Type: schema.TypeString,
Required: true,
ForceNew: true,
},

"region_id": {
Type: schema.TypeInt,
Required: true,
ForceNew: true,
},

"type": {
Type: schema.TypeString,
Default: "v4",
Optional: true,
ForceNew: true,
ValidateFunc: validateReservedIPType,
},
},
}
}

func resourceReservedIPCreate(d *schema.ResourceData, meta interface{}) error {
client := meta.(*Client)

aid := d.Get("attached_id").(string)
name := d.Get("name").(string)
regionID := d.Get("region_id").(int)
ipType := d.Get("type").(string)

log.Printf("[INFO] Creating new reserved ip")
rid, err := client.CreateReservedIP(regionID, ipType, name)
if err != nil {
return fmt.Errorf("Error creating reserved ip: %v", err)
}

d.SetId(rid)

if aid != "" {
rip, err := client.GetReservedIP(rid)
if err != nil {
return fmt.Errorf("Error getting address for reserved ip (%s): %v", d.Id(), err)
}
err = client.AttachReservedIP(reservedIPtoCIDR(rip), aid)
if err != nil {
return fmt.Errorf("Error attaching reserved ip (%s) to instance (%s): %v", d.Id(), aid, err)
}
}

return resourceReservedIPRead(d, meta)
}

func resourceReservedIPRead(d *schema.ResourceData, meta interface{}) error {
client := meta.(*Client)

rip, err := client.GetReservedIP(d.Id())
if err != nil {
return fmt.Errorf("Error getting reserved ip (%s): %v", d.Id(), err)
}

if rip == (lib.IP{}) {
log.Printf("[WARN] Removing reserved ip (%s) because it is gone", d.Id())
d.SetId("")
return nil
}

d.Set("attached_id", rip.AttachedTo)
d.Set("cidr", reservedIPtoCIDR(rip))
d.Set("name", rip.Label)
d.Set("region_id", rip.RegionID)
d.Set("type", rip.IPType)

return nil
}

func resourceReservedIPUpdate(d *schema.ResourceData, meta interface{}) error {
client := meta.(*Client)

if d.HasChange("attached_id") {
ip := d.Get("cidr").(string)
log.Printf("[INFO] Updating reserved IP (%s) attachment", d.Id())
old, new := d.GetChange("attached_id")
if old.(string) != "" {
if err := client.DetachReservedIP(old.(string), ip); err != nil {
return fmt.Errorf("Error detaching reserved IP (%s) from instance (%s): %v", d.Id(), old.(string), err)
}
}
if new.(string) != "" {
if err := client.AttachReservedIP(ip, new.(string)); err != nil {
return fmt.Errorf("Error attaching reserved IP (%s) to instance (%s): %v", d.Id(), new.(string), err)
}
}
}

return resourceReservedIPRead(d, meta)
}

func resourceReservedIPDelete(d *schema.ResourceData, meta interface{}) error {
client := meta.(*Client)

log.Printf("[INFO] Destroying reserved ip (%s)", d.Id())

aid := d.Get("attached_id").(string)
if aid != "" {
ip := d.Get("cidr").(string)
if err := client.DetachReservedIP(aid, ip); err != nil {
return fmt.Errorf("Error detaching reserved IP (%s) from instance (%s): %v", d.Id(), aid, err)
}
}

if err := client.DestroyReservedIP(d.Id()); err != nil {
return fmt.Errorf("Error destroying reserved ip (%s): %v", d.Id(), err)
}

return nil
}

func reservedIPtoCIDR(rip lib.IP) string {
return fmt.Sprintf("%s/%d", rip.Subnet, rip.SubnetSize)
}
10 changes: 10 additions & 0 deletions vultr/validators.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,16 @@ func validateIPAddress(v interface{}, k string) (ws []string, errors []error) {
return
}

// validateReservedIPType ensures that the string value is either "v4" or "v6".
func validateReservedIPType(v interface{}, k string) (ws []string, errors []error) {
value := v.(string)
if value != "v6" && value != "v4" {
errors = append(errors, fmt.Errorf("%q must be either 'v4' or 'v6'", k))
return
}
return
}

// validateFirewallRuleProtocol ensures that the string value is a valid
// firewall rule protocol and returns an error otherwise.
func validateFirewallRuleProtocol(v interface{}, k string) (ws []string, errors []error) {
Expand Down

0 comments on commit c8cc3a1

Please sign in to comment.