github.com/makyo/juju@v0.0.0-20160425123129-2608902037e9/provider/maas/instance_test.go (about)

     1  // Copyright 2013 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package maas
     5  
     6  import (
     7  	"bytes"
     8  	"encoding/json"
     9  	"fmt"
    10  
    11  	"github.com/juju/gomaasapi"
    12  	jc "github.com/juju/testing/checkers"
    13  	gc "gopkg.in/check.v1"
    14  
    15  	"github.com/juju/juju/instance"
    16  	"github.com/juju/juju/network"
    17  )
    18  
    19  type instanceTest struct {
    20  	providerSuite
    21  }
    22  
    23  var _ = gc.Suite(&instanceTest{})
    24  
    25  func defaultSubnet() gomaasapi.CreateSubnet {
    26  	var s gomaasapi.CreateSubnet
    27  	s.DNSServers = []string{"192.168.1.2"}
    28  	s.Name = "maas-eth0"
    29  	s.Space = "space-0"
    30  	s.GatewayIP = "192.168.1.1"
    31  	s.CIDR = "192.168.1.0/24"
    32  	s.ID = 1
    33  	return s
    34  }
    35  
    36  func (s *instanceTest) newSubnet(cidr, space string, id uint) *bytes.Buffer {
    37  	var sub gomaasapi.CreateSubnet
    38  	sub.DNSServers = []string{"192.168.1.2"}
    39  	sub.Name = cidr
    40  	sub.Space = space
    41  	sub.GatewayIP = "192.168.1.1"
    42  	sub.CIDR = cidr
    43  	sub.ID = id
    44  	return s.subnetJSON(sub)
    45  }
    46  
    47  func (s *instanceTest) subnetJSON(subnet gomaasapi.CreateSubnet) *bytes.Buffer {
    48  	var out bytes.Buffer
    49  	err := json.NewEncoder(&out).Encode(subnet)
    50  	if err != nil {
    51  		panic(err)
    52  	}
    53  	return &out
    54  }
    55  
    56  func (s *instanceTest) SetUpTest(c *gc.C) {
    57  	s.providerSuite.SetUpTest(c)
    58  
    59  	// Create a subnet so that the spaces cache will be populated.
    60  	s.testMAASObject.TestServer.NewSubnet(s.subnetJSON(defaultSubnet()))
    61  }
    62  
    63  func (s *instanceTest) TestId(c *gc.C) {
    64  	jsonValue := `{"system_id": "system_id", "test": "test"}`
    65  	obj := s.testMAASObject.TestServer.NewNode(jsonValue)
    66  	resourceURI, _ := obj.GetField("resource_uri")
    67  	// TODO(perrito666) make a decent mock status getter
    68  	statusGetter := func(instance.Id) (string, string) {
    69  		return "unknown", "FAKE"
    70  	}
    71  	instance := maas1Instance{&obj, nil, statusGetter}
    72  
    73  	c.Check(string(instance.Id()), gc.Equals, resourceURI)
    74  }
    75  
    76  func (s *instanceTest) TestString(c *gc.C) {
    77  	jsonValue := `{"hostname": "thethingintheplace", "system_id": "system_id", "test": "test"}`
    78  	obj := s.testMAASObject.TestServer.NewNode(jsonValue)
    79  	statusGetter := func(instance.Id) (string, string) {
    80  		return "unknown", "FAKE"
    81  	}
    82  
    83  	instance := &maas1Instance{&obj, nil, statusGetter}
    84  	hostname, err := instance.hostname()
    85  	c.Assert(err, jc.ErrorIsNil)
    86  	expected := hostname + ":" + string(instance.Id())
    87  	c.Assert(fmt.Sprint(instance), gc.Equals, expected)
    88  }
    89  
    90  func (s *instanceTest) TestStringWithoutHostname(c *gc.C) {
    91  	// For good measure, test what happens if we don't have a hostname.
    92  	jsonValue := `{"system_id": "system_id", "test": "test"}`
    93  	obj := s.testMAASObject.TestServer.NewNode(jsonValue)
    94  	statusGetter := func(instance.Id) (string, string) {
    95  		return "unknown", "FAKE"
    96  	}
    97  
    98  	instance := &maas1Instance{&obj, nil, statusGetter}
    99  	_, err := instance.hostname()
   100  	c.Assert(err, gc.NotNil)
   101  	expected := fmt.Sprintf("<DNSName failed: %q>", err) + ":" + string(instance.Id())
   102  	c.Assert(fmt.Sprint(instance), gc.Equals, expected)
   103  }
   104  
   105  func (s *instanceTest) TestAddressesViaInterfaces(c *gc.C) {
   106  	server := s.testMAASObject.TestServer
   107  	server.SetVersionJSON(`{"capabilities": ["network-deployment-ubuntu"]}`)
   108  	// We simulate an newer MAAS (1.9+) which returns both ip_addresses and
   109  	// interface_set for a node. To verify we use interfaces we deliberately put
   110  	// different items in ip_addresses
   111  	jsonValue := `{
   112      "hostname": "-testing.invalid",
   113      "system_id": "system_id",
   114      "interface_set" : [
   115  	{ "name": "eth0", "links": [
   116  	    { "subnet": { "space": "bar", "cidr": "8.7.6.0/24" }, "ip_address": "8.7.6.5" },
   117  	    { "subnet": { "space": "bar", "cidr": "8.7.6.0/24"  }, "ip_address": "8.7.6.6" }
   118  	] },
   119  	{ "name": "eth1", "links": [
   120  	    { "subnet": { "space": "storage", "cidr": "10.0.1.1/24" }, "ip_address": "10.0.1.1" }
   121  	] },
   122  	{ "name": "eth3", "links": [
   123  	    { "subnet": { "space": "db", "cidr": "fc00::/64" }, "ip_address": "fc00::123" }
   124  	] },
   125  	{ "name": "eth4" },
   126  	{ "name": "eth5", "links": [
   127  	    { "mode": "link-up" }
   128  	] }
   129      ],
   130      "ip_addresses": [ "anything", "foo", "0.1.2.3" ]
   131  }`
   132  	obj := s.testMAASObject.TestServer.NewNode(jsonValue)
   133  	statusGetter := func(instance.Id) (string, string) {
   134  		return "unknown", "FAKE"
   135  	}
   136  
   137  	barSpace := server.NewSpace(spaceJSON(gomaasapi.CreateSpace{Name: "bar"}))
   138  	storageSpace := server.NewSpace(spaceJSON(gomaasapi.CreateSpace{Name: "storage"}))
   139  	dbSpace := server.NewSpace(spaceJSON(gomaasapi.CreateSpace{Name: "db"}))
   140  	server.NewSubnet(s.newSubnet("8.7.6.0/24", "bar", 2))
   141  	server.NewSubnet(s.newSubnet("10.0.1.1/24", "storage", 3))
   142  	server.NewSubnet(s.newSubnet("fc00::/64", "db", 4))
   143  	inst := maas1Instance{&obj, s.makeEnviron(), statusGetter}
   144  
   145  	// Since gomaasapi treats "interface_set" specially and the only way to
   146  	// change it is via SetNodeNetworkLink(), which in turn does not allow you
   147  	// to specify ip_address, we need to patch the call which gets a fresh copy
   148  	// of the node details from the test server to avoid mangling the
   149  	// interface_set we used above.
   150  	s.PatchValue(&refreshMAASObject, func(mo *gomaasapi.MAASObject) (gomaasapi.MAASObject, error) {
   151  		return *mo, nil
   152  	})
   153  
   154  	idFromUint := func(u uint) network.Id {
   155  		return network.Id(fmt.Sprintf("%d", u))
   156  	}
   157  	expected := []network.Address{
   158  		newAddressOnSpaceWithId("bar", idFromUint(barSpace.ID), "8.7.6.5"),
   159  		newAddressOnSpaceWithId("bar", idFromUint(barSpace.ID), "8.7.6.6"),
   160  		newAddressOnSpaceWithId("storage", idFromUint(storageSpace.ID), "10.0.1.1"),
   161  		newAddressOnSpaceWithId("db", idFromUint(dbSpace.ID), "fc00::123"),
   162  	}
   163  
   164  	addr, err := inst.Addresses()
   165  	c.Assert(err, jc.ErrorIsNil)
   166  	c.Check(addr, jc.DeepEquals, expected)
   167  }
   168  
   169  func (s *instanceTest) TestAddressesInvalid(c *gc.C) {
   170  	jsonValue := `{
   171  		"hostname": "testing.invalid",
   172  		"system_id": "system_id",
   173  		"ip_addresses": "incompatible"
   174  		}`
   175  	obj := s.testMAASObject.TestServer.NewNode(jsonValue)
   176  	statusGetter := func(instance.Id) (string, string) {
   177  		return "unknown", "FAKE"
   178  	}
   179  
   180  	inst := maas1Instance{&obj, s.makeEnviron(), statusGetter}
   181  
   182  	_, err := inst.Addresses()
   183  	c.Assert(err, gc.NotNil)
   184  }
   185  
   186  func (s *instanceTest) TestAddressesInvalidContents(c *gc.C) {
   187  	jsonValue := `{
   188  		"hostname": "testing.invalid",
   189  		"system_id": "system_id",
   190  		"ip_addresses": [42]
   191  		}`
   192  	obj := s.testMAASObject.TestServer.NewNode(jsonValue)
   193  	statusGetter := func(instance.Id) (string, string) {
   194  		return "unknown", "FAKE"
   195  	}
   196  
   197  	inst := maas1Instance{&obj, s.makeEnviron(), statusGetter}
   198  
   199  	_, err := inst.Addresses()
   200  	c.Assert(err, gc.NotNil)
   201  }
   202  
   203  func (s *instanceTest) TestHardwareCharacteristics(c *gc.C) {
   204  	jsonValue := `{
   205  		"system_id": "system_id",
   206          "architecture": "amd64/generic",
   207          "cpu_count": 6,
   208          "zone": {"name": "tst"},
   209          "memory": 16384
   210  	}`
   211  	obj := s.testMAASObject.TestServer.NewNode(jsonValue)
   212  	statusGetter := func(instance.Id) (string, string) {
   213  		return "unknown", "FAKE"
   214  	}
   215  
   216  	inst := maas1Instance{&obj, nil, statusGetter}
   217  	hc, err := inst.hardwareCharacteristics()
   218  	c.Assert(err, jc.ErrorIsNil)
   219  	c.Assert(hc, gc.NotNil)
   220  	c.Assert(hc.String(), gc.Equals, `arch=amd64 cpu-cores=6 mem=16384M availability-zone=tst`)
   221  }
   222  
   223  func (s *instanceTest) TestHardwareCharacteristicsWithTags(c *gc.C) {
   224  	jsonValue := `{
   225  		"system_id": "system_id",
   226          "architecture": "amd64/generic",
   227          "cpu_count": 6,
   228          "memory": 16384,
   229          "zone": {"name": "tst"},
   230          "tag_names": ["a", "b"]
   231  	}`
   232  	obj := s.testMAASObject.TestServer.NewNode(jsonValue)
   233  	statusGetter := func(instance.Id) (string, string) {
   234  		return "unknown", "FAKE"
   235  	}
   236  
   237  	inst := maas1Instance{&obj, nil, statusGetter}
   238  	hc, err := inst.hardwareCharacteristics()
   239  	c.Assert(err, jc.ErrorIsNil)
   240  	c.Assert(hc, gc.NotNil)
   241  	c.Assert(hc.String(), gc.Equals, `arch=amd64 cpu-cores=6 mem=16384M tags=a,b availability-zone=tst`)
   242  }
   243  
   244  func (s *instanceTest) TestHardwareCharacteristicsMissing(c *gc.C) {
   245  	s.testHardwareCharacteristicsMissing(c, `{"system_id": "id", "cpu_count": 6, "memory": 16384}`,
   246  		`error determining architecture: Requested string, got <nil>.`)
   247  	s.testHardwareCharacteristicsMissing(c, `{"system_id": "id", "architecture": "amd64", "memory": 16384}`,
   248  		`error determining cpu count: Requested float64, got <nil>.`)
   249  	s.testHardwareCharacteristicsMissing(c, `{"system_id": "id", "architecture": "armhf", "cpu_count": 6}`,
   250  		`error determining available memory: Requested float64, got <nil>.`)
   251  	s.testHardwareCharacteristicsMissing(c, `{"system_id": "id", "architecture": "armhf", "cpu_count": 6, "memory": 1}`,
   252  		`error determining availability zone: zone property not set on maas`)
   253  	s.testHardwareCharacteristicsMissing(c, `{"system_id": "id", "architecture": "armhf", "cpu_count": 6, "memory": 1, "zone": ""}`,
   254  		`error determining availability zone: zone property is not an expected type`)
   255  	s.testHardwareCharacteristicsMissing(c, `{"system_id": "id", "architecture": "armhf", "cpu_count": 6, "memory": 1, "zone": {}}`,
   256  		`error determining availability zone: zone property is not set correctly: name is missing`)
   257  	s.testHardwareCharacteristicsMissing(c, `{"system_id": "id", "architecture": "armhf", "cpu_count": 6, "memory": 1, "zone": {"name": "tst"}, "tag_names": "wot"}`,
   258  		`error determining tag names: Requested array, got string.`)
   259  }
   260  
   261  func (s *instanceTest) testHardwareCharacteristicsMissing(c *gc.C, json, expect string) {
   262  	obj := s.testMAASObject.TestServer.NewNode(json)
   263  	statusGetter := func(instance.Id) (string, string) {
   264  		return "unknown", "FAKE"
   265  	}
   266  
   267  	inst := maas1Instance{&obj, nil, statusGetter}
   268  	_, err := inst.hardwareCharacteristics()
   269  	c.Assert(err, gc.ErrorMatches, expect)
   270  }