github.com/makyo/juju@v0.0.0-20160425123129-2608902037e9/state/constraintsvalidation_test.go (about)

     1  // Copyright 2014 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package state_test
     5  
     6  import (
     7  	jc "github.com/juju/testing/checkers"
     8  	gc "gopkg.in/check.v1"
     9  
    10  	"github.com/juju/juju/constraints"
    11  	"github.com/juju/juju/environs/config"
    12  	"github.com/juju/juju/state"
    13  )
    14  
    15  type constraintsValidationSuite struct {
    16  	ConnSuite
    17  }
    18  
    19  var _ = gc.Suite(&constraintsValidationSuite{})
    20  
    21  func (s *constraintsValidationSuite) SetUpTest(c *gc.C) {
    22  	s.ConnSuite.SetUpTest(c)
    23  	s.policy.GetConstraintsValidator = func(*config.Config, state.SupportedArchitecturesQuerier) (constraints.Validator, error) {
    24  		validator := constraints.NewValidator()
    25  		validator.RegisterConflicts(
    26  			[]string{constraints.InstanceType},
    27  			[]string{constraints.Mem, constraints.Arch},
    28  		)
    29  		validator.RegisterUnsupported([]string{constraints.CpuPower})
    30  		return validator, nil
    31  	}
    32  }
    33  
    34  func (s *constraintsValidationSuite) addOneMachine(c *gc.C, cons constraints.Value) (*state.Machine, error) {
    35  	return s.State.AddOneMachine(state.MachineTemplate{
    36  		Series:      "quantal",
    37  		Jobs:        []state.MachineJob{state.JobHostUnits},
    38  		Constraints: cons,
    39  	})
    40  }
    41  
    42  var setConstraintsTests = []struct {
    43  	about        string
    44  	consToSet    string
    45  	consFallback string
    46  
    47  	effectiveModelCons   string // model constraints after setting consFallback
    48  	effectiveServiceCons string // service constraints after setting consToSet
    49  	effectiveUnitCons    string // unit constraints after setting consToSet on the service
    50  	effectiveMachineCons string // machine constraints after setting consToSet
    51  }{{
    52  	about:        "(implictly) empty constraints are OK and stored as empty",
    53  	consToSet:    "",
    54  	consFallback: "",
    55  
    56  	effectiveModelCons:   "",
    57  	effectiveServiceCons: "",
    58  	effectiveUnitCons:    "",
    59  	effectiveMachineCons: "",
    60  }, {
    61  	about:        "(implicitly) empty fallback constraints never override set constraints",
    62  	consToSet:    "instance-type=foo-42 cpu-power=9001 spaces=bar",
    63  	consFallback: "",
    64  
    65  	effectiveModelCons: "", // model constraints are stored as empty.
    66  	// i.e. there are no fallbacks and all the following cases are the same.
    67  	effectiveServiceCons: "instance-type=foo-42 cpu-power=9001 spaces=bar",
    68  	effectiveUnitCons:    "instance-type=foo-42 cpu-power=9001 spaces=bar",
    69  	effectiveMachineCons: "instance-type=foo-42 cpu-power=9001 spaces=bar",
    70  }, {
    71  	about:        "(implicitly) empty constraints never override explictly set fallbacks",
    72  	consToSet:    "",
    73  	consFallback: "arch=amd64 cpu-cores=42 mem=2G tags=foo",
    74  
    75  	effectiveModelCons:   "arch=amd64 cpu-cores=42 mem=2G tags=foo",
    76  	effectiveServiceCons: "", // set as given.
    77  	effectiveUnitCons:    "arch=amd64 cpu-cores=42 mem=2G tags=foo",
    78  	// set as given, then merged with fallbacks; since consToSet is
    79  	// empty, the effective values inherit everything from fallbacks;
    80  	// like the unit, but only because the service constraints are
    81  	// also empty.
    82  	effectiveMachineCons: "arch=amd64 cpu-cores=42 mem=2G tags=foo",
    83  }, {
    84  	about:        "(explicitly) empty constraints are OK and stored as given",
    85  	consToSet:    "cpu-cores= cpu-power= root-disk= instance-type= container= tags= spaces=",
    86  	consFallback: "",
    87  
    88  	effectiveModelCons:   "",
    89  	effectiveServiceCons: "cpu-cores= cpu-power= root-disk= instance-type= container= tags= spaces=",
    90  	effectiveUnitCons:    "cpu-cores= cpu-power= root-disk= instance-type= container= tags= spaces=",
    91  	effectiveMachineCons: "cpu-cores= cpu-power= instance-type= root-disk= tags= spaces=", // container= is dropped
    92  }, {
    93  	about:        "(explicitly) empty fallback constraints are OK and stored as given",
    94  	consToSet:    "",
    95  	consFallback: "cpu-cores= cpu-power= root-disk= instance-type= container= tags= spaces=",
    96  
    97  	effectiveModelCons:   "cpu-cores= cpu-power= root-disk= instance-type= container= tags= spaces=",
    98  	effectiveServiceCons: "",
    99  	effectiveUnitCons:    "cpu-cores= cpu-power= root-disk= instance-type= container= tags= spaces=",
   100  	effectiveMachineCons: "cpu-cores= cpu-power= instance-type= root-disk= tags= spaces=", // container= is dropped
   101  }, {
   102  	about:                "(explicitly) empty constraints and fallbacks are OK and stored as given",
   103  	consToSet:            "arch= mem= cpu-cores= container=",
   104  	consFallback:         "cpu-cores= cpu-power= root-disk= instance-type= container= tags= spaces=",
   105  	effectiveModelCons:   "cpu-cores= cpu-power= root-disk= instance-type= container= tags= spaces=",
   106  	effectiveServiceCons: "arch= mem= cpu-cores= container=",
   107  	effectiveUnitCons:    "arch= container= cpu-cores= cpu-power= mem= root-disk= tags= spaces=",
   108  	effectiveMachineCons: "arch= cpu-cores= cpu-power= mem= root-disk= tags= spaces=", // container= is dropped
   109  }, {
   110  	about:        "(explicitly) empty constraints override set fallbacks for deployment and provisioning",
   111  	consToSet:    "cpu-cores= arch= spaces= cpu-power=",
   112  	consFallback: "cpu-cores=42 arch=amd64 tags=foo spaces=default,^dmz mem=4G",
   113  
   114  	effectiveModelCons:   "cpu-cores=42 arch=amd64 tags=foo spaces=default,^dmz mem=4G",
   115  	effectiveServiceCons: "cpu-cores= arch= spaces= cpu-power=",
   116  	effectiveUnitCons:    "arch= cpu-cores= cpu-power= mem=4G tags=foo spaces=",
   117  	effectiveMachineCons: "arch= cpu-cores= cpu-power= mem=4G tags=foo spaces=",
   118  	// we're also checking if m.SetConstraints() does the same with
   119  	// regards to the effective constraints as AddMachine(), because
   120  	// some of these tests proved they had different behavior (i.e.
   121  	// container= was not set to empty)
   122  }, {
   123  	about:        "non-empty constraints always override empty or unset fallbacks",
   124  	consToSet:    "cpu-cores=42 root-disk=20G arch=amd64 tags=foo,bar",
   125  	consFallback: "cpu-cores= arch= tags=",
   126  
   127  	effectiveModelCons:   "cpu-cores= arch= tags=",
   128  	effectiveServiceCons: "cpu-cores=42 root-disk=20G arch=amd64 tags=foo,bar",
   129  	effectiveUnitCons:    "cpu-cores=42 root-disk=20G arch=amd64 tags=foo,bar",
   130  	effectiveMachineCons: "cpu-cores=42 root-disk=20G arch=amd64 tags=foo,bar",
   131  }, {
   132  	about:        "non-empty constraints always override set fallbacks",
   133  	consToSet:    "cpu-cores=42 root-disk=20G arch=amd64 tags=foo,bar",
   134  	consFallback: "cpu-cores=12 root-disk=10G arch=i386  tags=bar",
   135  
   136  	effectiveModelCons:   "cpu-cores=12 root-disk=10G arch=i386  tags=bar",
   137  	effectiveServiceCons: "cpu-cores=42 root-disk=20G arch=amd64 tags=foo,bar",
   138  	effectiveUnitCons:    "cpu-cores=42 root-disk=20G arch=amd64 tags=foo,bar",
   139  	effectiveMachineCons: "cpu-cores=42 root-disk=20G arch=amd64 tags=foo,bar",
   140  }, {
   141  	about:        "non-empty constraints override conflicting set fallbacks",
   142  	consToSet:    "mem=8G arch=amd64 cpu-cores=4 tags=bar",
   143  	consFallback: "instance-type=small cpu-power=1000", // instance-type conflicts mem, arch
   144  
   145  	effectiveModelCons:   "instance-type=small cpu-power=1000",
   146  	effectiveServiceCons: "mem=8G arch=amd64 cpu-cores=4 tags=bar",
   147  	// both of the following contain the explicitly set constraints after
   148  	// resolving any conflicts with fallbacks (by dropping them).
   149  	effectiveUnitCons:    "mem=8G arch=amd64 cpu-cores=4 tags=bar cpu-power=1000",
   150  	effectiveMachineCons: "mem=8G arch=amd64 cpu-cores=4 tags=bar cpu-power=1000",
   151  }, {
   152  	about:        "set fallbacks are overriden the same way for provisioning and deployment",
   153  	consToSet:    "tags= cpu-power= spaces=bar",
   154  	consFallback: "tags=foo cpu-power=42",
   155  
   156  	// a variation of the above case showing there's no difference
   157  	// between deployment (service, unit) and provisioning (machine)
   158  	// constraints when it comes to effective values.
   159  	effectiveModelCons:   "tags=foo cpu-power=42",
   160  	effectiveServiceCons: "cpu-power= tags= spaces=bar",
   161  	effectiveUnitCons:    "cpu-power= tags= spaces=bar",
   162  	effectiveMachineCons: "cpu-power= tags= spaces=bar",
   163  }, {
   164  	about:        "container type can only be used for deployment, not provisioning",
   165  	consToSet:    "container=kvm arch=amd64",
   166  	consFallback: "container=lxc mem=8G",
   167  
   168  	// service deployment constraints are transformed into machine
   169  	// provisioning constraints, and the container type only makes
   170  	// sense currently as a deployment constraint, so it's cleared
   171  	// when merging service/model deployment constraints into
   172  	// effective machine provisioning constraints.
   173  	effectiveModelCons:   "container=lxc mem=8G",
   174  	effectiveServiceCons: "container=kvm arch=amd64",
   175  	effectiveUnitCons:    "container=kvm mem=8G arch=amd64",
   176  	effectiveMachineCons: "mem=8G arch=amd64",
   177  }}
   178  
   179  func (s *constraintsValidationSuite) TestMachineConstraints(c *gc.C) {
   180  	for i, t := range setConstraintsTests {
   181  		c.Logf(
   182  			"test %d: %s\nconsToSet: %q\nconsFallback: %q\n",
   183  			i, t.about, t.consToSet, t.consFallback,
   184  		)
   185  		// Set fallbacks as model constraints and verify them.
   186  		err := s.State.SetModelConstraints(constraints.MustParse(t.consFallback))
   187  		c.Check(err, jc.ErrorIsNil)
   188  		econs, err := s.State.ModelConstraints()
   189  		c.Check(econs, jc.DeepEquals, constraints.MustParse(t.effectiveModelCons))
   190  		// Set the machine provisioning constraints.
   191  		m, err := s.addOneMachine(c, constraints.MustParse(t.consToSet))
   192  		c.Check(err, jc.ErrorIsNil)
   193  		// New machine provisioning constraints get merged with the fallbacks.
   194  		cons, err := m.Constraints()
   195  		c.Check(err, jc.ErrorIsNil)
   196  		c.Check(cons, jc.DeepEquals, constraints.MustParse(t.effectiveMachineCons))
   197  		// Changing them should result in the same result before provisioning.
   198  		err = m.SetConstraints(constraints.MustParse(t.consToSet))
   199  		c.Check(err, jc.ErrorIsNil)
   200  		cons, err = m.Constraints()
   201  		c.Check(err, jc.ErrorIsNil)
   202  		c.Check(cons, jc.DeepEquals, constraints.MustParse(t.effectiveMachineCons))
   203  	}
   204  }
   205  
   206  func (s *constraintsValidationSuite) TestServiceConstraints(c *gc.C) {
   207  	charm := s.AddTestingCharm(c, "wordpress")
   208  	service := s.AddTestingService(c, "wordpress", charm)
   209  	for i, t := range setConstraintsTests {
   210  		c.Logf(
   211  			"test %d: %s\nconsToSet: %q\nconsFallback: %q\n",
   212  			i, t.about, t.consToSet, t.consFallback,
   213  		)
   214  		// Set fallbacks as model constraints and verify them.
   215  		err := s.State.SetModelConstraints(constraints.MustParse(t.consFallback))
   216  		c.Check(err, jc.ErrorIsNil)
   217  		econs, err := s.State.ModelConstraints()
   218  		c.Check(econs, jc.DeepEquals, constraints.MustParse(t.effectiveModelCons))
   219  		// Set the service deployment constraints.
   220  		err = service.SetConstraints(constraints.MustParse(t.consToSet))
   221  		c.Check(err, jc.ErrorIsNil)
   222  		u, err := service.AddUnit()
   223  		c.Check(err, jc.ErrorIsNil)
   224  		// New unit deployment constraints get merged with the fallbacks.
   225  		ucons, err := u.Constraints()
   226  		c.Check(err, jc.ErrorIsNil)
   227  		c.Check(*ucons, jc.DeepEquals, constraints.MustParse(t.effectiveUnitCons))
   228  		// Service constraints remain as set.
   229  		scons, err := service.Constraints()
   230  		c.Check(err, jc.ErrorIsNil)
   231  		c.Check(scons, jc.DeepEquals, constraints.MustParse(t.effectiveServiceCons))
   232  	}
   233  }