summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDuncan Mac-Vicar P <dmacvicar@suse.de>2016-05-22 01:16:49 +0200
committerDuncan Mac-Vicar P <dmacvicar@suse.de>2016-05-22 01:16:49 +0200
commitc1ee126e821b1a13aca72e3380f3873f3bc1d9a0 (patch)
treee3462df027282097dd80d16beff4daa3f07b2b74
parent751af6b6bb99a5e805e2fe5753359812983a06ae (diff)
parent9edf9cbfd7013b6d7ffed798bed31fda6a84bbc8 (diff)
downloadterraform-provider-libvirt-c1ee126e821b1a13aca72e3380f3873f3bc1d9a0.tar
terraform-provider-libvirt-c1ee126e821b1a13aca72e3380f3873f3bc1d9a0.tar.gz
Adds the ip address to the schema and enable the connect/ssh for provisioners.
Closes #18. Merge branch 'connect_ip_address'
-rw-r--r--docs/providers/libvirt/r/domain.html.markdown2
-rw-r--r--libvirt/network_interface_def.go41
-rw-r--r--libvirt/resource_libvirt_domain.go99
-rw-r--r--libvirt/utils.go16
4 files changed, 154 insertions, 4 deletions
diff --git a/docs/providers/libvirt/r/domain.html.markdown b/docs/providers/libvirt/r/domain.html.markdown
index 36c5216e..22da6dda 100644
--- a/docs/providers/libvirt/r/domain.html.markdown
+++ b/docs/providers/libvirt/r/domain.html.markdown
@@ -61,4 +61,4 @@ The `network_interface` block supports:
* `mac` - (Optional) The specific MAC address to use for this interface.
* `network` - (Optional) The network to attach this interface to.
-
+* `wait_for_lease`- (Optional) When creating the domain resource, wait until the network interface gets a DHCP lease from libvirt, so that the computed ip addresses will be available when the domain is up and the plan applied.
diff --git a/libvirt/network_interface_def.go b/libvirt/network_interface_def.go
index 4e401a6f..5043ac24 100644
--- a/libvirt/network_interface_def.go
+++ b/libvirt/network_interface_def.go
@@ -9,8 +9,8 @@ type defNetworkInterface struct {
XMLName xml.Name `xml:"interface"`
Type string `xml:"type,attr"`
Mac struct {
- Address string `xml:"address,attr,omitempty"`
- } `xml:"mac,omitempty"`
+ Address string `xml:"address,attr"`
+ } `xml:"mac"`
Source struct {
Network string `xml:"network,attr"`
} `xml:"source"`
@@ -19,6 +19,26 @@ type defNetworkInterface struct {
} `xml:"model"`
}
+func networkAddressCommonSchema() map[string]*schema.Schema {
+ return map[string]*schema.Schema{
+ "type": &schema.Schema{
+ Type: schema.TypeString,
+ Optional: true,
+ Computed: true,
+ },
+ "address": &schema.Schema{
+ Type: schema.TypeString,
+ Optional: true,
+ Computed: true,
+ },
+ "prefix": &schema.Schema{
+ Type: schema.TypeInt,
+ Optional: true,
+ Computed: true,
+ },
+ }
+}
+
func networkInterfaceCommonSchema() map[string]*schema.Schema {
return map[string]*schema.Schema{
"network": &schema.Schema{
@@ -30,6 +50,23 @@ func networkInterfaceCommonSchema() map[string]*schema.Schema {
Type: schema.TypeString,
Optional: true,
ForceNew: true,
+ DefaultFunc: func() (interface{}, error) {
+ return RandomMACAddress()
+ },
+ },
+ "wait_for_lease": &schema.Schema{
+ Type: schema.TypeBool,
+ Optional: true,
+ Default: false,
+ ForceNew: true,
+ },
+ "address": &schema.Schema{
+ Type: schema.TypeList,
+ Optional: true,
+ Computed: true,
+ Elem: &schema.Resource{
+ Schema: networkAddressCommonSchema(),
+ },
},
}
}
diff --git a/libvirt/resource_libvirt_domain.go b/libvirt/resource_libvirt_domain.go
index 095ebab7..b24b5cf0 100644
--- a/libvirt/resource_libvirt_domain.go
+++ b/libvirt/resource_libvirt_domain.go
@@ -147,6 +147,11 @@ func resourceLibvirtDomainCreate(d *schema.ResourceData, meta interface{}) error
return fmt.Errorf("Error waiting for domain to reach RUNNING state: %s", err)
}
+ err = waitForNetworkAddresses(d, domain)
+ if err != nil {
+ return err
+ }
+
return resourceLibvirtDomainRead(d, meta)
}
@@ -203,16 +208,62 @@ func resourceLibvirtDomainRead(d *schema.ResourceData, meta interface{}) error {
}
d.Set("disks", disks)
+ // look interfaces with addresses
+ ifacesWithAddr, err := domain.ListAllInterfaceAddresses(libvirt.VIR_DOMAIN_INTERFACE_ADDRESSES_SRC_LEASE)
+ if err != nil {
+ return fmt.Errorf("Error retrieving interface addresses: %s", err)
+ }
+
netIfaces := make([]map[string]interface{}, 0)
for _, networkInterfaceDef := range domainDef.Devices.NetworkInterfaces {
+
+ if networkInterfaceDef.Type != "network" {
+ log.Printf("[DEBUG] ignoring interface of type '%s'", networkInterfaceDef.Type)
+ continue
+ }
+
netIface := map[string]interface{}{
"network": networkInterfaceDef.Source.Network,
"mac": networkInterfaceDef.Mac.Address,
}
+
+ netIfaceAddrs := make([]map[string]interface{}, 0)
+ // look for an ip address and try to match it with the mac address
+ // not sure if using the target device name is a better idea here
+ for _, ifaceWithAddr := range ifacesWithAddr {
+ if ifaceWithAddr.Hwaddr == networkInterfaceDef.Mac.Address {
+ for _, addr := range ifaceWithAddr.Addrs {
+ netIfaceAddr := map[string]interface{}{
+ "type": func() string {
+ switch addr.Type {
+ case libvirt.VIR_IP_ADDR_TYPE_IPV4:
+ return "ipv4"
+ case libvirt.VIR_IP_ADDR_TYPE_IPV6:
+ return "ipv6"
+ default:
+ return "other"
+ }
+ }(),
+ "address": addr.Addr,
+ "prefix": addr.Prefix,
+ }
+ netIfaceAddrs = append(netIfaceAddrs, netIfaceAddr)
+ }
+ }
+ }
+
+ log.Printf("[DEBUG] %d addresses for %s\n", len(netIfaceAddrs), networkInterfaceDef.Mac.Address)
+ netIface["address"] = netIfaceAddrs
netIfaces = append(netIfaces, netIface)
}
- d.Set("network_interfaces", netIfaces)
+ d.Set("network_interface", netIfaces)
+ if len(ifacesWithAddr) > 0 {
+ d.SetConnInfo(map[string]string{
+ "type": "ssh",
+ "host": ifacesWithAddr[0].Addrs[0].Addr,
+ })
+ }
return nil
}
@@ -280,3 +331,49 @@ func waitForDomainDestroyed(virConn *libvirt.VirConnection, uuid string) error {
}
}
}
+
+func waitForNetworkAddresses(d *schema.ResourceData, domain libvirt.VirDomain) error {
+ log.Printf("[DEBUG] waiting for network addresses.\n")
+ // wait for network interfaces with 'wait_for_lease' to get an address
+ netIfacesCount := d.Get("network_interface.#").(int)
+ for i := 0; i < netIfacesCount; i++ {
+ prefix := fmt.Sprintf("network_interface.%d", i)
+
+ if wait, ok := d.GetOk(prefix + ".wait_for_lease"); !ok || !wait.(bool) {
+ continue
+ }
+
+ var mac string
+ if v, ok := d.GetOk(prefix + ".mac"); !ok {
+ // we can't get the ip without a mac address
+ continue
+ } else {
+ mac = v.(string)
+ }
+ log.Printf("[DEBUG] waiting for network addresses on %s\n", mac)
+
+ // loop until address appear, with timeout
+ start := time.Now()
+ waitLoop:
+ for {
+ ifacesWithAddr, err := domain.ListAllInterfaceAddresses(libvirt.VIR_DOMAIN_INTERFACE_ADDRESSES_SRC_LEASE)
+ if err != nil {
+ return fmt.Errorf("Error retrieving interface addresses: %s", err)
+ }
+
+ for _, ifaceWithAddr := range ifacesWithAddr {
+ // found
+ if mac == ifaceWithAddr.Hwaddr {
+ break waitLoop
+ }
+ }
+
+ time.Sleep(1 * time.Second)
+ if time.Since(start) > 5*time.Minute {
+ return fmt.Errorf("Timeout waiting for interface addresses")
+ }
+ }
+ }
+
+ return nil
+}
diff --git a/libvirt/utils.go b/libvirt/utils.go
index 3dc8e17e..ffaa8ba6 100644
--- a/libvirt/utils.go
+++ b/libvirt/utils.go
@@ -1,6 +1,7 @@
package libvirt
import (
+ "crypto/rand"
"fmt"
"time"
)
@@ -35,3 +36,18 @@ func WaitForSuccess(errorMessage string, f func() error) error {
}
}
}
+
+func RandomMACAddress() (string, error) {
+ buf := make([]byte, 6)
+ _, err := rand.Read(buf)
+ if err != nil {
+ return "", err
+ }
+
+ // set local bit and unicast
+ buf[0] = (buf[0] | 2) & 0xfe
+ // Set the local bit
+ buf[0] |= 2
+
+ return fmt.Sprintf("%02x:%02x:%02x:%02x:%02x:%02x", buf[0], buf[1], buf[2], buf[3], buf[4], buf[5]), nil
+}