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

     1  // Copyright 2014 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package gce_test
     5  
     6  import (
     7  	"github.com/juju/errors"
     8  	jc "github.com/juju/testing/checkers"
     9  	gc "gopkg.in/check.v1"
    10  
    11  	"github.com/juju/juju/core/constraints"
    12  	"github.com/juju/juju/environs"
    13  	"github.com/juju/juju/provider/gce"
    14  	"github.com/juju/juju/provider/gce/google"
    15  	"github.com/juju/juju/storage"
    16  	"github.com/juju/juju/version"
    17  )
    18  
    19  type environPolSuite struct {
    20  	gce.BaseSuite
    21  }
    22  
    23  var _ = gc.Suite(&environPolSuite{})
    24  
    25  func (s *environPolSuite) SetUpTest(c *gc.C) {
    26  	s.BaseSuite.SetUpTest(c)
    27  
    28  	// NOTE(achilleasa): at least one zone is required so that any tests
    29  	// that trigger a call to InstanceTypes can obtain a non-empty instance
    30  	// list.
    31  	zone := google.NewZone("a-zone", google.StatusUp, "", "")
    32  	s.FakeConn.Zones = []google.AvailabilityZone{zone}
    33  }
    34  
    35  func (s *environPolSuite) TestPrecheckInstanceDefaults(c *gc.C) {
    36  	err := s.Env.PrecheckInstance(s.CallCtx, environs.PrecheckInstanceParams{
    37  		Base: version.DefaultSupportedLTSBase()})
    38  	c.Assert(err, jc.ErrorIsNil)
    39  
    40  	c.Check(s.FakeConn.Calls, gc.HasLen, 0)
    41  }
    42  
    43  func (s *environPolSuite) TestPrecheckInstanceFullAPI(c *gc.C) {
    44  	s.FakeConn.Zones = []google.AvailabilityZone{
    45  		google.NewZone("home-zone", google.StatusUp, "", ""),
    46  	}
    47  
    48  	cons := constraints.MustParse("instance-type=n1-standard-2 arch=amd64 root-disk=1G")
    49  	placement := "zone=home-zone"
    50  	err := s.Env.PrecheckInstance(s.CallCtx, environs.PrecheckInstanceParams{
    51  		Base: version.DefaultSupportedLTSBase(), Constraints: cons, Placement: placement})
    52  	c.Assert(err, jc.ErrorIsNil)
    53  
    54  	c.Check(s.FakeConn.Calls, gc.HasLen, 3)
    55  	c.Check(s.FakeConn.Calls[0].FuncName, gc.Equals, "AvailabilityZones")
    56  	c.Check(s.FakeConn.Calls[0].Region, gc.Equals, "us-east1")
    57  	c.Check(s.FakeConn.Calls[1].FuncName, gc.Equals, "AvailabilityZones")
    58  	c.Check(s.FakeConn.Calls[1].Region, gc.Equals, "us-east1")
    59  	// NOTE(achilleas): If the constraint specifies an instance type,
    60  	// the precheck logic will fetch the machine types for the current zone
    61  	// to validate the constraint value.
    62  	c.Check(s.FakeConn.Calls[2].FuncName, gc.Equals, "ListMachineTypes")
    63  	c.Check(s.FakeConn.Calls[2].ZoneName, gc.Equals, "home-zone")
    64  }
    65  
    66  func (s *environPolSuite) TestPrecheckInstanceValidInstanceType(c *gc.C) {
    67  	cons := constraints.MustParse("instance-type=n1-standard-2")
    68  	err := s.Env.PrecheckInstance(s.CallCtx, environs.PrecheckInstanceParams{
    69  		Base: version.DefaultSupportedLTSBase(), Constraints: cons})
    70  
    71  	c.Check(err, jc.ErrorIsNil)
    72  }
    73  
    74  func (s *environPolSuite) TestPrecheckInstanceInvalidInstanceType(c *gc.C) {
    75  	cons := constraints.MustParse("instance-type=n1-standard-1.invalid")
    76  	err := s.Env.PrecheckInstance(s.CallCtx, environs.PrecheckInstanceParams{
    77  		Base: version.DefaultSupportedLTSBase(), Constraints: cons})
    78  
    79  	c.Check(err, gc.ErrorMatches, `.*invalid GCE instance type.*`)
    80  }
    81  
    82  func (s *environPolSuite) TestPrecheckInstanceDiskSize(c *gc.C) {
    83  	cons := constraints.MustParse("instance-type=n1-standard-2 root-disk=1G")
    84  	placement := ""
    85  	err := s.Env.PrecheckInstance(s.CallCtx, environs.PrecheckInstanceParams{
    86  		Base: version.DefaultSupportedLTSBase(), Constraints: cons, Placement: placement})
    87  
    88  	c.Check(err, jc.ErrorIsNil)
    89  }
    90  
    91  func (s *environPolSuite) TestPrecheckInstanceUnsupportedArch(c *gc.C) {
    92  	cons := constraints.MustParse("instance-type=n1-standard-2 arch=arm64")
    93  	err := s.Env.PrecheckInstance(s.CallCtx, environs.PrecheckInstanceParams{
    94  		Base: version.DefaultSupportedLTSBase(), Constraints: cons})
    95  
    96  	c.Check(err, jc.ErrorIsNil)
    97  }
    98  
    99  func (s *environPolSuite) TestPrecheckInstanceAvailZone(c *gc.C) {
   100  	s.FakeConn.Zones = []google.AvailabilityZone{
   101  		google.NewZone("a-zone", google.StatusUp, "", ""),
   102  	}
   103  
   104  	placement := "zone=a-zone"
   105  	err := s.Env.PrecheckInstance(s.CallCtx, environs.PrecheckInstanceParams{
   106  		Base: version.DefaultSupportedLTSBase(), Placement: placement})
   107  
   108  	c.Check(err, jc.ErrorIsNil)
   109  }
   110  
   111  func (s *environPolSuite) TestPrecheckInstanceAvailZoneUnavailable(c *gc.C) {
   112  	s.FakeConn.Zones = []google.AvailabilityZone{
   113  		google.NewZone("a-zone", google.StatusDown, "", ""),
   114  	}
   115  
   116  	placement := "zone=a-zone"
   117  	err := s.Env.PrecheckInstance(s.CallCtx, environs.PrecheckInstanceParams{
   118  		Base: version.DefaultSupportedLTSBase(), Placement: placement})
   119  
   120  	c.Check(err, gc.ErrorMatches, `.*availability zone "a-zone" is DOWN`)
   121  }
   122  
   123  func (s *environPolSuite) TestPrecheckInstanceAvailZoneUnknown(c *gc.C) {
   124  	s.FakeConn.Zones = []google.AvailabilityZone{
   125  		google.NewZone("home-zone", google.StatusUp, "", ""),
   126  	}
   127  
   128  	placement := "zone=a-zone"
   129  	err := s.Env.PrecheckInstance(s.CallCtx, environs.PrecheckInstanceParams{
   130  		Base: version.DefaultSupportedLTSBase(), Placement: placement})
   131  
   132  	c.Check(err, jc.Satisfies, errors.IsNotFound)
   133  }
   134  
   135  func (s *environPolSuite) TestPrecheckInstanceVolumeAvailZoneNoPlacement(c *gc.C) {
   136  	s.testPrecheckInstanceVolumeAvailZone(c, "")
   137  }
   138  
   139  func (s *environPolSuite) TestPrecheckInstanceVolumeAvailZoneSameZonePlacement(c *gc.C) {
   140  	s.testPrecheckInstanceVolumeAvailZone(c, "zone=away-zone")
   141  }
   142  
   143  func (s *environPolSuite) testPrecheckInstanceVolumeAvailZone(c *gc.C, placement string) {
   144  	s.FakeConn.Zones = []google.AvailabilityZone{
   145  		google.NewZone("away-zone", google.StatusUp, "", ""),
   146  	}
   147  
   148  	err := s.Env.PrecheckInstance(s.CallCtx, environs.PrecheckInstanceParams{
   149  		Base:      version.DefaultSupportedLTSBase(),
   150  		Placement: placement,
   151  		VolumeAttachments: []storage.VolumeAttachmentParams{{
   152  			VolumeId: "away-zone--c930380d-8337-4bf5-b07a-9dbb5ae771e4",
   153  		}},
   154  	})
   155  	c.Check(err, jc.ErrorIsNil)
   156  }
   157  
   158  func (s *environPolSuite) TestPrecheckInstanceAvailZoneConflictsVolume(c *gc.C) {
   159  	s.FakeConn.Zones = []google.AvailabilityZone{
   160  		google.NewZone("away-zone", google.StatusUp, "", ""),
   161  	}
   162  
   163  	err := s.Env.PrecheckInstance(s.CallCtx, environs.PrecheckInstanceParams{
   164  		Base:      version.DefaultSupportedLTSBase(),
   165  		Placement: "zone=away-zone",
   166  		VolumeAttachments: []storage.VolumeAttachmentParams{{
   167  			VolumeId: "home-zone--c930380d-8337-4bf5-b07a-9dbb5ae771e4",
   168  		}},
   169  	})
   170  
   171  	c.Check(err, gc.ErrorMatches, `cannot create instance with placement "zone=away-zone", as this will prevent attaching the requested disks in zone "home-zone"`)
   172  }
   173  
   174  func (s *environPolSuite) TestConstraintsValidator(c *gc.C) {
   175  	validator, err := s.Env.ConstraintsValidator(s.CallCtx)
   176  	c.Assert(err, jc.ErrorIsNil)
   177  
   178  	cons := constraints.MustParse("arch=amd64")
   179  	unsupported, err := validator.Validate(cons)
   180  	c.Assert(err, jc.ErrorIsNil)
   181  	c.Check(unsupported, gc.HasLen, 0)
   182  }
   183  
   184  func (s *environPolSuite) TestConstraintsValidatorEmpty(c *gc.C) {
   185  	validator, err := s.Env.ConstraintsValidator(s.CallCtx)
   186  	c.Assert(err, jc.ErrorIsNil)
   187  
   188  	unsupported, err := validator.Validate(constraints.Value{})
   189  	c.Assert(err, jc.ErrorIsNil)
   190  
   191  	c.Check(unsupported, gc.HasLen, 0)
   192  }
   193  
   194  func (s *environPolSuite) TestConstraintsValidatorUnsupported(c *gc.C) {
   195  	validator, err := s.Env.ConstraintsValidator(s.CallCtx)
   196  	c.Assert(err, jc.ErrorIsNil)
   197  
   198  	cons := constraints.MustParse("arch=amd64 tags=foo virt-type=kvm")
   199  	unsupported, err := validator.Validate(cons)
   200  	c.Assert(err, jc.ErrorIsNil)
   201  
   202  	c.Check(unsupported, jc.SameContents, []string{"tags", "virt-type"})
   203  }
   204  
   205  func (s *environPolSuite) TestConstraintsValidatorVocabInstType(c *gc.C) {
   206  	validator, err := s.Env.ConstraintsValidator(s.CallCtx)
   207  	c.Assert(err, jc.ErrorIsNil)
   208  
   209  	cons := constraints.MustParse("instance-type=foo")
   210  	_, err = validator.Validate(cons)
   211  
   212  	c.Check(err, gc.ErrorMatches, "invalid constraint value: instance-type=foo\nvalid values are:.*")
   213  }
   214  
   215  func (s *environPolSuite) TestConstraintsValidatorVocabContainer(c *gc.C) {
   216  	validator, err := s.Env.ConstraintsValidator(s.CallCtx)
   217  	c.Assert(err, jc.ErrorIsNil)
   218  
   219  	cons := constraints.MustParse("container=lxd")
   220  	_, err = validator.Validate(cons)
   221  
   222  	c.Check(err, gc.ErrorMatches, "invalid constraint value: container=lxd\nvalid values are:.*")
   223  }
   224  
   225  func (s *environPolSuite) TestConstraintsValidatorConflicts(c *gc.C) {
   226  	validator, err := s.Env.ConstraintsValidator(s.CallCtx)
   227  	c.Assert(err, jc.ErrorIsNil)
   228  
   229  	cons := constraints.MustParse("instance-type=n1-standard-2")
   230  	// We do not check arch or container since there is only one valid
   231  	// value for each and will always match.
   232  	consFallback := constraints.MustParse("cores=2 cpu-power=1000 mem=10000 tags=bar")
   233  	merged, err := validator.Merge(consFallback, cons)
   234  	c.Assert(err, jc.ErrorIsNil)
   235  
   236  	// tags is not supported, but we're not validating here...
   237  	expected := constraints.MustParse("instance-type=n1-standard-2 tags=bar")
   238  	c.Check(merged, jc.DeepEquals, expected)
   239  }
   240  
   241  func (s *environPolSuite) TestSupportNetworks(c *gc.C) {
   242  	isSupported := s.Env.SupportNetworks(s.CallCtx)
   243  
   244  	c.Check(isSupported, jc.IsFalse)
   245  }