github.com/juju/juju@v0.0.0-20240430160146-1752b71fcf00/apiserver/common/modelstatus_test.go (about) 1 // Copyright 2016 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package common_test 5 6 import ( 7 "github.com/juju/errors" 8 "github.com/juju/loggo" 9 jc "github.com/juju/testing/checkers" 10 gc "gopkg.in/check.v1" 11 12 "github.com/juju/juju/apiserver/common" 13 apiservererrors "github.com/juju/juju/apiserver/errors" 14 "github.com/juju/juju/apiserver/facade/facadetest" 15 "github.com/juju/juju/apiserver/facades/client/controller" 16 apiservertesting "github.com/juju/juju/apiserver/testing" 17 "github.com/juju/juju/core/arch" 18 "github.com/juju/juju/core/constraints" 19 "github.com/juju/juju/core/instance" 20 "github.com/juju/juju/core/life" 21 "github.com/juju/juju/environs" 22 "github.com/juju/juju/environs/config" 23 "github.com/juju/juju/environs/context" 24 "github.com/juju/juju/provider/dummy" 25 "github.com/juju/juju/rpc/params" 26 "github.com/juju/juju/state" 27 statetesting "github.com/juju/juju/state/testing" 28 "github.com/juju/juju/storage" 29 "github.com/juju/juju/storage/provider" 30 "github.com/juju/juju/testing" 31 "github.com/juju/juju/testing/factory" 32 ) 33 34 type modelStatusSuite struct { 35 statetesting.StateSuite 36 37 controller *controller.ControllerAPI 38 resources *common.Resources 39 authorizer apiservertesting.FakeAuthorizer 40 } 41 42 var _ = gc.Suite(&modelStatusSuite{}) 43 44 func (s *modelStatusSuite) SetUpTest(c *gc.C) { 45 // Initial config needs to be set before the StateSuite SetUpTest. 46 s.InitialConfig = testing.CustomModelConfig(c, testing.Attrs{ 47 "name": "controller", 48 }) 49 s.NewPolicy = func(*state.State) state.Policy { 50 return statePolicy{} 51 } 52 53 s.StateSuite.SetUpTest(c) 54 s.resources = common.NewResources() 55 s.AddCleanup(func(_ *gc.C) { s.resources.StopAll() }) 56 57 s.authorizer = apiservertesting.FakeAuthorizer{ 58 Tag: s.Owner, 59 AdminTag: s.Owner, 60 } 61 62 controller, err := controller.LatestAPI( 63 facadetest.Context{ 64 State_: s.State, 65 Resources_: s.resources, 66 Auth_: s.authorizer, 67 StatePool_: s.StatePool, 68 }) 69 c.Assert(err, jc.ErrorIsNil) 70 s.controller = controller 71 72 loggo.GetLogger("juju.apiserver.controller").SetLogLevel(loggo.TRACE) 73 } 74 75 func (s *modelStatusSuite) TestModelStatusNonAuth(c *gc.C) { 76 // Set up the user making the call. 77 user := s.Factory.MakeUser(c, &factory.UserParams{NoModelUser: true}) 78 anAuthoriser := apiservertesting.FakeAuthorizer{ 79 Tag: user.Tag(), 80 } 81 endpoint, err := controller.TestingAPI( 82 facadetest.Context{ 83 State_: s.State, 84 StatePool_: s.StatePool, 85 Resources_: s.resources, 86 Auth_: anAuthoriser, 87 }) 88 c.Assert(err, jc.ErrorIsNil) 89 controllerModelTag := s.Model.ModelTag().String() 90 91 req := params.Entities{ 92 Entities: []params.Entity{{Tag: controllerModelTag}}, 93 } 94 result, err := endpoint.ModelStatus(req) 95 c.Assert(err, jc.ErrorIsNil) 96 c.Assert(result.Results[0].Error, gc.ErrorMatches, "permission denied") 97 } 98 99 func (s *modelStatusSuite) TestModelStatusOwnerAllowed(c *gc.C) { 100 // Set up the user making the call. 101 owner := s.Factory.MakeUser(c, nil) 102 anAuthoriser := apiservertesting.FakeAuthorizer{ 103 Tag: owner.Tag(), 104 } 105 st := s.Factory.MakeModel(c, &factory.ModelParams{Owner: owner.Tag()}) 106 defer st.Close() 107 endpoint, err := controller.TestingAPI( 108 facadetest.Context{ 109 State_: s.State, 110 Resources_: s.resources, 111 Auth_: anAuthoriser, 112 StatePool_: s.StatePool, 113 }) 114 c.Assert(err, jc.ErrorIsNil) 115 116 model, err := st.Model() 117 c.Assert(err, jc.ErrorIsNil) 118 req := params.Entities{ 119 Entities: []params.Entity{{Tag: model.ModelTag().String()}}, 120 } 121 _, err = endpoint.ModelStatus(req) 122 c.Assert(err, jc.ErrorIsNil) 123 } 124 125 func (s *modelStatusSuite) TestModelStatus(c *gc.C) { 126 otherModelOwner := s.Factory.MakeModelUser(c, nil) 127 otherSt := s.Factory.MakeModel(c, &factory.ModelParams{ 128 Name: "dummytoo", 129 Owner: otherModelOwner.UserTag, 130 ConfigAttrs: testing.Attrs{ 131 "controller": false, 132 }, 133 }) 134 defer otherSt.Close() 135 136 eight := uint64(8) 137 s.Factory.MakeMachine(c, &factory.MachineParams{ 138 Jobs: []state.MachineJob{state.JobManageModel}, 139 Characteristics: &instance.HardwareCharacteristics{CpuCores: &eight}, 140 InstanceId: "id-4", 141 DisplayName: "snowflake", 142 Volumes: []state.HostVolumeParams{{ 143 Volume: state.VolumeParams{ 144 Pool: "modelscoped", 145 Size: 123, 146 }, 147 }}, 148 }) 149 s.Factory.MakeMachine(c, &factory.MachineParams{ 150 Jobs: []state.MachineJob{state.JobHostUnits}, 151 InstanceId: "id-5", 152 Filesystems: []state.HostFilesystemParams{{ 153 Filesystem: state.FilesystemParams{ 154 Pool: "modelscoped", 155 Size: 123, 156 }, 157 }, { 158 Filesystem: state.FilesystemParams{ 159 Pool: "machinescoped", 160 Size: 123, 161 }, 162 }}, 163 }) 164 s.Factory.MakeApplication(c, &factory.ApplicationParams{ 165 Charm: s.Factory.MakeCharm(c, nil), 166 }) 167 168 otherFactory := factory.NewFactory(otherSt, s.StatePool) 169 otherFactory.MakeMachine(c, &factory.MachineParams{InstanceId: "id-8"}) 170 otherFactory.MakeMachine(c, &factory.MachineParams{InstanceId: "id-9"}) 171 otherFactory.MakeApplication(c, &factory.ApplicationParams{ 172 Charm: otherFactory.MakeCharm(c, nil), 173 }) 174 175 otherModel, err := otherSt.Model() 176 c.Assert(err, jc.ErrorIsNil) 177 178 controllerModelTag := s.Model.ModelTag().String() 179 hostedModelTag := otherModel.ModelTag().String() 180 181 req := params.Entities{ 182 Entities: []params.Entity{{Tag: controllerModelTag}, {Tag: hostedModelTag}}, 183 } 184 results, err := s.controller.ModelStatus(req) 185 c.Assert(err, jc.ErrorIsNil) 186 187 arch := arch.DefaultArchitecture 188 mem := uint64(64 * 1024 * 1024 * 1024) 189 stdHw := ¶ms.MachineHardware{ 190 Arch: &arch, 191 Mem: &mem, 192 } 193 c.Assert(results.Results, jc.DeepEquals, []params.ModelStatus{ 194 { 195 ModelTag: controllerModelTag, 196 HostedMachineCount: 1, 197 ApplicationCount: 1, 198 OwnerTag: s.Owner.String(), 199 Life: life.Alive, 200 Type: string(state.ModelTypeIAAS), 201 Machines: []params.ModelMachineInfo{ 202 {Id: "0", Hardware: ¶ms.MachineHardware{Cores: &eight}, InstanceId: "id-4", DisplayName: "snowflake", Status: "pending", WantsVote: true}, 203 {Id: "1", Hardware: stdHw, InstanceId: "id-5", Status: "pending"}, 204 }, 205 Applications: []params.ModelApplicationInfo{ 206 {Name: "mysql"}, 207 }, 208 Volumes: []params.ModelVolumeInfo{{ 209 Id: "0", Status: "pending", Detachable: true, 210 }}, 211 Filesystems: []params.ModelFilesystemInfo{{ 212 Id: "0", Status: "pending", Detachable: true, 213 }, { 214 Id: "1/1", Status: "pending", Detachable: false, 215 }}, 216 }, 217 { 218 ModelTag: hostedModelTag, 219 HostedMachineCount: 2, 220 ApplicationCount: 1, 221 OwnerTag: otherModelOwner.UserTag.String(), 222 Life: life.Alive, 223 Type: string(state.ModelTypeIAAS), 224 Machines: []params.ModelMachineInfo{ 225 {Id: "0", Hardware: stdHw, InstanceId: "id-8", Status: "pending"}, 226 {Id: "1", Hardware: stdHw, InstanceId: "id-9", Status: "pending"}, 227 }, 228 Applications: []params.ModelApplicationInfo{ 229 {Name: "mysql"}, 230 }, 231 }, 232 }) 233 } 234 235 func (s *modelStatusSuite) TestModelStatusCAAS(c *gc.C) { 236 otherModelOwner := s.Factory.MakeModelUser(c, nil) 237 otherSt := s.Factory.MakeCAASModel(c, &factory.ModelParams{ 238 Owner: otherModelOwner.UserTag, 239 ConfigAttrs: testing.Attrs{ 240 "controller": false, 241 }, 242 }) 243 defer otherSt.Close() 244 245 otherFactory := factory.NewFactory(otherSt, s.StatePool) 246 app := otherFactory.MakeApplication(c, &factory.ApplicationParams{ 247 Charm: otherFactory.MakeCharm(c, &factory.CharmParams{Name: "gitlab", Series: "kubernetes"}), 248 }) 249 otherFactory.MakeUnit(c, &factory.UnitParams{ 250 Application: app, 251 }) 252 253 otherModel, err := otherSt.Model() 254 c.Assert(err, jc.ErrorIsNil) 255 256 controllerModelTag := s.Model.ModelTag().String() 257 hostedModelTag := otherModel.ModelTag().String() 258 259 req := params.Entities{ 260 Entities: []params.Entity{{Tag: controllerModelTag}, {Tag: hostedModelTag}}, 261 } 262 results, err := s.controller.ModelStatus(req) 263 c.Assert(err, jc.ErrorIsNil) 264 265 c.Assert(results.Results, jc.DeepEquals, []params.ModelStatus{ 266 { 267 ModelTag: controllerModelTag, 268 HostedMachineCount: 0, 269 ApplicationCount: 0, 270 OwnerTag: s.Owner.String(), 271 Life: life.Alive, 272 Type: string(state.ModelTypeIAAS), 273 Applications: []params.ModelApplicationInfo{}, 274 }, 275 { 276 ModelTag: hostedModelTag, 277 HostedMachineCount: 0, 278 ApplicationCount: 1, 279 UnitCount: 1, 280 OwnerTag: otherModelOwner.UserTag.String(), 281 Life: life.Alive, 282 Type: string(state.ModelTypeCAAS), 283 Applications: []params.ModelApplicationInfo{ 284 {Name: "gitlab"}, 285 }, 286 }, 287 }) 288 } 289 290 func (s *modelStatusSuite) TestModelStatusRunsForAllModels(c *gc.C) { 291 req := params.Entities{ 292 Entities: []params.Entity{ 293 {Tag: "fail.me"}, 294 {Tag: s.Model.ModelTag().String()}, 295 }, 296 } 297 expected := params.ModelStatusResults{ 298 Results: []params.ModelStatus{ 299 { 300 Error: apiservererrors.ServerError(errors.New(`"fail.me" is not a valid tag`))}, 301 { 302 ModelTag: s.Model.ModelTag().String(), 303 Life: life.Value(s.Model.Life().String()), 304 OwnerTag: s.Model.Owner().String(), 305 Type: string(state.ModelTypeIAAS), 306 }, 307 }, 308 } 309 result, err := s.controller.ModelStatus(req) 310 c.Assert(err, jc.ErrorIsNil) 311 c.Assert(result, jc.DeepEquals, expected) 312 } 313 314 type statePolicy struct{} 315 316 func (statePolicy) Prechecker() (environs.InstancePrechecker, error) { 317 return nil, errors.NotImplementedf("Prechecker") 318 } 319 320 func (statePolicy) ConfigValidator() (config.Validator, error) { 321 return nil, errors.NotImplementedf("ConfigValidator") 322 } 323 324 func (statePolicy) ConstraintsValidator(context.ProviderCallContext) (constraints.Validator, error) { 325 return nil, errors.NotImplementedf("ConstraintsValidator") 326 } 327 328 func (statePolicy) InstanceDistributor() (context.Distributor, error) { 329 return nil, errors.NotImplementedf("InstanceDistributor") 330 } 331 332 func (statePolicy) StorageProviderRegistry() (storage.ProviderRegistry, error) { 333 return storage.ChainedProviderRegistry{ 334 dummy.StorageProviders(), 335 provider.CommonStorageProviders(), 336 }, nil 337 } 338 339 func (statePolicy) ProviderConfigSchemaSource(cloudName string) (config.ConfigSchemaSource, error) { 340 return nil, errors.NotImplementedf("ConfigSchemaSource") 341 }