triton: add nics
This commit is contained in:
parent
c6b768eaa5
commit
b02ed0f3f7
|
@ -6,6 +6,7 @@ import (
|
|||
"regexp"
|
||||
"time"
|
||||
|
||||
"github.com/hashicorp/terraform/helper/hashcode"
|
||||
"github.com/hashicorp/terraform/helper/schema"
|
||||
"github.com/joyent/gosdc/cloudapi"
|
||||
)
|
||||
|
@ -108,17 +109,53 @@ func resourceMachine() *schema.Resource {
|
|||
Type: schema.TypeString,
|
||||
Computed: true,
|
||||
},
|
||||
"networks": {
|
||||
Description: "desired network IDs",
|
||||
Type: schema.TypeList,
|
||||
Optional: true,
|
||||
"nic": {
|
||||
Description: "network interface",
|
||||
Type: schema.TypeSet,
|
||||
Computed: true,
|
||||
// TODO: this really should ForceNew but the Network IDs don't seem to
|
||||
// be returned by the API, meaning if we track them here TF will replace
|
||||
// the resource on every run.
|
||||
// ForceNew: true,
|
||||
Elem: &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
Set: func(v interface{}) int {
|
||||
m := v.(map[string]interface{})
|
||||
return hashcode.String(m["network"].(string))
|
||||
},
|
||||
Elem: &schema.Resource{
|
||||
Schema: map[string]*schema.Schema{
|
||||
"ip": {
|
||||
Description: "NIC's IPv4 address",
|
||||
Computed: true,
|
||||
Type: schema.TypeString,
|
||||
},
|
||||
"mac": {
|
||||
Description: "NIC's MAC address",
|
||||
Computed: true,
|
||||
Type: schema.TypeString,
|
||||
},
|
||||
"primary": {
|
||||
Description: "Whether this is the machine's primary NIC",
|
||||
Computed: true,
|
||||
Type: schema.TypeBool,
|
||||
},
|
||||
"netmask": {
|
||||
Description: "IPv4 netmask",
|
||||
Computed: true,
|
||||
Type: schema.TypeString,
|
||||
},
|
||||
"gateway": {
|
||||
Description: "IPv4 gateway",
|
||||
Computed: true,
|
||||
Type: schema.TypeString,
|
||||
},
|
||||
"state": {
|
||||
Description: "describes the state of the NIC (e.g. provisioning, running, or stopped)",
|
||||
Computed: true,
|
||||
Type: schema.TypeString,
|
||||
},
|
||||
"network": {
|
||||
Description: "Network ID this NIC is attached to",
|
||||
Required: true,
|
||||
Type: schema.TypeString,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
"firewall_enabled": {
|
||||
|
@ -153,6 +190,18 @@ func resourceMachine() *schema.Resource {
|
|||
Optional: true,
|
||||
Computed: true,
|
||||
},
|
||||
|
||||
// deprecated fields
|
||||
"networks": {
|
||||
Description: "desired network IDs",
|
||||
Type: schema.TypeList,
|
||||
Optional: true,
|
||||
Computed: true,
|
||||
Deprecated: "Networks is deprecated, please use `nic`",
|
||||
Elem: &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
@ -164,6 +213,11 @@ func resourceMachineCreate(d *schema.ResourceData, meta interface{}) error {
|
|||
for _, network := range d.Get("networks").([]interface{}) {
|
||||
networks = append(networks, network.(string))
|
||||
}
|
||||
nics := d.Get("nic").(*schema.Set)
|
||||
for _, nicI := range nics.List() {
|
||||
nic := nicI.(map[string]interface{})
|
||||
networks = append(networks, nic["network"].(string))
|
||||
}
|
||||
|
||||
metadata := map[string]string{}
|
||||
for schemaName, metadataKey := range resourceMachineMetadataKeys {
|
||||
|
@ -221,6 +275,11 @@ func resourceMachineRead(d *schema.ResourceData, meta interface{}) error {
|
|||
return err
|
||||
}
|
||||
|
||||
nics, err := client.ListNICs(d.Id())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
d.SetId(machine.Id)
|
||||
d.Set("name", machine.Name)
|
||||
d.Set("type", machine.Type)
|
||||
|
@ -235,9 +294,31 @@ func resourceMachineRead(d *schema.ResourceData, meta interface{}) error {
|
|||
d.Set("package", machine.Package)
|
||||
d.Set("image", machine.Image)
|
||||
d.Set("primaryip", machine.PrimaryIP)
|
||||
d.Set("networks", machine.Networks)
|
||||
d.Set("firewall_enabled", machine.FirewallEnabled)
|
||||
|
||||
// create and update NICs
|
||||
var (
|
||||
machineNICs []map[string]interface{}
|
||||
networks []string
|
||||
)
|
||||
for _, nic := range nics {
|
||||
machineNICs = append(
|
||||
machineNICs,
|
||||
map[string]interface{}{
|
||||
"ip": nic.IP,
|
||||
"mac": nic.MAC,
|
||||
"primary": nic.Primary,
|
||||
"netmask": nic.Netmask,
|
||||
"gateway": nic.Gateway,
|
||||
"state": nic.State,
|
||||
"network": nic.Network,
|
||||
},
|
||||
)
|
||||
networks = append(networks, nic.Network)
|
||||
}
|
||||
d.Set("nic", machineNICs)
|
||||
d.Set("networks", networks)
|
||||
|
||||
// computed attributes from metadata
|
||||
for schemaName, metadataKey := range resourceMachineMetadataKeys {
|
||||
d.Set(schemaName, machine.Metadata[metadataKey])
|
||||
|
@ -336,6 +417,41 @@ func resourceMachineUpdate(d *schema.ResourceData, meta interface{}) error {
|
|||
d.SetPartial("firewall_enabled")
|
||||
}
|
||||
|
||||
if d.HasChange("nic") {
|
||||
o, n := d.GetChange("nic")
|
||||
if o == nil {
|
||||
o = new(schema.Set)
|
||||
}
|
||||
if n == nil {
|
||||
n = new(schema.Set)
|
||||
}
|
||||
|
||||
oldNICs := o.(*schema.Set)
|
||||
newNICs := o.(*schema.Set)
|
||||
|
||||
// add new NICs that are not in old NICs
|
||||
for _, nicI := range newNICs.Difference(oldNICs).List() {
|
||||
nic := nicI.(map[string]interface{})
|
||||
fmt.Printf("adding %+v\n", nic)
|
||||
_, err := client.AddNIC(d.Id(), nic["network"].(string))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// remove old NICs that are not in new NICs
|
||||
for _, nicI := range oldNICs.Difference(newNICs).List() {
|
||||
nic := nicI.(map[string]interface{})
|
||||
fmt.Printf("removing %+v\n", nic)
|
||||
err := client.RemoveNIC(d.Id(), nic["mac"].(string))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
d.SetPartial("nic")
|
||||
}
|
||||
|
||||
// metadata stuff
|
||||
metadata := map[string]string{}
|
||||
for schemaName, metadataKey := range resourceMachineMetadataKeys {
|
||||
|
|
|
@ -34,6 +34,62 @@ func TestAccTritonMachine_basic(t *testing.T) {
|
|||
})
|
||||
}
|
||||
|
||||
func TestAccTritonMachine_nic(t *testing.T) {
|
||||
machineName := fmt.Sprintf("acctest-%d", acctest.RandInt())
|
||||
config := fmt.Sprintf(testAccTritonMachine_withnic, machineName, machineName)
|
||||
|
||||
resource.Test(t, resource.TestCase{
|
||||
PreCheck: func() { testAccPreCheck(t) },
|
||||
Providers: testAccProviders,
|
||||
CheckDestroy: testCheckTritonMachineDestroy,
|
||||
Steps: []resource.TestStep{
|
||||
resource.TestStep{
|
||||
Config: config,
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
testCheckTritonMachineExists("triton_machine.test"),
|
||||
func(*terraform.State) error {
|
||||
time.Sleep(10 * time.Second)
|
||||
return nil
|
||||
},
|
||||
testCheckTritonMachineHasFabric("triton_machine.test", "triton_fabric.test"),
|
||||
),
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func TestAccTritonMachine_addnic(t *testing.T) {
|
||||
machineName := fmt.Sprintf("acctest-%d", acctest.RandInt())
|
||||
without := fmt.Sprintf(testAccTritonMachine_withoutnic, machineName, machineName)
|
||||
with := fmt.Sprintf(testAccTritonMachine_withnic, machineName, machineName)
|
||||
|
||||
resource.Test(t, resource.TestCase{
|
||||
PreCheck: func() { testAccPreCheck(t) },
|
||||
Providers: testAccProviders,
|
||||
CheckDestroy: testCheckTritonMachineDestroy,
|
||||
Steps: []resource.TestStep{
|
||||
resource.TestStep{
|
||||
Config: without,
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
testCheckTritonMachineExists("triton_machine.test"),
|
||||
func(*terraform.State) error {
|
||||
time.Sleep(10 * time.Second)
|
||||
return nil
|
||||
},
|
||||
testCheckTritonMachineHasNoFabric("triton_machine.test", "triton_fabric.test"),
|
||||
),
|
||||
},
|
||||
resource.TestStep{
|
||||
Config: with,
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
testCheckTritonMachineExists("triton_machine.test"),
|
||||
testCheckTritonMachineHasFabric("triton_machine.test", "triton_fabric.test"),
|
||||
),
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func testCheckTritonMachineExists(name string) resource.TestCheckFunc {
|
||||
return func(s *terraform.State) error {
|
||||
// Ensure we have enough information in state to look up in API
|
||||
|
@ -56,6 +112,66 @@ func testCheckTritonMachineExists(name string) resource.TestCheckFunc {
|
|||
}
|
||||
}
|
||||
|
||||
func testCheckTritonMachineHasFabric(name, fabricName string) resource.TestCheckFunc {
|
||||
return func(s *terraform.State) error {
|
||||
// Ensure we have enough information in state to look up in API
|
||||
machine, ok := s.RootModule().Resources[name]
|
||||
if !ok {
|
||||
return fmt.Errorf("Not found: %s", name)
|
||||
}
|
||||
|
||||
network, ok := s.RootModule().Resources[fabricName]
|
||||
if !ok {
|
||||
return fmt.Errorf("Not found: %s", fabricName)
|
||||
}
|
||||
conn := testAccProvider.Meta().(*cloudapi.Client)
|
||||
|
||||
nics, err := conn.ListNICs(machine.Primary.ID)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Bad: Check NICs Exist: %s", err)
|
||||
}
|
||||
|
||||
fmt.Printf("%+v\n", machine.Primary)
|
||||
for _, nic := range nics {
|
||||
fmt.Printf("---\n%+v\n%+v\n", nic, network.Primary)
|
||||
if nic.Network == network.Primary.ID {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
return fmt.Errorf("Bad: Machine %q does not have Fabric %q", machine.Primary.ID, network.Primary.ID)
|
||||
}
|
||||
}
|
||||
|
||||
func testCheckTritonMachineHasNoFabric(name, fabricName string) resource.TestCheckFunc {
|
||||
return func(s *terraform.State) error {
|
||||
// Ensure we have enough information in state to look up in API
|
||||
machine, ok := s.RootModule().Resources[name]
|
||||
if !ok {
|
||||
return fmt.Errorf("Not found: %s", name)
|
||||
}
|
||||
|
||||
network, ok := s.RootModule().Resources[fabricName]
|
||||
if !ok {
|
||||
return fmt.Errorf("Not found: %s", fabricName)
|
||||
}
|
||||
conn := testAccProvider.Meta().(*cloudapi.Client)
|
||||
|
||||
nics, err := conn.ListNICs(machine.Primary.ID)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Bad: Check NICs Exist: %s", err)
|
||||
}
|
||||
|
||||
for _, nic := range nics {
|
||||
if nic.Network == network.Primary.ID {
|
||||
return fmt.Errorf("Bad: Machine %q has Fabric %q", machine.Primary.ID, network.Primary.ID)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func testCheckTritonMachineDestroy(s *terraform.State) error {
|
||||
conn := testAccProvider.Meta().(*cloudapi.Client)
|
||||
|
||||
|
@ -84,7 +200,59 @@ resource "triton_machine" "test" {
|
|||
image = "842e6fa6-6e9b-11e5-8402-1b490459e334"
|
||||
|
||||
tags = {
|
||||
test = "hello!"
|
||||
}
|
||||
test = "hello!"
|
||||
}
|
||||
}
|
||||
`
|
||||
|
||||
var testAccTritonMachine_withnic = `
|
||||
resource "triton_fabric" "test" {
|
||||
name = "%s-network"
|
||||
description = "test network"
|
||||
vlan_id = 2 # every DC seems to have a vlan 2 available
|
||||
|
||||
subnet = "10.0.0.0/22"
|
||||
gateway = "10.0.0.1"
|
||||
provision_start_ip = "10.0.0.5"
|
||||
provision_end_ip = "10.0.3.250"
|
||||
|
||||
resolvers = ["8.8.8.8", "8.8.4.4"]
|
||||
}
|
||||
|
||||
resource "triton_machine" "test" {
|
||||
name = "%s"
|
||||
package = "g3-standard-0.25-smartos"
|
||||
image = "842e6fa6-6e9b-11e5-8402-1b490459e334"
|
||||
|
||||
tags = {
|
||||
test = "hello!"
|
||||
}
|
||||
|
||||
nic { network = "${triton_fabric.test.id}" }
|
||||
}
|
||||
`
|
||||
|
||||
var testAccTritonMachine_withoutnic = `
|
||||
resource "triton_fabric" "test" {
|
||||
name = "%s-network"
|
||||
description = "test network"
|
||||
vlan_id = 2 # every DC seems to have a vlan 2 available
|
||||
|
||||
subnet = "10.0.0.0/22"
|
||||
gateway = "10.0.0.1"
|
||||
provision_start_ip = "10.0.0.5"
|
||||
provision_end_ip = "10.0.3.250"
|
||||
|
||||
resolvers = ["8.8.8.8", "8.8.4.4"]
|
||||
}
|
||||
|
||||
resource "triton_machine" "test" {
|
||||
name = "%s"
|
||||
package = "g3-standard-0.25-smartos"
|
||||
image = "842e6fa6-6e9b-11e5-8402-1b490459e334"
|
||||
|
||||
tags = {
|
||||
test = "hello!"
|
||||
}
|
||||
}
|
||||
`
|
||||
|
|
Loading…
Reference in New Issue