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

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

Issue 6250068: cmd/jujud: strawman provisioning agent (Closed)
Patch Set: cmd/jujud: strawman provisioning agent Created 11 years, 10 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
OLDNEW
1 package main 1 package main
2 2
3 import ( 3 import (
4 "fmt" 4 "fmt"
5
5 "launchpad.net/gnuflag" 6 "launchpad.net/gnuflag"
6 "launchpad.net/juju/go/cmd" 7 "launchpad.net/juju/go/cmd"
8 "launchpad.net/juju/go/environs"
9 "launchpad.net/juju/go/log"
10 "launchpad.net/juju/go/state"
11
12 // register providers
13 _ "launchpad.net/juju/go/environs/dummy"
14 _ "launchpad.net/juju/go/environs/ec2"
7 ) 15 )
8 16
17 const PROVIDER_MACHINE_ID = "provider-machine-id"
niemeyer 2012/05/30 21:09:21 providerMachineId would be the convention, I think
dfc 2012/05/31 07:10:01 Done.
18
9 // ProvisioningAgent is a cmd.Command responsible for running a provisioning age nt. 19 // ProvisioningAgent is a cmd.Command responsible for running a provisioning age nt.
10 type ProvisioningAgent struct { 20 type ProvisioningAgent struct {
11 » Conf AgentConf 21 » Conf AgentConf
22 » environ environs.Environ // the provider this agent operates against.
23 » State *state.State
24
25 » providerIdToInstance map[string]environs.Instance
26 » machineIdToProviderId map[int]string
27 }
28
29 func NewProvisioningAgent() *ProvisioningAgent {
30 » return &ProvisioningAgent{
31 » » providerIdToInstance: make(map[string]environs.Instance),
32 » » machineIdToProviderId: make(map[int]string),
33 » }
12 } 34 }
13 35
14 // Info returns usage information for the command. 36 // Info returns usage information for the command.
15 func (a *ProvisioningAgent) Info() *cmd.Info { 37 func (a *ProvisioningAgent) Info() *cmd.Info {
16 return &cmd.Info{"provisioning", "", "run a juju provisioning agent", "" } 38 return &cmd.Info{"provisioning", "", "run a juju provisioning agent", "" }
17 } 39 }
18 40
19 // Init initializes the command for running. 41 // Init initializes the command for running.
20 func (a *ProvisioningAgent) Init(f *gnuflag.FlagSet, args []string) error { 42 func (a *ProvisioningAgent) Init(f *gnuflag.FlagSet, args []string) error {
21 a.Conf.addFlags(f) 43 a.Conf.addFlags(f)
22 if err := f.Parse(true, args); err != nil { 44 if err := f.Parse(true, args); err != nil {
23 return err 45 return err
24 } 46 }
25 return a.Conf.checkArgs(f.Args()) 47 return a.Conf.checkArgs(f.Args())
26 } 48 }
27 49
28 // Run runs a provisioning agent. 50 // Run runs a provisioning agent.
29 func (a *ProvisioningAgent) Run(_ *cmd.Context) error { 51 func (a *ProvisioningAgent) Run(_ *cmd.Context) error {
30 » return fmt.Errorf("MachineAgent.Run not implemented") 52 » var err error
53 » a.State, err = state.Open(&a.Conf.StateInfo)
niemeyer 2012/05/30 21:27:20 This is a rather extensive function that might be
54 » if err != nil {
55 » » return err
56 » }
57
58 » // step 1. wait for a valid environment
59 » configWatcher := a.State.WatchEnvironConfig()
60 » for {
61 » » log.Printf("provisioning: waiting for valid environment")
62 » » config, ok := <-configWatcher.Changes()
63 » » if !ok {
64 » » » return fmt.Errorf("environment watcher has shutdown: %v" , configWatcher.Stop())
65 » » }
66 » » var err error
67 » » a.environ, err = environs.NewEnviron(config.Map())
68 » » if err == nil {
69 » » » break
70 » » }
71 » » log.Printf("provisioning: unable to create environment from supp lied configuration: %v", err)
72 » }
73 » log.Printf("provisioning: valid environment configured")
74
75 » // step 2. listen for changes to the environment or the machine topology and action both.
niemeyer 2012/05/30 21:27:20 Step 1 needs to be able to be more resilient, and
dfc 2012/05/31 07:10:01 Understood, will redo. On 2012/05/30 21:27:20, ni
76 » machinesWatcher := a.State.WatchMachines()
77 » for {
78 » » select {
79 » » case changes, ok := <-configWatcher.Changes():
80 » » » if !ok {
81 » » » » return fmt.Errorf("environment watcher has shutd own: %v", configWatcher.Stop())
82 » » » }
83 » » » config, err := environs.NewConfig(changes.Map())
84 » » » if err != nil {
85 » » » » log.Printf("provisioning: new configuration rece ived, but was not valid: %v", err)
86 » » » » continue
87 » » » }
88 » » » a.environ.SetConfig(config)
89 » » » log.Printf("provisioning: new configuartion applied")
90 » » case changes, ok := <-machinesWatcher.Changes():
91 » » » if !ok {
92 » » » » return fmt.Errorf("machines watcher has shutdown : %v", configWatcher.Stop())
93 » » » }
94 » » » for _, added := range changes.Added {
95 » » » » if err := a.addMachine(added); err != nil {
96 » » » » » // TODO(dfc) implement retry logic
97 » » » » » return err
98 » » » » }
99 » » » » log.Printf("provisioning: machine %d added", add ed.Id())
100 » » » }
101 » » » for _, deleted := range changes.Deleted {
102 » » » » if err := a.deleteMachine(deleted); err != nil {
103 » » » » » // TODO(dfc) implement retry logic
104 » » » » » return err
105 » » » » }
106 » » » » log.Printf("provisioning: machine %d deleted", d eleted.Id())
107 » » » }
108 » » }
109 » }
110 » if err = configWatcher.Stop(); err == nil {
111 » » err = machinesWatcher.Stop()
112 » }
113 » return err
31 } 114 }
115
116 func (a *ProvisioningAgent) addMachine(m *state.Machine) error {
117 id, err := m.InstanceId()
118 if err != nil {
119 return err
120 }
121 if id != "" {
122 return fmt.Errorf("machine-%010d already reports a provider id % q, skipping", m.Id(), id)
niemeyer 2012/05/30 21:27:20 We should never talk about internal ZooKeeper keys
dfc 2012/05/31 07:10:01 I think it is time that state.Machine grows a Stri
123 }
124
125 // TODO(dfc) the state.Info passed to environ.StartInstance remains cont entious
126 // however as the PA only knows one state.Info, and that info is used by MAs and·
127 // UAs to locate the ZK for this environment, it is logical to use the s ame·
128 // state.Info as the PA.·
129 inst, err := a.environ.StartInstance(m.Id(), &a.Conf.StateInfo)
130 if err != nil {
131 return err
132 }
133
134 // store the reference from the provider in ZK
niemeyer 2012/05/30 21:27:20 Let's please not reference ZooKeeper all the time.
dfc 2012/05/31 07:10:01 Done.
135 if err := m.SetInstanceId(inst.Id()); err != nil {
136 return fmt.Errorf("unable to store provider id: %v", err)
137 }
138
139 // data is stashed in ZK, populate the caches
140 a.machineIdToProviderId[m.Id()] = inst.Id()
141 a.providerIdToInstance[inst.Id()] = inst
142 return nil
143 }
144
145 func (a *ProvisioningAgent) deleteMachine(m *state.Machine) error {
146 insts, err := a.InstancesForMachines(m)
147 if err != nil {
148 return fmt.Errorf("machine-%010d has no refrence to a provider i d, skipping", m.Id())
149 }
150 return a.environ.StopInstances(insts)
151 }
152
153 // InstanceForMachine returns the environs.Instance that represents this machine s' running
154 // instance.
155 func (a *ProvisioningAgent) InstanceForMachine(m *state.Machine) (environs.Insta nce, error) {
156 id, ok := a.machineIdToProviderId[m.Id()]
157 if !ok {
158 // not cached locally, ask the provider.
159 var err error
160 id, err = m.InstanceId()
161 if err != nil {
162 return nil, err
163 }
164 if id == "" {
165 // nobody knows about this machine, give up.
166 return nil, fmt.Errorf("instance not found")
167 }
168 a.machineIdToProviderId[m.Id()] = id
169 }
170 inst, ok := a.providerIdToInstance[id]
171 if !ok {
172 // not cached locally, ask the provider
173 var err error
174 inst, err = a.findInstance(id)
175 if err != nil {
176 // the provider doesn't know about this instance, give u p.
177 return nil, err
178 }
179 return nil, nil
180 }
181 return inst, nil
182 }
183
184 // InstancesForMachines returns a list of environs.Instance that represent the l ist of machines running
185 // in the provider.
186 func (a *ProvisioningAgent) InstancesForMachines(machines ...*state.Machine) ([] environs.Instance, error) {
187 var insts []environs.Instance
188 for _, m := range machines {
189 inst, err := a.InstanceForMachine(m)
190 if err != nil {
191 return nil, err
192 }
193 insts = append(insts, inst)
194 }
195 return insts, nil
196 }
197
198 func (a *ProvisioningAgent) findInstance(id string) (environs.Instance, error) {
199 insts, err := a.environ.Instances([]string{id})
200 if err != nil {
201 return nil, err
202 }
203 if len(insts) < 1 {
204 return nil, fmt.Errorf("instance not found")
205 }
206 return insts[0], nil
207 }
OLDNEW

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