func (mm *ModelManagerAPI) newModelConfig(args params.ModelCreateArgs, source ConfigSource) (*config.Config, error) { // For now, we just smash to the two maps together as we store // the account values and the model config together in the // *config.Config instance. joint := make(map[string]interface{}) for key, value := range args.Config { joint[key] = value } // Account info overrides any config values. for key, value := range args.Account { joint[key] = value } if _, ok := joint["uuid"]; ok { return nil, errors.New("uuid is generated, you cannot specify one") } baseConfig, err := source.Config() if err != nil { return nil, errors.Trace(err) } creator := modelmanager.ModelConfigCreator{ FindTools: func(n version.Number) (tools.List, error) { result, err := mm.toolsFinder.FindTools(params.FindToolsParams{ Number: n, }) if err != nil { return nil, errors.Trace(err) } return result.List, nil }, } return creator.NewModelConfig(mm.isAdmin, baseConfig, joint) }
func (m *ModelManagerAPI) newModelConfig( cloudSpec environs.CloudSpec, args params.ModelCreateArgs, source ConfigSource, ) (*config.Config, error) { // For now, we just smash to the two maps together as we store // the account values and the model config together in the // *config.Config instance. joint := make(map[string]interface{}) for key, value := range args.Config { joint[key] = value } if _, ok := joint["uuid"]; ok { return nil, errors.New("uuid is generated, you cannot specify one") } if args.Name == "" { return nil, errors.NewNotValid(nil, "Name must be specified") } if _, ok := joint[config.NameKey]; ok { return nil, errors.New("name must not be specified in config") } joint[config.NameKey] = args.Name baseConfig, err := source.Config() if err != nil { return nil, errors.Trace(err) } regionSpec := &environs.RegionSpec{Cloud: cloudSpec.Name, Region: cloudSpec.Region} if joint, err = m.state.ComposeNewModelConfig(joint, regionSpec); err != nil { return nil, errors.Trace(err) } creator := modelmanager.ModelConfigCreator{ Provider: environs.Provider, FindTools: func(n version.Number) (tools.List, error) { result, err := m.toolsFinder.FindTools(params.FindToolsParams{ Number: n, }) if err != nil { return nil, errors.Trace(err) } return result.List, nil }, } return creator.NewModelConfig(cloudSpec, baseConfig, joint) }
// InitializeState should be called on the bootstrap machine's agent // configuration. It uses that information to create the controller, dial the // controller, and initialize it. It also generates a new password for the // bootstrap machine and calls Write to save the the configuration. // // The cfg values will be stored in the state's ModelConfig; the // machineCfg values will be used to configure the bootstrap Machine, // and its constraints will be also be used for the model-level // constraints. The connection to the controller will respect the // given timeout parameter. // // InitializeState returns the newly initialized state and bootstrap // machine. If it fails, the state may well be irredeemably compromised. func InitializeState( adminUser names.UserTag, c agent.ConfigSetter, args InitializeStateParams, dialOpts mongo.DialOpts, newPolicy state.NewPolicyFunc, ) (_ *state.State, _ *state.Machine, resultErr error) { if c.Tag() != names.NewMachineTag(agent.BootstrapMachineId) { return nil, nil, errors.Errorf("InitializeState not called with bootstrap machine's configuration") } servingInfo, ok := c.StateServingInfo() if !ok { return nil, nil, errors.Errorf("state serving information not available") } // N.B. no users are set up when we're initializing the state, // so don't use any tag or password when opening it. info, ok := c.MongoInfo() if !ok { return nil, nil, errors.Errorf("stateinfo not available") } info.Tag = nil info.Password = c.OldPassword() if err := initMongoAdminUser(info.Info, dialOpts, info.Password); err != nil { return nil, nil, errors.Annotate(err, "failed to initialize mongo admin user") } cloudCredentials := make(map[names.CloudCredentialTag]cloud.Credential) var cloudCredentialTag names.CloudCredentialTag if args.ControllerCloudCredential != nil && args.ControllerCloudCredentialName != "" { cloudCredentialTag = names.NewCloudCredentialTag(fmt.Sprintf( "%s/%s/%s", args.ControllerCloudName, adminUser.Canonical(), args.ControllerCloudCredentialName, )) cloudCredentials[cloudCredentialTag] = *args.ControllerCloudCredential } logger.Debugf("initializing address %v", info.Addrs) st, err := state.Initialize(state.InitializeParams{ Clock: clock.WallClock, ControllerModelArgs: state.ModelArgs{ Owner: adminUser, Config: args.ControllerModelConfig, Constraints: args.ModelConstraints, CloudName: args.ControllerCloudName, CloudRegion: args.ControllerCloudRegion, CloudCredential: cloudCredentialTag, StorageProviderRegistry: args.StorageProviderRegistry, }, CloudName: args.ControllerCloudName, Cloud: args.ControllerCloud, CloudCredentials: cloudCredentials, ControllerConfig: args.ControllerConfig, ControllerInheritedConfig: args.ControllerInheritedConfig, RegionInheritedConfig: args.RegionInheritedConfig, MongoInfo: info, MongoDialOpts: dialOpts, NewPolicy: newPolicy, }) if err != nil { return nil, nil, errors.Errorf("failed to initialize state: %v", err) } logger.Debugf("connected to initial state") defer func() { if resultErr != nil { st.Close() } }() servingInfo.SharedSecret = args.SharedSecret c.SetStateServingInfo(servingInfo) // Filter out any LXC or LXD bridge addresses from the machine addresses. args.BootstrapMachineAddresses = network.FilterBridgeAddresses(args.BootstrapMachineAddresses) if err = initAPIHostPorts(c, st, args.BootstrapMachineAddresses, servingInfo.APIPort); err != nil { return nil, nil, err } ssi := paramsStateServingInfoToStateStateServingInfo(servingInfo) if err := st.SetStateServingInfo(ssi); err != nil { return nil, nil, errors.Errorf("cannot set state serving info: %v", err) } m, err := initBootstrapMachine(c, st, args) if err != nil { return nil, nil, errors.Annotate(err, "cannot initialize bootstrap machine") } // Create the initial hosted model, with the model config passed to // bootstrap, which contains the UUID, name for the hosted model, // and any user supplied config. We also copy the authorized-keys // from the controller model. attrs := make(map[string]interface{}) for k, v := range args.HostedModelConfig { attrs[k] = v } attrs[config.AuthorizedKeysKey] = args.ControllerModelConfig.AuthorizedKeys() // Construct a CloudSpec to pass on to NewModelConfig below. cloudSpec, err := environs.MakeCloudSpec( args.ControllerCloud, args.ControllerCloudName, args.ControllerCloudRegion, args.ControllerCloudCredential, ) if err != nil { return nil, nil, errors.Trace(err) } controllerUUID := args.ControllerConfig.ControllerUUID() creator := modelmanager.ModelConfigCreator{Provider: args.Provider} hostedModelConfig, err := creator.NewModelConfig( cloudSpec, args.ControllerModelConfig, attrs, ) if err != nil { return nil, nil, errors.Annotate(err, "creating hosted model config") } provider, err := args.Provider(cloudSpec.Type) if err != nil { return nil, nil, errors.Annotate(err, "getting environ provider") } hostedModelEnv, err := provider.Open(environs.OpenParams{ Cloud: cloudSpec, Config: hostedModelConfig, }) if err != nil { return nil, nil, errors.Annotate(err, "opening hosted model environment") } if err := hostedModelEnv.Create(environs.CreateParams{ ControllerUUID: controllerUUID, }); err != nil { return nil, nil, errors.Annotate(err, "creating hosted model environment") } _, hostedModelState, err := st.NewModel(state.ModelArgs{ Owner: adminUser, Config: hostedModelConfig, Constraints: args.ModelConstraints, CloudName: args.ControllerCloudName, CloudRegion: args.ControllerCloudRegion, CloudCredential: cloudCredentialTag, StorageProviderRegistry: args.StorageProviderRegistry, }) if err != nil { return nil, nil, errors.Annotate(err, "creating hosted model") } hostedModelState.Close() return st, m, nil }