summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--libvirt/domain.go73
-rw-r--r--libvirt/resource_libvirt_domain.go9
-rw-r--r--libvirt/resource_libvirt_domain_test.go127
3 files changed, 200 insertions, 9 deletions
diff --git a/libvirt/domain.go b/libvirt/domain.go
index 9991dc42..d85a1473 100644
--- a/libvirt/domain.go
+++ b/libvirt/domain.go
@@ -21,8 +21,10 @@ const domWaitLeaseDone = "all-addresses-obtained"
var errDomainInvalidState = errors.New("invalid state for domain")
-func domainWaitForLeases(domain *libvirt.Domain, waitForLeases map[libvirtxml.DomainInterface]struct{}, timeout time.Duration) error {
+func domainWaitForLeases(domain *libvirt.Domain, waitForLeases map[libvirtxml.DomainInterface]struct{},
+ timeout time.Duration, domainDef libvirtxml.Domain, virConn *libvirt.Connect) error {
waitFunc := func() (interface{}, string, error) {
+
state, err := domainGetState(*domain)
if err != nil {
return false, "", err
@@ -40,7 +42,7 @@ func domainWaitForLeases(domain *libvirt.Domain, waitForLeases map[libvirtxml.Do
// check we have IPs for all the interfaces we are waiting for
for iface := range waitForLeases {
- found, ignore, err := domainIfaceHasAddress(*domain, iface)
+ found, ignore, err := domainIfaceHasAddress(*domain, iface, domainDef, virConn)
if err != nil {
return false, "", err
}
@@ -72,7 +74,8 @@ func domainWaitForLeases(domain *libvirt.Domain, waitForLeases map[libvirtxml.Do
return err
}
-func domainIfaceHasAddress(domain libvirt.Domain, iface libvirtxml.DomainInterface) (found bool, ignore bool, err error) {
+func domainIfaceHasAddress(domain libvirt.Domain, iface libvirtxml.DomainInterface,
+ domainDef libvirtxml.Domain, virConn *libvirt.Connect) (found bool, ignore bool, err error) {
mac := strings.ToUpper(iface.MAC.Address)
if mac == "" {
@@ -82,7 +85,7 @@ func domainIfaceHasAddress(domain libvirt.Domain, iface libvirtxml.DomainInterfa
}
log.Printf("[DEBUG] waiting for network address for iface=%s\n", mac)
- ifacesWithAddr, err := domainGetIfacesInfo(domain)
+ ifacesWithAddr, err := domainGetIfacesInfo(domain, domainDef, virConn)
if err != nil {
return false, false, fmt.Errorf("Error retrieving interface addresses: %s", err)
}
@@ -140,7 +143,8 @@ func domainIsRunning(domain libvirt.Domain) (bool, error) {
return state == libvirt.DOMAIN_RUNNING, nil
}
-func domainGetIfacesInfo(domain libvirt.Domain) ([]libvirt.DomainInterface, error) {
+func domainGetIfacesInfo(domain libvirt.Domain, domainDef libvirtxml.Domain,
+ virConn *libvirt.Connect) ([]libvirt.DomainInterface, error) {
_, found := os.LookupEnv(skipQemuEnvVar)
if found {
@@ -159,6 +163,12 @@ func domainGetIfacesInfo(domain libvirt.Domain) ([]libvirt.DomainInterface, erro
}
}
+ log.Print("[DEBUG] getting domain addresses from networks")
+ interfaces := getDomainInterfacesFromNetworks(domainDef, virConn)
+ if len(interfaces) > 0 {
+ return interfaces, nil
+ }
+
// get all the interfaces attached to libvirt networks
log.Print("[DEBUG] no interfaces could be obtained with qemu-agent: falling back to the libvirt API")
interfaces, err := domain.ListAllInterfaceAddresses(libvirt.DOMAIN_INTERFACE_ADDRESSES_SRC_LEASE)
@@ -177,3 +187,56 @@ func domainGetIfacesInfo(domain libvirt.Domain) ([]libvirt.DomainInterface, erro
return interfaces, nil
}
+
+func getDomainInterfacesFromNetworks(domain libvirtxml.Domain,
+ virConn *libvirt.Connect) []libvirt.DomainInterface {
+
+ var ifacesList []libvirt.DomainInterface
+ var networkNames []string
+ var macAddresses []string
+
+ for _, networkInterface := range domain.Devices.Interfaces {
+ networkNames = append(networkNames, networkInterface.Source.Network)
+ macAddresses = append(macAddresses, strings.ToUpper(networkInterface.MAC.Address))
+ }
+
+ networkMacAddresses := make(map[string]map[string][]string)
+ for _, networkName := range networkNames {
+ network, err := virConn.LookupNetworkByName(networkName)
+ if err != nil {
+ log.Printf("[ERROR] Error retrieving libvirt network: %s", err)
+ return ifacesList
+ }
+ defer network.Free()
+
+ networkDef, err := newDefNetworkfromLibvirt(network)
+ macAddresses := make(map[string][]string)
+ for _, ips := range networkDef.IPs {
+ for _, dhcpHost := range ips.DHCP.Hosts {
+ macAddresses[dhcpHost.MAC] = append(macAddresses[dhcpHost.MAC], dhcpHost.IP)
+ }
+ }
+ networkMacAddresses[networkName] = macAddresses
+ }
+
+ for name, networkMacAddress := range networkMacAddresses {
+ for mac, ips := range networkMacAddress {
+ for _, domMac := range macAddresses {
+ if mac == domMac {
+ virDom := libvirt.DomainInterface{}
+ virDom.Name = name
+ virDom.Hwaddr = mac
+ for _, ip := range ips {
+ virDomIP := libvirt.DomainIPAddress{}
+ virDomIP.Addr = ip
+ virDom.Addrs = append(virDom.Addrs, virDomIP)
+ }
+ ifacesList = append(ifacesList, virDom)
+ }
+ }
+ }
+ }
+
+ log.Printf("[DEBUG] Interfaces: %s", spew.Sdump(ifacesList))
+ return ifacesList
+}
diff --git a/libvirt/resource_libvirt_domain.go b/libvirt/resource_libvirt_domain.go
index 616f919b..25516f7b 100644
--- a/libvirt/resource_libvirt_domain.go
+++ b/libvirt/resource_libvirt_domain.go
@@ -593,6 +593,8 @@ func resourceLibvirtDomainCreate(d *schema.ResourceData, meta interface{}) error
continue
}
+ networkXMLDesc, err := network.GetXMLDesc(0)
+ log.Printf("[DEBUG] network def xml in create: %s", networkXMLDesc)
hostname := domainDef.Name
if hostnameI, ok := d.GetOk(prefix + ".hostname"); ok {
hostname = hostnameI.(string)
@@ -605,7 +607,6 @@ func resourceLibvirtDomainCreate(d *schema.ResourceData, meta interface{}) error
if ip == nil {
return fmt.Errorf("Could not parse addresses '%s'", address)
}
-
log.Printf("[INFO] Adding IP/MAC/host=%s/%s/%s to %s", ip.String(), mac, hostname, networkName)
if err := updateOrAddHost(network, ip.String(), mac, hostname); err != nil {
return err
@@ -711,7 +712,7 @@ func resourceLibvirtDomainCreate(d *schema.ResourceData, meta interface{}) error
log.Printf("[INFO] Domain ID: %s", d.Id())
if len(waitForLeases) > 0 {
- err = domainWaitForLeases(domain, waitForLeases, d.Timeout(schema.TimeoutCreate))
+ err = domainWaitForLeases(domain, waitForLeases, d.Timeout(schema.TimeoutCreate), domainDef, virConn)
if err != nil {
return err
}
@@ -986,8 +987,8 @@ func resourceLibvirtDomainRead(d *schema.ResourceData, meta interface{}) error {
}
d.Set("filesystems", filesystems)
- // look interfaces with addresses
- ifacesWithAddr, err := domainGetIfacesInfo(*domain)
+ // lookup interfaces with addresses
+ ifacesWithAddr, err := domainGetIfacesInfo(*domain, domainDef, virConn)
if err != nil {
return fmt.Errorf("Error retrieving interface addresses: %s", err)
}
diff --git a/libvirt/resource_libvirt_domain_test.go b/libvirt/resource_libvirt_domain_test.go
index 43ce2478..ac05c494 100644
--- a/libvirt/resource_libvirt_domain_test.go
+++ b/libvirt/resource_libvirt_domain_test.go
@@ -335,6 +335,65 @@ func TestAccLibvirtDomain_NetworkInterface(t *testing.T) {
})
}
+func TestAccLibvirtDomain_CheckDHCPEntries(t *testing.T) {
+ var domain libvirt.Domain
+ var network libvirt.Network
+
+ var configWithDomain = fmt.Sprintf(`
+ resource "libvirt_network" "acceptance-test-network" {
+ name = "acceptance-test-network"
+ mode = "nat"
+ domain = "acceptance-test-network-local"
+ addresses = ["192.0.0.0/24"]
+ }
+
+ resource "libvirt_domain" "acceptance-test-domain" {
+ name = "terraform-test"
+ network_interface {
+ network_id = "${libvirt_network.acceptance-test-network.id}"
+ hostname = "terraform-test"
+ addresses = ["192.0.0.2"]
+ }
+ }`)
+
+ var configWithoutDomain = fmt.Sprintf(`
+ resource "libvirt_network" "acceptance-test-network" {
+ name = "acceptance-test-network"
+ mode = "nat"
+ domain = "acceptance-test-network-local"
+ addresses = ["192.0.0.0/24"]
+ }`)
+
+ resource.Test(t, resource.TestCase{
+ PreCheck: func() { testAccPreCheck(t) },
+ Providers: testAccProviders,
+ CheckDestroy: testAccCheckLibvirtDomainDestroy,
+ Steps: []resource.TestStep{
+ resource.TestStep{
+ Config: configWithDomain,
+ Check: resource.ComposeTestCheckFunc(
+ testAccCheckLibvirtDomainExists("libvirt_domain.acceptance-test-domain", &domain),
+ testAccCheckLibvirtNetworkExists("libvirt_network.acceptance-test-network", &network),
+ ),
+ },
+ resource.TestStep{
+ Config: configWithoutDomain,
+ Check: resource.ComposeTestCheckFunc(
+ testAccCheckLibvirtDestroyLeavesIPs("libvirt_network.acceptance-test-network",
+ "192.0.0.2", &network),
+ ),
+ },
+ resource.TestStep{
+ Config: configWithDomain,
+ ExpectNonEmptyPlan: true,
+ Check: resource.ComposeTestCheckFunc(
+ testAccCheckLibvirtDomainExists("libvirt_domain.acceptance-test-domain", &domain),
+ ),
+ },
+ },
+ })
+}
+
func TestAccLibvirtDomain_Graphics(t *testing.T) {
var domain libvirt.Domain
@@ -717,6 +776,38 @@ func testAccCheckLibvirtURLDisk(u *url.URL, domain *libvirt.Domain) resource.Tes
}
}
+func testAccCheckLibvirtDestroyLeavesIPs(n string, ip string, network *libvirt.Network) resource.TestCheckFunc {
+ return func(s *terraform.State) error {
+ rs, ok := s.RootModule().Resources[n]
+ if !ok {
+ return fmt.Errorf("Not found: %s", n)
+ }
+
+ if rs.Primary.ID == "" {
+ return fmt.Errorf("No libvirt network ID is set")
+ }
+
+ virConn := testAccProvider.Meta().(*Client).libvirt
+
+ retrieveNetwork, err := virConn.LookupNetworkByUUIDString(rs.Primary.ID)
+
+ if err != nil {
+ return err
+ }
+
+ networkDef, err := newDefNetworkfromLibvirt(retrieveNetwork)
+
+ for _, ips := range networkDef.IPs {
+ for _, dhcpHost := range ips.DHCP.Hosts {
+ if dhcpHost.IP == ip {
+ return nil
+ }
+ }
+ }
+ return fmt.Errorf("Hostname with ip '%s' does not have a dhcp entry in network", ip)
+ }
+}
+
func testAccCheckLibvirtDomainKernelInitrdCmdline(domain *libvirt.Domain, kernel *libvirt.StorageVol, initrd *libvirt.StorageVol) resource.TestCheckFunc {
return func(s *terraform.State) error {
xmlDesc, err := domain.GetXMLDesc(0)
@@ -923,3 +1014,39 @@ func TestAccLibvirtDomain_ArchType(t *testing.T) {
},
})
}
+
+func testAccCheckLibvirtNetworkExists(n string, network *libvirt.Network) resource.TestCheckFunc {
+ return func(s *terraform.State) error {
+ rs, ok := s.RootModule().Resources[n]
+ if !ok {
+ return fmt.Errorf("Not found: %s", n)
+ }
+
+ if rs.Primary.ID == "" {
+ return fmt.Errorf("No libvirt network ID is set")
+ }
+
+ virConn := testAccProvider.Meta().(*Client).libvirt
+
+ retrieveNetwork, err := virConn.LookupNetworkByUUIDString(rs.Primary.ID)
+
+ if err != nil {
+ return err
+ }
+
+ log.Printf("The ID is %s", rs.Primary.ID)
+
+ realID, err := retrieveNetwork.GetUUIDString()
+ if err != nil {
+ return err
+ }
+
+ if realID != rs.Primary.ID {
+ return fmt.Errorf("Libvirt network not found")
+ }
+
+ network = retrieveNetwork
+
+ return nil
+ }
+}