github.com/axw/juju@v0.0.0-20161005053422-4bd6544d08d4/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/errors" 10 jc "github.com/juju/testing/checkers" 11 "github.com/juju/utils" 12 "github.com/juju/utils/set" 13 gc "gopkg.in/check.v1" 14 "gopkg.in/juju/names.v2" 15 16 "github.com/juju/juju/cloud" 17 "github.com/juju/juju/constraints" 18 "github.com/juju/juju/environs" 19 "github.com/juju/juju/environs/config" 20 "github.com/juju/juju/mongo/mongotest" 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() (config.ConfigSchemaSource, error) { 56 return &statetesting.MockConfigSchemaSource{}, 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.State.UpdateModelConfig(updateAttrs, nil, configValidator1) 84 c.Assert(err, gc.ErrorMatches, "cannot change logging-config") 85 err = s.State.UpdateModelConfig(nil, removeAttrs, configValidator2) 86 c.Assert(err, gc.ErrorMatches, "cannot remove some-attr") 87 err = s.State.UpdateModelConfig(updateAttrs, nil, configValidator3) 88 c.Assert(err, jc.ErrorIsNil) 89 } 90 91 func (s *ModelConfigSuite) TestModelConfig(c *gc.C) { 92 attrs := map[string]interface{}{ 93 "authorized-keys": "different-keys", 94 "arbitrary-key": "shazam!", 95 } 96 cfg, err := s.State.ModelConfig() 97 c.Assert(err, jc.ErrorIsNil) 98 err = s.State.UpdateModelConfig(attrs, nil, nil) 99 c.Assert(err, jc.ErrorIsNil) 100 cfg, err = cfg.Apply(attrs) 101 c.Assert(err, jc.ErrorIsNil) 102 oldCfg, err := s.State.ModelConfig() 103 c.Assert(err, jc.ErrorIsNil) 104 105 c.Assert(oldCfg, jc.DeepEquals, cfg) 106 } 107 108 func (s *ModelConfigSuite) TestComposeNewModelConfig(c *gc.C) { 109 attrs := map[string]interface{}{ 110 "authorized-keys": "different-keys", 111 "arbitrary-key": "shazam!", 112 "uuid": testing.ModelTag.Id(), 113 "type": "dummy", 114 "name": "test", 115 "resource-tags": map[string]string{"a": "b", "c": "d"}, 116 } 117 118 cfgAttrs, err := s.State.ComposeNewModelConfig( 119 attrs, &environs.RegionSpec{ 120 Cloud: "dummy", 121 Region: "dummy-region"}) 122 c.Assert(err, jc.ErrorIsNil) 123 expectedCfg, err := config.New(config.UseDefaults, attrs) 124 c.Assert(err, jc.ErrorIsNil) 125 expected := expectedCfg.AllAttrs() 126 expected["apt-mirror"] = "http://cloud-mirror" 127 expected["providerAttr"] = "vulch" 128 expected["whimsy-key"] = "whimsy-value" 129 expected["image-stream"] = "dummy-image-stream" 130 expected["no-proxy"] = "dummy-proxy" 131 // config.New() adds logging-config so remove it. 132 expected["logging-config"] = "" 133 c.Assert(cfgAttrs, jc.DeepEquals, expected) 134 } 135 136 func (s *ModelConfigSuite) TestComposeNewModelConfigRegionMisses(c *gc.C) { 137 attrs := map[string]interface{}{ 138 "authorized-keys": "different-keys", 139 "arbitrary-key": "shazam!", 140 "uuid": testing.ModelTag.Id(), 141 "type": "dummy", 142 "name": "test", 143 "resource-tags": map[string]string{"a": "b", "c": "d"}, 144 } 145 rspec := &environs.RegionSpec{Cloud: "dummy", Region: "dummy-region"} 146 cfgAttrs, err := s.State.ComposeNewModelConfig(attrs, rspec) 147 c.Assert(err, jc.ErrorIsNil) 148 expectedCfg, err := config.New(config.UseDefaults, attrs) 149 c.Assert(err, jc.ErrorIsNil) 150 expected := expectedCfg.AllAttrs() 151 expected["apt-mirror"] = "http://cloud-mirror" 152 expected["providerAttr"] = "vulch" 153 expected["whimsy-key"] = "whimsy-value" 154 expected["no-proxy"] = "dummy-proxy" 155 expected["image-stream"] = "dummy-image-stream" 156 // config.New() adds logging-config so remove it. 157 expected["logging-config"] = "" 158 c.Assert(cfgAttrs, jc.DeepEquals, expected) 159 } 160 161 func (s *ModelConfigSuite) TestComposeNewModelConfigRegionInherits(c *gc.C) { 162 attrs := map[string]interface{}{ 163 "authorized-keys": "different-keys", 164 "arbitrary-key": "shazam!", 165 "uuid": testing.ModelTag.Id(), 166 "type": "dummy", 167 "name": "test", 168 "resource-tags": map[string]string{"a": "b", "c": "d"}, 169 } 170 rspec := &environs.RegionSpec{Cloud: "dummy", Region: "nether-region"} 171 cfgAttrs, err := s.State.ComposeNewModelConfig(attrs, rspec) 172 c.Assert(err, jc.ErrorIsNil) 173 expectedCfg, err := config.New(config.UseDefaults, attrs) 174 c.Assert(err, jc.ErrorIsNil) 175 expected := expectedCfg.AllAttrs() 176 expected["no-proxy"] = "nether-proxy" 177 expected["apt-mirror"] = "http://nether-region-mirror" 178 expected["providerAttr"] = "vulch" 179 // config.New() adds logging-config so remove it. 180 expected["logging-config"] = "" 181 c.Assert(cfgAttrs, jc.DeepEquals, expected) 182 } 183 184 func (s *ModelConfigSuite) TestUpdateModelConfigRejectsControllerConfig(c *gc.C) { 185 updateAttrs := map[string]interface{}{"api-port": 1234} 186 err := s.State.UpdateModelConfig(updateAttrs, nil, nil) 187 c.Assert(err, gc.ErrorMatches, `cannot set controller attribute "api-port" on a model`) 188 } 189 190 func (s *ModelConfigSuite) TestUpdateModelConfigRemoveInherited(c *gc.C) { 191 attrs := map[string]interface{}{ 192 "apt-mirror": "http://different-mirror", // controller 193 "arbitrary-key": "shazam!", 194 "providerAttr": "beef", // provider 195 "whimsy-key": "eggs", // region 196 } 197 err := s.State.UpdateModelConfig(attrs, nil, nil) 198 c.Assert(err, jc.ErrorIsNil) 199 200 err = s.State.UpdateModelConfig(nil, []string{"apt-mirror", "arbitrary-key", "providerAttr", "whimsy-key"}, nil) 201 c.Assert(err, jc.ErrorIsNil) 202 cfg, err := s.State.ModelConfig() 203 c.Assert(err, jc.ErrorIsNil) 204 allAttrs := cfg.AllAttrs() 205 c.Assert(allAttrs["apt-mirror"], gc.Equals, "http://cloud-mirror") 206 c.Assert(allAttrs["providerAttr"], gc.Equals, "vulch") 207 c.Assert(allAttrs["whimsy-key"], gc.Equals, "whimsy-value") 208 _, ok := allAttrs["arbitrary-key"] 209 c.Assert(ok, jc.IsFalse) 210 } 211 212 func (s *ModelConfigSuite) TestUpdateModelConfigCoerce(c *gc.C) { 213 attrs := map[string]interface{}{ 214 "resource-tags": map[string]string{"a": "b", "c": "d"}, 215 } 216 err := s.State.UpdateModelConfig(attrs, nil, nil) 217 c.Assert(err, jc.ErrorIsNil) 218 219 modelSettings, err := s.State.ReadSettings(state.SettingsC, state.ModelGlobalKey) 220 c.Assert(err, jc.ErrorIsNil) 221 expectedTags := map[string]string{"a": "b", "c": "d"} 222 tagsStr := config.CoerceForStorage(modelSettings.Map())["resource-tags"].(string) 223 tagItems := strings.Split(tagsStr, " ") 224 tagsMap := make(map[string]string) 225 for _, kv := range tagItems { 226 parts := strings.Split(kv, "=") 227 tagsMap[parts[0]] = parts[1] 228 } 229 c.Assert(tagsMap, gc.DeepEquals, expectedTags) 230 231 cfg, err := s.State.ModelConfig() 232 c.Assert(err, jc.ErrorIsNil) 233 c.Assert(cfg.AllAttrs()["resource-tags"], gc.DeepEquals, expectedTags) 234 } 235 236 func (s *ModelConfigSuite) TestUpdateModelConfigPreferredOverRemove(c *gc.C) { 237 attrs := map[string]interface{}{ 238 "apt-mirror": "http://different-mirror", // controller 239 "arbitrary-key": "shazam!", 240 "providerAttr": "beef", // provider 241 } 242 err := s.State.UpdateModelConfig(attrs, nil, nil) 243 c.Assert(err, jc.ErrorIsNil) 244 245 err = s.State.UpdateModelConfig(map[string]interface{}{ 246 "apt-mirror": "http://another-mirror", 247 "providerAttr": "pork", 248 }, []string{"apt-mirror", "arbitrary-key"}, nil) 249 c.Assert(err, jc.ErrorIsNil) 250 cfg, err := s.State.ModelConfig() 251 c.Assert(err, jc.ErrorIsNil) 252 allAttrs := cfg.AllAttrs() 253 c.Assert(allAttrs["apt-mirror"], gc.Equals, "http://another-mirror") 254 c.Assert(allAttrs["providerAttr"], gc.Equals, "pork") 255 _, ok := allAttrs["arbitrary-key"] 256 c.Assert(ok, jc.IsFalse) 257 } 258 259 type ModelConfigSourceSuite struct { 260 ConnSuite 261 } 262 263 var _ = gc.Suite(&ModelConfigSourceSuite{}) 264 265 func (s *ModelConfigSourceSuite) SetUpTest(c *gc.C) { 266 s.ControllerInheritedConfig = map[string]interface{}{ 267 "apt-mirror": "http://cloud-mirror", 268 "http-proxy": "http://proxy", 269 } 270 s.RegionConfig = cloud.RegionConfig{ 271 "dummy-region": cloud.Attrs{ 272 "apt-mirror": "http://dummy-mirror", 273 "no-proxy": "dummy-proxy", 274 }, 275 } 276 s.ConnSuite.SetUpTest(c) 277 278 localControllerSettings, err := s.State.ReadSettings(state.GlobalSettingsC, state.ControllerInheritedSettingsGlobalKey) 279 c.Assert(err, jc.ErrorIsNil) 280 localControllerSettings.Set("apt-mirror", "http://mirror") 281 _, err = localControllerSettings.Write() 282 c.Assert(err, jc.ErrorIsNil) 283 } 284 285 func (s *ModelConfigSourceSuite) TestModelConfigWhenSetOverridesControllerValue(c *gc.C) { 286 attrs := map[string]interface{}{ 287 "authorized-keys": "different-keys", 288 "apt-mirror": "http://anothermirror", 289 } 290 err := s.State.UpdateModelConfig(attrs, nil, nil) 291 c.Assert(err, jc.ErrorIsNil) 292 293 cfg, err := s.State.ModelConfig() 294 c.Assert(err, jc.ErrorIsNil) 295 c.Assert(cfg.AllAttrs()["apt-mirror"], gc.Equals, "http://anothermirror") 296 } 297 298 func (s *ModelConfigSourceSuite) TestControllerModelConfigForksControllerValue(c *gc.C) { 299 modelCfg, err := s.State.ModelConfig() 300 c.Assert(err, jc.ErrorIsNil) 301 c.Assert(modelCfg.AllAttrs()["apt-mirror"], gc.Equals, "http://cloud-mirror") 302 303 // Change the local controller settings and ensure the model setting stays the same. 304 localControllerSettings, err := s.State.ReadSettings(state.GlobalSettingsC, state.ControllerInheritedSettingsGlobalKey) 305 c.Assert(err, jc.ErrorIsNil) 306 localControllerSettings.Set("apt-mirror", "http://anothermirror") 307 _, err = localControllerSettings.Write() 308 c.Assert(err, jc.ErrorIsNil) 309 310 modelCfg, err = s.State.ModelConfig() 311 c.Assert(err, jc.ErrorIsNil) 312 c.Assert(modelCfg.AllAttrs()["apt-mirror"], gc.Equals, "http://cloud-mirror") 313 } 314 315 func (s *ModelConfigSourceSuite) TestNewModelConfigForksControllerValue(c *gc.C) { 316 uuid, err := utils.NewUUID() 317 c.Assert(err, jc.ErrorIsNil) 318 cfg := testing.CustomModelConfig(c, testing.Attrs{ 319 "name": "another", 320 "uuid": uuid.String(), 321 }) 322 owner := names.NewUserTag("test@remote") 323 _, st, err := s.State.NewModel(state.ModelArgs{ 324 Config: cfg, Owner: owner, CloudName: "dummy", CloudRegion: "nether-region", 325 StorageProviderRegistry: storage.StaticProviderRegistry{}, 326 }) 327 c.Assert(err, jc.ErrorIsNil) 328 defer st.Close() 329 330 modelCfg, err := st.ModelConfig() 331 c.Assert(err, jc.ErrorIsNil) 332 c.Assert(modelCfg.AllAttrs()["apt-mirror"], gc.Equals, "http://mirror") 333 334 // Change the local controller settings and ensure the model setting stays the same. 335 localCloudSettings, err := s.State.ReadSettings(state.GlobalSettingsC, state.ControllerInheritedSettingsGlobalKey) 336 c.Assert(err, jc.ErrorIsNil) 337 localCloudSettings.Set("apt-mirror", "http://anothermirror") 338 _, err = localCloudSettings.Write() 339 c.Assert(err, jc.ErrorIsNil) 340 341 modelCfg, err = st.ModelConfig() 342 c.Assert(err, jc.ErrorIsNil) 343 c.Assert(modelCfg.AllAttrs()["apt-mirror"], gc.Equals, "http://mirror") 344 } 345 346 func (s *ModelConfigSourceSuite) assertModelConfigValues(c *gc.C, modelCfg *config.Config, modelAttributes, controllerAttributes set.Strings) { 347 expectedValues := make(config.ConfigValues) 348 defaultAttributes := set.NewStrings() 349 for defaultAttr := range config.ConfigDefaults() { 350 defaultAttributes.Add(defaultAttr) 351 } 352 for attr, val := range modelCfg.AllAttrs() { 353 source := "model" 354 if defaultAttributes.Contains(attr) { 355 source = "default" 356 } 357 if modelAttributes.Contains(attr) { 358 source = "model" 359 } 360 if controllerAttributes.Contains(attr) { 361 source = "controller" 362 } 363 expectedValues[attr] = config.ConfigValue{ 364 Value: val, 365 Source: source, 366 } 367 } 368 sources, err := s.State.ModelConfigValues() 369 c.Assert(err, jc.ErrorIsNil) 370 c.Assert(sources, jc.DeepEquals, expectedValues) 371 } 372 373 func (s *ModelConfigSourceSuite) TestModelConfigValues(c *gc.C) { 374 modelCfg, err := s.State.ModelConfig() 375 c.Assert(err, jc.ErrorIsNil) 376 modelAttributes := set.NewStrings("name", "apt-mirror", "logging-config", "authorized-keys", "resource-tags") 377 s.assertModelConfigValues(c, modelCfg, modelAttributes, set.NewStrings("http-proxy")) 378 } 379 380 func (s *ModelConfigSourceSuite) TestModelConfigUpdateSource(c *gc.C) { 381 attrs := map[string]interface{}{ 382 "http-proxy": "http://anotherproxy", 383 "apt-mirror": "http://mirror", 384 } 385 err := s.State.UpdateModelConfig(attrs, nil, nil) 386 c.Assert(err, jc.ErrorIsNil) 387 modelCfg, err := s.State.ModelConfig() 388 c.Assert(err, jc.ErrorIsNil) 389 modelAttributes := set.NewStrings("name", "http-proxy", "logging-config", "authorized-keys", "resource-tags") 390 s.assertModelConfigValues(c, modelCfg, modelAttributes, set.NewStrings("apt-mirror")) 391 } 392 393 func (s *ModelConfigSourceSuite) TestModelConfigDefaults(c *gc.C) { 394 expectedValues := make(config.ModelDefaultAttributes) 395 for attr, val := range config.ConfigDefaults() { 396 expectedValues[attr] = config.AttributeDefaultValues{ 397 Default: val, 398 } 399 } 400 ds := expectedValues["http-proxy"] 401 ds.Controller = "http://proxy" 402 expectedValues["http-proxy"] = ds 403 404 ds = expectedValues["apt-mirror"] 405 ds.Controller = "http://mirror" 406 ds.Regions = []config.RegionDefaultValue{{ 407 Name: "dummy-region", 408 Value: "http://dummy-mirror", 409 }} 410 expectedValues["apt-mirror"] = ds 411 412 ds = expectedValues["no-proxy"] 413 ds.Regions = []config.RegionDefaultValue{{ 414 Name: "dummy-region", 415 Value: "dummy-proxy"}} 416 expectedValues["no-proxy"] = ds 417 418 sources, err := s.State.ModelConfigDefaultValues() 419 c.Assert(err, jc.ErrorIsNil) 420 c.Assert(sources, jc.DeepEquals, expectedValues) 421 } 422 423 func (s *ModelConfigSourceSuite) TestUpdateModelConfigDefaults(c *gc.C) { 424 // Set up values that will be removed. 425 attrs := map[string]interface{}{ 426 "http-proxy": "http://http-proxy", 427 "https-proxy": "https://https-proxy", 428 } 429 err := s.State.UpdateModelConfigDefaultValues(attrs, nil, nil) 430 c.Assert(err, jc.ErrorIsNil) 431 432 attrs = map[string]interface{}{ 433 "apt-mirror": "http://different-mirror", 434 } 435 err = s.State.UpdateModelConfigDefaultValues(attrs, []string{"http-proxy", "https-proxy"}, nil) 436 c.Assert(err, jc.ErrorIsNil) 437 438 info := statetesting.NewMongoInfo() 439 anotherState, err := state.Open(s.modelTag, s.State.ControllerTag(), info, mongotest.DialOpts(), state.NewPolicyFunc(nil)) 440 c.Assert(err, jc.ErrorIsNil) 441 defer anotherState.Close() 442 443 cfg, err := anotherState.ModelConfigDefaultValues() 444 c.Assert(err, jc.ErrorIsNil) 445 expectedValues := make(config.ModelDefaultAttributes) 446 for attr, val := range config.ConfigDefaults() { 447 expectedValues[attr] = config.AttributeDefaultValues{ 448 Default: val, 449 } 450 } 451 delete(expectedValues, "http-mirror") 452 delete(expectedValues, "https-mirror") 453 expectedValues["apt-mirror"] = config.AttributeDefaultValues{ 454 Controller: "http://different-mirror", 455 Default: "", 456 Regions: []config.RegionDefaultValue{{ 457 Name: "dummy-region", 458 Value: "http://dummy-mirror", 459 }}} 460 expectedValues["no-proxy"] = config.AttributeDefaultValues{ 461 Default: "", 462 Regions: []config.RegionDefaultValue{{ 463 Name: "dummy-region", 464 Value: "dummy-proxy", 465 }}} 466 c.Assert(cfg, jc.DeepEquals, expectedValues) 467 } 468 469 func (s *ModelConfigSourceSuite) TestUpdateModelConfigRegionDefaults(c *gc.C) { 470 // The test env is setup with dummy/dummy-region having a no-proxy 471 // dummy-proxy value and nether-region with a nether-proxy value. 472 // 473 // First we change the no-proxy setting in dummy-region 474 attrs := map[string]interface{}{ 475 "no-proxy": "changed-proxy", 476 } 477 478 rspec, err := environs.NewRegionSpec("dummy", "dummy-region") 479 c.Assert(err, jc.ErrorIsNil) 480 481 err = s.State.UpdateModelConfigDefaultValues(attrs, nil, rspec) 482 c.Assert(err, jc.ErrorIsNil) 483 484 // Then check in another state. 485 info := statetesting.NewMongoInfo() 486 anotherState, err := state.Open(s.modelTag, s.State.ControllerTag(), info, mongotest.DialOpts(), state.NewPolicyFunc(nil)) 487 c.Assert(err, jc.ErrorIsNil) 488 defer anotherState.Close() 489 490 cfg, err := anotherState.ModelConfigDefaultValues() 491 c.Assert(err, jc.ErrorIsNil) 492 expectedValues := make(config.ModelDefaultAttributes) 493 for attr, val := range config.ConfigDefaults() { 494 expectedValues[attr] = config.AttributeDefaultValues{ 495 Default: val, 496 } 497 } 498 expectedValues["http-proxy"] = config.AttributeDefaultValues{ 499 Controller: "http://proxy", 500 Default: "", 501 } 502 expectedValues["apt-mirror"] = config.AttributeDefaultValues{ 503 Controller: "http://mirror", 504 Default: "", 505 Regions: []config.RegionDefaultValue{{ 506 Name: "dummy-region", 507 Value: "http://dummy-mirror", 508 }}} 509 expectedValues["no-proxy"] = config.AttributeDefaultValues{ 510 Default: "", 511 Regions: []config.RegionDefaultValue{{ 512 Name: "dummy-region", 513 Value: "changed-proxy", 514 }}} 515 c.Assert(cfg, jc.DeepEquals, expectedValues) 516 517 // remove the dummy-region setting 518 err = s.State.UpdateModelConfigDefaultValues(nil, []string{"no-proxy"}, rspec) 519 520 // and check again 521 cfg, err = anotherState.ModelConfigDefaultValues() 522 c.Assert(err, jc.ErrorIsNil) 523 cfg, err = anotherState.ModelConfigDefaultValues() 524 c.Assert(err, jc.ErrorIsNil) 525 expectedValues = make(config.ModelDefaultAttributes) 526 for attr, val := range config.ConfigDefaults() { 527 expectedValues[attr] = config.AttributeDefaultValues{ 528 Default: val, 529 } 530 } 531 expectedValues["http-proxy"] = config.AttributeDefaultValues{ 532 Controller: "http://proxy", 533 Default: "", 534 } 535 expectedValues["apt-mirror"] = config.AttributeDefaultValues{ 536 Controller: "http://mirror", 537 Default: "", 538 Regions: []config.RegionDefaultValue{{ 539 Name: "dummy-region", 540 Value: "http://dummy-mirror", 541 }}} 542 c.Assert(cfg, jc.DeepEquals, expectedValues) 543 }