~juju-qa/ubuntu/xenial/juju/xenial-2.0-beta3

« back to all changes in this revision

Viewing changes to src/github.com/juju/juju/provider/dummy/environs.go

  • Committer: Martin Packman
  • Date: 2016-03-30 19:31:08 UTC
  • mfrom: (1.1.41)
  • Revision ID: martin.packman@canonical.com-20160330193108-h9iz3ak334uk0z5r
Merge new upstream source 2.0~beta3

Show diffs side-by-side

added added

removed removed

Lines of Context:
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"
68
69
 
69
70
var (
70
71
        ErrNotPrepared = errors.New("model is not prepared")
71
 
        ErrDestroyed   = errors.New("model has been destroyed")
72
72
)
73
73
 
74
74
// SampleConfig() returns an environment configuration with all required
78
78
                "type":                      "dummy",
79
79
                "name":                      "only",
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
236
 
        maxStateId int
 
235
        // We have one state for each prepared controller.
 
236
        state map[string]*environState
237
237
}
238
238
 
239
239
var providerInstance environProvider
240
240
 
241
 
const noStateId = 0
242
 
 
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 {
247
 
        id           int
248
 
        name         string
249
 
        ops          chan<- Operation
250
 
        statePolicy  state.Policy
251
 
        mu           sync.Mutex
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
256
 
        bootstrapped bool
257
 
        apiListener  net.Listener
258
 
        apiServer    *apiserver.Server
259
 
        apiState     *state.State
260
 
        preferIPv6   bool
 
245
        name            string
 
246
        ops             chan<- Operation
 
247
        statePolicy     state.Policy
 
248
        mu              sync.Mutex
 
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
 
253
        bootstrapped    bool
 
254
        apiListener     net.Listener
 
255
        apiServer       *apiserver.Server
 
256
        apiState        *state.State
 
257
        bootstrapConfig *config.Config
 
258
        preferIPv6      bool
261
259
}
262
260
 
263
261
// environ represents a client's connection to a given environment's
310
308
                }
311
309
                s.destroy()
312
310
        }
313
 
        providerInstance.state = make(map[int]*environState)
 
311
        providerInstance.state = make(map[string]*environState)
314
312
        if mongoAlive() {
315
313
                if err := gitjujutesting.MgoServer.Reset(); err != nil {
316
314
                        return errors.Trace(err)
448
446
                Description: "A secret",
449
447
                Type:        environschema.Tstring,
450
448
        },
451
 
        "state-id": {
452
 
                Description: "Id of controller",
453
 
                Type:        environschema.Tstring,
454
 
                Group:       environschema.JujuGroup,
455
 
        },
456
449
}
457
450
 
458
451
var configFields = func() schema.Fields {
466
459
var configDefaults = schema.Defaults{
467
460
        "broken":     "",
468
461
        "secret":     "pork",
469
 
        "state-id":   schema.Omit,
470
462
        "controller": false,
471
463
}
472
464
 
487
479
        return c.attrs["secret"].(string)
488
480
}
489
481
 
490
 
func (c *environConfig) stateId() int {
491
 
        idStr, ok := c.attrs["state-id"].(string)
492
 
        if !ok {
493
 
                return noStateId
494
 
        }
495
 
        id, err := strconv.Atoi(idStr)
496
 
        if err != nil {
497
 
                panic(fmt.Errorf("unexpected state-id %q (should have pre-checked)", idStr))
498
 
        }
499
 
        return id
500
 
}
501
 
 
502
482
func (p *environProvider) newConfig(cfg *config.Config) (*environConfig, error) {
503
483
        valid, err := p.Validate(cfg, nil)
504
484
        if err != nil {
536
516
        if err != nil {
537
517
                return nil, err
538
518
        }
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)
542
 
                }
543
 
        }
544
519
        // Apply the coerced unknown values back into the config.
545
520
        return cfg.Apply(validated)
546
521
}
547
522
 
548
523
func (e *environ) state() (*environState, error) {
549
 
        stateId := e.ecfg().stateId()
550
 
        if stateId == noStateId {
551
 
                return nil, ErrNotPrepared
552
 
        }
553
524
        p := &providerInstance
554
525
        p.mu.Lock()
555
526
        defer p.mu.Unlock()
556
 
        if state := p.state[stateId]; state != nil {
557
 
                return state, nil
 
527
        state, ok := p.state[e.Config().ControllerUUID()]
 
528
        if !ok {
 
529
                return nil, ErrNotPrepared
558
530
        }
559
 
        return nil, ErrDestroyed
 
531
        return state, nil
560
532
}
561
533
 
562
534
func (p *environProvider) Open(cfg *config.Config) (environs.Environ, error) {
566
538
        if err != nil {
567
539
                return nil, err
568
540
        }
569
 
        if ecfg.stateId() == noStateId {
 
541
        if _, ok := p.state[cfg.ControllerUUID()]; !ok {
570
542
                return nil, ErrNotPrepared
571
543
        }
572
544
        env := &environ{
589
561
        return cfg, nil
590
562
}
591
563
 
592
 
func (p *environProvider) PrepareForBootstrap(ctx environs.BootstrapContext, args environs.PrepareForBootstrapParams) (environs.Environ, error) {
593
 
        cfg := args.Config
594
 
        cfg, err := p.prepare(cfg)
595
 
        if err != nil {
596
 
                return nil, err
597
 
        }
 
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)
599
567
}
600
568
 
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)
605
572
        if err != nil {
606
573
                return nil, err
607
574
        }
608
575
        p.mu.Lock()
609
576
        defer p.mu.Unlock()
610
 
        name := cfg.Name()
611
 
        if ecfg.stateId() != noStateId {
612
 
                return cfg, nil
 
577
 
 
578
        envState, ok := p.state[args.Config.ControllerUUID()]
 
579
        if ok {
 
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
613
584
        }
 
585
 
 
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))
617
590
                }
618
591
        }
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)
622
 
        p.maxStateId++
623
 
        state.id = p.maxStateId
624
 
        p.state[state.id] = state
625
592
 
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)
 
597
        cfg := args.Config
627
598
        if ecfg.controller() {
628
 
                attrs["api-port"] = state.listenAPI()
 
599
                apiPort := envState.listenAPI()
 
600
                cfg, err = cfg.Apply(map[string]interface{}{
 
601
                        "api-port": apiPort,
 
602
                })
 
603
                if err != nil {
 
604
                        return nil, err
 
605
                }
629
606
        }
630
 
        return cfg.Apply(attrs)
 
607
        envState.bootstrapConfig = cfg
 
608
        p.state[cfg.ControllerUUID()] = envState
 
609
        return cfg, nil
631
610
}
632
611
 
633
612
func (*environProvider) SecretAttrs(cfg *config.Config) (map[string]string, error) {
740
719
                if err != nil {
741
720
                        panic(err)
742
721
                }
743
 
                if err := st.SetModelConstraints(args.EnvironConstraints); err != nil {
 
722
                if err := st.SetModelConstraints(args.ModelConstraints); err != nil {
744
723
                        panic(err)
745
724
                }
746
725
                if err := st.SetAdminMongoPassword(password); err != nil {
834
813
        defer delay()
835
814
        estate, err := e.state()
836
815
        if err != nil {
837
 
                if err == ErrDestroyed {
 
816
                if err == ErrNotPrepared {
838
817
                        return nil
839
818
                }
840
819
                return err
845
824
        }
846
825
        p := &providerInstance
847
826
        p.mu.Lock()
848
 
        delete(p.state, estate.id)
 
827
        delete(p.state, estate.bootstrapConfig.ControllerUUID())
849
828
        p.mu.Unlock()
850
829
 
851
830
        estate.mu.Lock()
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
863
842
}
1085
1064
                return []network.SpaceInfo{}, err
1086
1065
        }
1087
1066
        return []network.SpaceInfo{{
1088
 
                ProviderId: network.Id("foo"),
 
1067
                Name:       "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"},
1095
1075
                }}}, {
1096
 
                ProviderId: network.Id("Another Foo 99!"),
 
1076
                Name:       "Another Foo 99!",
 
1077
                ProviderId: "1",
1097
1078
                Subnets: []network.SubnetInfo{{
1098
1079
                        ProviderId:        network.Id("3"),
1099
1080
                        AvailabilityZones: []string{"zone1"},
1100
1081
                }}}, {
1101
 
                ProviderId: network.Id("foo-"),
 
1082
                Name:       "foo-",
 
1083
                ProviderId: "2",
1102
1084
                Subnets: []network.SubnetInfo{{
1103
1085
                        ProviderId:        network.Id("4"),
1104
1086
                        AvailabilityZones: []string{"zone1"},
1105
1087
                }}}, {
1106
 
                ProviderId: network.Id("---"),
 
1088
                Name:       "---",
 
1089
                ProviderId: "3",
1107
1090
                Subnets: []network.SubnetInfo{{
1108
1091
                        ProviderId:        network.Id("5"),
1109
1092
                        AvailabilityZones: []string{"zone1"},
1525
1508
        return inst.id
1526
1509
}
1527
1510
 
1528
 
func (inst *dummyInstance) Status() string {
 
1511
func (inst *dummyInstance) Status() instance.InstanceStatus {
1529
1512
        inst.mu.Lock()
1530
1513
        defer inst.mu.Unlock()
1531
 
        return inst.status
 
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
 
1520
                }
 
1521
        }
 
1522
 
 
1523
        return instance.InstanceStatus{
 
1524
                Status:  jujuStatus,
 
1525
                Message: inst.status,
 
1526
        }
 
1527
 
1532
1528
}
1533
1529
 
1534
1530
// SetInstanceAddresses sets the addresses associated with the given
1663
1659
                <-time.After(providerDelay)
1664
1660
        }
1665
1661
}
 
1662
 
 
1663
// MigrationConfigUpdate implements MigrationConfigUpdater.
 
1664
func (*environ) MigrationConfigUpdate(controllerConfig *config.Config) map[string]interface{} {
 
1665
        return map[string]interface{}{
 
1666
                "controller-uuid": controllerConfig.UUID(),
 
1667
        }
 
1668
}