summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.travis.yml29
-rw-r--r--libvirt/domain_def.go7
-rw-r--r--libvirt/libvirt_domain_mock_test.go9
-rw-r--r--libvirt/libvirt_interfaces.go11
-rw-r--r--libvirt/libvirt_network_mock_test.go10
-rw-r--r--libvirt/network_def.go4
-rw-r--r--libvirt/network_def_test.go73
-rw-r--r--libvirt/pool_sync_test.go46
-rw-r--r--libvirt/qemu_agent.go25
-rw-r--r--libvirt/qemu_agent_test.go196
-rw-r--r--libvirt/resource_libvirt_domain_test.go2
-rw-r--r--libvirt/utils.go7
-rw-r--r--libvirt/utils_test.go46
13 files changed, 434 insertions, 31 deletions
diff --git a/.travis.yml b/.travis.yml
index 687158cf..eed2d261 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -5,18 +5,15 @@ go:
- 1.7
before_install:
+ - sudo add-apt-repository -y cloud-archive:mitaka
- sudo apt-get -qq update
- - sudo apt-get install -y wget
- - sudo apt-get build-dep -y libvirt
- - wget https://libvirt.org/sources/libvirt-1.2.14.tar.gz
- - sudo mkdir -p /usr/src
- - sudo tar xvzf libvirt-1.2.14.tar.gz -C /usr/src
- - pushd /usr/src/libvirt-1.2.14
- - sudo ./configure --prefix=/usr/
- - sudo make
- - sudo make install
- - sudo libvirtd -d
- - popd
+ - sudo apt-get install -y qemu libvirt-bin libvirt-dev
+ - sudo usermod -a -G libvirtd $USER
+ - echo -e "<pool type='dir'>\n<name>default</name>\n<target>\n<path>/pool-default</path>\n</target>\n</pool>" > pool.xml
+ - sudo mkdir /pool-default
+ - sudo chmod a+rwx /pool-default
+ - sudo virsh pool-define pool.xml
+ - sudo virsh pool-start default
- go get github.com/mattn/goveralls
- go get -u github.com/govend/govend
- govend -v
@@ -27,6 +24,12 @@ install:
# override the custom test script, this would trigger
# also the execution of the unit tests of the vendored
# code
+env:
+ global:
+ - TERRAFORM_LIBVIRT_TEST_DOMAIN_TYPE=qemu
+ - TF_ACC=true
+ - LIBVIRT_DEFAULT_URI="qemu:///system"
+
script:
- - go test ./libvirt
- - $HOME/gopath/bin/goveralls -service=travis-ci
+ - sg libvirtd -c "go test -v ./libvirt"
+ - sg libvirtd -c "$HOME/gopath/bin/goveralls -v -service=travis-ci"
diff --git a/libvirt/domain_def.go b/libvirt/domain_def.go
index f41a88bd..306286ed 100644
--- a/libvirt/domain_def.go
+++ b/libvirt/domain_def.go
@@ -2,6 +2,7 @@ package libvirt
import (
"encoding/xml"
+ "os"
)
type defDomain struct {
@@ -117,7 +118,11 @@ type defConsole struct {
func newDomainDef() defDomain {
// libvirt domain definition
domainDef := defDomain{}
- domainDef.Type = "kvm"
+ if v := os.Getenv("TERRAFORM_LIBVIRT_TEST_DOMAIN_TYPE"); v != "" {
+ domainDef.Type = v
+ } else {
+ domainDef.Type = "kvm"
+ }
domainDef.Xmlns = ""
domainDef.Os = defOs{}
diff --git a/libvirt/libvirt_domain_mock_test.go b/libvirt/libvirt_domain_mock_test.go
new file mode 100644
index 00000000..9a4c0290
--- /dev/null
+++ b/libvirt/libvirt_domain_mock_test.go
@@ -0,0 +1,9 @@
+package libvirt
+
+type LibVirtDomainMock struct {
+ QemuAgentCommandResponse string
+}
+
+func (d LibVirtDomainMock) QemuAgentCommand(cmd string, timeout int, flags uint32) string {
+ return d.QemuAgentCommandResponse
+}
diff --git a/libvirt/libvirt_interfaces.go b/libvirt/libvirt_interfaces.go
new file mode 100644
index 00000000..13bdbe35
--- /dev/null
+++ b/libvirt/libvirt_interfaces.go
@@ -0,0 +1,11 @@
+package libvirt
+
+// Interface used to expose a libvirt.VirDomain
+// Used to allow testing
+type LibVirtDomain interface {
+ QemuAgentCommand(cmd string, timeout int, flags uint32) string
+}
+
+type LibVirtNetwork interface {
+ GetXMLDesc(flags uint32) (string, error)
+}
diff --git a/libvirt/libvirt_network_mock_test.go b/libvirt/libvirt_network_mock_test.go
new file mode 100644
index 00000000..b219cb91
--- /dev/null
+++ b/libvirt/libvirt_network_mock_test.go
@@ -0,0 +1,10 @@
+package libvirt
+
+type LibVirtNetworkMock struct {
+ GetXMLDescReply string
+ GetXMLDescError error
+}
+
+func (n LibVirtNetworkMock) GetXMLDesc(flags uint32) (string, error) {
+ return n.GetXMLDescReply, n.GetXMLDescError
+}
diff --git a/libvirt/network_def.go b/libvirt/network_def.go
index 86f6dc6c..bd758747 100644
--- a/libvirt/network_def.go
+++ b/libvirt/network_def.go
@@ -3,8 +3,6 @@ package libvirt
import (
"encoding/xml"
"fmt"
-
- libvirt "github.com/dmacvicar/libvirt-go"
)
type defNetworkIpDhcpRange struct {
@@ -118,7 +116,7 @@ func newDefNetworkFromXML(s string) (defNetwork, error) {
return networkDef, nil
}
-func newDefNetworkfromLibvirt(network *libvirt.VirNetwork) (defNetwork, error) {
+func newDefNetworkfromLibvirt(network LibVirtNetwork) (defNetwork, error) {
networkXmlDesc, err := network.GetXMLDesc(0)
if err != nil {
return defNetwork{}, fmt.Errorf("Error retrieving libvirt domain XML description: %s", err)
diff --git a/libvirt/network_def_test.go b/libvirt/network_def_test.go
index d84c3ce8..14901f2f 100644
--- a/libvirt/network_def_test.go
+++ b/libvirt/network_def_test.go
@@ -3,6 +3,7 @@ package libvirt
import (
"bytes"
"encoding/xml"
+ "errors"
"testing"
"github.com/davecgh/go-spew/spew"
@@ -103,3 +104,75 @@ func TestBrokenNetworkDefUnmarshall(t *testing.T) {
t.Error("Unmarshal was supposed to fail")
}
}
+
+func TestHasDHCPNoForwardSet(t *testing.T) {
+ net := defNetwork{}
+
+ if net.HasDHCP() {
+ t.Error("Expected to not have forward enabled")
+ }
+}
+
+func TestHasDHCPForwardSet(t *testing.T) {
+ createNet := func(mode string) defNetwork {
+ return defNetwork{
+ Forward: &defNetworkForward{
+ Mode: mode,
+ },
+ }
+ }
+
+ for _, mode := range []string{"nat", "route", ""} {
+ net := createNet(mode)
+ if !net.HasDHCP() {
+ t.Errorf(
+ "Expected to have forward enabled with forward set to be '%s'",
+ mode)
+ }
+ }
+}
+
+func TestNetworkFromLibvirtError(t *testing.T) {
+ net := LibVirtNetworkMock{
+ GetXMLDescError: errors.New("boom"),
+ }
+
+ _, err := newDefNetworkfromLibvirt(net)
+ if err == nil {
+ t.Error("Expected error")
+ }
+}
+
+func TestNetworkFromLibvirtWrongResponse(t *testing.T) {
+ net := LibVirtNetworkMock{
+ GetXMLDescReply: "wrong xml",
+ }
+
+ _, err := newDefNetworkfromLibvirt(net)
+ if err == nil {
+ t.Error("Expected error")
+ }
+}
+
+func TestNetworkFromLibvirt(t *testing.T) {
+ net := LibVirtNetworkMock{
+ GetXMLDescReply: `
+ <network>
+ <name>default</name>
+ <forward mode='nat'>
+ <nat>
+ <port start='1024' end='65535'/>
+ </nat>
+ </forward>
+ </network>`,
+ }
+
+ dn, err := newDefNetworkfromLibvirt(net)
+ if err != nil {
+ t.Errorf("Unexpected error %v", err)
+ }
+
+ if dn.Forward.Mode != "nat" {
+ t.Errorf("Wrong forward mode: %s", dn.Forward.Mode)
+ }
+}
diff --git a/libvirt/pool_sync_test.go b/libvirt/pool_sync_test.go
new file mode 100644
index 00000000..630ae2a4
--- /dev/null
+++ b/libvirt/pool_sync_test.go
@@ -0,0 +1,46 @@
+package libvirt
+
+import (
+ "testing"
+)
+
+func TestAcquireLock(t *testing.T) {
+ ps := NewLibVirtPoolSync()
+
+ ps.AcquireLock("test")
+
+ _, found := ps.PoolLocks["test"]
+
+ if !found {
+ t.Errorf("lock not found")
+ }
+}
+
+func TestReleaseLock(t *testing.T) {
+ ps := NewLibVirtPoolSync()
+
+ ps.AcquireLock("test")
+
+ _, found := ps.PoolLocks["test"]
+ if !found {
+ t.Errorf("lock not found")
+ }
+
+ ps.ReleaseLock("test")
+ _, found = ps.PoolLocks["test"]
+ if !found {
+ t.Errorf("lock not found")
+ }
+}
+
+func TestReleaseNotExistingLock(t *testing.T) {
+ ps := NewLibVirtPoolSync()
+
+ ps.ReleaseLock("test")
+ _, found := ps.PoolLocks["test"]
+ if found {
+ t.Errorf("lock found")
+ }
+ // moreover there should be no runtime error because
+ // we are not trying to unlock a not-locked mutex
+}
diff --git a/libvirt/qemu_agent.go b/libvirt/qemu_agent.go
index 5b87dbd5..946aa39f 100644
--- a/libvirt/qemu_agent.go
+++ b/libvirt/qemu_agent.go
@@ -13,13 +13,15 @@ type QemuAgentInterfacesResponse struct {
}
type QemuAgentInterface struct {
- Name string `json:"name"`
- Hwaddr string `json:"hardware-address"`
- IpAddresses []struct {
- Type string `json:"ip-address-type"`
- Address string `json:"ip-address"`
- Prefix uint `json:"prefix"`
- } `json:"ip-addresses"`
+ Name string `json:"name"`
+ Hwaddr string `json:"hardware-address"`
+ IpAddresses []QemuAgentInterfaceIpAddress `json:"ip-addresses"`
+}
+
+type QemuAgentInterfaceIpAddress struct {
+ Type string `json:"ip-address-type"`
+ Address string `json:"ip-address"`
+ Prefix uint `json:"prefix"`
}
// Retrieve all the interfaces attached to a domain and their addresses. Only
@@ -27,7 +29,7 @@ type QemuAgentInterface struct {
// 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 *libvirt.VirDomain, wait4ipv4 bool) []libvirt.VirDomainInterface {
+func getDomainInterfacesViaQemuAgent(domain LibVirtDomain, wait4ipv4 bool) []libvirt.VirDomainInterface {
log.Print("[DEBUG] get network interfaces using qemu agent")
var interfaces []libvirt.VirDomainInterface
@@ -54,9 +56,9 @@ func getDomainInterfacesViaQemuAgent(domain *libvirt.VirDomain, wait4ipv4 bool)
continue
}
- libVirtIface := libvirt.VirDomainInterface{}
- libVirtIface.Name = iface.Name
- libVirtIface.Hwaddr = iface.Hwaddr
+ libVirtIface := libvirt.VirDomainInterface{
+ Name: iface.Name,
+ Hwaddr: iface.Hwaddr}
ipv4Assigned := false
for _, addr := range iface.IpAddresses {
@@ -78,6 +80,7 @@ func getDomainInterfacesViaQemuAgent(domain *libvirt.VirDomain, wait4ipv4 bool)
libVirtAddr.Type = libvirt.VIR_IP_ADDR_TYPE_IPV6
default:
log.Printf("[ERROR] Cannot handle unknown address type %s", addr.Type)
+ continue
}
libVirtIface.Addrs = append(libVirtIface.Addrs, libVirtAddr)
}
diff --git a/libvirt/qemu_agent_test.go b/libvirt/qemu_agent_test.go
new file mode 100644
index 00000000..095af723
--- /dev/null
+++ b/libvirt/qemu_agent_test.go
@@ -0,0 +1,196 @@
+package libvirt
+
+import (
+ "encoding/json"
+ "testing"
+
+ libvirt "github.com/dmacvicar/libvirt-go"
+)
+
+func TestGetDomainInterfacesViaQemuAgentInvalidResponse(t *testing.T) {
+ domain := LibVirtDomainMock{}
+
+ interfaces := getDomainInterfacesViaQemuAgent(domain, false)
+
+ if len(interfaces) != 0 {
+ t.Errorf("wrong number of interfaces: %d instead of 0", len(interfaces))
+ }
+}
+
+func TestGetDomainInterfacesViaQemuAgentNoInterfaces(t *testing.T) {
+
+ response := QemuAgentInterfacesResponse{
+ Interfaces: []QemuAgentInterface{}}
+ data, err := json.Marshal(response)
+ if err != nil {
+ t.Errorf("error: %v", err)
+ }
+ domain := LibVirtDomainMock{
+ QemuAgentCommandResponse: string(data),
+ }
+
+ interfaces := getDomainInterfacesViaQemuAgent(domain, false)
+ if len(interfaces) != 0 {
+ t.Errorf("wrong number of interfaces: %d instead of 0", len(interfaces))
+ }
+}
+
+func TestGetDomainInterfacesViaQemuAgentIgnoreLoopbackDevice(t *testing.T) {
+ response := QemuAgentInterfacesResponse{
+ Interfaces: []QemuAgentInterface{
+ QemuAgentInterface{
+ Name: "lo",
+ Hwaddr: "ho:me",
+ IpAddresses: []QemuAgentInterfaceIpAddress{
+ QemuAgentInterfaceIpAddress{
+ Type: "ipv4",
+ Address: "127.0.0.1",
+ Prefix: 1,
+ },
+ },
+ },
+ },
+ }
+ data, err := json.Marshal(response)
+ if err != nil {
+ t.Errorf("error: %v", err)
+ }
+ domain := LibVirtDomainMock{
+ QemuAgentCommandResponse: string(data),
+ }
+
+ interfaces := getDomainInterfacesViaQemuAgent(domain, false)
+
+ if len(interfaces) != 0 {
+ t.Errorf("wrong number of interfaces)")
+ }
+}
+
+func TestGetDomainInterfacesViaQemuAgentIgnoreDevicesWithoutAddress(t *testing.T) {
+ response := QemuAgentInterfacesResponse{
+ Interfaces: []QemuAgentInterface{
+ QemuAgentInterface{
+ Name: "eth1",
+ Hwaddr: "xy:yy:zz",
+ IpAddresses: []QemuAgentInterfaceIpAddress{
+ QemuAgentInterfaceIpAddress{
+ Type: "ipv4",
+ Address: "",
+ Prefix: 1,
+ },
+ },
+ },
+ },
+ }
+ data, err := json.Marshal(response)
+ if err != nil {
+ t.Errorf("error: %v", err)
+ }
+ domain := LibVirtDomainMock{
+ QemuAgentCommandResponse: string(data),
+ }
+
+ interfaces := getDomainInterfacesViaQemuAgent(domain, false)
+
+ if len(interfaces) != 0 {
+ t.Errorf("wrong number of interfaces")
+ }
+}
+
+func TestGetDomainInterfacesViaQemuAgentUnknownIpAddressType(t *testing.T) {
+ response := QemuAgentInterfacesResponse{
+ Interfaces: []QemuAgentInterface{
+ QemuAgentInterface{
+ Name: "eth2",
+ Hwaddr: "zy:yy:zz",
+ IpAddresses: []QemuAgentInterfaceIpAddress{
+ QemuAgentInterfaceIpAddress{
+ Type: "ipv8",
+ Address: "i don't exist",
+ Prefix: 1,
+ },
+ },
+ },
+ },
+ }
+ data, err := json.Marshal(response)
+ if err != nil {
+ t.Errorf("error: %v", err)
+ }
+ domain := LibVirtDomainMock{
+ QemuAgentCommandResponse: string(data),
+ }
+
+ interfaces := getDomainInterfacesViaQemuAgent(domain, false)
+
+ if len(interfaces) != 0 {
+ t.Errorf("wrong number of interfaces: %d instead of 1", len(interfaces))
+ }
+}
+
+func TestGetDomainInterfacesViaQemuAgent(t *testing.T) {
+ device := "eth0"
+ mac := "xx:yy:zz"
+ ipv4Addr := "192.168.1.1"
+ ipv6Addr := "2001:0db8:0000:0000:0000:ff00:0042:8329"
+
+ response := QemuAgentInterfacesResponse{
+ Interfaces: []QemuAgentInterface{
+ QemuAgentInterface{
+ Name: device,
+ Hwaddr: mac,
+ IpAddresses: []QemuAgentInterfaceIpAddress{
+ QemuAgentInterfaceIpAddress{
+ Type: "ipv4",
+ Address: ipv4Addr,
+ Prefix: 1,
+ },
+ QemuAgentInterfaceIpAddress{
+ Type: "ipv6",
+ Address: ipv6Addr,
+ Prefix: 1,
+ },
+ },
+ },
+ },
+ }
+ data, err := json.Marshal(response)
+ if err != nil {
+ t.Errorf("error: %v", err)
+ }
+ domain := LibVirtDomainMock{
+ QemuAgentCommandResponse: string(data),
+ }
+
+ interfaces := getDomainInterfacesViaQemuAgent(domain, false)
+
+ if len(interfaces) != 1 {
+ t.Errorf("wrong number of interfaces: %d instead of 1", len(interfaces))
+ }
+
+ if interfaces[0].Name != device {
+ t.Errorf("wrong interface name: %s", interfaces[0].Name)
+ }
+
+ if interfaces[0].Hwaddr != mac {
+ t.Errorf("wrong interface name: %s", interfaces[0].Hwaddr)
+ }
+
+ if len(interfaces[0].Addrs) != 2 {
+ t.Errorf("wrong number of addresses: %d", len(interfaces[0].Addrs))
+ }
+
+ for _, addr := range interfaces[0].Addrs {
+ var expected string
+
+ if addr.Type == libvirt.VIR_IP_ADDR_TYPE_IPV4 {
+ expected = ipv4Addr
+ } else {
+ expected = ipv6Addr
+ }
+
+ if expected != addr.Addr {
+ t.Errorf("Expected %s, got %s", expected, addr.Addr)
+ }
+ }
+}
diff --git a/libvirt/resource_libvirt_domain_test.go b/libvirt/resource_libvirt_domain_test.go
index dbb68863..b27df0e4 100644
--- a/libvirt/resource_libvirt_domain_test.go
+++ b/libvirt/resource_libvirt_domain_test.go
@@ -181,7 +181,7 @@ func TestAccLibvirtDomain_NetworkInterface(t *testing.T) {
network_name = "default"
}
network_interface = {
- bridge = "br0"
+ network_name = "default"
mac = "52:54:00:A9:F5:17"
}
disk {
diff --git a/libvirt/utils.go b/libvirt/utils.go
index 0700b756..1f8bbfcd 100644
--- a/libvirt/utils.go
+++ b/libvirt/utils.go
@@ -26,6 +26,9 @@ func DiskLetterForIndex(i int) string {
return fmt.Sprintf("%s%c", DiskLetterForIndex(q-1), letter)
}
+var WAIT_SLEEP_INTERVAL time.Duration = 1 * time.Second
+var WAIT_TIMEOUT time.Duration = 5 * time.Minute
+
// wait for success and timeout after 5 minutes.
func WaitForSuccess(errorMessage string, f func() error) error {
start := time.Now()
@@ -36,8 +39,8 @@ func WaitForSuccess(errorMessage string, f func() error) error {
}
log.Printf("[DEBUG] %s. Re-trying.\n", err)
- time.Sleep(1 * time.Second)
- if time.Since(start) > 5*time.Minute {
+ time.Sleep(WAIT_SLEEP_INTERVAL)
+ if time.Since(start) > WAIT_TIMEOUT {
return fmt.Errorf("%s: %s", errorMessage, err)
}
}
diff --git a/libvirt/utils_test.go b/libvirt/utils_test.go
index 62000f34..cdcf05b9 100644
--- a/libvirt/utils_test.go
+++ b/libvirt/utils_test.go
@@ -1,8 +1,10 @@
package libvirt
import (
+ "errors"
"net"
"testing"
+ "time"
)
func TestDiskLetterForIndex(t *testing.T) {
@@ -32,3 +34,47 @@ func TestIPsRange(t *testing.T) {
t.Errorf("unexpected range start for '%s': %s", net, start)
}
}
+
+func TestWaitForSuccessEverythingFine(t *testing.T) {
+ wait_sleep := WAIT_SLEEP_INTERVAL
+ wait_timeout := WAIT_TIMEOUT
+ defer func() {
+ WAIT_SLEEP_INTERVAL = wait_sleep
+ WAIT_TIMEOUT = wait_timeout
+ }()
+
+ WAIT_TIMEOUT = 1 * time.Second
+ WAIT_SLEEP_INTERVAL = 1 * time.Nanosecond
+
+ err := WaitForSuccess(
+ "boom",
+ func() error {
+ return nil
+ })
+
+ if err != nil {
+ t.Errorf("unexpected error %v", err)
+ }
+}
+
+func TestWaitForSuccessBrokenFunction(t *testing.T) {
+ wait_sleep := WAIT_SLEEP_INTERVAL
+ wait_timeout := WAIT_TIMEOUT
+ defer func() {
+ WAIT_SLEEP_INTERVAL = wait_sleep
+ WAIT_TIMEOUT = wait_timeout
+ }()
+
+ WAIT_TIMEOUT = 1 * time.Second
+ WAIT_SLEEP_INTERVAL = 1 * time.Nanosecond
+
+ err := WaitForSuccess(
+ "boom",
+ func() error {
+ return errors.New("something went wrong")
+ })
+
+ if err == nil {
+ t.Error("expected error")
+ }
+}