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 }