From 39b7567db8477cebf98ca7ff225c2a356b42bd98 Mon Sep 17 00:00:00 2001 From: Alvaro Saurin Date: Mon, 21 Aug 2017 18:23:13 +0200 Subject: Retry the query about interfaces to the qemu-agent --- libvirt/qemu_agent.go | 135 ++++++++++++++++++++++--------------- libvirt/resource_libvirt_domain.go | 4 +- 2 files changed, 81 insertions(+), 58 deletions(-) diff --git a/libvirt/qemu_agent.go b/libvirt/qemu_agent.go index b884f7c4..fd7cef39 100644 --- a/libvirt/qemu_agent.go +++ b/libvirt/qemu_agent.go @@ -4,7 +4,9 @@ import ( "encoding/json" "log" "strings" + "time" + "github.com/hashicorp/terraform/helper/resource" libvirt "github.com/libvirt/libvirt-go" ) @@ -27,75 +29,96 @@ type QemuAgentInterfaceIPAddress struct { Prefix uint `json:"prefix"` } -// Retrieve all the interfaces attached to a domain and their addresses. Only -// the interfaces with at least an IP address are returned. -// When wait4ipv4 is turned on the code will not report interfaces that don't -// have a ipv4 address set. This is useful when a domain gets the ipv6 address -// before the ipv4 one. -func getDomainInterfacesViaQemuAgent(domain Domain, wait4ipv4 bool) []libvirt.DomainInterface { - log.Print("[DEBUG] get network interfaces using qemu agent") +func qemuAgentInterfacesRefreshFunc(domain LibVirtDomain, wait4ipv4 bool) resource.StateRefreshFunc { + return func() (interface{}, string, error) { - var interfaces []libvirt.DomainInterface + var interfaces []libvirt.DomainInterface - result, err := domain.QemuAgentCommand( - "{\"execute\":\"guest-network-get-interfaces\"}", - libvirt.DOMAIN_QEMU_AGENT_COMMAND_DEFAULT, - 0) - if err != nil { - return interfaces - } - - log.Printf("[DEBUG] qemu-agent response: %s", result) + log.Printf("[DEBUG] sending command to qemu-agent in %s", domain) + result, err := domain.QemuAgentCommand( + "{\"execute\":\"guest-network-get-interfaces\"}", + libvirt.DOMAIN_QEMU_AGENT_COMMAND_DEFAULT, + 0) + if err != nil { + log.Printf("[DEBUG] command error: %s", err) + return interfaces, "failed", nil + } - response := QemuAgentInterfacesResponse{} - if err := json.Unmarshal([]byte(result), &response); err != nil { - log.Printf("[DEBUG] Error converting Qemu agent response about domain interfaces: %s", err) - log.Printf("[DEBUG] Original message: %v", response) - log.Print("[DEBUG] Returning an empty list of interfaces") - return interfaces - } - log.Printf("[DEBUG] Parsed response %+v", response) + log.Printf("[DEBUG] qemu-agent response: %s", result) - for _, iface := range response.Interfaces { - if iface.Name == "lo" { - // ignore loopback interface - continue + response := QemuAgentInterfacesResponse{} + if err := json.Unmarshal([]byte(result), &response); err != nil { + log.Printf("[DEBUG] Error converting qemu-agent response about domain interfaces: %s", err) + log.Printf("[DEBUG] Original message: %s", response) + log.Print("[DEBUG] Returning an empty list of interfaces") + return interfaces, "fatal", nil } + log.Printf("[DEBUG] Parsed response %+v", response) - libVirtIface := libvirt.DomainInterface{ - Name: iface.Name, - Hwaddr: iface.Hwaddr} - - ipv4Assigned := false - for _, addr := range iface.IPAddresses { - if addr.Address == "" { - // ignore interfaces without an address (eg. waiting for dhcp lease) + for _, iface := range response.Interfaces { + if iface.Name == "lo" { + // ignore loopback interface continue } - libVirtAddr := libvirt.DomainIPAddress{ - Addr: addr.Address, - Prefix: addr.Prefix, + libVirtIface := libvirt.DomainInterface{ + Name: iface.Name, + Hwaddr: iface.Hwaddr} + + ipv4Assigned := false + for _, addr := range iface.IpAddresses { + if addr.Address == "" { + // ignore interfaces without an address (eg. waiting for dhcp lease) + continue + } + + libVirtAddr := libvirt.DomainIPAddress{ + Addr: addr.Address, + Prefix: addr.Prefix, + } + + switch strings.ToLower(addr.Type) { + case "ipv4": + libVirtAddr.Type = int(libvirt.IP_ADDR_TYPE_IPV4) + ipv4Assigned = true + case "ipv6": + libVirtAddr.Type = int(libvirt.IP_ADDR_TYPE_IPV6) + default: + log.Printf("[ERROR] Cannot handle unknown address type %s", addr.Type) + continue + } + libVirtIface.Addrs = append(libVirtIface.Addrs, libVirtAddr) } - - switch strings.ToLower(addr.Type) { - case "ipv4": - libVirtAddr.Type = int(libvirt.IP_ADDR_TYPE_IPV4) - ipv4Assigned = true - case "ipv6": - libVirtAddr.Type = int(libvirt.IP_ADDR_TYPE_IPV6) - default: - log.Printf("[ERROR] Cannot handle unknown address type %s", addr.Type) - continue + if len(libVirtIface.Addrs) > 0 && (ipv4Assigned || !wait4ipv4) { + interfaces = append(interfaces, libVirtIface) } - libVirtIface.Addrs = append(libVirtIface.Addrs, libVirtAddr) - } - if len(libVirtIface.Addrs) > 0 && (ipv4Assigned || !wait4ipv4) { - interfaces = append(interfaces, libVirtIface) } + + log.Printf("[DEBUG] Interfaces obtained via qemu-agent: %+v", interfaces) + return interfaces, "success", nil + } +} + +// Retrieve all the interfaces attached to a domain and their addresses. Only +// the interfaces with at least an IP address are returned. +// When wait4ipv4 is turned on the code will not report interfaces that don't +// have a ipv4 address set. This is useful when a domain gets the ipv6 address +// before the ipv4 one. +func getDomainInterfacesViaQemuAgent(domain LibVirtDomain, wait4ipv4 bool) []libvirt.DomainInterface { + + qemuAgentQuery := &resource.StateChangeConf{ + Pending: []string{"failed"}, + Target: []string{"success"}, + Refresh: qemuAgentInterfacesRefreshFunc(domain, wait4ipv4), + MinTimeout: 4 * time.Second, + Delay: 4 * time.Second, // Wait this time before starting checks + Timeout: 16 * time.Second, } - log.Printf("[DEBUG] Interfaces obtained via qemu Agent: %+v", interfaces) + interfaces, err := qemuAgentQuery.WaitForState() + if err != nil { + return []libvirt.DomainInterface{} + } - return interfaces + return interfaces.([]libvirt.DomainInterface) } diff --git a/libvirt/resource_libvirt_domain.go b/libvirt/resource_libvirt_domain.go index b5d0fb6d..25829f35 100644 --- a/libvirt/resource_libvirt_domain.go +++ b/libvirt/resource_libvirt_domain.go @@ -1300,6 +1300,7 @@ func getDomainInterfaces(domain libvirt.Domain) ([]libvirt.DomainInterface, erro // get all the interfaces using the qemu-agent, this includes also // interfaces that are not attached to networks managed by libvirt // (eg. bridges, macvtap,...) + log.Print("[DEBUG] fetching networking interfaces using qemu-agent") interfaces := getDomainInterfacesViaQemuAgent(&domain, true) if len(interfaces) > 0 { // the agent will always return all the interfaces, both the @@ -1308,9 +1309,8 @@ func getDomainInterfaces(domain libvirt.Domain) ([]libvirt.DomainInterface, erro return interfaces, nil } - log.Print("[DEBUG] fetching networking interfaces using libvirt API") - // get all the interfaces attached to libvirt networks + log.Print("[DEBUG] fetching networking interfaces using libvirt API") interfaces, err := domain.ListAllInterfaceAddresses(libvirt.DOMAIN_INTERFACE_ADDRESSES_SRC_LEASE) if err != nil { switch err.(type) { -- cgit v1.2.3