1
// Copyright 2013 Canonical Ltd.
2
// Licensed under the AGPLv3, see LICENCE file for details.
7
gitjujutesting "github.com/juju/testing"
8
jc "github.com/juju/testing/checkers"
10
"gopkg.in/juju/names.v2"
12
"github.com/juju/juju/cloud"
13
"github.com/juju/juju/constraints"
14
"github.com/juju/juju/controller"
15
"github.com/juju/juju/environs/config"
16
"github.com/juju/juju/mongo/mongotest"
17
"github.com/juju/juju/state"
18
statetesting "github.com/juju/juju/state/testing"
19
"github.com/juju/juju/storage"
20
"github.com/juju/juju/testing"
23
type InitializeSuite struct {
24
gitjujutesting.MgoSuite
29
var _ = gc.Suite(&InitializeSuite{})
31
func (s *InitializeSuite) SetUpSuite(c *gc.C) {
32
s.BaseSuite.SetUpSuite(c)
33
s.MgoSuite.SetUpSuite(c)
36
func (s *InitializeSuite) TearDownSuite(c *gc.C) {
37
s.MgoSuite.TearDownSuite(c)
38
s.BaseSuite.TearDownSuite(c)
41
func (s *InitializeSuite) SetUpTest(c *gc.C) {
42
s.BaseSuite.SetUpTest(c)
43
s.MgoSuite.SetUpTest(c)
46
func (s *InitializeSuite) openState(c *gc.C, modelTag names.ModelTag) {
47
st, err := state.Open(
49
statetesting.NewMongoInfo(),
51
state.NewPolicyFunc(nil),
53
c.Assert(err, jc.ErrorIsNil)
57
func (s *InitializeSuite) TearDownTest(c *gc.C) {
59
err := s.State.Close()
60
c.Check(err, jc.ErrorIsNil)
62
s.MgoSuite.TearDownTest(c)
63
s.BaseSuite.TearDownTest(c)
66
func (s *InitializeSuite) TestInitialize(c *gc.C) {
67
cfg := testing.ModelConfig(c)
69
owner := names.NewLocalUserTag("initialize-admin")
71
userpassCredential := cloud.NewCredential(
72
cloud.UserPassAuthType,
75
"password": "hunter2",
78
userpassCredential.Label = "some-credential"
79
emptyCredential := cloud.NewEmptyCredential()
80
emptyCredential.Label = "empty-credential"
81
cloudCredentialsIn := map[string]cloud.Credential{
82
userpassCredential.Label: userpassCredential,
83
emptyCredential.Label: emptyCredential,
85
controllerCfg := testing.FakeControllerConfig()
86
controllerCfg["controller-uuid"] = uuid
88
st, err := state.Initialize(state.InitializeParams{
89
ControllerConfig: controllerCfg,
90
ControllerModelArgs: state.ModelArgs{
94
CloudRegion: "some-region",
95
CloudCredential: "some-credential",
96
StorageProviderRegistry: storage.StaticProviderRegistry{},
101
AuthTypes: []cloud.AuthType{
102
cloud.EmptyAuthType, cloud.UserPassAuthType,
104
Regions: []cloud.Region{{Name: "some-region"}},
106
CloudCredentials: cloudCredentialsIn,
107
MongoInfo: statetesting.NewMongoInfo(),
108
MongoDialOpts: mongotest.DialOpts(),
110
c.Assert(err, jc.ErrorIsNil)
111
c.Assert(st, gc.NotNil)
112
modelTag := st.ModelTag()
113
c.Assert(modelTag.Id(), gc.Equals, uuid)
115
c.Assert(err, jc.ErrorIsNil)
117
s.openState(c, modelTag)
119
cfg, err = s.State.ModelConfig()
120
c.Assert(err, jc.ErrorIsNil)
121
expected := cfg.AllAttrs()
122
for k, v := range config.ConfigDefaults() {
123
if _, ok := expected[k]; !ok {
127
c.Assert(cfg.AllAttrs(), jc.DeepEquals, expected)
128
// Check that the model has been created.
129
model, err := s.State.Model()
130
c.Assert(err, jc.ErrorIsNil)
131
c.Assert(model.Tag(), gc.Equals, modelTag)
132
c.Assert(model.CloudRegion(), gc.Equals, "some-region")
133
// Check that the owner has been created.
134
c.Assert(model.Owner(), gc.Equals, owner)
135
// Check that the owner can be retrieved by the tag.
136
entity, err := s.State.FindEntity(model.Owner())
137
c.Assert(err, jc.ErrorIsNil)
138
c.Assert(entity.Tag(), gc.Equals, owner)
139
// Check that the owner has an ModelUser created for the bootstrapped model.
140
modelUser, err := s.State.UserAccess(model.Owner(), model.Tag())
141
c.Assert(err, jc.ErrorIsNil)
142
c.Assert(modelUser.UserTag, gc.Equals, owner)
143
c.Assert(modelUser.Object, gc.Equals, model.Tag())
145
// Check that the model can be found through the tag.
146
entity, err = s.State.FindEntity(modelTag)
147
c.Assert(err, jc.ErrorIsNil)
148
cons, err := s.State.ModelConstraints()
149
c.Assert(err, jc.ErrorIsNil)
150
c.Assert(&cons, jc.Satisfies, constraints.IsEmpty)
152
addrs, err := s.State.APIHostPorts()
153
c.Assert(err, jc.ErrorIsNil)
154
c.Assert(addrs, gc.HasLen, 0)
156
info, err := s.State.ControllerInfo()
157
c.Assert(err, jc.ErrorIsNil)
158
c.Assert(info, jc.DeepEquals, &state.ControllerInfo{ModelTag: modelTag, CloudName: "dummy"})
160
// Check that the model's cloud and credential names are as
161
// expected, and the owner's cloud credentials are initialised.
162
c.Assert(model.Cloud(), gc.Equals, "dummy")
163
c.Assert(model.CloudCredential(), gc.Equals, "some-credential")
164
cloudCredentials, err := s.State.CloudCredentials(model.Owner(), "dummy")
165
c.Assert(err, jc.ErrorIsNil)
166
c.Assert(cloudCredentials, jc.DeepEquals, cloudCredentialsIn)
169
func (s *InitializeSuite) TestInitializeWithInvalidCredentialType(c *gc.C) {
170
owner := names.NewLocalUserTag("initialize-admin")
171
modelCfg := testing.ModelConfig(c)
172
controllerCfg := testing.FakeControllerConfig()
173
controllerCfg["controller-uuid"] = modelCfg.UUID()
174
_, err := state.Initialize(state.InitializeParams{
175
ControllerConfig: controllerCfg,
176
ControllerModelArgs: state.ModelArgs{
180
StorageProviderRegistry: storage.StaticProviderRegistry{},
185
AuthTypes: []cloud.AuthType{
186
cloud.AccessKeyAuthType, cloud.OAuth1AuthType,
189
CloudCredentials: map[string]cloud.Credential{
190
"borken": cloud.NewCredential(cloud.UserPassAuthType, nil),
192
MongoInfo: statetesting.NewMongoInfo(),
193
MongoDialOpts: mongotest.DialOpts(),
195
c.Assert(err, gc.ErrorMatches,
196
`validating initialization args: validating cloud credentials: credential "borken" with auth-type "userpass" is not supported \(expected one of \["access-key" "oauth1"\]\)`,
200
func (s *InitializeSuite) TestInitializeWithControllerInheritedConfig(c *gc.C) {
201
cfg := testing.ModelConfig(c)
203
initial := cfg.AllAttrs()
204
controllerInheritedConfigIn := map[string]interface{}{
205
"default-series": initial["default-series"],
207
owner := names.NewLocalUserTag("initialize-admin")
208
controllerCfg := testing.FakeControllerConfig()
209
controllerCfg["controller-uuid"] = uuid
211
st, err := state.Initialize(state.InitializeParams{
212
ControllerConfig: controllerCfg,
213
ControllerModelArgs: state.ModelArgs{
217
StorageProviderRegistry: storage.StaticProviderRegistry{},
222
AuthTypes: []cloud.AuthType{cloud.EmptyAuthType},
224
ControllerInheritedConfig: controllerInheritedConfigIn,
225
MongoInfo: statetesting.NewMongoInfo(),
226
MongoDialOpts: mongotest.DialOpts(),
228
c.Assert(err, jc.ErrorIsNil)
229
c.Assert(st, gc.NotNil)
230
modelTag := st.ModelTag()
231
c.Assert(modelTag.Id(), gc.Equals, uuid)
233
c.Assert(err, jc.ErrorIsNil)
235
s.openState(c, modelTag)
237
controllerInheritedConfig, err := state.ReadSettings(s.State, state.GlobalSettingsC, state.ControllerInheritedSettingsGlobalKey)
238
c.Assert(err, jc.ErrorIsNil)
239
c.Assert(controllerInheritedConfig.Map(), jc.DeepEquals, controllerInheritedConfigIn)
241
expected := cfg.AllAttrs()
242
for k, v := range config.ConfigDefaults() {
243
if _, ok := expected[k]; !ok {
247
// Config as read from state has resources tags coerced to a map.
248
expected["resource-tags"] = map[string]string{}
249
cfg, err = s.State.ModelConfig()
250
c.Assert(err, jc.ErrorIsNil)
251
c.Assert(cfg.AllAttrs(), jc.DeepEquals, expected)
254
func (s *InitializeSuite) TestDoubleInitializeConfig(c *gc.C) {
255
cfg := testing.ModelConfig(c)
256
owner := names.NewLocalUserTag("initialize-admin")
258
mgoInfo := statetesting.NewMongoInfo()
259
dialOpts := mongotest.DialOpts()
260
controllerCfg := testing.FakeControllerConfig()
261
controllerCfg["controller-uuid"] = cfg.UUID()
263
args := state.InitializeParams{
264
ControllerConfig: controllerCfg,
265
ControllerModelArgs: state.ModelArgs{
269
StorageProviderRegistry: storage.StaticProviderRegistry{},
274
AuthTypes: []cloud.AuthType{cloud.EmptyAuthType},
277
MongoDialOpts: dialOpts,
279
st, err := state.Initialize(args)
280
c.Assert(err, jc.ErrorIsNil)
282
c.Check(err, jc.ErrorIsNil)
284
st, err = state.Initialize(args)
285
c.Check(err, gc.ErrorMatches, "already initialized")
286
if !c.Check(st, gc.IsNil) {
288
c.Check(err, jc.ErrorIsNil)
292
func (s *InitializeSuite) TestModelConfigWithAdminSecret(c *gc.C) {
293
update := map[string]interface{}{"admin-secret": "foo"}
295
s.testBadModelConfig(c, update, remove, "admin-secret should never be written to the state")
298
func (s *InitializeSuite) TestModelConfigWithCAPrivateKey(c *gc.C) {
299
update := map[string]interface{}{"ca-private-key": "foo"}
301
s.testBadModelConfig(c, update, remove, "ca-private-key should never be written to the state")
304
func (s *InitializeSuite) TestModelConfigWithoutAgentVersion(c *gc.C) {
305
update := map[string]interface{}{}
306
remove := []string{"agent-version"}
307
s.testBadModelConfig(c, update, remove, "agent-version must always be set in state")
310
func (s *InitializeSuite) testBadModelConfig(c *gc.C, update map[string]interface{}, remove []string, expect string) {
311
good := testing.CustomModelConfig(c, testing.Attrs{"uuid": testing.ModelTag.Id()})
312
bad, err := good.Apply(update)
313
c.Assert(err, jc.ErrorIsNil)
314
bad, err = bad.Remove(remove)
315
c.Assert(err, jc.ErrorIsNil)
317
owner := names.NewLocalUserTag("initialize-admin")
318
controllerCfg := testing.FakeControllerConfig()
319
controllerCfg["controller-uuid"] = good.UUID()
321
args := state.InitializeParams{
322
ControllerConfig: controllerCfg,
323
ControllerModelArgs: state.ModelArgs{
327
StorageProviderRegistry: storage.StaticProviderRegistry{},
332
AuthTypes: []cloud.AuthType{cloud.EmptyAuthType},
334
MongoInfo: statetesting.NewMongoInfo(),
335
MongoDialOpts: mongotest.DialOpts(),
337
_, err = state.Initialize(args)
338
c.Assert(err, gc.ErrorMatches, expect)
340
args.ControllerModelArgs.Config = good
341
st, err := state.Initialize(args)
342
c.Assert(err, jc.ErrorIsNil)
345
s.openState(c, st.ModelTag())
346
err = s.State.UpdateModelConfig(update, remove, nil)
347
c.Assert(err, gc.ErrorMatches, expect)
349
// ModelConfig remains inviolate.
350
cfg, err := s.State.ModelConfig()
351
c.Assert(err, jc.ErrorIsNil)
352
goodWithDefaults, err := config.New(config.UseDefaults, good.AllAttrs())
353
c.Assert(err, jc.ErrorIsNil)
354
c.Assert(cfg.AllAttrs(), jc.DeepEquals, goodWithDefaults.AllAttrs())
357
func (s *InitializeSuite) TestCloudConfigWithForbiddenValues(c *gc.C) {
358
badAttrNames := []string{
361
config.AgentVersionKey,
363
for _, attr := range controller.ControllerOnlyConfigAttributes {
364
badAttrNames = append(badAttrNames, attr)
367
modelCfg := testing.ModelConfig(c)
368
controllerCfg := testing.FakeControllerConfig()
369
controllerCfg["controller-uuid"] = modelCfg.UUID()
370
args := state.InitializeParams{
371
ControllerConfig: controllerCfg,
372
ControllerModelArgs: state.ModelArgs{
374
Owner: names.NewLocalUserTag("initialize-admin"),
376
StorageProviderRegistry: storage.StaticProviderRegistry{},
381
AuthTypes: []cloud.AuthType{cloud.EmptyAuthType},
383
MongoInfo: statetesting.NewMongoInfo(),
384
MongoDialOpts: mongotest.DialOpts(),
387
for _, badAttrName := range badAttrNames {
388
badAttrs := map[string]interface{}{badAttrName: "foo"}
389
args.ControllerInheritedConfig = badAttrs
390
_, err := state.Initialize(args)
391
c.Assert(err, gc.ErrorMatches, "local cloud config cannot contain .*")