Left: | ||
Right: |
OLD | NEW |
---|---|
1 package main | 1 package main |
2 | 2 |
3 import ( | 3 import ( |
4 "fmt" | |
5 "launchpad.net/gnuflag" | 4 "launchpad.net/gnuflag" |
6 "launchpad.net/juju/go/cmd" | 5 "launchpad.net/juju/go/cmd" |
6 "launchpad.net/juju/go/environs" | |
7 "launchpad.net/juju/go/log" | |
8 "launchpad.net/juju/go/state" | |
9 "launchpad.net/tomb" | |
10 | |
11 // register providers | |
12 _ "launchpad.net/juju/go/environs/dummy" | |
13 _ "launchpad.net/juju/go/environs/ec2" | |
7 ) | 14 ) |
8 | 15 |
9 // ProvisioningAgent is a cmd.Command responsible for running a provisioning age nt. | 16 // ProvisioningAgent is a cmd.Command responsible for running a provisioning age nt. |
10 type ProvisioningAgent struct { | 17 type ProvisioningAgent struct { |
11 Conf AgentConf | 18 Conf AgentConf |
12 } | 19 } |
13 | 20 |
14 // Info returns usage information for the command. | 21 // Info returns usage information for the command. |
15 func (a *ProvisioningAgent) Info() *cmd.Info { | 22 func (a *ProvisioningAgent) Info() *cmd.Info { |
16 return &cmd.Info{"provisioning", "", "run a juju provisioning agent", "" } | 23 return &cmd.Info{"provisioning", "", "run a juju provisioning agent", "" } |
17 } | 24 } |
18 | 25 |
19 // Init initializes the command for running. | 26 // Init initializes the command for running. |
20 func (a *ProvisioningAgent) Init(f *gnuflag.FlagSet, args []string) error { | 27 func (a *ProvisioningAgent) Init(f *gnuflag.FlagSet, args []string) error { |
21 a.Conf.addFlags(f) | 28 a.Conf.addFlags(f) |
22 if err := f.Parse(true, args); err != nil { | 29 if err := f.Parse(true, args); err != nil { |
23 return err | 30 return err |
24 } | 31 } |
25 return a.Conf.checkArgs(f.Args()) | 32 return a.Conf.checkArgs(f.Args()) |
26 } | 33 } |
27 | 34 |
28 // Run runs a provisioning agent. | 35 // Run runs a provisioning agent. |
29 func (a *ProvisioningAgent) Run(_ *cmd.Context) error { | 36 func (a *ProvisioningAgent) Run(_ *cmd.Context) error { |
30 » return fmt.Errorf("MachineAgent.Run not implemented") | 37 » st, err := state.Open(&a.Conf.StateInfo) |
niemeyer
2012/05/31 11:46:59
What happens if the connection is broken? We'll ne
dave_cheney.net
2012/05/31 22:40:03
I have been operating under the assumption (I thin
dave_cheney.net
2012/06/01 01:58:27
I looked into this more this morning and it looks
niemeyer
2012/06/04 23:22:23
We've covered this on juju-dev@. A TODO would be g
| |
38 » if err != nil { | |
39 » » return err | |
40 » } | |
41 » p := NewProvisioner(st) | |
42 » return p.tomb.Wait() | |
31 } | 43 } |
44 | |
45 type Provisioner struct { | |
46 st *state.State | |
47 environ environs.Environ | |
48 tomb tomb.Tomb | |
49 | |
50 environment | |
51 machines | |
52 } | |
53 | |
54 // environment ensures that the watcher for the environ | |
55 // configuration is valid. | |
56 type environment struct { | |
niemeyer
2012/05/31 11:46:59
Those two types feel unnecessary. It looks like yo
dave_cheney.net
2012/05/31 22:40:03
This was an indulgence. I am besotted with the abi
| |
57 st *state.State | |
58 watcher *state.ConfigWatcher | |
59 } | |
60 | |
61 // changes returns a channel that will receive the new *ConfigNode when a | |
62 // change is detected.· | |
63 func (e *environment) changes() <-chan *state.ConfigNode { | |
64 if e.watcher == nil { | |
65 e.watcher = e.st.WatchEnvironConfig() | |
66 } | |
67 return e.watcher.Changes() | |
68 } | |
69 | |
70 // invalidate stops the current watcher. | |
71 func (e *environment) invalidate() { | |
niemeyer
2012/05/31 11:46:59
This should return the error it finds. Call sites
dave_cheney.net
2012/05/31 22:40:03
Done.
| |
72 if e.watcher != nil { | |
73 log.Printf("provisioner: environment watcher exited: %v", e.watc her.Stop()) | |
niemeyer
2012/05/31 11:46:59
That Stop call is the most critical task done by t
dave_cheney.net
2012/05/31 22:40:03
Done.
| |
74 } | |
75 e.watcher = nil | |
76 } | |
77 | |
78 // machines ensures that the watcher for machines changes | |
79 // is valid. | |
80 type machines struct { | |
81 st *state.State | |
82 watcher *state.MachinesWatcher | |
83 } | |
84 | |
85 // changes returns a channel that will receive the new *ConfigNode when a | |
86 // change is detected.· | |
87 func (m *machines) changes() <-chan *state.MachinesChange { | |
88 if m.watcher == nil { | |
89 m.watcher = m.st.WatchMachines() | |
90 } | |
91 return m.watcher.Changes() | |
92 } | |
93 | |
94 // invalidate stops the current watcher. | |
95 func (m *machines) invalidate() { | |
96 if m.watcher != nil { | |
97 log.Printf("provisioner: machines watcher exited: %v", m.watcher .Stop()) | |
98 } | |
99 m.watcher = nil | |
100 } | |
101 | |
102 // NewProvisioner returns a Provisioner. | |
103 func NewProvisioner(st *state.State) *Provisioner { | |
104 p := &Provisioner{ | |
105 st: st, | |
106 environment: environment{st: st}, | |
107 machines: machines{st: st}, | |
108 } | |
109 go p.loop() | |
110 return p | |
111 } | |
112 | |
113 func (p *Provisioner) loop() { | |
114 defer p.tomb.Done() | |
115 for { | |
116 select { | |
117 case <-p.tomb.Dying(): | |
118 return | |
119 case config, ok := <-p.environment.changes(): | |
120 if !ok { | |
121 p.environment.invalidate() | |
122 continue | |
123 } | |
124 var err error | |
125 p.environ, err = environs.NewEnviron(config.Map()) | |
126 if err != nil { | |
127 log.Printf("provisioner: unable to create enviro nment from supplied configuration: %v", err) | |
128 continue | |
129 } | |
130 log.Printf("provisioning: valid environment configured") | |
131 p.innerLoop() | |
132 } | |
133 } | |
134 } | |
135 | |
136 func (p *Provisioner) innerLoop() { | |
niemeyer
2012/05/31 11:46:59
Nice organization.
dave_cheney.net
2012/05/31 22:40:03
Thank you. As much as I would like to have only on
| |
137 for { | |
138 select { | |
139 case <-p.tomb.Dying(): | |
140 return | |
141 case change, ok := <-p.environment.changes(): | |
142 if !ok { | |
143 p.environment.invalidate() | |
144 continue | |
145 } | |
146 config, err := environs.NewConfig(change.Map()) | |
147 if err != nil { | |
148 log.Printf("provisioning: new configuration rece ived, but was not valid: %v", err) | |
149 continue | |
150 } | |
151 p.environ.SetConfig(config) | |
152 log.Printf("provisioning: new configuartion applied") | |
niemeyer
2012/05/31 11:46:59
s/configuartion/environment configuration/ (note t
dave_cheney.net
2012/05/31 22:40:03
Done.
| |
153 case machines, ok := <-p.machines.changes(): | |
154 if !ok { | |
155 p.machines.invalidate() | |
156 continue | |
157 } | |
158 p.processMachines(machines) | |
159 } | |
niemeyer
2012/05/31 11:46:59
I'm wondering if rather than "continue" in the pro
dave_cheney.net
2012/05/31 22:40:03
At the moment, by my reading, a watcher is always
| |
160 } | |
161 } | |
162 | |
163 // Stop stops the Provisioner and returns any error encountered while | |
164 // provisioning. | |
165 func (p *Provisioner) Stop() error { | |
166 p.tomb.Kill(nil) | |
167 p.environment.invalidate() | |
niemeyer
2012/05/31 11:46:59
I suggest logic like this here:
p.tomb.Kill(nil)
dave_cheney.net
2012/05/31 22:40:03
SGTM. I'm never sure how to merge several error va
| |
168 p.machines.invalidate() | |
169 return p.tomb.Wait() | |
170 } | |
171 | |
172 func (p *Provisioner) processMachines(changes *state.MachinesChange) {} | |
OLD | NEW |