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