53
53
"github.com/juju/juju/provider/common"
54
54
"github.com/juju/juju/state"
55
55
"github.com/juju/juju/state/multiwatcher"
56
"github.com/juju/juju/status"
56
57
"github.com/juju/juju/storage"
57
58
"github.com/juju/juju/testing"
58
59
coretools "github.com/juju/juju/tools"
80
80
"uuid": testing.ModelTag.Id(),
81
"controller-uuid": testing.ModelTag.Id(),
81
82
"authorized-keys": testing.FakeAuthKeys,
82
83
"firewall-mode": config.FwInstance,
83
84
"admin-secret": testing.DefaultMongoPassword,
231
232
statePolicy state.Policy
232
233
supportsSpaces bool
233
234
supportsSpaceDiscovery bool
234
// We have one state for each environment name.
235
state map[int]*environState
235
// We have one state for each prepared controller.
236
state map[string]*environState
239
239
var providerInstance environProvider
243
241
// environState represents the state of an environment.
244
242
// It can be shared between several environ values,
245
243
// so that a given environment can be opened several times.
246
244
type environState struct {
250
statePolicy state.Policy
252
maxId int // maximum instance id allocated so far.
253
maxAddr int // maximum allocated address last byte
254
insts map[instance.Id]*dummyInstance
255
globalPorts map[network.PortRange]bool
257
apiListener net.Listener
258
apiServer *apiserver.Server
259
apiState *state.State
247
statePolicy state.Policy
249
maxId int // maximum instance id allocated so far.
250
maxAddr int // maximum allocated address last byte
251
insts map[instance.Id]*dummyInstance
252
globalPorts map[network.PortRange]bool
254
apiListener net.Listener
255
apiServer *apiserver.Server
256
apiState *state.State
257
bootstrapConfig *config.Config
263
261
// environ represents a client's connection to a given environment's
448
446
Description: "A secret",
449
447
Type: environschema.Tstring,
452
Description: "Id of controller",
453
Type: environschema.Tstring,
454
Group: environschema.JujuGroup,
458
451
var configFields = func() schema.Fields {
487
479
return c.attrs["secret"].(string)
490
func (c *environConfig) stateId() int {
491
idStr, ok := c.attrs["state-id"].(string)
495
id, err := strconv.Atoi(idStr)
497
panic(fmt.Errorf("unexpected state-id %q (should have pre-checked)", idStr))
502
482
func (p *environProvider) newConfig(cfg *config.Config) (*environConfig, error) {
503
483
valid, err := p.Validate(cfg, nil)
539
if idStr, ok := validated["state-id"].(string); ok {
540
if _, err := strconv.Atoi(idStr); err != nil {
541
return nil, fmt.Errorf("invalid state-id %q", idStr)
544
519
// Apply the coerced unknown values back into the config.
545
520
return cfg.Apply(validated)
548
523
func (e *environ) state() (*environState, error) {
549
stateId := e.ecfg().stateId()
550
if stateId == noStateId {
551
return nil, ErrNotPrepared
553
524
p := &providerInstance
555
526
defer p.mu.Unlock()
556
if state := p.state[stateId]; state != nil {
527
state, ok := p.state[e.Config().ControllerUUID()]
529
return nil, ErrNotPrepared
559
return nil, ErrDestroyed
562
534
func (p *environProvider) Open(cfg *config.Config) (environs.Environ, error) {
592
func (p *environProvider) PrepareForBootstrap(ctx environs.BootstrapContext, args environs.PrepareForBootstrapParams) (environs.Environ, error) {
594
cfg, err := p.prepare(cfg)
564
// PrepareForBootstrap is specified in the EnvironProvider interface.
565
func (p *environProvider) PrepareForBootstrap(ctx environs.BootstrapContext, cfg *config.Config) (environs.Environ, error) {
598
566
return p.Open(cfg)
601
// prepare is the internal version of Prepare - it prepares the
602
// environment but does not open it.
603
func (p *environProvider) prepare(cfg *config.Config) (*config.Config, error) {
604
ecfg, err := p.newConfig(cfg)
569
// BootstrapConfig is specified in the EnvironProvider interface.
570
func (p *environProvider) BootstrapConfig(args environs.BootstrapConfigParams) (*config.Config, error) {
571
ecfg, err := p.newConfig(args.Config)
609
576
defer p.mu.Unlock()
611
if ecfg.stateId() != noStateId {
578
envState, ok := p.state[args.Config.ControllerUUID()]
580
// BootstrapConfig is expected to return the same result given
581
// the same input. We assume that the args are the same for a
582
// previously prepared/bootstrapped controller.
583
return envState.bootstrapConfig, nil
586
name := args.Config.Name()
614
587
if ecfg.controller() && len(p.state) != 0 {
615
588
for _, old := range p.state {
616
589
panic(fmt.Errorf("cannot share a state between two dummy environs; old %q; new %q", old.name, name))
619
// The environment has not been prepared,
620
// so create it and set its state identifier accordingly.
621
state := newState(name, p.ops, p.statePolicy)
623
state.id = p.maxStateId
624
p.state[state.id] = state
626
attrs := map[string]interface{}{"state-id": fmt.Sprint(state.id)}
593
// The environment has not been prepared, so create it and record it.
594
// We don't start listening for State or API connections until
595
// PrepareForBootstrapConfig has been called.
596
envState = newState(name, p.ops, p.statePolicy)
627
598
if ecfg.controller() {
628
attrs["api-port"] = state.listenAPI()
599
apiPort := envState.listenAPI()
600
cfg, err = cfg.Apply(map[string]interface{}{
630
return cfg.Apply(attrs)
607
envState.bootstrapConfig = cfg
608
p.state[cfg.ControllerUUID()] = envState
633
612
func (*environProvider) SecretAttrs(cfg *config.Config) (map[string]string, error) {
857
836
// ConstraintsValidator is defined on the Environs interface.
858
837
func (e *environ) ConstraintsValidator() (constraints.Validator, error) {
859
838
validator := constraints.NewValidator()
860
validator.RegisterUnsupported([]string{constraints.CpuPower})
839
validator.RegisterUnsupported([]string{constraints.CpuPower, constraints.VirtType})
861
840
validator.RegisterConflicts([]string{constraints.InstanceType}, []string{constraints.Mem})
862
841
return validator, nil
1085
1064
return []network.SpaceInfo{}, err
1087
1066
return []network.SpaceInfo{{
1088
ProviderId: network.Id("foo"),
1068
ProviderId: network.Id("0"),
1089
1069
Subnets: []network.SubnetInfo{{
1090
1070
ProviderId: network.Id("1"),
1091
1071
AvailabilityZones: []string{"zone1"},
1093
1073
ProviderId: network.Id("2"),
1094
1074
AvailabilityZones: []string{"zone1"},
1096
ProviderId: network.Id("Another Foo 99!"),
1076
Name: "Another Foo 99!",
1097
1078
Subnets: []network.SubnetInfo{{
1098
1079
ProviderId: network.Id("3"),
1099
1080
AvailabilityZones: []string{"zone1"},
1101
ProviderId: network.Id("foo-"),
1102
1084
Subnets: []network.SubnetInfo{{
1103
1085
ProviderId: network.Id("4"),
1104
1086
AvailabilityZones: []string{"zone1"},
1106
ProviderId: network.Id("---"),
1107
1090
Subnets: []network.SubnetInfo{{
1108
1091
ProviderId: network.Id("5"),
1109
1092
AvailabilityZones: []string{"zone1"},
1528
func (inst *dummyInstance) Status() string {
1511
func (inst *dummyInstance) Status() instance.InstanceStatus {
1530
1513
defer inst.mu.Unlock()
1514
// TODO(perrito666) add a provider status -> juju status mapping.
1515
jujuStatus := status.StatusPending
1516
if inst.status != "" {
1517
dummyStatus := status.Status(inst.status)
1518
if dummyStatus.KnownInstanceStatus() {
1519
jujuStatus = dummyStatus
1523
return instance.InstanceStatus{
1525
Message: inst.status,
1534
1530
// SetInstanceAddresses sets the addresses associated with the given