github.com/juju/juju@v0.0.0-20240430160146-1752b71fcf00/controller/modelmanager/createmodel_test.go (about) 1 // Copyright 2016 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package modelmanager_test 5 6 import ( 7 "github.com/juju/errors" 8 "github.com/juju/names/v5" 9 "github.com/juju/testing" 10 jc "github.com/juju/testing/checkers" 11 "github.com/juju/utils/v3" 12 "github.com/juju/version/v2" 13 gc "gopkg.in/check.v1" 14 15 "github.com/juju/juju/cloud" 16 "github.com/juju/juju/controller/modelmanager" 17 "github.com/juju/juju/environs" 18 environscloudspec "github.com/juju/juju/environs/cloudspec" 19 "github.com/juju/juju/environs/config" 20 _ "github.com/juju/juju/provider/azure" 21 _ "github.com/juju/juju/provider/dummy" 22 _ "github.com/juju/juju/provider/ec2" 23 _ "github.com/juju/juju/provider/maas" 24 _ "github.com/juju/juju/provider/openstack" 25 coretesting "github.com/juju/juju/testing" 26 "github.com/juju/juju/tools" 27 ) 28 29 type ModelConfigCreatorSuite struct { 30 coretesting.BaseSuite 31 fake fakeProvider 32 creator modelmanager.ModelConfigCreator 33 baseConfig *config.Config 34 } 35 36 var _ = gc.Suite(&ModelConfigCreatorSuite{}) 37 38 func (s *ModelConfigCreatorSuite) SetUpTest(c *gc.C) { 39 s.BaseSuite.SetUpTest(c) 40 s.fake = fakeProvider{ 41 restrictedConfigAttributes: []string{"restricted"}, 42 } 43 s.creator = modelmanager.ModelConfigCreator{ 44 Provider: func(provider string) (environs.EnvironProvider, error) { 45 if provider != "fake" { 46 return nil, errors.Errorf("expected fake, got %s", provider) 47 } 48 return &s.fake, nil 49 }, 50 } 51 baseConfig, err := config.New( 52 config.UseDefaults, 53 coretesting.FakeConfig().Merge(coretesting.Attrs{ 54 "type": "fake", 55 "restricted": "area51", 56 "agent-version": "2.0.0", 57 }), 58 ) 59 c.Assert(err, jc.ErrorIsNil) 60 s.baseConfig = baseConfig 61 } 62 63 func (s *ModelConfigCreatorSuite) newModelConfig(attrs map[string]interface{}) (*config.Config, error) { 64 cloudSpec := environscloudspec.CloudSpec{Type: "fake"} 65 return s.creator.NewModelConfig(cloudSpec, s.baseConfig, attrs) 66 } 67 68 func (s *ModelConfigCreatorSuite) TestCreateModelValidatesConfig(c *gc.C) { 69 newModelUUID := utils.MustNewUUID().String() 70 cfg, err := s.newModelConfig(coretesting.Attrs( 71 s.baseConfig.AllAttrs(), 72 ).Merge(coretesting.Attrs{ 73 "name": "new-model", 74 "additional": "value", 75 "uuid": newModelUUID, 76 })) 77 c.Assert(err, jc.ErrorIsNil) 78 expected := s.baseConfig.AllAttrs() 79 expected["name"] = "new-model" 80 expected["type"] = "fake" 81 expected["additional"] = "value" 82 expected["uuid"] = newModelUUID 83 c.Assert(cfg.AllAttrs(), jc.DeepEquals, expected) 84 85 s.fake.Stub.CheckCallNames(c, 86 "PrepareConfig", 87 "Validate", 88 ) 89 validateCall := s.fake.Stub.Calls()[1] 90 c.Assert(validateCall.Args, gc.HasLen, 2) 91 c.Assert(validateCall.Args[0], gc.Equals, cfg) 92 c.Assert(validateCall.Args[1], gc.IsNil) 93 } 94 95 func (s *ModelConfigCreatorSuite) TestCreateModelCheckAuthorizedKeys(c *gc.C) { 96 authorizedKeys := ` 97 ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDLNN6YxkRJ8liYGh9qymZi23lDRlFrD3ujGfcgkjqa7vOqBHJaWklaIW4vFX0XkYuhgnDlXREi7RRK+4I0XBD051LxADobguLXyeGoOhSRlLLThYMF7Ui8nNylLxY0MYpKUIE6ejve2DHtrwGXBJBUXGJr8z5gKuIZD9J39B3ld1e7v2fpK3SqQ84H8mSZxPBbZqA0NIoq9wl+ke780fYsDxBpsAJhaZW2SjCqcrmNc3m9HgYwzeHhsXDZN2xonoyK2UVMGCsqR0vTHZNpnhME4FdGsmK6WIRMq+z5Mxrw3rSYIgbWi1uACfSsPeBMXmkWORujZrf1w1OKoy1dKeWp juju-client-key 98 ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQCwvae4M/oc+p5d3vj5TBS/4Mx+us5nVuMBgpYCQYq1Bk+QyfyefVfhQwuILAhmzehKnxUse1kGERQ0wNCtn7wU/HhvAuzQBWkxMvShyO9x7GS+4cDEGhkhMGGCu5NvBBCvp24+WdNeqsvoMDRHtBO1kFVc3FQZ01IjR+FTAICW5hE8e7ssCFK+pIDa8TI44rz41grytVJ1iACvaXc7nTyFZg95EXxSurPv0EnO82Gxfdt4bkiSXPXQqNcTLNiJ2oKRyDVYAjZNIr2Yf+UGCK9fy0VAdM7dwVZ9FOQX430blrDpDNo096+FXs2MoRB5SLzueZo2Eurya5OxcYpfIkdrzNpgAUgiL7cVURCh0+xJrIX/Ow9Axle+GvDcWAS9aZsRO+nsJ9Mry0zGWN/2IAEEZY9KVr7YO8xcCJ/yZ2gFXhyRAjD2oNBBrIfwpFNHZ35TbT5znmTX1wrJapLPyXqosGHZed8FkTDIyocCZzDlB0PpuBzUtjWp8gKwrPNsBGzTMvso3Qah3xOiznc7DTBCeSf2mqsX+6iY6p2k4YmF9LST+hepbgF4WW8Y3xgSuJ510TE3wtf/QZXDjQY+r7+yLraHSlE6CzQvL07snDyn4NHqfGw3GMAT71dpoa7WVGWW4HdcpCa8ALCtOx1GpyaydFANwNuwr1wOMQuY/9R5dw== juju-system-key 99 ` 100 baseConfig, err := config.New( 101 config.UseDefaults, 102 coretesting.FakeConfig().Merge(coretesting.Attrs{ 103 "type": "fake", 104 "restricted": "area51", 105 "agent-version": "2.0.0", 106 "authorized-keys": authorizedKeys, 107 }), 108 ) 109 c.Check(err, jc.ErrorIsNil) 110 cfg, err := s.newModelConfig(coretesting.Attrs(baseConfig.AllAttrs())) 111 c.Check(err, jc.ErrorIsNil) 112 c.Assert(cfg.AuthorizedKeys(), jc.DeepEquals, authorizedKeys) 113 } 114 115 func (s *ModelConfigCreatorSuite) TestCreateModelAuthorizedKeysNotIncluded(c *gc.C) { 116 // Ensure that if the new model config has no authorized-keys, 117 // that the resulting config from NewModelConfig has a 118 // juju-system-key at the end. 119 modelTag := names.NewModelTag("deadbeef-0bad-400d-8000-4b1d0d06f00d") 120 modelConfig, err := config.New( 121 config.UseDefaults, 122 coretesting.Attrs{ 123 "uuid": modelTag.Id(), 124 "type": "someprovider", 125 "name": "testmodel", 126 "firewall-mode": config.FwInstance, 127 "ssl-hostname-verification": true, 128 "secret-backend": "auto", 129 "development": false, 130 }, 131 ) 132 c.Check(err, jc.ErrorIsNil) 133 attrs := modelConfig.AllAttrs() 134 // Ensure the modelConfig has no authorized-keys 135 delete(attrs, "authorized-keys") 136 137 authorizedKeys := ` 138 ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDLNN6YxkRJ8liYGh9qymZi23lDRlFrD3ujGfcgkjqa7vOqBHJaWklaIW4vFX0XkYuhgnDlXREi7RRK+4I0XBD051LxADobguLXyeGoOhSRlLLThYMF7Ui8nNylLxY0MYpKUIE6ejve2DHtrwGXBJBUXGJr8z5gKuIZD9J39B3ld1e7v2fpK3SqQ84H8mSZxPBbZqA0NIoq9wl+ke780fYsDxBpsAJhaZW2SjCqcrmNc3m9HgYwzeHhsXDZN2xonoyK2UVMGCsqR0vTHZNpnhME4FdGsmK6WIRMq+z5Mxrw3rSYIgbWi1uACfSsPeBMXmkWORujZrf1w1OKoy1dKeWp juju-client-key 139 ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQCwvae4M/oc+p5d3vj5TBS/4Mx+us5nVuMBgpYCQYq1Bk+QyfyefVfhQwuILAhmzehKnxUse1kGERQ0wNCtn7wU/HhvAuzQBWkxMvShyO9x7GS+4cDEGhkhMGGCu5NvBBCvp24+WdNeqsvoMDRHtBO1kFVc3FQZ01IjR+FTAICW5hE8e7ssCFK+pIDa8TI44rz41grytVJ1iACvaXc7nTyFZg95EXxSurPv0EnO82Gxfdt4bkiSXPXQqNcTLNiJ2oKRyDVYAjZNIr2Yf+UGCK9fy0VAdM7dwVZ9FOQX430blrDpDNo096+FXs2MoRB5SLzueZo2Eurya5OxcYpfIkdrzNpgAUgiL7cVURCh0+xJrIX/Ow9Axle+GvDcWAS9aZsRO+nsJ9Mry0zGWN/2IAEEZY9KVr7YO8xcCJ/yZ2gFXhyRAjD2oNBBrIfwpFNHZ35TbT5znmTX1wrJapLPyXqosGHZed8FkTDIyocCZzDlB0PpuBzUtjWp8gKwrPNsBGzTMvso3Qah3xOiznc7DTBCeSf2mqsX+6iY6p2k4YmF9LST+hepbgF4WW8Y3xgSuJ510TE3wtf/QZXDjQY+r7+yLraHSlE6CzQvL07snDyn4NHqfGw3GMAT71dpoa7WVGWW4HdcpCa8ALCtOx1GpyaydFANwNuwr1wOMQuY/9R5dw== juju-system-key 140 ` 141 customBaseConfig, err := config.New( 142 config.UseDefaults, 143 coretesting.FakeConfig().Merge(coretesting.Attrs{ 144 "type": "fake", 145 "restricted": "area51", 146 "agent-version": "2.0.0", 147 "authorized-keys": authorizedKeys, 148 }), 149 ) 150 c.Check(err, jc.ErrorIsNil) 151 152 cloudSpec := environscloudspec.CloudSpec{Type: "fake"} 153 cfg, err := s.creator.NewModelConfig(cloudSpec, customBaseConfig, modelConfig.AllAttrs()) 154 c.Check(err, jc.ErrorIsNil) 155 obtainedAuthorizedKeys := cfg.AuthorizedKeys() 156 c.Assert(obtainedAuthorizedKeys, jc.Contains, "juju-system-key") 157 } 158 159 func (s *ModelConfigCreatorSuite) TestCreateModelSameAgentVersion(c *gc.C) { 160 cfg, err := s.newModelConfig(coretesting.Attrs( 161 s.baseConfig.AllAttrs(), 162 ).Merge(coretesting.Attrs{ 163 "name": "new-model", 164 "uuid": utils.MustNewUUID().String(), 165 })) 166 c.Assert(err, jc.ErrorIsNil) 167 168 baseAgentVersion, ok := s.baseConfig.AgentVersion() 169 c.Assert(ok, jc.IsTrue) 170 agentVersion, ok := cfg.AgentVersion() 171 c.Assert(ok, jc.IsTrue) 172 c.Assert(agentVersion, gc.Equals, baseAgentVersion) 173 } 174 175 func (s *ModelConfigCreatorSuite) TestCreateModelGreaterAgentVersion(c *gc.C) { 176 _, err := s.newModelConfig(coretesting.Attrs( 177 s.baseConfig.AllAttrs(), 178 ).Merge(coretesting.Attrs{ 179 "name": "new-model", 180 "uuid": utils.MustNewUUID().String(), 181 "agent-version": "2.0.1", 182 })) 183 c.Assert(err, gc.ErrorMatches, 184 "agent-version .* cannot be greater than the controller .*") 185 } 186 187 func (s *ModelConfigCreatorSuite) TestCreateModelLesserAgentVersionNoToolsFinder(c *gc.C) { 188 _, err := s.newModelConfig(coretesting.Attrs( 189 s.baseConfig.AllAttrs(), 190 ).Merge(coretesting.Attrs{ 191 "name": "new-model", 192 "uuid": utils.MustNewUUID().String(), 193 "agent-version": "1.9.9", 194 })) 195 c.Assert(err, gc.ErrorMatches, 196 "agent-version does not match base config, and no tools-finder is supplied") 197 } 198 199 func (s *ModelConfigCreatorSuite) TestCreateModelLesserAgentVersionToolsFinderFound(c *gc.C) { 200 s.creator.FindTools = func(version.Number) (tools.List, error) { 201 return tools.List{ 202 {}, //contents don't matter, just need a non-empty list 203 }, nil 204 } 205 cfg, err := s.newModelConfig(coretesting.Attrs( 206 s.baseConfig.AllAttrs(), 207 ).Merge(coretesting.Attrs{ 208 "name": "new-model", 209 "uuid": utils.MustNewUUID().String(), 210 "agent-version": "1.9.9", 211 })) 212 c.Assert(err, jc.ErrorIsNil) 213 agentVersion, ok := cfg.AgentVersion() 214 c.Assert(ok, jc.IsTrue) 215 c.Assert(agentVersion, gc.Equals, version.MustParse("1.9.9")) 216 } 217 218 func (s *ModelConfigCreatorSuite) TestCreateModelLesserAgentVersionToolsFinderNotFound(c *gc.C) { 219 s.creator.FindTools = func(version.Number) (tools.List, error) { 220 return tools.List{}, nil 221 } 222 _, err := s.newModelConfig(coretesting.Attrs( 223 s.baseConfig.AllAttrs(), 224 ).Merge(coretesting.Attrs{ 225 "name": "new-model", 226 "uuid": utils.MustNewUUID().String(), 227 "agent-version": "1.9.9", 228 })) 229 c.Assert(err, gc.ErrorMatches, "no agent binaries found for version .*") 230 } 231 232 type fakeProvider struct { 233 testing.Stub 234 environs.EnvironProvider 235 restrictedConfigAttributes []string 236 } 237 238 func (p *fakeProvider) Validate(cfg, old *config.Config) (*config.Config, error) { 239 p.MethodCall(p, "Validate", cfg, old) 240 return cfg, p.NextErr() 241 } 242 243 func (p *fakeProvider) PrepareConfig(args environs.PrepareConfigParams) (*config.Config, error) { 244 p.MethodCall(p, "PrepareConfig", args) 245 return args.Config, p.NextErr() 246 } 247 248 func (p *fakeProvider) CredentialSchemas() map[cloud.AuthType]cloud.CredentialSchema { 249 return map[cloud.AuthType]cloud.CredentialSchema{ 250 cloud.UserPassAuthType: { 251 { 252 "username", cloud.CredentialAttr{Description: "The username"}, 253 }, { 254 "password", cloud.CredentialAttr{ 255 Description: "The password", 256 Hidden: true, 257 }, 258 }, 259 }, 260 } 261 } 262 263 func (p *fakeProvider) DetectCredentials(cloudName string) (*cloud.CloudCredential, error) { 264 return nil, errors.NotFoundf("credentials") 265 }