github.com/makyo/juju@v0.0.0-20160425123129-2608902037e9/core/description/machine_test.go (about) 1 // Copyright 2016 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package description 5 6 import ( 7 "github.com/juju/names" 8 jc "github.com/juju/testing/checkers" 9 "github.com/juju/version" 10 gc "gopkg.in/check.v1" 11 "gopkg.in/yaml.v2" 12 ) 13 14 type MachineSerializationSuite struct { 15 SliceSerializationSuite 16 PortRangeCheck 17 StatusHistoryMixinSuite 18 } 19 20 var _ = gc.Suite(&MachineSerializationSuite{}) 21 22 func (s *MachineSerializationSuite) SetUpTest(c *gc.C) { 23 s.SliceSerializationSuite.SetUpTest(c) 24 s.importName = "machines" 25 s.sliceName = "machines" 26 s.importFunc = func(m map[string]interface{}) (interface{}, error) { 27 return importMachines(m) 28 } 29 s.testFields = func(m map[string]interface{}) { 30 m["machines"] = []interface{}{} 31 } 32 s.StatusHistoryMixinSuite.creator = func() HasStatusHistory { 33 return minimalMachine("1") 34 } 35 s.StatusHistoryMixinSuite.serializer = func(c *gc.C, initial interface{}) HasStatusHistory { 36 return s.exportImport(c, initial.(*machine)) 37 } 38 } 39 40 func minimalMachineMap(id string, containers ...interface{}) map[interface{}]interface{} { 41 return map[interface{}]interface{}{ 42 "id": id, 43 "nonce": "a-nonce", 44 "password-hash": "some-hash", 45 "instance": minimalCloudInstanceMap(), 46 "series": "zesty", 47 "tools": minimalAgentToolsMap(), 48 "jobs": []interface{}{"host-units"}, 49 "containers": containers, 50 "status": minimalStatusMap(), 51 "status-history": emptyStatusHistoryMap(), 52 } 53 } 54 55 func minimalMachine(id string, containers ...*machine) *machine { 56 m := newMachine(MachineArgs{ 57 Id: names.NewMachineTag(id), 58 Nonce: "a-nonce", 59 PasswordHash: "some-hash", 60 Series: "zesty", 61 Jobs: []string{"host-units"}, 62 }) 63 m.Containers_ = containers 64 m.SetInstance(minimalCloudInstanceArgs()) 65 m.SetTools(minimalAgentToolsArgs()) 66 m.SetStatus(minimalStatusArgs()) 67 return m 68 } 69 70 func addMinimalMachine(model Model, id string) { 71 m := model.AddMachine(MachineArgs{ 72 Id: names.NewMachineTag(id), 73 Nonce: "a-nonce", 74 PasswordHash: "some-hash", 75 Series: "zesty", 76 Jobs: []string{"host-units"}, 77 }) 78 m.SetInstance(minimalCloudInstanceArgs()) 79 m.SetTools(minimalAgentToolsArgs()) 80 m.SetStatus(minimalStatusArgs()) 81 } 82 83 func (s *MachineSerializationSuite) machineArgs(id string) MachineArgs { 84 return MachineArgs{ 85 Id: names.NewMachineTag(id), 86 Nonce: "a nonce", 87 PasswordHash: "some-hash", 88 Placement: "placement", 89 Series: "zesty", 90 ContainerType: "magic", 91 Jobs: []string{"this", "that"}, 92 } 93 } 94 95 func (s *MachineSerializationSuite) TestNewMachine(c *gc.C) { 96 m := newMachine(s.machineArgs("42")) 97 c.Assert(m.Id(), gc.Equals, "42") 98 c.Assert(m.Tag(), gc.Equals, names.NewMachineTag("42")) 99 c.Assert(m.Nonce(), gc.Equals, "a nonce") 100 c.Assert(m.PasswordHash(), gc.Equals, "some-hash") 101 c.Assert(m.Placement(), gc.Equals, "placement") 102 c.Assert(m.Series(), gc.Equals, "zesty") 103 c.Assert(m.ContainerType(), gc.Equals, "magic") 104 c.Assert(m.Jobs(), jc.DeepEquals, []string{"this", "that"}) 105 supportedContainers, ok := m.SupportedContainers() 106 c.Assert(ok, jc.IsFalse) 107 c.Assert(supportedContainers, gc.IsNil) 108 } 109 110 func (s *MachineSerializationSuite) TestMinimalMachineValid(c *gc.C) { 111 m := minimalMachine("1") 112 c.Assert(m.Validate(), jc.ErrorIsNil) 113 } 114 115 func (s *MachineSerializationSuite) TestNewMachineWithSupportedContainers(c *gc.C) { 116 supported := []string{"lxd", "kvm"} 117 args := s.machineArgs("id") 118 args.SupportedContainers = &supported 119 m := newMachine(args) 120 supportedContainers, ok := m.SupportedContainers() 121 c.Assert(ok, jc.IsTrue) 122 c.Assert(supportedContainers, jc.DeepEquals, supported) 123 } 124 125 func (s *MachineSerializationSuite) TestNewMachineWithNoSupportedContainers(c *gc.C) { 126 supported := []string{} 127 args := s.machineArgs("id") 128 args.SupportedContainers = &supported 129 m := newMachine(args) 130 supportedContainers, ok := m.SupportedContainers() 131 c.Assert(ok, jc.IsTrue) 132 c.Assert(supportedContainers, gc.HasLen, 0) 133 } 134 135 func (s *MachineSerializationSuite) TestNewMachineWithNoSupportedContainersNil(c *gc.C) { 136 var supported []string 137 args := s.machineArgs("id") 138 args.SupportedContainers = &supported 139 m := newMachine(args) 140 supportedContainers, ok := m.SupportedContainers() 141 c.Assert(ok, jc.IsTrue) 142 c.Assert(supportedContainers, gc.HasLen, 0) 143 } 144 145 func (s *MachineSerializationSuite) TestMinimalMatches(c *gc.C) { 146 bytes, err := yaml.Marshal(minimalMachine("0")) 147 c.Assert(err, jc.ErrorIsNil) 148 149 var source map[interface{}]interface{} 150 err = yaml.Unmarshal(bytes, &source) 151 c.Assert(err, jc.ErrorIsNil) 152 c.Assert(source, jc.DeepEquals, minimalMachineMap("0")) 153 } 154 155 func (*MachineSerializationSuite) TestNestedParsing(c *gc.C) { 156 machines, err := importMachines(map[string]interface{}{ 157 "version": 1, 158 "machines": []interface{}{ 159 minimalMachineMap("0"), 160 minimalMachineMap("1", 161 minimalMachineMap("1/lxc/0"), 162 minimalMachineMap("1/lxc/1"), 163 ), 164 minimalMachineMap("2", 165 minimalMachineMap("2/kvm/0", 166 minimalMachineMap("2/kvm/0/lxc/0"), 167 minimalMachineMap("2/kvm/0/lxc/1"), 168 ), 169 ), 170 }}) 171 c.Assert(err, jc.ErrorIsNil) 172 expected := []*machine{ 173 minimalMachine("0"), 174 minimalMachine("1", 175 minimalMachine("1/lxc/0"), 176 minimalMachine("1/lxc/1"), 177 ), 178 minimalMachine("2", 179 minimalMachine("2/kvm/0", 180 minimalMachine("2/kvm/0/lxc/0"), 181 minimalMachine("2/kvm/0/lxc/1"), 182 ), 183 ), 184 } 185 c.Assert(machines, jc.DeepEquals, expected) 186 } 187 188 func (s *MachineSerializationSuite) addOpenedPorts(m Machine) []OpenedPortsArgs { 189 args := []OpenedPortsArgs{ 190 { 191 SubnetID: "0.1.2.0/24", 192 OpenedPorts: []PortRangeArgs{ 193 { 194 UnitName: "magic/0", 195 FromPort: 1234, 196 ToPort: 2345, 197 Protocol: "tcp", 198 }, 199 }, 200 }, { 201 SubnetID: "", 202 OpenedPorts: []PortRangeArgs{ 203 { 204 UnitName: "unicorn/0", 205 FromPort: 80, 206 ToPort: 80, 207 Protocol: "tcp", 208 }, 209 }, 210 }, 211 } 212 m.AddOpenedPorts(args[0]) 213 m.AddOpenedPorts(args[1]) 214 return args 215 } 216 217 func (s *MachineSerializationSuite) TestOpenedPorts(c *gc.C) { 218 m := newMachine(s.machineArgs("42")) 219 args := s.addOpenedPorts(m) 220 ports := m.OpenedPorts() 221 c.Assert(ports, gc.HasLen, 2) 222 withSubnet, withoutSubnet := ports[0], ports[1] 223 c.Assert(withSubnet.SubnetID(), gc.Equals, "0.1.2.0/24") 224 c.Assert(withoutSubnet.SubnetID(), gc.Equals, "") 225 opened := withSubnet.OpenPorts() 226 c.Assert(opened, gc.HasLen, 1) 227 s.AssertPortRange(c, opened[0], args[0].OpenedPorts[0]) 228 opened = withoutSubnet.OpenPorts() 229 c.Assert(opened, gc.HasLen, 1) 230 s.AssertPortRange(c, opened[0], args[1].OpenedPorts[0]) 231 } 232 233 func (s *MachineSerializationSuite) TestAnnotations(c *gc.C) { 234 initial := minimalMachine("42") 235 annotations := map[string]string{ 236 "string": "value", 237 "another": "one", 238 } 239 initial.SetAnnotations(annotations) 240 241 machine := s.exportImport(c, initial) 242 c.Assert(machine.Annotations(), jc.DeepEquals, annotations) 243 } 244 245 func (s *MachineSerializationSuite) TestConstraints(c *gc.C) { 246 initial := minimalMachine("42") 247 args := ConstraintsArgs{ 248 Architecture: "amd64", 249 Memory: 8 * gig, 250 RootDisk: 40 * gig, 251 } 252 initial.SetConstraints(args) 253 254 machine := s.exportImport(c, initial) 255 c.Assert(machine.Constraints(), jc.DeepEquals, newConstraints(args)) 256 } 257 258 func (s *MachineSerializationSuite) exportImport(c *gc.C, machine_ *machine) *machine { 259 initial := machines{ 260 Version: 1, 261 Machines_: []*machine{machine_}, 262 } 263 264 bytes, err := yaml.Marshal(initial) 265 c.Assert(err, jc.ErrorIsNil) 266 267 var source map[string]interface{} 268 err = yaml.Unmarshal(bytes, &source) 269 c.Assert(err, jc.ErrorIsNil) 270 271 machines, err := importMachines(source) 272 c.Assert(err, jc.ErrorIsNil) 273 c.Assert(machines, gc.HasLen, 1) 274 return machines[0] 275 } 276 277 func (s *MachineSerializationSuite) TestParsingSerializedData(c *gc.C) { 278 // TODO: need to fully specify a machine. 279 args := s.machineArgs("0") 280 supported := []string{"kvm", "lxd"} 281 args.SupportedContainers = &supported 282 m := newMachine(args) 283 m.SetTools(minimalAgentToolsArgs()) 284 m.SetStatus(minimalStatusArgs()) 285 m.SetInstance(minimalCloudInstanceArgs()) 286 s.addOpenedPorts(m) 287 288 // Just use one set of address args for both machine and provider. 289 addrArgs := []AddressArgs{ 290 { 291 Value: "10.0.0.10", 292 Type: "special", 293 }, { 294 Value: "10.1.2.3", 295 Type: "other", 296 }, 297 } 298 m.SetAddresses(addrArgs, addrArgs) 299 m.SetPreferredAddresses(addrArgs[0], addrArgs[1]) 300 301 // Make sure the machine is valid. 302 c.Assert(m.Validate(), jc.ErrorIsNil) 303 304 machine := s.exportImport(c, m) 305 c.Assert(machine, jc.DeepEquals, m) 306 } 307 308 type CloudInstanceSerializationSuite struct { 309 SerializationSuite 310 } 311 312 var _ = gc.Suite(&CloudInstanceSerializationSuite{}) 313 314 func (s *CloudInstanceSerializationSuite) SetUpTest(c *gc.C) { 315 s.importName = "cloudInstance" 316 s.importFunc = func(m map[string]interface{}) (interface{}, error) { 317 return importCloudInstance(m) 318 } 319 } 320 321 func minimalCloudInstanceMap() map[interface{}]interface{} { 322 return map[interface{}]interface{}{ 323 "version": 1, 324 "instance-id": "instance id", 325 "status": "some status", 326 } 327 } 328 329 func minimalCloudInstance() *cloudInstance { 330 return newCloudInstance(minimalCloudInstanceArgs()) 331 } 332 333 func minimalCloudInstanceArgs() CloudInstanceArgs { 334 return CloudInstanceArgs{ 335 InstanceId: "instance id", 336 Status: "some status", 337 } 338 } 339 340 func (s *CloudInstanceSerializationSuite) TestNewCloudInstance(c *gc.C) { 341 // NOTE: using gig from package_test.go 342 args := CloudInstanceArgs{ 343 InstanceId: "instance id", 344 Status: "working", 345 Architecture: "amd64", 346 Memory: 16 * gig, 347 RootDisk: 200 * gig, 348 CpuCores: 8, 349 CpuPower: 4000, 350 Tags: []string{"much", "strong"}, 351 AvailabilityZone: "everywhere", 352 } 353 354 instance := newCloudInstance(args) 355 356 c.Assert(instance.InstanceId(), gc.Equals, args.InstanceId) 357 c.Assert(instance.Status(), gc.Equals, args.Status) 358 c.Assert(instance.Architecture(), gc.Equals, args.Architecture) 359 c.Assert(instance.Memory(), gc.Equals, args.Memory) 360 c.Assert(instance.RootDisk(), gc.Equals, args.RootDisk) 361 c.Assert(instance.CpuCores(), gc.Equals, args.CpuCores) 362 c.Assert(instance.CpuPower(), gc.Equals, args.CpuPower) 363 c.Assert(instance.AvailabilityZone(), gc.Equals, args.AvailabilityZone) 364 365 // Before we check tags, modify args to make sure that the instance ones 366 // don't change. 367 368 args.Tags[0] = "weird" 369 tags := instance.Tags() 370 c.Assert(tags, jc.DeepEquals, []string{"much", "strong"}) 371 372 // Also, changing the tags returned, doesn't modify the instance 373 tags[0] = "weird" 374 c.Assert(instance.Tags(), jc.DeepEquals, []string{"much", "strong"}) 375 } 376 377 func (s *CloudInstanceSerializationSuite) TestMinimalMatches(c *gc.C) { 378 bytes, err := yaml.Marshal(minimalCloudInstance()) 379 c.Assert(err, jc.ErrorIsNil) 380 381 var source map[interface{}]interface{} 382 err = yaml.Unmarshal(bytes, &source) 383 c.Assert(err, jc.ErrorIsNil) 384 c.Assert(source, jc.DeepEquals, minimalCloudInstanceMap()) 385 } 386 387 func (s *CloudInstanceSerializationSuite) TestParsingSerializedData(c *gc.C) { 388 const MaxUint64 = 1<<64 - 1 389 initial := newCloudInstance(CloudInstanceArgs{ 390 InstanceId: "instance id", 391 Status: "working", 392 Architecture: "amd64", 393 Memory: 16 * gig, 394 CpuPower: MaxUint64, 395 Tags: []string{"much", "strong"}, 396 }) 397 bytes, err := yaml.Marshal(initial) 398 c.Assert(err, jc.ErrorIsNil) 399 400 var source map[string]interface{} 401 err = yaml.Unmarshal(bytes, &source) 402 c.Assert(err, jc.ErrorIsNil) 403 404 instance, err := importCloudInstance(source) 405 c.Assert(err, jc.ErrorIsNil) 406 c.Assert(instance, jc.DeepEquals, initial) 407 } 408 409 type AgentToolsSerializationSuite struct { 410 SerializationSuite 411 } 412 413 var _ = gc.Suite(&AgentToolsSerializationSuite{}) 414 415 func (s *AgentToolsSerializationSuite) SetUpTest(c *gc.C) { 416 s.importName = "agentTools" 417 s.importFunc = func(m map[string]interface{}) (interface{}, error) { 418 return importAgentTools(m) 419 } 420 } 421 422 func (s *AgentToolsSerializationSuite) TestNewAgentTools(c *gc.C) { 423 args := AgentToolsArgs{ 424 Version: version.MustParseBinary("3.4.5-trusty-amd64"), 425 URL: "some-url", 426 SHA256: "long-hash", 427 Size: 123456789, 428 } 429 instance := newAgentTools(args) 430 431 c.Assert(instance.Version(), gc.Equals, args.Version) 432 c.Assert(instance.URL(), gc.Equals, args.URL) 433 c.Assert(instance.SHA256(), gc.Equals, args.SHA256) 434 c.Assert(instance.Size(), gc.Equals, args.Size) 435 } 436 437 func minimalAgentToolsMap() map[interface{}]interface{} { 438 return map[interface{}]interface{}{ 439 "version": 1, 440 "tools-version": "3.4.5-trusty-amd64", 441 "url": "some-url", 442 "sha256": "long-hash", 443 "size": 123456789, 444 } 445 } 446 447 func minimalAgentToolsArgs() AgentToolsArgs { 448 return AgentToolsArgs{ 449 Version: version.MustParseBinary("3.4.5-trusty-amd64"), 450 URL: "some-url", 451 SHA256: "long-hash", 452 Size: 123456789, 453 } 454 } 455 456 func minimalAgentTools() *agentTools { 457 return newAgentTools(minimalAgentToolsArgs()) 458 } 459 460 func (s *AgentToolsSerializationSuite) TestMinimalMatches(c *gc.C) { 461 bytes, err := yaml.Marshal(minimalAgentTools()) 462 c.Assert(err, jc.ErrorIsNil) 463 464 var source map[interface{}]interface{} 465 err = yaml.Unmarshal(bytes, &source) 466 c.Assert(err, jc.ErrorIsNil) 467 c.Assert(source, jc.DeepEquals, minimalAgentToolsMap()) 468 } 469 470 func (s *AgentToolsSerializationSuite) TestParsingSerializedData(c *gc.C) { 471 initial := newAgentTools(AgentToolsArgs{ 472 Version: version.MustParseBinary("2.0.4-trusty-amd64"), 473 URL: "some-url", 474 SHA256: "long-hash", 475 Size: 123456789, 476 }) 477 bytes, err := yaml.Marshal(initial) 478 c.Assert(err, jc.ErrorIsNil) 479 480 var source map[string]interface{} 481 err = yaml.Unmarshal(bytes, &source) 482 c.Assert(err, jc.ErrorIsNil) 483 484 instance, err := importAgentTools(source) 485 c.Assert(err, jc.ErrorIsNil) 486 c.Assert(instance, jc.DeepEquals, initial) 487 }