LEFT | RIGHT |
1 // The dummy provider implements an environment provider for testing | 1 // The dummy provider implements an environment provider for testing |
2 // purposes, registered with environs under the name "dummy". | 2 // purposes, registered with environs under the name "dummy". |
3 // | 3 // |
4 // The configuration YAML for the testing environment | 4 // The configuration YAML for the testing environment |
5 // must specify a "state-server" property with a boolean | 5 // must specify a "state-server" property with a boolean |
6 // value. If this is true, a state server will be started | 6 // value. If this is true, a state server will be started |
7 // the first time StateInfo is called on a newly reset environment. | 7 // the first time StateInfo is called on a newly reset environment. |
8 // | 8 // |
9 // The configuration data also accepts a "broken" property | 9 // The configuration data also accepts a "broken" property |
10 // of type boolean. If this is non-empty, any operation | 10 // of type boolean. If this is non-empty, any operation |
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
63 } | 63 } |
64 | 64 |
65 type OpBootstrap struct { | 65 type OpBootstrap struct { |
66 Env string | 66 Env string |
67 Constraints constraints.Value | 67 Constraints constraints.Value |
68 } | 68 } |
69 | 69 |
70 type OpDestroy GenericOperation | 70 type OpDestroy GenericOperation |
71 | 71 |
72 type OpStartInstance struct { | 72 type OpStartInstance struct { |
73 » Env string | 73 » Env string |
74 » MachineId string | 74 » MachineId string |
75 » Instance environs.Instance | 75 » MachineNonce string |
76 » Constraints constraints.Value | 76 » Instance environs.Instance |
77 » Info *state.Info | 77 » Constraints constraints.Value |
78 » APIInfo *api.Info | 78 » Info *state.Info |
79 » Secret string | 79 » APIInfo *api.Info |
| 80 » Secret string |
80 } | 81 } |
81 | 82 |
82 type OpStopInstances struct { | 83 type OpStopInstances struct { |
83 Env string | 84 Env string |
84 Instances []environs.Instance | 85 Instances []environs.Instance |
85 } | 86 } |
86 | 87 |
87 type OpOpenPorts struct { | 88 type OpOpenPorts struct { |
88 Env string | 89 Env string |
89 MachineId string | 90 MachineId string |
(...skipping 27 matching lines...) Expand all Loading... |
117 type environState struct { | 118 type environState struct { |
118 name string | 119 name string |
119 ops chan<- Operation | 120 ops chan<- Operation |
120 mu sync.Mutex | 121 mu sync.Mutex |
121 maxId int // maximum instance id allocated so far. | 122 maxId int // maximum instance id allocated so far. |
122 insts map[state.InstanceId]*instance | 123 insts map[state.InstanceId]*instance |
123 globalPorts map[params.Port]bool | 124 globalPorts map[params.Port]bool |
124 firewallMode config.FirewallMode | 125 firewallMode config.FirewallMode |
125 bootstrapped bool | 126 bootstrapped bool |
126 storageDelay time.Duration | 127 storageDelay time.Duration |
127 » storage *memStorage | 128 » storage *storage |
128 » publicStorage *memStorage | 129 » publicStorage *storage |
129 httpListener net.Listener | 130 httpListener net.Listener |
130 apiServer *apiserver.Server | 131 apiServer *apiserver.Server |
131 apiState *state.State | 132 apiState *state.State |
132 } | 133 } |
133 | 134 |
134 // environ represents a client's connection to a given environment's | 135 // environ represents a client's connection to a given environment's |
135 // state. | 136 // state. |
136 type environ struct { | 137 type environ struct { |
137 state *environState | 138 state *environState |
138 ecfgMutex sync.Mutex | 139 ecfgMutex sync.Mutex |
139 ecfgUnlocked *environConfig | 140 ecfgUnlocked *environConfig |
140 } | 141 } |
141 | 142 |
142 // memStorage holds the storage for an environState. | 143 // storage holds the storage for an environState. |
143 // There are two instances for each environState | 144 // There are two instances for each environState |
144 // instance, one for public files and one for private. | 145 // instance, one for public files and one for private. |
145 type memStorage struct { | 146 type storage struct { |
146 path string // path prefix in http space. | 147 path string // path prefix in http space. |
147 state *environState | 148 state *environState |
148 files map[string][]byte | 149 files map[string][]byte |
149 poisoned map[string]error | 150 poisoned map[string]error |
150 } | 151 } |
151 | 152 |
152 // discardOperations discards all Operations written to it. | 153 // discardOperations discards all Operations written to it. |
153 var discardOperations chan<- Operation | 154 var discardOperations chan<- Operation |
154 | 155 |
155 func init() { | 156 func init() { |
(...skipping 155 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
311 | 312 |
312 func (p *environProvider) newConfig(cfg *config.Config) (*environConfig, error)
{ | 313 func (p *environProvider) newConfig(cfg *config.Config) (*environConfig, error)
{ |
313 valid, err := p.Validate(cfg, nil) | 314 valid, err := p.Validate(cfg, nil) |
314 if err != nil { | 315 if err != nil { |
315 return nil, err | 316 return nil, err |
316 } | 317 } |
317 return &environConfig{valid, valid.UnknownAttrs()}, nil | 318 return &environConfig{valid, valid.UnknownAttrs()}, nil |
318 } | 319 } |
319 | 320 |
320 func (p *environProvider) Validate(cfg, old *config.Config) (valid *config.Confi
g, err error) { | 321 func (p *environProvider) Validate(cfg, old *config.Config) (valid *config.Confi
g, err error) { |
| 322 // Check for valid changes for the base config values. |
| 323 if err := config.Validate(cfg, old); err != nil { |
| 324 return nil, err |
| 325 } |
321 v, err := checker.Coerce(cfg.UnknownAttrs(), nil) | 326 v, err := checker.Coerce(cfg.UnknownAttrs(), nil) |
322 if err != nil { | 327 if err != nil { |
323 return nil, err | 328 return nil, err |
324 } | 329 } |
| 330 // Apply the coerced unknown values back into the config. |
325 attrs := v.(map[string]interface{}) | 331 attrs := v.(map[string]interface{}) |
326 switch cfg.FirewallMode() { | |
327 case config.FwDefault: | |
328 attrs["firewall-mode"] = config.FwInstance | |
329 case config.FwInstance, config.FwGlobal: | |
330 default: | |
331 return nil, fmt.Errorf("unsupported firewall mode: %q", cfg.Fire
wallMode()) | |
332 } | |
333 return cfg.Apply(attrs) | 332 return cfg.Apply(attrs) |
334 } | 333 } |
335 | 334 |
336 func (p *environProvider) Open(cfg *config.Config) (environs.Environ, error) { | 335 func (p *environProvider) Open(cfg *config.Config) (environs.Environ, error) { |
337 p.mu.Lock() | 336 p.mu.Lock() |
338 defer p.mu.Unlock() | 337 defer p.mu.Unlock() |
339 name := cfg.Name() | 338 name := cfg.Name() |
340 ecfg, err := p.newConfig(cfg) | 339 ecfg, err := p.newConfig(cfg) |
341 if err != nil { | 340 if err != nil { |
342 return nil, err | 341 return nil, err |
(...skipping 184 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
527 if err := e.checkBroken("Destroy"); err != nil { | 526 if err := e.checkBroken("Destroy"); err != nil { |
528 return err | 527 return err |
529 } | 528 } |
530 e.state.mu.Lock() | 529 e.state.mu.Lock() |
531 defer e.state.mu.Unlock() | 530 defer e.state.mu.Unlock() |
532 e.state.ops <- OpDestroy{Env: e.state.name} | 531 e.state.ops <- OpDestroy{Env: e.state.name} |
533 e.state.destroy() | 532 e.state.destroy() |
534 return nil | 533 return nil |
535 } | 534 } |
536 | 535 |
537 func (e *environ) StartInstance(machineId string, series string, cons constraint
s.Value, info *state.Info, apiInfo *api.Info) (environs.Instance, error) { | 536 func (e *environ) StartInstance(machineId, machineNonce string, series string, c
ons constraints.Value, info *state.Info, apiInfo *api.Info) (environs.Instance,
error) { |
538 defer delay() | 537 defer delay() |
539 log.Infof("environs/dummy: dummy startinstance, machine %s", machineId) | 538 log.Infof("environs/dummy: dummy startinstance, machine %s", machineId) |
540 if err := e.checkBroken("StartInstance"); err != nil { | 539 if err := e.checkBroken("StartInstance"); err != nil { |
541 return nil, err | 540 return nil, err |
542 } | 541 } |
543 e.state.mu.Lock() | 542 e.state.mu.Lock() |
544 defer e.state.mu.Unlock() | 543 defer e.state.mu.Unlock() |
| 544 if machineNonce == "" { |
| 545 return nil, fmt.Errorf("cannot start instance: missing machine n
once") |
| 546 } |
545 if _, ok := e.Config().CACert(); !ok { | 547 if _, ok := e.Config().CACert(); !ok { |
546 return nil, fmt.Errorf("no CA certificate in environment configu
ration") | 548 return nil, fmt.Errorf("no CA certificate in environment configu
ration") |
547 } | 549 } |
548 if info.Tag != state.MachineTag(machineId) { | 550 if info.Tag != state.MachineTag(machineId) { |
549 return nil, fmt.Errorf("entity tag must match started machine") | 551 return nil, fmt.Errorf("entity tag must match started machine") |
550 } | 552 } |
551 if apiInfo.Tag != state.MachineTag(machineId) { | 553 if apiInfo.Tag != state.MachineTag(machineId) { |
552 return nil, fmt.Errorf("entity tag must match started machine") | 554 return nil, fmt.Errorf("entity tag must match started machine") |
553 } | 555 } |
554 if strings.HasPrefix(series, "unknown") { | 556 if strings.HasPrefix(series, "unknown") { |
555 return nil, &environs.NotFoundError{fmt.Errorf("no compatible to
ols found")} | 557 return nil, &environs.NotFoundError{fmt.Errorf("no compatible to
ols found")} |
556 } | 558 } |
557 i := &instance{ | 559 i := &instance{ |
558 state: e.state, | 560 state: e.state, |
559 id: state.InstanceId(fmt.Sprintf("%s-%d", e.state.name, e
.state.maxId)), | 561 id: state.InstanceId(fmt.Sprintf("%s-%d", e.state.name, e
.state.maxId)), |
560 ports: make(map[params.Port]bool), | 562 ports: make(map[params.Port]bool), |
561 machineId: machineId, | 563 machineId: machineId, |
562 series: series, | 564 series: series, |
563 } | 565 } |
564 e.state.insts[i.id] = i | 566 e.state.insts[i.id] = i |
565 e.state.maxId++ | 567 e.state.maxId++ |
566 e.state.ops <- OpStartInstance{ | 568 e.state.ops <- OpStartInstance{ |
567 » » Env: e.state.name, | 569 » » Env: e.state.name, |
568 » » MachineId: machineId, | 570 » » MachineId: machineId, |
569 » » Constraints: cons, | 571 » » MachineNonce: machineNonce, |
570 » » Instance: i, | 572 » » Constraints: cons, |
571 » » Info: info, | 573 » » Instance: i, |
572 » » APIInfo: apiInfo, | 574 » » Info: info, |
573 » » Secret: e.ecfg().secret(), | 575 » » APIInfo: apiInfo, |
| 576 » » Secret: e.ecfg().secret(), |
574 } | 577 } |
575 return i, nil | 578 return i, nil |
576 } | 579 } |
577 | 580 |
578 func (e *environ) StopInstances(is []environs.Instance) error { | 581 func (e *environ) StopInstances(is []environs.Instance) error { |
579 defer delay() | 582 defer delay() |
580 if err := e.checkBroken("StopInstance"); err != nil { | 583 if err := e.checkBroken("StopInstance"); err != nil { |
581 return err | 584 return err |
582 } | 585 } |
583 e.state.mu.Lock() | 586 e.state.mu.Lock() |
(...skipping 182 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
766 // time.Durations into this value. | 769 // time.Durations into this value. |
767 var providerDelay time.Duration | 770 var providerDelay time.Duration |
768 | 771 |
769 // pause execution to simulate the latency of a real provider | 772 // pause execution to simulate the latency of a real provider |
770 func delay() { | 773 func delay() { |
771 if providerDelay > 0 { | 774 if providerDelay > 0 { |
772 log.Infof("environs/dummy: pausing for %v", providerDelay) | 775 log.Infof("environs/dummy: pausing for %v", providerDelay) |
773 <-time.After(providerDelay) | 776 <-time.After(providerDelay) |
774 } | 777 } |
775 } | 778 } |
LEFT | RIGHT |