Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code | Sign in
(12)

Side by Side Diff: cmd/jujud/provisioning.go

Issue 6250068: cmd/jujud: strawman provisioning agent (Closed)
Patch Set: cmd/jujud: strawman provisioning agent Created 12 years, 9 months ago
Left:
Right:
Use n/p to move between diff chunks; N/P to move between comments. Please Sign in to add in-line comments.
Jump to:
View unified diff | Download patch
« no previous file with comments | « cmd/jujud/export_test.go ('k') | cmd/jujud/provisioning_test.go » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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) {}
OLDNEW
« no previous file with comments | « cmd/jujud/export_test.go ('k') | cmd/jujud/provisioning_test.go » ('j') | no next file with comments »

Powered by Google App Engine
RSS Feeds Recent Issues | This issue
This is Rietveld f62528b