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 }