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 }