github.com/juju/juju@v0.0.0-20240430160146-1752b71fcf00/provider/lxd/environ_policy_test.go (about)

     1  // Copyright 2015 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package lxd_test
     5  
     6  import (
     7  	"fmt"
     8  	"strings"
     9  
    10  	"github.com/canonical/lxd/shared/api"
    11  	jc "github.com/juju/testing/checkers"
    12  	"go.uber.org/mock/gomock"
    13  	gc "gopkg.in/check.v1"
    14  
    15  	"github.com/juju/juju/core/arch"
    16  	"github.com/juju/juju/core/constraints"
    17  	"github.com/juju/juju/environs"
    18  	environscloudspec "github.com/juju/juju/environs/cloudspec"
    19  	"github.com/juju/juju/environs/context"
    20  	"github.com/juju/juju/provider/lxd"
    21  	"github.com/juju/juju/version"
    22  )
    23  
    24  type environPolicySuite struct {
    25  	lxd.EnvironSuite
    26  
    27  	svr     *lxd.MockServer
    28  	env     environs.Environ
    29  	callCtx context.ProviderCallContext
    30  }
    31  
    32  var _ = gc.Suite(&environPolicySuite{})
    33  
    34  func (s *environPolicySuite) SetUpTest(c *gc.C) {
    35  	s.BaseSuite.SetUpTest(c)
    36  	s.callCtx = context.NewEmptyCloudCallContext()
    37  }
    38  
    39  func (s *environPolicySuite) TestPrecheckInstanceDefaults(c *gc.C) {
    40  	defer s.setupMocks(c).Finish()
    41  	err := s.env.PrecheckInstance(s.callCtx, environs.PrecheckInstanceParams{Base: version.DefaultSupportedLTSBase()})
    42  	c.Assert(err, jc.ErrorIsNil)
    43  }
    44  
    45  func (s *environPolicySuite) TestPrecheckInstanceHasInstanceType(c *gc.C) {
    46  	defer s.setupMocks(c).Finish()
    47  
    48  	cons := constraints.MustParse("instance-type=some-instance-type")
    49  	err := s.env.PrecheckInstance(
    50  		s.callCtx, environs.PrecheckInstanceParams{Base: version.DefaultSupportedLTSBase(), Constraints: cons})
    51  
    52  	c.Check(err, jc.ErrorIsNil)
    53  }
    54  
    55  func (s *environPolicySuite) TestPrecheckInstanceDiskSize(c *gc.C) {
    56  	defer s.setupMocks(c).Finish()
    57  
    58  	cons := constraints.MustParse("root-disk=1G")
    59  	err := s.env.PrecheckInstance(
    60  		s.callCtx, environs.PrecheckInstanceParams{Base: version.DefaultSupportedLTSBase(), Constraints: cons})
    61  
    62  	c.Check(err, jc.ErrorIsNil)
    63  }
    64  
    65  func (s *environPolicySuite) TestPrecheckInstanceUnsupportedArch(c *gc.C) {
    66  	defer s.setupMocks(c).Finish()
    67  
    68  	cons := constraints.MustParse("arch=arm64")
    69  	err := s.env.PrecheckInstance(
    70  		s.callCtx, environs.PrecheckInstanceParams{Base: version.DefaultSupportedLTSBase(), Constraints: cons})
    71  
    72  	c.Check(err, jc.ErrorIsNil)
    73  }
    74  
    75  func (s *environPolicySuite) TestPrecheckInstanceAvailZone(c *gc.C) {
    76  	defer s.setupMocks(c).Finish()
    77  
    78  	members := []api.ClusterMember{
    79  		{
    80  			ServerName: "node01",
    81  			Status:     "ONLINE",
    82  		},
    83  		{
    84  			ServerName: "node02",
    85  			Status:     "ONLINE",
    86  		},
    87  	}
    88  
    89  	exp := s.svr.EXPECT()
    90  	gomock.InOrder(
    91  		exp.IsClustered().Return(true),
    92  		exp.GetClusterMembers().Return(members, nil),
    93  	)
    94  
    95  	placement := "zone=a-zone"
    96  	err := s.env.PrecheckInstance(
    97  		s.callCtx, environs.PrecheckInstanceParams{Base: version.DefaultSupportedLTSBase(), Placement: placement})
    98  
    99  	c.Check(err, gc.ErrorMatches, `availability zone "a-zone" not valid`)
   100  }
   101  
   102  func (s *environPolicySuite) TestConstraintsValidatorArch(c *gc.C) {
   103  	defer s.setupMocks(c).Finish()
   104  
   105  	validator, err := s.env.ConstraintsValidator(s.callCtx)
   106  	c.Assert(err, jc.ErrorIsNil)
   107  
   108  	cons := constraints.MustParse("arch=amd64")
   109  	unsupported, err := validator.Validate(cons)
   110  	c.Assert(err, jc.ErrorIsNil)
   111  
   112  	c.Check(unsupported, gc.HasLen, 0)
   113  }
   114  
   115  func (s *environPolicySuite) TestConstraintsValidatorArchWithUnsupportedArches(c *gc.C) {
   116  	// Don't use setupMocks because we need to mock SupportedArches
   117  	// to return a list of unsupported arches.
   118  	ctrl := gomock.NewController(c)
   119  	defer ctrl.Finish()
   120  
   121  	s.svr = lxd.NewMockServer(ctrl)
   122  	s.svr.EXPECT().SupportedArches().Return([]string{arch.AMD64, arch.ARM64, "i386", "armhf", "ppc64"}).MaxTimes(1)
   123  
   124  	s.env = s.NewEnviron(c, s.svr, nil, environscloudspec.CloudSpec{})
   125  
   126  	validator, err := s.env.ConstraintsValidator(s.callCtx)
   127  	c.Assert(err, jc.ErrorIsNil)
   128  
   129  	for _, arches := range []string{"arm64", "amd64"} {
   130  		cons := constraints.MustParse(fmt.Sprintf("arch=%s", arches))
   131  		unsupported, err := validator.Validate(cons)
   132  		c.Assert(err, jc.ErrorIsNil)
   133  
   134  		c.Check(unsupported, gc.HasLen, 0)
   135  	}
   136  }
   137  
   138  func (s *environPolicySuite) TestConstraintsValidatorVirtType(c *gc.C) {
   139  	defer s.setupMocks(c).Finish()
   140  
   141  	validator, err := s.env.ConstraintsValidator(s.callCtx)
   142  	c.Assert(err, jc.ErrorIsNil)
   143  
   144  	cons := constraints.MustParse("virt-type=container")
   145  	unsupported, err := validator.Validate(cons)
   146  	c.Assert(err, jc.ErrorIsNil)
   147  
   148  	c.Check(unsupported, gc.HasLen, 0)
   149  }
   150  
   151  func (s *environPolicySuite) TestConstraintsValidatorEmptyVirtType(c *gc.C) {
   152  	defer s.setupMocks(c).Finish()
   153  
   154  	validator, err := s.env.ConstraintsValidator(s.callCtx)
   155  	c.Assert(err, jc.ErrorIsNil)
   156  
   157  	cons := constraints.MustParse("virt-type=")
   158  	unsupported, err := validator.Validate(cons)
   159  	c.Assert(err, jc.ErrorIsNil)
   160  
   161  	c.Check(unsupported, gc.HasLen, 0)
   162  }
   163  
   164  func (s *environPolicySuite) TestConstraintsValidatorEmpty(c *gc.C) {
   165  	defer s.setupMocks(c).Finish()
   166  
   167  	validator, err := s.env.ConstraintsValidator(s.callCtx)
   168  	c.Assert(err, jc.ErrorIsNil)
   169  
   170  	unsupported, err := validator.Validate(constraints.Value{})
   171  	c.Assert(err, jc.ErrorIsNil)
   172  
   173  	c.Check(unsupported, gc.HasLen, 0)
   174  }
   175  
   176  func (s *environPolicySuite) TestConstraintsValidatorUnsupported(c *gc.C) {
   177  	defer s.setupMocks(c).Finish()
   178  
   179  	validator, err := s.env.ConstraintsValidator(context.NewEmptyCloudCallContext())
   180  	c.Assert(err, jc.ErrorIsNil)
   181  
   182  	cons := constraints.MustParse(strings.Join([]string{
   183  		"arch=amd64",
   184  		"tags=foo",
   185  		"mem=3",
   186  		"instance-type=some-type",
   187  		"cores=2",
   188  		"cpu-power=250",
   189  		"virt-type=virtual-machine",
   190  	}, " "))
   191  	unsupported, err := validator.Validate(cons)
   192  	c.Assert(err, jc.ErrorIsNil)
   193  
   194  	expected := []string{
   195  		"tags",
   196  		"cpu-power",
   197  	}
   198  	c.Check(unsupported, jc.SameContents, expected)
   199  }
   200  
   201  func (s *environPolicySuite) TestConstraintsValidatorVocabArchKnown(c *gc.C) {
   202  	defer s.setupMocks(c).Finish()
   203  
   204  	validator, err := s.env.ConstraintsValidator(s.callCtx)
   205  	c.Assert(err, jc.ErrorIsNil)
   206  
   207  	cons := constraints.MustParse("arch=amd64")
   208  	_, err = validator.Validate(cons)
   209  
   210  	c.Check(err, jc.ErrorIsNil)
   211  }
   212  
   213  func (s *environPolicySuite) TestConstraintsValidatorVocabArchUnknown(c *gc.C) {
   214  	defer s.setupMocks(c).Finish()
   215  
   216  	validator, err := s.env.ConstraintsValidator(s.callCtx)
   217  	c.Assert(err, jc.ErrorIsNil)
   218  
   219  	cons := constraints.MustParse("arch=ppc64el")
   220  	_, err = validator.Validate(cons)
   221  
   222  	c.Check(err, gc.ErrorMatches, "invalid constraint value: arch=ppc64el\nvalid values are: \\[amd64\\]")
   223  }
   224  
   225  func (s *environPolicySuite) TestConstraintsValidatorVocabContainerUnknown(c *gc.C) {
   226  	c.Skip("this will fail until we add a container vocabulary")
   227  
   228  	defer s.setupMocks(c).Finish()
   229  
   230  	validator, err := s.env.ConstraintsValidator(s.callCtx)
   231  	c.Assert(err, jc.ErrorIsNil)
   232  
   233  	cons := constraints.MustParse("container=lxd")
   234  	_, err = validator.Validate(cons)
   235  
   236  	c.Check(err, gc.ErrorMatches, "invalid constraint value: container=lxd\nvalid values are:.*")
   237  }
   238  
   239  func (s *environPolicySuite) TestConstraintsValidatorConflicts(c *gc.C) {
   240  	defer s.setupMocks(c).Finish()
   241  
   242  	validator, err := s.env.ConstraintsValidator(s.callCtx)
   243  	c.Assert(err, jc.ErrorIsNil)
   244  
   245  	cons := constraints.MustParse("instance-type=n1-standard-1")
   246  	consFallback := constraints.MustParse("cores=2 cpu-power=1000 mem=10000 tags=bar")
   247  	merged, err := validator.Merge(consFallback, cons)
   248  	c.Assert(err, jc.ErrorIsNil)
   249  
   250  	// tags is not supported, but we're not validating here...
   251  	expected := constraints.MustParse("instance-type=n1-standard-1 tags=bar cores=2 cpu-power=1000 mem=10000")
   252  	c.Check(merged, jc.DeepEquals, expected)
   253  }
   254  
   255  func (s *environPolicySuite) TestSupportNetworks(c *gc.C) {
   256  	defer s.setupMocks(c).Finish()
   257  
   258  	isSupported := s.env.(interface {
   259  		SupportNetworks(context.ProviderCallContext) bool
   260  	}).SupportNetworks(context.NewEmptyCloudCallContext())
   261  
   262  	c.Check(isSupported, jc.IsFalse)
   263  }
   264  
   265  func (s *environPolicySuite) TestShouldApplyControllerConstraints(c *gc.C) {
   266  	defer s.setupMocks(c).Finish()
   267  
   268  	cons := constraints.MustParse("")
   269  
   270  	ok := s.env.(environs.DefaultConstraintsChecker).ShouldApplyControllerConstraints(cons)
   271  	c.Assert(ok, jc.IsFalse)
   272  }
   273  
   274  func (s *environPolicySuite) TestShouldApplyControllerConstraintsInvalid(c *gc.C) {
   275  	defer s.setupMocks(c).Finish()
   276  
   277  	cons := constraints.MustParse("virt-type=invalid")
   278  
   279  	ok := s.env.(environs.DefaultConstraintsChecker).ShouldApplyControllerConstraints(cons)
   280  	c.Assert(ok, jc.IsFalse)
   281  }
   282  
   283  func (s *environPolicySuite) TestShouldApplyControllerConstraintsForVirtualMachine(c *gc.C) {
   284  	defer s.setupMocks(c).Finish()
   285  
   286  	cons := constraints.MustParse("virt-type=virtual-machine")
   287  
   288  	ok := s.env.(environs.DefaultConstraintsChecker).ShouldApplyControllerConstraints(cons)
   289  	c.Assert(ok, jc.IsTrue)
   290  }
   291  
   292  func (s *environPolicySuite) setupMocks(c *gc.C) *gomock.Controller {
   293  	ctrl := gomock.NewController(c)
   294  
   295  	s.svr = lxd.NewMockServer(ctrl)
   296  	s.svr.EXPECT().SupportedArches().Return([]string{arch.AMD64}).MaxTimes(1)
   297  
   298  	s.env = s.NewEnviron(c, s.svr, nil, environscloudspec.CloudSpec{})
   299  
   300  	return ctrl
   301  }