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  }