1
// Copyright 2016 Canonical Ltd.
2
// Licensed under the AGPLv3, see LICENCE file for details.
7
"github.com/juju/names"
8
jc "github.com/juju/testing/checkers"
9
"github.com/juju/version"
10
gc "gopkg.in/check.v1"
14
type MachineSerializationSuite struct {
15
SliceSerializationSuite
17
StatusHistoryMixinSuite
20
var _ = gc.Suite(&MachineSerializationSuite{})
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)
29
s.testFields = func(m map[string]interface{}) {
30
m["machines"] = []interface{}{}
32
s.StatusHistoryMixinSuite.creator = func() HasStatusHistory {
33
return minimalMachine("1")
35
s.StatusHistoryMixinSuite.serializer = func(c *gc.C, initial interface{}) HasStatusHistory {
36
return s.exportImport(c, initial.(*machine))
40
func minimalMachineMap(id string, containers ...interface{}) map[interface{}]interface{} {
41
return map[interface{}]interface{}{
44
"password-hash": "some-hash",
45
"instance": minimalCloudInstanceMap(),
47
"tools": minimalAgentToolsMap(),
48
"jobs": []interface{}{"host-units"},
49
"containers": containers,
50
"status": minimalStatusMap(),
51
"status-history": emptyStatusHistoryMap(),
55
func minimalMachine(id string, containers ...*machine) *machine {
56
m := newMachine(MachineArgs{
57
Id: names.NewMachineTag(id),
59
PasswordHash: "some-hash",
61
Jobs: []string{"host-units"},
63
m.Containers_ = containers
64
m.SetInstance(minimalCloudInstanceArgs())
65
m.SetTools(minimalAgentToolsArgs())
66
m.SetStatus(minimalStatusArgs())
70
func addMinimalMachine(model Model, id string) {
71
m := model.AddMachine(MachineArgs{
72
Id: names.NewMachineTag(id),
74
PasswordHash: "some-hash",
76
Jobs: []string{"host-units"},
78
m.SetInstance(minimalCloudInstanceArgs())
79
m.SetTools(minimalAgentToolsArgs())
80
m.SetStatus(minimalStatusArgs())
83
func (s *MachineSerializationSuite) machineArgs(id string) MachineArgs {
85
Id: names.NewMachineTag(id),
87
PasswordHash: "some-hash",
88
Placement: "placement",
90
ContainerType: "magic",
91
Jobs: []string{"this", "that"},
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)
110
func (s *MachineSerializationSuite) TestMinimalMachineValid(c *gc.C) {
111
m := minimalMachine("1")
112
c.Assert(m.Validate(), jc.ErrorIsNil)
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)
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)
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)
145
func (s *MachineSerializationSuite) TestMinimalMatches(c *gc.C) {
146
bytes, err := yaml.Marshal(minimalMachine("0"))
147
c.Assert(err, jc.ErrorIsNil)
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"))
155
func (*MachineSerializationSuite) TestNestedParsing(c *gc.C) {
156
machines, err := importMachines(map[string]interface{}{
158
"machines": []interface{}{
159
minimalMachineMap("0"),
160
minimalMachineMap("1",
161
minimalMachineMap("1/lxc/0"),
162
minimalMachineMap("1/lxc/1"),
164
minimalMachineMap("2",
165
minimalMachineMap("2/kvm/0",
166
minimalMachineMap("2/kvm/0/lxc/0"),
167
minimalMachineMap("2/kvm/0/lxc/1"),
171
c.Assert(err, jc.ErrorIsNil)
172
expected := []*machine{
175
minimalMachine("1/lxc/0"),
176
minimalMachine("1/lxc/1"),
179
minimalMachine("2/kvm/0",
180
minimalMachine("2/kvm/0/lxc/0"),
181
minimalMachine("2/kvm/0/lxc/1"),
185
c.Assert(machines, jc.DeepEquals, expected)
188
func (s *MachineSerializationSuite) addNetworkPorts(m Machine) []NetworkPortsArgs {
189
args := []NetworkPortsArgs{
191
NetworkName: "storage",
192
OpenPorts: []PortRangeArgs{
201
NetworkName: "workload",
202
OpenPorts: []PortRangeArgs{
204
UnitName: "unicorn/0",
212
m.AddNetworkPorts(args[0])
213
m.AddNetworkPorts(args[1])
217
func (s *MachineSerializationSuite) TestNetworkPorts(c *gc.C) {
218
m := newMachine(s.machineArgs("42"))
219
args := s.addNetworkPorts(m)
220
ports := m.NetworkPorts()
221
c.Assert(ports, gc.HasLen, 2)
222
storage, workload := ports[0], ports[1]
223
c.Assert(storage.NetworkName(), gc.Equals, "storage")
224
c.Assert(workload.NetworkName(), gc.Equals, "workload")
225
opened := storage.OpenPorts()
226
c.Assert(opened, gc.HasLen, 1)
227
s.AssertPortRange(c, opened[0], args[0].OpenPorts[0])
228
opened = workload.OpenPorts()
229
c.Assert(opened, gc.HasLen, 1)
230
s.AssertPortRange(c, opened[0], args[1].OpenPorts[0])
233
func (s *MachineSerializationSuite) TestAnnotations(c *gc.C) {
234
initial := minimalMachine("42")
235
annotations := map[string]string{
239
initial.SetAnnotations(annotations)
241
machine := s.exportImport(c, initial)
242
c.Assert(machine.Annotations(), jc.DeepEquals, annotations)
245
func (s *MachineSerializationSuite) TestConstraints(c *gc.C) {
246
initial := minimalMachine("42")
247
args := ConstraintsArgs{
248
Architecture: "amd64",
252
initial.SetConstraints(args)
254
machine := s.exportImport(c, initial)
255
c.Assert(machine.Constraints(), jc.DeepEquals, newConstraints(args))
258
func (s *MachineSerializationSuite) exportImport(c *gc.C, machine_ *machine) *machine {
261
Machines_: []*machine{machine_},
264
bytes, err := yaml.Marshal(initial)
265
c.Assert(err, jc.ErrorIsNil)
267
var source map[string]interface{}
268
err = yaml.Unmarshal(bytes, &source)
269
c.Assert(err, jc.ErrorIsNil)
271
machines, err := importMachines(source)
272
c.Assert(err, jc.ErrorIsNil)
273
c.Assert(machines, gc.HasLen, 1)
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())
288
// Just use one set of address args for both machine and provider.
289
addrArgs := []AddressArgs{
298
m.SetAddresses(addrArgs, addrArgs)
299
m.SetPreferredAddresses(addrArgs[0], addrArgs[1])
301
// Make sure the machine is valid.
302
c.Assert(m.Validate(), jc.ErrorIsNil)
304
machine := s.exportImport(c, m)
305
c.Assert(machine, jc.DeepEquals, m)
308
type CloudInstanceSerializationSuite struct {
312
var _ = gc.Suite(&CloudInstanceSerializationSuite{})
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)
321
func minimalCloudInstanceMap() map[interface{}]interface{} {
322
return map[interface{}]interface{}{
324
"instance-id": "instance id",
325
"status": "some status",
329
func minimalCloudInstance() *cloudInstance {
330
return newCloudInstance(minimalCloudInstanceArgs())
333
func minimalCloudInstanceArgs() CloudInstanceArgs {
334
return CloudInstanceArgs{
335
InstanceId: "instance id",
336
Status: "some status",
340
func (s *CloudInstanceSerializationSuite) TestNewCloudInstance(c *gc.C) {
341
// NOTE: using gig from package_test.go
342
args := CloudInstanceArgs{
343
InstanceId: "instance id",
345
Architecture: "amd64",
350
Tags: []string{"much", "strong"},
351
AvailabilityZone: "everywhere",
354
instance := newCloudInstance(args)
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)
365
// Before we check tags, modify args to make sure that the instance ones
368
args.Tags[0] = "weird"
369
tags := instance.Tags()
370
c.Assert(tags, jc.DeepEquals, []string{"much", "strong"})
372
// Also, changing the tags returned, doesn't modify the instance
374
c.Assert(instance.Tags(), jc.DeepEquals, []string{"much", "strong"})
377
func (s *CloudInstanceSerializationSuite) TestMinimalMatches(c *gc.C) {
378
bytes, err := yaml.Marshal(minimalCloudInstance())
379
c.Assert(err, jc.ErrorIsNil)
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())
387
func (s *CloudInstanceSerializationSuite) TestParsingSerializedData(c *gc.C) {
388
const MaxUint64 = 1<<64 - 1
389
initial := newCloudInstance(CloudInstanceArgs{
390
InstanceId: "instance id",
392
Architecture: "amd64",
395
Tags: []string{"much", "strong"},
397
bytes, err := yaml.Marshal(initial)
398
c.Assert(err, jc.ErrorIsNil)
400
var source map[string]interface{}
401
err = yaml.Unmarshal(bytes, &source)
402
c.Assert(err, jc.ErrorIsNil)
404
instance, err := importCloudInstance(source)
405
c.Assert(err, jc.ErrorIsNil)
406
c.Assert(instance, jc.DeepEquals, initial)
409
type AgentToolsSerializationSuite struct {
413
var _ = gc.Suite(&AgentToolsSerializationSuite{})
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)
422
func (s *AgentToolsSerializationSuite) TestNewAgentTools(c *gc.C) {
423
args := AgentToolsArgs{
424
Version: version.MustParseBinary("3.4.5-trusty-amd64"),
429
instance := newAgentTools(args)
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)
437
func minimalAgentToolsMap() map[interface{}]interface{} {
438
return map[interface{}]interface{}{
440
"tools-version": "3.4.5-trusty-amd64",
442
"sha256": "long-hash",
447
func minimalAgentToolsArgs() AgentToolsArgs {
448
return AgentToolsArgs{
449
Version: version.MustParseBinary("3.4.5-trusty-amd64"),
456
func minimalAgentTools() *agentTools {
457
return newAgentTools(minimalAgentToolsArgs())
460
func (s *AgentToolsSerializationSuite) TestMinimalMatches(c *gc.C) {
461
bytes, err := yaml.Marshal(minimalAgentTools())
462
c.Assert(err, jc.ErrorIsNil)
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())
470
func (s *AgentToolsSerializationSuite) TestParsingSerializedData(c *gc.C) {
471
initial := newAgentTools(AgentToolsArgs{
472
Version: version.MustParseBinary("2.0.4-trusty-amd64"),
477
bytes, err := yaml.Marshal(initial)
478
c.Assert(err, jc.ErrorIsNil)
480
var source map[string]interface{}
481
err = yaml.Unmarshal(bytes, &source)
482
c.Assert(err, jc.ErrorIsNil)
484
instance, err := importAgentTools(source)
485
c.Assert(err, jc.ErrorIsNil)
486
c.Assert(instance, jc.DeepEquals, initial)