github.com/juju/juju@v0.0.0-20240430160146-1752b71fcf00/state/modelconfig_test.go (about) 1 // Copyright 2016 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package state_test 5 6 import ( 7 "strings" 8 9 "github.com/juju/collections/set" 10 "github.com/juju/errors" 11 "github.com/juju/names/v5" 12 jc "github.com/juju/testing/checkers" 13 "github.com/juju/utils/v3" 14 "github.com/juju/version/v2" 15 gc "gopkg.in/check.v1" 16 17 "github.com/juju/juju/cloud" 18 "github.com/juju/juju/core/constraints" 19 environscloudspec "github.com/juju/juju/environs/cloudspec" 20 "github.com/juju/juju/environs/config" 21 "github.com/juju/juju/state" 22 statetesting "github.com/juju/juju/state/testing" 23 "github.com/juju/juju/storage" 24 "github.com/juju/juju/testing" 25 ) 26 27 type ModelConfigSuite struct { 28 ConnSuite 29 } 30 31 var _ = gc.Suite(&ModelConfigSuite{}) 32 33 func (s *ModelConfigSuite) SetUpTest(c *gc.C) { 34 s.ControllerInheritedConfig = map[string]interface{}{ 35 "apt-mirror": "http://cloud-mirror", 36 } 37 s.RegionConfig = cloud.RegionConfig{ 38 "nether-region": cloud.Attrs{ 39 "apt-mirror": "http://nether-region-mirror", 40 "no-proxy": "nether-proxy", 41 }, 42 "dummy-region": cloud.Attrs{ 43 "no-proxy": "dummy-proxy", 44 "image-stream": "dummy-image-stream", 45 "whimsy-key": "whimsy-value", 46 }, 47 } 48 s.ConnSuite.SetUpTest(c) 49 s.policy.GetConstraintsValidator = func() (constraints.Validator, error) { 50 validator := constraints.NewValidator() 51 validator.RegisterConflicts([]string{constraints.InstanceType}, []string{constraints.Mem}) 52 validator.RegisterUnsupported([]string{constraints.CpuPower}) 53 return validator, nil 54 } 55 s.policy.GetProviderConfigSchemaSource = func(cloudName string) (config.ConfigSchemaSource, error) { 56 return &statetesting.MockConfigSchemaSource{CloudName: cloudName}, nil 57 } 58 } 59 60 func (s *ModelConfigSuite) TestAdditionalValidation(c *gc.C) { 61 updateAttrs := map[string]interface{}{"logging-config": "juju=ERROR"} 62 configValidator1 := func(updateAttrs map[string]interface{}, removeAttrs []string, oldConfig *config.Config) error { 63 c.Assert(updateAttrs, jc.DeepEquals, map[string]interface{}{"logging-config": "juju=ERROR"}) 64 if lc, found := updateAttrs["logging-config"]; found && lc != "" { 65 return errors.New("cannot change logging-config") 66 } 67 return nil 68 } 69 removeAttrs := []string{"some-attr"} 70 configValidator2 := func(updateAttrs map[string]interface{}, removeAttrs []string, oldConfig *config.Config) error { 71 c.Assert(removeAttrs, jc.DeepEquals, []string{"some-attr"}) 72 for _, i := range removeAttrs { 73 if i == "some-attr" { 74 return errors.New("cannot remove some-attr") 75 } 76 } 77 return nil 78 } 79 configValidator3 := func(updateAttrs map[string]interface{}, removeAttrs []string, oldConfig *config.Config) error { 80 return nil 81 } 82 83 err := s.Model.UpdateModelConfig(updateAttrs, nil, configValidator1) 84 c.Assert(err, gc.ErrorMatches, "cannot change logging-config") 85 err = s.Model.UpdateModelConfig(nil, removeAttrs, configValidator2) 86 c.Assert(err, gc.ErrorMatches, "cannot remove some-attr") 87 err = s.Model.UpdateModelConfig(updateAttrs, nil, configValidator3) 88 c.Assert(err, jc.ErrorIsNil) 89 // First error is returned. 90 err = s.Model.UpdateModelConfig(updateAttrs, nil, configValidator1, configValidator2) 91 c.Assert(err, gc.ErrorMatches, "cannot change logging-config") 92 } 93 94 func (s *ModelConfigSuite) TestModelConfig(c *gc.C) { 95 attrs := map[string]interface{}{ 96 "authorized-keys": "different-keys", 97 "arbitrary-key": "shazam!", 98 } 99 cfg, err := s.Model.ModelConfig() 100 c.Assert(err, jc.ErrorIsNil) 101 err = s.Model.UpdateModelConfig(attrs, nil) 102 c.Assert(err, jc.ErrorIsNil) 103 cfg, err = cfg.Apply(attrs) 104 c.Assert(err, jc.ErrorIsNil) 105 oldCfg, err := s.Model.ModelConfig() 106 c.Assert(err, jc.ErrorIsNil) 107 108 c.Assert(oldCfg, jc.DeepEquals, cfg) 109 } 110 111 func (s *ModelConfigSuite) TestAgentVersion(c *gc.C) { 112 attrs := map[string]interface{}{ 113 "agent-version": "2.2.3", 114 "arbitrary-key": "shazam!", 115 } 116 ver, err := s.Model.AgentVersion() 117 c.Assert(err, jc.ErrorIsNil) 118 c.Assert(ver, gc.DeepEquals, version.Number{Major: 2, Minor: 0, Patch: 0}) 119 120 err = s.Model.UpdateModelConfig(attrs, nil) 121 c.Assert(err, jc.ErrorIsNil) 122 123 ver, err = s.Model.AgentVersion() 124 c.Assert(err, jc.ErrorIsNil) 125 c.Assert(ver, gc.DeepEquals, version.Number{Major: 2, Minor: 2, Patch: 3}) 126 } 127 128 func (s *ModelConfigSuite) TestComposeNewModelConfig(c *gc.C) { 129 attrs := map[string]interface{}{ 130 "authorized-keys": "different-keys", 131 "arbitrary-key": "shazam!", 132 "uuid": testing.ModelTag.Id(), 133 "type": "dummy", 134 "name": "test", 135 "resource-tags": map[string]string{"a": "b", "c": "d"}, 136 } 137 138 cfgAttrs, err := s.State.ComposeNewModelConfig( 139 attrs, &environscloudspec.CloudRegionSpec{ 140 Cloud: "dummy", 141 Region: "dummy-region"}) 142 c.Assert(err, jc.ErrorIsNil) 143 expectedCfg, err := config.New(config.UseDefaults, attrs) 144 c.Assert(err, jc.ErrorIsNil) 145 expected := expectedCfg.AllAttrs() 146 expected["apt-mirror"] = "http://cloud-mirror" 147 expected["providerAttrdummy"] = "vulch" 148 expected["whimsy-key"] = "whimsy-value" 149 expected["image-stream"] = "dummy-image-stream" 150 expected["no-proxy"] = "dummy-proxy" 151 // config.New() adds logging-config so remove it. 152 expected["logging-config"] = "" 153 c.Assert(cfgAttrs, jc.DeepEquals, expected) 154 } 155 156 func (s *ModelConfigSuite) TestComposeNewModelConfigRegionMisses(c *gc.C) { 157 attrs := map[string]interface{}{ 158 "authorized-keys": "different-keys", 159 "arbitrary-key": "shazam!", 160 "uuid": testing.ModelTag.Id(), 161 "type": "dummy", 162 "name": "test", 163 "resource-tags": map[string]string{"a": "b", "c": "d"}, 164 } 165 rspec := &environscloudspec.CloudRegionSpec{Cloud: "dummy", Region: "dummy-region"} 166 cfgAttrs, err := s.State.ComposeNewModelConfig(attrs, rspec) 167 c.Assert(err, jc.ErrorIsNil) 168 expectedCfg, err := config.New(config.UseDefaults, attrs) 169 c.Assert(err, jc.ErrorIsNil) 170 expected := expectedCfg.AllAttrs() 171 expected["apt-mirror"] = "http://cloud-mirror" 172 expected["providerAttrdummy"] = "vulch" 173 expected["whimsy-key"] = "whimsy-value" 174 expected["no-proxy"] = "dummy-proxy" 175 expected["image-stream"] = "dummy-image-stream" 176 // config.New() adds logging-config so remove it. 177 expected["logging-config"] = "" 178 c.Assert(cfgAttrs, jc.DeepEquals, expected) 179 } 180 181 func (s *ModelConfigSuite) TestComposeNewModelConfigRegionInherits(c *gc.C) { 182 attrs := map[string]interface{}{ 183 "authorized-keys": "different-keys", 184 "arbitrary-key": "shazam!", 185 "uuid": testing.ModelTag.Id(), 186 "type": "dummy", 187 "name": "test", 188 "resource-tags": map[string]string{"a": "b", "c": "d"}, 189 } 190 rspec := &environscloudspec.CloudRegionSpec{Cloud: "dummy", Region: "nether-region"} 191 cfgAttrs, err := s.State.ComposeNewModelConfig(attrs, rspec) 192 c.Assert(err, jc.ErrorIsNil) 193 expectedCfg, err := config.New(config.UseDefaults, attrs) 194 c.Assert(err, jc.ErrorIsNil) 195 expected := expectedCfg.AllAttrs() 196 expected["no-proxy"] = "nether-proxy" 197 expected["apt-mirror"] = "http://nether-region-mirror" 198 expected["providerAttrdummy"] = "vulch" 199 // config.New() adds logging-config so remove it. 200 expected["logging-config"] = "" 201 c.Assert(cfgAttrs, jc.DeepEquals, expected) 202 } 203 204 func (s *ModelConfigSuite) TestUpdateModelConfigRejectsControllerConfig(c *gc.C) { 205 updateAttrs := map[string]interface{}{"api-port": 1234} 206 err := s.Model.UpdateModelConfig(updateAttrs, nil) 207 c.Assert(err, gc.ErrorMatches, `cannot set controller attribute "api-port" on a model`) 208 } 209 210 func (s *ModelConfigSuite) TestUpdateModelConfigRemoveInherited(c *gc.C) { 211 attrs := map[string]interface{}{ 212 "apt-mirror": "http://different-mirror", // controller 213 "arbitrary-key": "shazam!", 214 "providerAttrdummy": "beef", // provider 215 "whimsy-key": "eggs", // region 216 } 217 err := s.Model.UpdateModelConfig(attrs, nil) 218 c.Assert(err, jc.ErrorIsNil) 219 220 err = s.Model.UpdateModelConfig(nil, []string{"apt-mirror", "arbitrary-key", "providerAttrdummy", "whimsy-key"}) 221 c.Assert(err, jc.ErrorIsNil) 222 cfg, err := s.Model.ModelConfig() 223 c.Assert(err, jc.ErrorIsNil) 224 allAttrs := cfg.AllAttrs() 225 c.Assert(allAttrs["apt-mirror"], gc.Equals, "http://cloud-mirror") 226 c.Assert(allAttrs["providerAttrdummy"], gc.Equals, "vulch") 227 c.Assert(allAttrs["whimsy-key"], gc.Equals, "whimsy-value") 228 _, ok := allAttrs["arbitrary-key"] 229 c.Assert(ok, jc.IsFalse) 230 } 231 232 func (s *ModelConfigSuite) TestUpdateModelConfigCoerce(c *gc.C) { 233 attrs := map[string]interface{}{ 234 "resource-tags": map[string]string{"a": "b", "c": "d"}, 235 } 236 err := s.Model.UpdateModelConfig(attrs, nil) 237 c.Assert(err, jc.ErrorIsNil) 238 239 modelSettings, err := s.State.ReadSettings(state.SettingsC, state.ModelGlobalKey) 240 c.Assert(err, jc.ErrorIsNil) 241 expectedTags := map[string]string{"a": "b", "c": "d"} 242 tagsStr := config.CoerceForStorage(modelSettings.Map())["resource-tags"].(string) 243 tagItems := strings.Split(tagsStr, " ") 244 tagsMap := make(map[string]string) 245 for _, kv := range tagItems { 246 parts := strings.Split(kv, "=") 247 tagsMap[parts[0]] = parts[1] 248 } 249 c.Assert(tagsMap, gc.DeepEquals, expectedTags) 250 251 cfg, err := s.Model.ModelConfig() 252 c.Assert(err, jc.ErrorIsNil) 253 c.Assert(cfg.AllAttrs()["resource-tags"], gc.DeepEquals, expectedTags) 254 } 255 256 func (s *ModelConfigSuite) TestUpdateModelConfigPreferredOverRemove(c *gc.C) { 257 attrs := map[string]interface{}{ 258 "apt-mirror": "http://different-mirror", // controller 259 "arbitrary-key": "shazam!", 260 "providerAttrdummy": "beef", // provider 261 } 262 err := s.Model.UpdateModelConfig(attrs, nil) 263 c.Assert(err, jc.ErrorIsNil) 264 265 err = s.Model.UpdateModelConfig(map[string]interface{}{ 266 "apt-mirror": "http://another-mirror", 267 "providerAttrdummy": "pork", 268 }, []string{"apt-mirror", "arbitrary-key"}) 269 c.Assert(err, jc.ErrorIsNil) 270 cfg, err := s.Model.ModelConfig() 271 c.Assert(err, jc.ErrorIsNil) 272 allAttrs := cfg.AllAttrs() 273 c.Assert(allAttrs["apt-mirror"], gc.Equals, "http://another-mirror") 274 c.Assert(allAttrs["providerAttrdummy"], gc.Equals, "pork") 275 _, ok := allAttrs["arbitrary-key"] 276 c.Assert(ok, jc.IsFalse) 277 } 278 279 type ModelConfigSourceSuite struct { 280 ConnSuite 281 } 282 283 var _ = gc.Suite(&ModelConfigSourceSuite{}) 284 285 func (s *ModelConfigSourceSuite) SetUpTest(c *gc.C) { 286 s.ControllerInheritedConfig = map[string]interface{}{ 287 "apt-mirror": "http://cloud-mirror", 288 "http-proxy": "http://proxy", 289 } 290 s.RegionConfig = cloud.RegionConfig{ 291 "dummy-region": cloud.Attrs{ 292 "apt-mirror": "http://dummy-mirror", 293 "no-proxy": "dummy-proxy", 294 }, 295 } 296 s.ConnSuite.SetUpTest(c) 297 298 localControllerSettings, err := s.State.ReadSettings(state.GlobalSettingsC, state.CloudGlobalKey("dummy")) 299 c.Assert(err, jc.ErrorIsNil) 300 localControllerSettings.Set("apt-mirror", "http://mirror") 301 _, err = localControllerSettings.Write() 302 c.Assert(err, jc.ErrorIsNil) 303 } 304 305 func (s *ModelConfigSourceSuite) TestModelConfigWhenSetOverridesControllerValue(c *gc.C) { 306 attrs := map[string]interface{}{ 307 "authorized-keys": "different-keys", 308 "apt-mirror": "http://anothermirror", 309 } 310 err := s.Model.UpdateModelConfig(attrs, nil) 311 c.Assert(err, jc.ErrorIsNil) 312 313 cfg, err := s.Model.ModelConfig() 314 c.Assert(err, jc.ErrorIsNil) 315 c.Assert(cfg.AllAttrs()["apt-mirror"], gc.Equals, "http://anothermirror") 316 } 317 318 func (s *ModelConfigSourceSuite) TestControllerModelConfigForksControllerValue(c *gc.C) { 319 modelCfg, err := s.Model.ModelConfig() 320 c.Assert(err, jc.ErrorIsNil) 321 c.Assert(modelCfg.AllAttrs()["apt-mirror"], gc.Equals, "http://cloud-mirror") 322 323 // Change the local controller settings and ensure the model setting stays the same. 324 localControllerSettings, err := s.State.ReadSettings(state.GlobalSettingsC, state.CloudGlobalKey("dummy")) 325 c.Assert(err, jc.ErrorIsNil) 326 localControllerSettings.Set("apt-mirror", "http://anothermirror") 327 _, err = localControllerSettings.Write() 328 c.Assert(err, jc.ErrorIsNil) 329 330 modelCfg, err = s.Model.ModelConfig() 331 c.Assert(err, jc.ErrorIsNil) 332 c.Assert(modelCfg.AllAttrs()["apt-mirror"], gc.Equals, "http://cloud-mirror") 333 } 334 335 func (s *ModelConfigSourceSuite) TestNewModelConfigForksControllerValue(c *gc.C) { 336 uuid, err := utils.NewUUID() 337 c.Assert(err, jc.ErrorIsNil) 338 cfg := testing.CustomModelConfig(c, testing.Attrs{ 339 "name": "another", 340 "uuid": uuid.String(), 341 }) 342 owner := names.NewUserTag("test@remote") 343 _, st, err := s.Controller.NewModel(state.ModelArgs{ 344 Type: state.ModelTypeIAAS, 345 Config: cfg, 346 Owner: owner, 347 CloudName: "dummy", 348 CloudRegion: "nether-region", 349 StorageProviderRegistry: storage.StaticProviderRegistry{}, 350 }) 351 c.Assert(err, jc.ErrorIsNil) 352 defer st.Close() 353 354 m, err := st.Model() 355 c.Assert(err, jc.ErrorIsNil) 356 357 modelCfg, err := m.ModelConfig() 358 c.Assert(err, jc.ErrorIsNil) 359 c.Assert(modelCfg.AllAttrs()["apt-mirror"], gc.Equals, "http://mirror") 360 361 // Change the local controller settings and ensure the model setting stays the same. 362 localCloudSettings, err := s.State.ReadSettings(state.GlobalSettingsC, state.CloudGlobalKey("dummy")) 363 c.Assert(err, jc.ErrorIsNil) 364 localCloudSettings.Set("apt-mirror", "http://anothermirror") 365 _, err = localCloudSettings.Write() 366 c.Assert(err, jc.ErrorIsNil) 367 368 modelCfg, err = m.ModelConfig() 369 c.Assert(err, jc.ErrorIsNil) 370 c.Assert(modelCfg.AllAttrs()["apt-mirror"], gc.Equals, "http://mirror") 371 } 372 373 func (s *ModelConfigSourceSuite) assertModelConfigValues(c *gc.C, modelCfg *config.Config, modelAttributes, controllerAttributes set.Strings) { 374 expectedValues := make(config.ConfigValues) 375 defaultAttributes := set.NewStrings() 376 for defaultAttr := range config.ConfigDefaults() { 377 defaultAttributes.Add(defaultAttr) 378 } 379 for attr, val := range modelCfg.AllAttrs() { 380 source := "model" 381 if defaultAttributes.Contains(attr) { 382 source = "default" 383 } 384 if modelAttributes.Contains(attr) { 385 source = "model" 386 } 387 if controllerAttributes.Contains(attr) { 388 source = "controller" 389 } 390 expectedValues[attr] = config.ConfigValue{ 391 Value: val, 392 Source: source, 393 } 394 } 395 sources, err := s.Model.ModelConfigValues() 396 c.Assert(err, jc.ErrorIsNil) 397 c.Assert(sources, jc.DeepEquals, expectedValues) 398 } 399 400 func (s *ModelConfigSourceSuite) TestModelConfigValues(c *gc.C) { 401 modelCfg, err := s.Model.ModelConfig() 402 c.Assert(err, jc.ErrorIsNil) 403 modelAttributes := set.NewStrings("name", "apt-mirror", "logging-config", "authorized-keys", "resource-tags") 404 s.assertModelConfigValues(c, modelCfg, modelAttributes, set.NewStrings("http-proxy")) 405 } 406 407 func (s *ModelConfigSourceSuite) TestModelConfigUpdateSource(c *gc.C) { 408 attrs := map[string]interface{}{ 409 "http-proxy": "http://anotherproxy", 410 "apt-mirror": "http://mirror", 411 } 412 err := s.Model.UpdateModelConfig(attrs, nil) 413 c.Assert(err, jc.ErrorIsNil) 414 modelCfg, err := s.Model.ModelConfig() 415 c.Assert(err, jc.ErrorIsNil) 416 modelAttributes := set.NewStrings("name", "http-proxy", "logging-config", "authorized-keys", "resource-tags") 417 s.assertModelConfigValues(c, modelCfg, modelAttributes, set.NewStrings("apt-mirror")) 418 } 419 420 func (s *ModelConfigSourceSuite) TestModelConfigDefaults(c *gc.C) { 421 expectedValues := make(config.ModelDefaultAttributes) 422 for attr, val := range config.ConfigDefaults() { 423 expectedValues[attr] = config.AttributeDefaultValues{ 424 Default: val, 425 } 426 } 427 ds := expectedValues["http-proxy"] 428 ds.Controller = "http://proxy" 429 expectedValues["http-proxy"] = ds 430 431 ds = expectedValues["apt-mirror"] 432 ds.Controller = "http://mirror" 433 ds.Regions = []config.RegionDefaultValue{{ 434 Name: "dummy-region", 435 Value: "http://dummy-mirror", 436 }} 437 expectedValues["apt-mirror"] = ds 438 439 ds = expectedValues["no-proxy"] 440 ds.Regions = []config.RegionDefaultValue{{ 441 Name: "dummy-region", 442 Value: "dummy-proxy"}} 443 expectedValues["no-proxy"] = ds 444 445 sources, err := s.State.ModelConfigDefaultValues(s.Model.CloudName()) 446 c.Assert(err, jc.ErrorIsNil) 447 c.Assert(sources, jc.DeepEquals, expectedValues) 448 } 449 450 func (s *ModelConfigSourceSuite) TestUpdateModelConfigDefaults(c *gc.C) { 451 // Set up values that will be removed. 452 attrs := map[string]interface{}{ 453 "http-proxy": "http://http-proxy", 454 "https-proxy": "https://https-proxy", 455 } 456 err := s.State.UpdateModelConfigDefaultValues(attrs, nil, nil) 457 c.Assert(err, jc.ErrorIsNil) 458 459 attrs = map[string]interface{}{ 460 "apt-mirror": "http://different-mirror", 461 "num-provision-workers": 66, 462 } 463 err = s.State.UpdateModelConfigDefaultValues(attrs, []string{"http-proxy", "https-proxy"}, nil) 464 c.Assert(err, jc.ErrorIsNil) 465 466 cfg, err := s.State.ModelConfigDefaultValues(s.Model.CloudName()) 467 c.Assert(err, jc.ErrorIsNil) 468 expectedValues := make(config.ModelDefaultAttributes) 469 for attr, val := range config.ConfigDefaults() { 470 expectedValues[attr] = config.AttributeDefaultValues{ 471 Default: val, 472 } 473 } 474 delete(expectedValues, "http-mirror") 475 delete(expectedValues, "https-mirror") 476 expectedValues["apt-mirror"] = config.AttributeDefaultValues{ 477 Controller: "http://different-mirror", 478 Default: "", 479 Regions: []config.RegionDefaultValue{{ 480 Name: "dummy-region", 481 Value: "http://dummy-mirror", 482 }}} 483 expectedValues["no-proxy"] = config.AttributeDefaultValues{ 484 Default: "127.0.0.1,localhost,::1", 485 Regions: []config.RegionDefaultValue{{ 486 Name: "dummy-region", 487 Value: "dummy-proxy", 488 }}} 489 expectedValues["num-provision-workers"] = config.AttributeDefaultValues{ 490 Controller: 66, 491 Default: 16, 492 } 493 c.Assert(cfg, jc.DeepEquals, expectedValues) 494 } 495 496 func (s *ModelConfigSourceSuite) TestUpdateModelConfigDefaultsArbitraryConfig(c *gc.C) { 497 attrs := map[string]interface{}{ 498 "hello": "world", 499 } 500 err := s.State.UpdateModelConfigDefaultValues(attrs, nil, nil) 501 c.Assert(err, jc.ErrorIsNil) 502 503 cfg, err := s.State.ModelConfigDefaultValues(s.Model.CloudName()) 504 c.Assert(err, jc.ErrorIsNil) 505 expectedValues := make(config.ModelDefaultAttributes) 506 for attr, val := range config.ConfigDefaults() { 507 expectedValues[attr] = config.AttributeDefaultValues{ 508 Default: val, 509 } 510 } 511 512 expectedValues["hello"] = config.AttributeDefaultValues{ 513 Controller: "world", 514 Default: nil, 515 } 516 expectedValues["http-proxy"] = config.AttributeDefaultValues{ 517 Controller: "http://proxy", 518 Default: "", 519 } 520 expectedValues["apt-mirror"] = config.AttributeDefaultValues{ 521 Controller: "http://mirror", 522 Default: "", 523 Regions: []config.RegionDefaultValue{{ 524 Name: "dummy-region", 525 Value: "http://dummy-mirror", 526 }}} 527 expectedValues["no-proxy"] = config.AttributeDefaultValues{ 528 Default: "127.0.0.1,localhost,::1", 529 Regions: []config.RegionDefaultValue{{ 530 Name: "dummy-region", 531 Value: "dummy-proxy", 532 }}} 533 c.Assert(cfg, jc.DeepEquals, expectedValues) 534 } 535 536 func (s *ModelConfigSourceSuite) TestUpdateModelConfigDefaultsWithValidationError(c *gc.C) { 537 // Set up values that will be removed. 538 attrs := map[string]interface{}{ 539 "http-proxy": "http://http-proxy", 540 "https-proxy": "https://https-proxy", 541 } 542 err := s.State.UpdateModelConfigDefaultValues(attrs, nil, nil) 543 c.Assert(err, jc.ErrorIsNil) 544 545 attrs = map[string]interface{}{ 546 "test-mode": "baz", 547 } 548 err = s.State.UpdateModelConfigDefaultValues(attrs, []string{"http-proxy", "https-proxy"}, nil) 549 c.Assert(err, gc.ErrorMatches, `test-mode: expected bool, got string\("baz"\)`) 550 } 551 552 func (s *ModelConfigSourceSuite) TestUpdateModelConfigRegionDefaults(c *gc.C) { 553 // The test env is setup with dummy/dummy-region having a no-proxy 554 // dummy-proxy value and nether-region with a nether-proxy value. 555 // 556 // First we change the no-proxy setting in dummy-region 557 attrs := map[string]interface{}{ 558 "no-proxy": "changed-proxy", 559 } 560 561 rspec, err := environscloudspec.NewCloudRegionSpec("dummy", "dummy-region") 562 c.Assert(err, jc.ErrorIsNil) 563 564 err = s.State.UpdateModelConfigDefaultValues(attrs, nil, rspec) 565 c.Assert(err, jc.ErrorIsNil) 566 567 cfg, err := s.State.ModelConfigDefaultValues(s.Model.CloudName()) 568 c.Assert(err, jc.ErrorIsNil) 569 expectedValues := make(config.ModelDefaultAttributes) 570 for attr, val := range config.ConfigDefaults() { 571 expectedValues[attr] = config.AttributeDefaultValues{ 572 Default: val, 573 } 574 } 575 expectedValues["http-proxy"] = config.AttributeDefaultValues{ 576 Controller: "http://proxy", 577 Default: "", 578 } 579 expectedValues["apt-mirror"] = config.AttributeDefaultValues{ 580 Controller: "http://mirror", 581 Default: "", 582 Regions: []config.RegionDefaultValue{{ 583 Name: "dummy-region", 584 Value: "http://dummy-mirror", 585 }}} 586 expectedValues["no-proxy"] = config.AttributeDefaultValues{ 587 Default: "127.0.0.1,localhost,::1", 588 Regions: []config.RegionDefaultValue{{ 589 Name: "dummy-region", 590 Value: "changed-proxy", 591 }}} 592 c.Assert(cfg, jc.DeepEquals, expectedValues) 593 594 // remove the dummy-region setting 595 err = s.State.UpdateModelConfigDefaultValues(nil, []string{"no-proxy"}, rspec) 596 c.Assert(err, jc.ErrorIsNil) 597 598 // and check again 599 cfg, err = s.State.ModelConfigDefaultValues(s.Model.CloudName()) 600 c.Assert(err, jc.ErrorIsNil) 601 expectedValues = make(config.ModelDefaultAttributes) 602 for attr, val := range config.ConfigDefaults() { 603 expectedValues[attr] = config.AttributeDefaultValues{ 604 Default: val, 605 } 606 } 607 expectedValues["http-proxy"] = config.AttributeDefaultValues{ 608 Controller: "http://proxy", 609 Default: "", 610 } 611 expectedValues["apt-mirror"] = config.AttributeDefaultValues{ 612 Controller: "http://mirror", 613 Default: "", 614 Regions: []config.RegionDefaultValue{{ 615 Name: "dummy-region", 616 Value: "http://dummy-mirror", 617 }}} 618 c.Assert(cfg, jc.DeepEquals, expectedValues) 619 } 620 621 func (s *ModelConfigSourceSuite) TestUpdateModelConfigDefaultValuesUnknownRegion(c *gc.C) { 622 // Set up settings to create 623 attrs := map[string]interface{}{ 624 "no-proxy": "changed-proxy", 625 } 626 627 rspec, err := environscloudspec.NewCloudRegionSpec("dummy", "unused-region") 628 c.Assert(err, jc.ErrorIsNil) 629 630 // We add this to the unused-region which has not been created in mongo 631 // yet. 632 err = s.State.UpdateModelConfigDefaultValues(attrs, nil, rspec) 633 c.Assert(err, jc.ErrorIsNil) 634 635 // Then check config. 636 cfg, err := s.State.ModelConfigDefaultValues(s.Model.CloudName()) 637 c.Assert(err, jc.ErrorIsNil) 638 c.Assert(cfg["no-proxy"], jc.DeepEquals, config.AttributeDefaultValues{ 639 Default: "127.0.0.1,localhost,::1", 640 Controller: nil, 641 Regions: []config.RegionDefaultValue{ 642 { 643 Name: "dummy-region", 644 Value: "dummy-proxy", 645 }, { 646 Name: "unused-region", 647 Value: "changed-proxy", 648 }}}) 649 }