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

Delta Between Two Patch Sets: state/unit.go

Issue 5727045: Continuation of the unit state implementation. (Closed)
Left Patch Set: Continuation of the unit state implementation. Created 12 years ago
Right Patch Set: Continuation of the unit state implementation. Created 12 years 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:
Left: Side by side diff | Download
Right: Side by side diff | Download
« no previous file with change/comment | « state/state_test.go ('k') | no next file » | no next file with change/comment »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
LEFTRIGHT
1 // launchpad.net/juju/state
2 //
3 // Copyright (c) 2011-2012 Canonical Ltd.
4
5 package state
6
7 import ( 1 import (
8 "errors" 2 "errors"
9 "fmt" 3 "fmt"
10 "launchpad.net/goyaml"
11 "launchpad.net/gozk/zookeeper" 4 "launchpad.net/gozk/zookeeper"
12 "launchpad.net/juju/go/charm" 5 "launchpad.net/juju/go/charm"
13 "strconv" 6 "strconv"
14 "strings" 7 "strings"
15 ) 8 )
16 9
17 // ResolvedMode describes the way state transition errors·
18 // are resolved.·
19 type ResolvedMode int
20
21 const (
22 ResolvedNone ResolvedMode = 0
23 ResolvedRetryHooks ResolvedMode = 1000
24 ResolvedNoHooks ResolvedMode = 1001
25 )
26
27 // Port identifies a network port number for a particular protocol.
28 type Port struct {
29 Protocol string `yaml:"proto"`
30 Number int `yaml:"port"`
31 }
32
33 // Unit represents the state of a service unit. 10 // Unit represents the state of a service unit.
34 type Unit struct { 11 type Unit struct {
35 » st *State 12 » zk *zookeeper.Conn
36 key string 13 key string
37 serviceKey string 14 serviceKey string
38 serviceName string 15 serviceName string
39 sequenceNo int
40 }
41
42 // ServiceName returns the service name.
43 func (u *Unit) ServiceName() string {
44 return u.serviceName
45 }
46
47 // Name returns the unit name.
48 func (u *Unit) Name() string {
49 return fmt.Sprintf("%s/%d", u.serviceName, u.sequenceNo)
50 }
51
52 // PublicAddress returns the public address of the unit.
53 func (u *Unit) PublicAddress() (string, error) {
54 cn, err := readConfigNode(u.st.zk, u.zkPath())
55 if err != nil {
56 return "", err
57 }
58 if address, ok := cn.Get("public-address"); ok {
59 return address.(string), nil
60 }
61 return "", errors.New("unit has no public address")
62 }
63
64 // SetPublicAddress sets the public address of the unit.
65 func (u *Unit) SetPublicAddress(address string) error {
66 cn, err := readConfigNode(u.st.zk, u.zkPath())
67 if err != nil {
68 return err
69 }
70 cn.Set("public-address", address)
71 _, err = cn.Write()
72 if err != nil {
73 return err
74 }
75 return nil
76 }
77
78 // PrivateAddress returns the private address of the unit.
79 func (u *Unit) PrivateAddress() (string, error) {
80 cn, err := readConfigNode(u.st.zk, u.zkPath())
81 if err != nil {
82 return "", err
83 }
84 if address, ok := cn.Get("private-address"); ok {
85 return address.(string), nil
86 }
87 return "", errors.New("unit has no private address")
88 }
89
90 // SetPrivateAddress sets the private address of the unit.
91 func (u *Unit) SetPrivateAddress(address string) error {
92 cn, err := readConfigNode(u.st.zk, u.zkPath())
93 if err != nil {
94 return err
95 }
96 cn.Set("private-address", address)
97 _, err = cn.Write()
98 if err != nil {
99 return err
100 }
101 return nil
102 }
103
104 // CharmURL returns the charm URL this unit is supposed
105 // to use.
106 func (u *Unit) CharmURL() (url *charm.URL, err error) {
107 cn, err := readConfigNode(u.st.zk, u.zkPath())
108 if err != nil {
109 return nil, err
110 }
111 if id, ok := cn.Get("charm"); ok {
112 url, err = charm.ParseURL(id.(string))
113 if err != nil {
114 return nil, err
115 }
116 return url, nil
117 }
118 return nil, errors.New("unit has no charm URL")
119 }
120
121 // SetCharmURL changes the charm URL for the unit.
122 func (u *Unit) SetCharmURL(url *charm.URL) error {
123 cn, err := readConfigNode(u.st.zk, u.zkPath())
124 if err != nil {
125 return err
126 }
127 cn.Set("charm", url.String())
128 _, err = cn.Write()
129 if err != nil {
130 return err
131 }
132 return nil
133 }
134
135 // AssignedMachineId returns the id of the assigned machine.
136 func (u *Unit) AssignedMachineId() (int, error) {
137 topology, err := readTopology(u.st.zk)
138 if err != nil {
139 return 0, err
140 }
141 if !topology.HasService(u.serviceKey) || !topology.HasUnit(u.serviceKey, u.key) {
142 return 0, stateChanged
143 }
144 machineKey, err := topology.UnitMachineKey(u.serviceKey, u.key)
145 if err != nil {
146 return 0, err
147 }
148 return machineId(machineKey), nil
149 }
150
151 // AssignToMachine assigns this unit to a given machine.
152 func (u *Unit) AssignToMachine(machine *Machine) error {
153 assignUnit := func(t *topology) error {
154 if !t.HasService(u.serviceKey) || !t.HasUnit(u.serviceKey, u.key ) {
155 return stateChanged
156 }
157 machineKey, err := t.UnitMachineKey(u.serviceKey, u.key)
158 if err == unitNotAssigned {
159 return t.AssignUnitToMachine(u.serviceKey, u.key, machin e.key)
160 } else if err != nil {
161 return err
162 } else if machineKey == machine.key {
163 // Everything is fine, it's already assigned.
164 return nil
165 }
166 return fmt.Errorf("unit %q already assigned to machine %d", u.Na me(), machineId(machineKey))
167 }
168 return retryTopologyChange(u.st.zk, assignUnit)
169 }
170
171 // AssignToUnusedMachine assigns u to a machine without other units.
172 // If there are no unused machines besides machine 0, an error is returned.
173 func (u *Unit) AssignToUnusedMachine() (*Machine, error) {
174 machineKey := ""
175 assignUnusedUnit := func(t *topology) error {
176 if !t.HasService(u.serviceKey) || !t.HasUnit(u.serviceKey, u.key ) {
177 return stateChanged
178 }
179 for _, machineKey = range t.MachineKeys() {
180 if machineId(machineKey) != 0 {
181 hasUnits, err := t.MachineHasUnits(machineKey)
182 if err != nil {
183 return err
184 }
185 if !hasUnits {
186 break
187 }
188 }
189 // Reset machine key.
190 machineKey = ""
191 }
192 if machineKey == "" {
193 return errors.New("no unused machine found")
194 }
195 if err := t.AssignUnitToMachine(u.serviceKey, u.key, machineKey) ; err != nil {
196 return err
197 }
198 return nil
199 }
200 if err := retryTopologyChange(u.st.zk, assignUnusedUnit); err != nil {
201 return nil, err
202 }
203 return &Machine{u.st, machineKey}, nil
204 }
205
206 // UnassignFromMachine removes the assignment between this unit and
207 // the machine it's assigned to.
208 func (u *Unit) UnassignFromMachine() error {
209 unassignUnit := func(t *topology) error {
210 if !t.HasService(u.serviceKey) || !t.HasUnit(u.serviceKey, u.key ) {
211 return stateChanged
212 }
213 // If for whatever reason it's already not assigned to a
214 // machine, ignore it and move forward so that we don't
215 // have to deal with conflicts.
216 key, err := t.UnitMachineKey(u.serviceKey, u.key)
217 if err == nil && key != "" {
218 t.UnassignUnitFromMachine(u.serviceKey, u.key)
219 }
220 return nil
221 }
222 return retryTopologyChange(u.st.zk, unassignUnit)
223 }
224
225 // NeedsUpgrade returns whether the unit needs an upgrade.
226 func (u *Unit) NeedsUpgrade() (bool, error) {
227 stat, err := u.st.zk.Exists(u.zkNeedsUpgradePath())
228 if err != nil {
229 return false, err
230 }
231 return stat != nil, nil
232 }
233
234 // SetNeedsUpgrade informs the unit that it should perform an upgrade.
235 func (u *Unit) SetNeedsUpgrade() error {
236 _, err := u.st.zk.Create(u.zkNeedsUpgradePath(), "", 0, zkPermAll)
237 if err == zookeeper.ZNODEEXISTS {
238 // Node already exists, so same state.
239 return nil
240 }
241 return err
242 }
243
244 // ClearNeedsUpgrade resets the upgrade notification. It is typically
245 // done by the unit agent before beginning the upgrade.
246 func (u *Unit) ClearNeedsUpgrade() error {
247 err := u.st.zk.Delete(u.zkNeedsUpgradePath(), -1)
248 if err == zookeeper.ZNONODE {
249 // Node doesn't exist, so same state.
250 return nil
251 }
252 return err
253 }
254
255 // Resolved returns the value of the resolved setting if any.
256 func (u *Unit) Resolved() (ResolvedMode, error) {
257 yaml, _, err := u.st.zk.Get(u.zkResolvedPath())
258 if err == zookeeper.ZNONODE {
259 // Default value.
260 return ResolvedNone, nil
261 }
262 if err != nil {
263 return ResolvedNone, err
264 }
265 setting := &struct{ Retry ResolvedMode }{}
266 if err = goyaml.Unmarshal([]byte(yaml), setting); err != nil {
267 return ResolvedNone, err
268 }
269 mode := setting.Retry
270 if err := validResolvedMode(mode); err != nil {
271 return ResolvedNone, err
272 }
273 return mode, nil
274 }
275
276 // SetResolved marks the unit as having had any previous state
277 // transition problems resolved, and informs the unit that it may
278 // attempt to reestablish normal workflow.
279 // The resolved mode parameter informs whether to attempt to·
280 // reexecute previous failed hooks or to continue as if they had·
281 // succeeded before.
282 func (u *Unit) SetResolved(mode ResolvedMode) error {
283 if err := validResolvedMode(mode); err != nil {
284 return err
285 }
286 setting := &struct{ Retry ResolvedMode }{mode}
287 yaml, err := goyaml.Marshal(setting)
288 if err != nil {
289 return err
290 }
291 _, err = u.st.zk.Create(u.zkResolvedPath(), string(yaml), 0, zkPermAll)
292 if err == zookeeper.ZNODEEXISTS {
293 return fmt.Errorf("unit %q resolved flag already set", u.Name())
294 }
295 return err
296 }
297
298 // ClearResolved removes any resolved setting on the unit.
299 func (u *Unit) ClearResolved() error {
300 err := u.st.zk.Delete(u.zkResolvedPath(), -1)
301 if err == zookeeper.ZNONODE {
302 // Node doesn't exist, so same state.
303 return nil
304 }
305 return err
306 }
307
308 // OpenPort sets the policy of the port with protocol and number to be opened.
309 func (u *Unit) OpenPort(protocol string, number int) error {
310 openPort := func(oldYaml string, stat *zookeeper.Stat) (string, error) {
311 ports := &struct{ Open []Port }{}
312 if oldYaml != "" {
313 if err := goyaml.Unmarshal([]byte(oldYaml), ports); err != nil {
314 return "", err
315 }
316 }
317 portToOpen := Port{protocol, number}
318 found := false
319 for _, openPort := range ports.Open {
320 if openPort == portToOpen {
321 found = true
322 break
323 }
324 }
325 if !found {
326 ports.Open = append(ports.Open, portToOpen)
327 }
328 newYaml, err := goyaml.Marshal(ports)
329 if err != nil {
330 return "", err
331 }
332 return string(newYaml), nil
333 }
334 return u.st.zk.RetryChange(u.zkPortsPath(), 0, zkPermAll, openPort)
335 }
336
337 // ClosePort sets the policy of the port with protocol and number to be closed.
338 func (u *Unit) ClosePort(protocol string, number int) error {
339 closePort := func(oldYaml string, stat *zookeeper.Stat) (string, error) {
340 ports := &struct{ Open []Port }{}
341 if oldYaml != "" {
342 if err := goyaml.Unmarshal([]byte(oldYaml), ports); err != nil {
343 return "", err
344 }
345 }
346 portToClose := Port{protocol, number}
347 newOpenPorts := []Port{}
348 for _, oldOpenPort := range ports.Open {
349 if oldOpenPort != portToClose {
350 newOpenPorts = append(newOpenPorts, oldOpenPort)
351 }
352 }
353 ports.Open = newOpenPorts
354 newYaml, err := goyaml.Marshal(ports)
355 if err != nil {
356 return "", err
357 }
358 return string(newYaml), nil
359 }
360 return u.st.zk.RetryChange(u.zkPortsPath(), 0, zkPermAll, closePort)
361 }
362
363 // OpenPorts returns a slice containing the open ports of the unit.
364 func (u *Unit) OpenPorts() ([]Port, error) {
365 yaml, _, err := u.st.zk.Get(u.zkPortsPath())
366 if err == zookeeper.ZNONODE {
367 // Default value.
368 return nil, nil
369 }
370 if err != nil {
371 return nil, err
372 }
373 ports := &struct{ Open []Port }{}
374 if err = goyaml.Unmarshal([]byte(yaml), &ports); err != nil {
375 return nil, err
376 }
377 return ports.Open, nil
378 }
379
380 // zkKey returns the ZooKeeper key of the unit.
381 func (u *Unit) zkKey() string {
382 return u.key
383 }
384
385 // zkPath returns the ZooKeeper base path for the unit.
386 func (u *Unit) zkPath() string {
387 return fmt.Sprintf("/units/%s", u.key)
388 }
389
390 // zkPortsPath returns the ZooKeeper path for the open ports.
391 func (u *Unit) zkPortsPath() string {
392 return fmt.Sprintf("/units/%s/ports", u.key)
393 }
394
395 // zkAgentPath returns the ZooKeeper path for the unit agent.
396 func (u *Unit) zkAgentPath() string {
397 return fmt.Sprintf("/units/%s/agent", u.key)
398 }
399
400 // zkNeedsUpgradePath returns the ZooKeeper path for the upgrade flag.
401 func (u *Unit) zkNeedsUpgradePath() string {
402 return fmt.Sprintf("/units/%s/upgrade", u.key)
403 }
404
405 // zkResolvedPath returns the ZooKeeper path for the mark to resolve a unit.
406 func (u *Unit) zkResolvedPath() string {
407 return fmt.Sprintf("/units/%s/resolved", u.key)
408 }
409
410 // parseUnitName parses a unit name like "wordpress/0" into
411 // its service name and sequence number parts.
412 func parseUnitName(name string) (serviceName string, seqNo int, err error) {
413 parts := strings.Split(name, "/")
414 if len(parts) != 2 {
415 return "", 0, fmt.Errorf("%q is not a valid unit name", name)
416 }
417 sequenceNo, err := strconv.ParseInt(parts[1], 10, 0)
418 if err != nil {
419 return "", 0, err
420 }
421 return parts[0], int(sequenceNo), nil
422 }
423
424 // validResolvedMode ensures that only valid values for the
425 // resolved mode are used.
426 func validResolvedMode(mode ResolvedMode) error {
427 if mode != ResolvedRetryHooks && mode != ResolvedNoHooks {
428 return fmt.Errorf("invalid error resolution mode: %d", mode)
429 }
430 return nil
431 }
LEFTRIGHT

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