Skip to content

Commit

Permalink
bootstrap: separate bootstrap config
Browse files Browse the repository at this point in the history
Extract bootstrap-specific config into its own
config struct, in the environs/bootstrap package.
Things that can only be defined or generated at
bootstrap time belong here. We now generate the
admin-secret, ca-cert and ca-private-key in
bootstrap config. Bootstrap timeouts are also
now specified here, and will no longer show up
in the output of get-model-config.

environs/config has been simplified as a result
of this change: there is no longer a need to
read files in that code. This makes the code
easier to reason about - there is no longer any
chance that instantating an environs/config.Config
will read files server-side.

The controller config schema has been dropped,
and the new controller.NewConfig function is made
responsible for creating a complete controller
config from user-specified attributes, setting
defaults as necessary. environs/config no longer
refers to controller config, except to validate
that no schema field reuse controller config
field names. Even this can probably be dropped
in time, as users become accustomed to the new
world order.
  • Loading branch information
axw committed Jul 13, 2016
1 parent b6d9fbd commit d40b8a7
Show file tree
Hide file tree
Showing 65 changed files with 1,042 additions and 1,484 deletions.
2 changes: 1 addition & 1 deletion api/testing/macaroonsuite.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ func (s *MacaroonSuite) SetUpTest(c *gc.C) {
}
return []checkers.Caveat{checkers.DeclaredCaveat("username", username)}, nil
})
s.JujuConnSuite.ConfigAttrs = map[string]interface{}{
s.JujuConnSuite.ControllerConfigAttrs = map[string]interface{}{
controller.IdentityURL: s.discharger.Location(),
}
s.JujuConnSuite.SetUpTest(c)
Expand Down
2 changes: 0 additions & 2 deletions apiserver/common/controllerconfig_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,6 @@ func (f *fakeControllerAccessor) ControllerConfig() (controller.Config, error) {
return map[string]interface{}{
controller.ControllerUUIDKey: testing.ModelTag.Id(),
controller.CACertKey: testing.CACert,
controller.CAPrivateKey: testing.CAKey,
controller.ApiPort: 4321,
controller.StatePort: 1234,
}, nil
Expand All @@ -54,7 +53,6 @@ func (*controllerConfigSuite) TestControllerConfigSuccess(c *gc.C) {
c.Assert(err, jc.ErrorIsNil)
c.Assert(map[string]interface{}(result.Config), jc.DeepEquals, map[string]interface{}{
"ca-cert": testing.CACert,
"ca-private-key": testing.CAKey,
"controller-uuid": "deadbeef-0bad-400d-8000-4b1d0d06f00d",
"state-port": 1234,
"api-port": 4321,
Expand Down
3 changes: 2 additions & 1 deletion apiserver/common/modelwatcher_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -124,10 +124,11 @@ func testingEnvConfig(c *gc.C) *config.Config {
modelcmd.BootstrapContext(testing.Context(c)),
jujuclienttesting.NewMemStore(),
bootstrap.PrepareParams{
ControllerConfig: testing.FakeControllerBootstrapConfig(),
ControllerConfig: testing.FakeControllerConfig(),
ControllerName: "dummycontroller",
BaseConfig: dummy.SampleConfig(),
CloudName: "dummy",
AdminSecret: "admin-secret",
},
)
c.Assert(err, jc.ErrorIsNil)
Expand Down
3 changes: 2 additions & 1 deletion apiserver/imagemetadata/functions_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,10 +37,11 @@ func (s *funcSuite) SetUpTest(c *gc.C) {
envtesting.BootstrapContext(c),
jujuclienttesting.NewMemStore(),
bootstrap.PrepareParams{
ControllerConfig: testing.FakeControllerBootstrapConfig(),
ControllerConfig: testing.FakeControllerConfig(),
ControllerName: "dummycontroller",
BaseConfig: mockConfig(),
CloudName: "dummy",
AdminSecret: "admin-secret",
},
)
c.Assert(err, jc.ErrorIsNil)
Expand Down
3 changes: 2 additions & 1 deletion apiserver/imagemetadata/package_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -127,10 +127,11 @@ func testConfig(c *gc.C) *config.Config {
envtesting.BootstrapContext(c),
jujuclienttesting.NewMemStore(),
bootstrap.PrepareParams{
ControllerConfig: coretesting.FakeControllerBootstrapConfig(),
ControllerConfig: coretesting.FakeControllerConfig(),
ControllerName: "dummycontroller",
BaseConfig: attrs,
CloudName: "dummy",
AdminSecret: "admin-secret",
},
)
c.Assert(err, jc.ErrorIsNil)
Expand Down
3 changes: 2 additions & 1 deletion apiserver/imagemetadata/updatefrompublished_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -169,10 +169,11 @@ func (s *imageMetadataUpdateSuite) TestUpdateFromPublishedImagesForProviderWithN
modelcmd.BootstrapContext(testing.Context(c)),
jujuclienttesting.NewMemStore(),
bootstrap.PrepareParams{
ControllerConfig: testing.FakeControllerBootstrapConfig(),
ControllerConfig: testing.FakeControllerConfig(),
ControllerName: "dummycontroller",
BaseConfig: dummy.SampleConfig(),
CloudName: "dummy",
AdminSecret: "admin-secret",
},
)
c.Assert(err, jc.ErrorIsNil)
Expand Down
3 changes: 2 additions & 1 deletion apiserver/migrationtarget/migrationtarget_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,10 +39,11 @@ func (s *Suite) SetUpTest(c *gc.C) {
modelcmd.BootstrapContext(testing.Context(c)),
jujuclienttesting.NewMemStore(),
bootstrap.PrepareParams{
ControllerConfig: testing.FakeControllerBootstrapConfig(),
ControllerConfig: testing.FakeControllerConfig(),
ControllerName: "dummycontroller",
BaseConfig: dummy.SampleConfig(),
CloudName: "dummy",
AdminSecret: "admin-secret",
},
)
c.Assert(err, jc.ErrorIsNil)
Expand Down
4 changes: 2 additions & 2 deletions apiserver/server_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -331,7 +331,7 @@ var _ = gc.Suite(&macaroonServerSuite{})

func (s *macaroonServerSuite) SetUpTest(c *gc.C) {
s.discharger = bakerytest.NewDischarger(nil, noCheck)
s.ConfigAttrs = map[string]interface{}{
s.ControllerConfigAttrs = map[string]interface{}{
controller.IdentityURL: s.discharger.Location(),
}
s.JujuConnSuite.SetUpTest(c)
Expand Down Expand Up @@ -381,7 +381,7 @@ func (s *macaroonServerWrongPublicKeySuite) SetUpTest(c *gc.C) {
s.discharger = bakerytest.NewDischarger(nil, noCheck)
wrongKey, err := bakery.GenerateKey()
c.Assert(err, gc.IsNil)
s.ConfigAttrs = map[string]interface{}{
s.ControllerConfigAttrs = map[string]interface{}{
controller.IdentityURL: s.discharger.Location(),
controller.IdentityPublicKey: wrongKey.Public.String(),
}
Expand Down
9 changes: 8 additions & 1 deletion cloudconfig/cloudinit/renderscript_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ func (s *configureSuite) getCloudConfig(c *gc.C, controller bool, vers version.B
modelConfig := testConfig(c, controller, vers)
if controller {
icfg, err = instancecfg.NewBootstrapInstanceConfig(
coretesting.FakeControllerBootstrapConfig(),
coretesting.FakeControllerConfig(),
constraints.Value{}, constraints.Value{},
vers.Series, "",
)
Expand All @@ -80,6 +80,13 @@ func (s *configureSuite) getCloudConfig(c *gc.C, controller bool, vers version.B
icfg.Bootstrap.HostedModelConfig = map[string]interface{}{
"name": "hosted-model",
}
icfg.Bootstrap.StateServingInfo = params.StateServingInfo{
Cert: coretesting.ServerCert,
PrivateKey: coretesting.ServerKey,
CAPrivateKey: coretesting.CAKey,
StatePort: 123,
APIPort: 456,
}
icfg.Jobs = []multiwatcher.MachineJob{multiwatcher.JobManageModel, multiwatcher.JobHostUnits}
icfg.Bootstrap.StateServingInfo = params.StateServingInfo{
Cert: coretesting.ServerCert,
Expand Down
2 changes: 1 addition & 1 deletion cloudconfig/providerinit/providerinit_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -183,7 +183,7 @@ func (*CloudInitSuite) testUserData(c *gc.C, series string, bootstrap bool) {
err = cfg.SetTools(toolsList)
c.Assert(err, jc.ErrorIsNil)
if bootstrap {
controllerCfg := testing.FakeControllerBootstrapConfig()
controllerCfg := testing.FakeControllerConfig()
cfg.Bootstrap = &instancecfg.BootstrapConfig{
StateInitializationParams: instancecfg.StateInitializationParams{
ControllerConfig: controllerCfg,
Expand Down
20 changes: 11 additions & 9 deletions cmd/juju/backups/restore.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"io"
"path/filepath"
"strings"
"time"

"github.com/juju/cmd"
"github.com/juju/errors"
Expand Down Expand Up @@ -138,6 +139,8 @@ type restoreBootstrapParams struct {
CloudRegion string
CredentialName string
Credential cloud.Credential
AdminSecret string
CAPrivateKey string
}

// getEnviron returns the environ for the specified controller, or
Expand Down Expand Up @@ -168,7 +171,6 @@ func (c *restoreCommand) getEnviron(
controllerCfg := controller.Config{
controller.ControllerUUIDKey: params.ControllerUUID,
controller.CACertKey: meta.CACert,
controller.CAPrivateKey: meta.CAPrivateKey,
}

// We may have previous controller metadata. We need to update that so it
Expand Down Expand Up @@ -204,7 +206,6 @@ func (c *restoreCommand) getEnviron(
// Also set the admin secret and ca cert info.
cfg, err = cfg.Apply(map[string]interface{}{
"provisioner-safe-mode": true,
"admin-secret": adminSecret,
})
if err != nil {
return nil, nil, errors.Annotatef(err, "cannot enable provisioner-safe-mode")
Expand All @@ -216,6 +217,7 @@ func (c *restoreCommand) getEnviron(
CloudRegion: config.CloudRegion,
CredentialName: config.Credential,
Credential: params.Credentials,
AdminSecret: adminSecret,
}, err
}

Expand Down Expand Up @@ -256,8 +258,6 @@ func (c *restoreCommand) rebootstrap(ctx *cmd.Context, meta *params.BackupsMetad
return errors.Trace(err)
}

sshOpts := env.Config().BootstrapSSHOpts()

bootVers := version.Current
var cred *cloud.Credential
if params.Credential.AuthType() != cloud.EmptyAuthType {
Expand All @@ -276,10 +276,12 @@ func (c *restoreCommand) rebootstrap(ctx *cmd.Context, meta *params.BackupsMetad
HostedModelConfig: hostedModelConfig,
BootstrapSeries: meta.Series,
AgentVersion: &bootVers,
AdminSecret: params.AdminSecret,
CAPrivateKey: meta.CAPrivateKey,
DialOpts: environs.BootstrapDialOpts{
Timeout: sshOpts.Timeout,
RetryDelay: sshOpts.RetryDelay,
AddressesDelay: sshOpts.AddressesDelay,
Timeout: time.Second * bootstrap.DefaultBootstrapSSHTimeout,
RetryDelay: time.Second * bootstrap.DefaultBootstrapSSHRetryDelay,
AddressesDelay: time.Second * bootstrap.DefaultBootstrapSSHAddressesDelay,
},
}
if err := BootstrapFunc(modelcmd.BootstrapContext(ctx), env, args); err != nil {
Expand All @@ -292,8 +294,8 @@ func (c *restoreCommand) rebootstrap(ctx *cmd.Context, meta *params.BackupsMetad

// New controller is bootstrapped, so now record the API address so
// we can connect.
controllerCfg := controller.ControllerConfig(env.Config().AllAttrs())
err = common.SetBootstrapEndpointAddress(store, c.ControllerName(), controllerCfg.APIPort(), env)
apiPort := params.ControllerConfig.APIPort()
err = common.SetBootstrapEndpointAddress(store, c.ControllerName(), apiPort, env)
if err != nil {
return errors.Trace(err)
}
Expand Down
13 changes: 2 additions & 11 deletions cmd/juju/backups/restore_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ import (
"github.com/juju/juju/cmd/juju/backups"
"github.com/juju/juju/environs"
"github.com/juju/juju/environs/bootstrap"
"github.com/juju/juju/environs/config"
"github.com/juju/juju/instance"
"github.com/juju/juju/jujuclient"
"github.com/juju/juju/jujuclient/jujuclienttesting"
Expand Down Expand Up @@ -167,8 +166,6 @@ func (s *restoreSuite) TestRestoreReboostrapReadsMetadata(c *gc.C) {
},
nil)
s.PatchValue(&backups.BootstrapFunc, func(ctx environs.BootstrapContext, environ environs.Environ, args bootstrap.BootstrapParams) error {
attr := environ.Config().AllAttrs()
c.Assert(attr["ca-cert"], gc.Equals, testing.CACert)
return errors.New("failed to bootstrap new controller")
})

Expand Down Expand Up @@ -200,8 +197,8 @@ func (s *restoreSuite) TestRestoreReboostrapWritesUpdatedControllerInfo(c *gc.C)
CloudRegion: "a-region",
CACert: testing.CACert,
ControllerUUID: "deadbeef-0bad-400d-8000-5b1d0d06f00d",
APIEndpoints: []string{"10.0.0.1:100"},
UnresolvedAPIEndpoints: []string{"10.0.0.1:100"},
APIEndpoints: []string{"10.0.0.1:17777"},
UnresolvedAPIEndpoints: []string{"10.0.0.1:17777"},
})
}

Expand Down Expand Up @@ -232,9 +229,3 @@ func (f fakeEnviron) Instances(ids []instance.Id) ([]instance.Instance, error) {
func (f fakeEnviron) AllInstances() ([]instance.Instance, error) {
return []instance.Instance{fakeInstance{id: "1"}}, nil
}

func (f fakeEnviron) Config() *config.Config {
attrs := testing.FakeConfig().Merge(map[string]interface{}{"api-port": "100"})
cfg, _ := config.New(config.NoDefaults, attrs)
return cfg
}
63 changes: 37 additions & 26 deletions cmd/juju/commands/bootstrap.go
Original file line number Diff line number Diff line change
Expand Up @@ -426,26 +426,49 @@ func (c *bootstrapCommand) Run(ctx *cmd.Context) (resultErr error) {
*credential = cred
}

// Create an environment config from the cloud and credentials.
configAttrs := map[string]interface{}{
// Create a model config, and split out any controller
// and bootstrap config attributes.
modelConfigAttrs := map[string]interface{}{
"type": cloud.Type,
"name": bootstrap.ControllerModelName,
config.UUIDKey: controllerUUID.String(),
}
for k, v := range cloud.Config {
configAttrs[k] = v
modelConfigAttrs[k] = v
}
userConfigAttrs, err := c.config.ReadAttrs(ctx)
if err != nil {
return errors.Trace(err)
}
for k, v := range userConfigAttrs {
configAttrs[k] = v
modelConfigAttrs[k] = v
}
bootstrapConfigAttrs := make(map[string]interface{})
controllerConfigAttrs := make(map[string]interface{})
for k, v := range modelConfigAttrs {
switch {
case bootstrap.IsBootstrapAttribute(k):
bootstrapConfigAttrs[k] = v
delete(modelConfigAttrs, k)
case controller.ControllerOnlyAttribute(k):
controllerConfigAttrs[k] = v
delete(modelConfigAttrs, k)
}
}
if err := common.FinalizeAuthorizedKeys(ctx, configAttrs); err != nil {
return errors.Trace(err)
bootstrapConfig, err := bootstrap.NewConfig(controllerUUID.String(), bootstrapConfigAttrs)
if err != nil {
return errors.Annotate(err, "constructing bootstrap config")
}
controllerConfig, err := controller.NewConfig(
controllerUUID.String(), bootstrapConfig.CACert, controllerConfigAttrs,
)
if err != nil {
return errors.Annotate(err, "constructing controller config")
}
logger.Debugf("preparing controller with config: %v", configAttrs)
if err := common.FinalizeAuthorizedKeys(ctx, modelConfigAttrs); err != nil {
return errors.Annotate(err, "finalizing authorized-keys")
}
logger.Debugf("preparing controller with config: %v", modelConfigAttrs)

// Read existing current controller so we can clean up on error.
var oldCurrentController string
Expand Down Expand Up @@ -476,23 +499,10 @@ func (c *bootstrapCommand) Run(ctx *cmd.Context) (resultErr error) {
}
}()

// TODO(wallyworld) - we need to separate controller and model schemas
// Extract any controller attributes from the bucket of config options
// the user may have specified.
controllerConfig := controller.Config{
controller.ControllerUUIDKey: controllerUUID.String(),
}
for attr, cfgValue := range configAttrs {
if !controller.ControllerOnlyAttribute(attr) {
continue
}
controllerConfig[attr] = cfgValue
}

environ, err := bootstrapPrepare(
modelcmd.BootstrapContext(ctx), store,
bootstrap.PrepareParams{
BaseConfig: configAttrs,
BaseConfig: modelConfigAttrs,
ControllerConfig: controllerConfig,
ControllerName: c.controllerName,
CloudName: c.Cloud,
Expand All @@ -501,6 +511,7 @@ func (c *bootstrapCommand) Run(ctx *cmd.Context) (resultErr error) {
CloudStorageEndpoint: region.StorageEndpoint,
Credential: *credential,
CredentialName: credentialName,
AdminSecret: bootstrapConfig.AdminSecret,
},
)
if err != nil {
Expand Down Expand Up @@ -630,8 +641,6 @@ to clean up the model.`[1:])
credentialName = detectedCredentialName
}

sshOpts := environ.Config().BootstrapSSHOpts()

err = bootstrapFuncs.Bootstrap(modelcmd.BootstrapContext(ctx), environ, bootstrap.BootstrapParams{
ModelConstraints: c.Constraints,
BootstrapConstraints: bootstrapConstraints,
Expand All @@ -651,10 +660,12 @@ to clean up the model.`[1:])
ControllerInheritedConfig: inheritedControllerAttrs,
HostedModelConfig: hostedModelConfig,
GUIDataSourceBaseURL: guiDataSourceBaseURL,
AdminSecret: bootstrapConfig.AdminSecret,
CAPrivateKey: bootstrapConfig.CAPrivateKey,
DialOpts: environs.BootstrapDialOpts{
Timeout: sshOpts.Timeout,
RetryDelay: sshOpts.RetryDelay,
AddressesDelay: sshOpts.AddressesDelay,
Timeout: bootstrapConfig.BootstrapTimeout,
RetryDelay: bootstrapConfig.BootstrapRetryDelay,
AddressesDelay: bootstrapConfig.BootstrapAddressesDelay,
},
})
if err != nil {
Expand Down
3 changes: 0 additions & 3 deletions cmd/modelcmd/base.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ import (
"github.com/juju/juju/api/modelmanager"
"github.com/juju/juju/apiserver/params"
"github.com/juju/juju/cloud"
"github.com/juju/juju/controller"
"github.com/juju/juju/environs"
"github.com/juju/juju/environs/config"
"github.com/juju/juju/juju"
Expand Down Expand Up @@ -372,8 +371,6 @@ func (g bootstrapConfigGetter) getBootstrapConfigParams(controllerName string) (
return nil, nil, errors.Trace(err)
}
bootstrapConfig.Config[config.UUIDKey] = controllerDetails.ControllerUUID
bootstrapConfig.Config[controller.CACertKey] = controllerDetails.CACert
bootstrapConfig.Config[controller.ControllerUUIDKey] = controllerDetails.ControllerUUID

cfg, err := config.New(config.UseDefaults, bootstrapConfig.Config)
if err != nil {
Expand Down
3 changes: 2 additions & 1 deletion cmd/plugins/juju-metadata/toolsmetadata_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,10 +58,11 @@ func (s *ToolsMetadataSuite) SetUpTest(c *gc.C) {
modelcmd.BootstrapContextNoVerify(coretesting.Context(c)),
jujuclienttesting.NewMemStore(),
bootstrap.PrepareParams{
ControllerConfig: coretesting.FakeControllerBootstrapConfig(),
ControllerConfig: coretesting.FakeControllerConfig(),
ControllerName: cfg.Name(),
BaseConfig: cfg.AllAttrs(),
CloudName: "dummy",
AdminSecret: "admin-secret",
},
)
c.Assert(err, jc.ErrorIsNil)
Expand Down
Loading

0 comments on commit d40b8a7

Please sign in to comment.