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  }