Left: | ||
Right: |
OLD | NEW |
---|---|
1 // The state package enables reading, observing, and changing | 1 // The state package enables reading, observing, and changing |
2 // the state stored in ZooKeeper of a whole environment | 2 // the state stored in ZooKeeper of a whole environment |
3 // managed by juju. | 3 // managed by juju. |
4 package state | 4 package state |
5 | 5 |
6 import ( | 6 import ( |
7 "fmt" | 7 "fmt" |
8 "launchpad.net/goyaml" | 8 "launchpad.net/goyaml" |
9 "launchpad.net/gozk/zookeeper" | 9 "launchpad.net/gozk/zookeeper" |
10 "launchpad.net/juju-core/juju/charm" | 10 "launchpad.net/juju-core/juju/charm" |
11 "net/url" | 11 "net/url" |
12 "strings" | 12 "strings" |
13 ) | 13 ) |
14 | 14 |
15 const ( | 15 const ( |
16 zkEnvironmentPath = "/environment" | 16 zkEnvironmentPath = "/environment" |
17 zkMachinesPath = "/machines" | 17 zkMachinesPath = "/machines" |
18 zkTopologyPath = "/topology" | 18 zkTopologyPath = "/topology" |
19 ) | 19 ) |
20 | 20 |
21 // State represents the state of an environment | 21 // State represents the state of an environment |
22 // managed by juju. | 22 // managed by juju. |
23 type State struct { | 23 type State struct { |
24 zk *zookeeper.Conn | 24 zk *zookeeper.Conn |
25 fwd *sshForwarder | 25 fwd *sshForwarder |
26 } | 26 } |
27 | 27 |
28 // AddMachine creates a new machine state. | 28 // AddMachine creates a new machine state. |
29 func (s *State) AddMachine() (*Machine, error) { | 29 func (s *State) AddMachine() (m *Machine, err error) { |
30 » path, err := s.zk.Create("/machines/machine-", "", zookeeper.SEQUENCE, z kPermAll) | 30 » defer errorContext(&err, "can't add a new machine: %v") |
31 » if err != nil { | 31 » var path string |
32 » » return nil, err | 32 » if path, err = s.zk.Create("/machines/machine-", "", zookeeper.SEQUENCE, zkPermAll); err != nil { |
33 » » return | |
33 } | 34 } |
34 key := strings.Split(path, "/")[2] | 35 key := strings.Split(path, "/")[2] |
35 addMachine := func(t *topology) error { | 36 addMachine := func(t *topology) error { |
36 return t.AddMachine(key) | 37 return t.AddMachine(key) |
37 } | 38 } |
38 if err = retryTopologyChange(s.zk, addMachine); err != nil { | 39 if err = retryTopologyChange(s.zk, addMachine); err != nil { |
39 » » return nil, err | 40 » » return |
40 } | 41 } |
41 return &Machine{s, key}, nil | 42 return &Machine{s, key}, nil |
42 } | 43 } |
43 | 44 |
44 // RemoveMachine removes the machine with the given id. | 45 // RemoveMachine removes the machine with the given id. |
45 func (s *State) RemoveMachine(id int) error { | 46 func (s *State) RemoveMachine(id int) (err error) { |
47 » defer errorContext(&err, "can't remove machine %d: %v", id) | |
46 key := machineKey(id) | 48 key := machineKey(id) |
47 removeMachine := func(t *topology) error { | 49 removeMachine := func(t *topology) error { |
48 if !t.HasMachine(key) { | 50 if !t.HasMachine(key) { |
49 return fmt.Errorf("machine not found") | 51 return fmt.Errorf("machine not found") |
50 } | 52 } |
51 hasUnits, err := t.MachineHasUnits(key) | 53 hasUnits, err := t.MachineHasUnits(key) |
52 if err != nil { | 54 if err != nil { |
53 return err | 55 return err |
54 } | 56 } |
55 if hasUnits { | 57 if hasUnits { |
56 return fmt.Errorf("machine has units") | 58 return fmt.Errorf("machine has units") |
57 } | 59 } |
58 return t.RemoveMachine(key) | 60 return t.RemoveMachine(key) |
59 } | 61 } |
60 » if err := retryTopologyChange(s.zk, removeMachine); err != nil { | 62 » if err = retryTopologyChange(s.zk, removeMachine); err != nil { |
61 » » return fmt.Errorf("can't remove machine %d: %v", id, err) | 63 » » return |
62 } | 64 } |
63 return zkRemoveTree(s.zk, fmt.Sprintf("/machines/%s", key)) | 65 return zkRemoveTree(s.zk, fmt.Sprintf("/machines/%s", key)) |
64 } | 66 } |
65 | 67 |
66 // WatchMachines watches for new Machines added or removed. | 68 // WatchMachines watches for new Machines added or removed. |
67 func (s *State) WatchMachines() *MachinesWatcher { | 69 func (s *State) WatchMachines() *MachinesWatcher { |
68 return newMachinesWatcher(s) | 70 return newMachinesWatcher(s) |
69 } | 71 } |
70 | 72 |
71 // WatchEnvironConfig returns a watcher for observing | 73 // WatchEnvironConfig returns a watcher for observing |
72 // changes to the environment configuration. | 74 // changes to the environment configuration. |
73 func (s *State) WatchEnvironConfig() *ConfigWatcher { | 75 func (s *State) WatchEnvironConfig() *ConfigWatcher { |
74 return newConfigWatcher(s, zkEnvironmentPath) | 76 return newConfigWatcher(s, zkEnvironmentPath) |
75 } | 77 } |
76 | 78 |
77 // EnvironConfig returns the current configuration of the environment. | 79 // EnvironConfig returns the current configuration of the environment. |
78 func (s *State) EnvironConfig() (*ConfigNode, error) { | 80 func (s *State) EnvironConfig() (*ConfigNode, error) { |
79 return readConfigNode(s.zk, zkEnvironmentPath) | 81 return readConfigNode(s.zk, zkEnvironmentPath) |
80 } | 82 } |
81 | 83 |
82 // Machine returns the machine with the given id. | 84 // Machine returns the machine with the given id. |
83 func (s *State) Machine(id int) (*Machine, error) { | 85 func (s *State) Machine(id int) (*Machine, error) { |
84 key := machineKey(id) | 86 key := machineKey(id) |
85 topology, err := readTopology(s.zk) | 87 topology, err := readTopology(s.zk) |
86 if err != nil { | 88 if err != nil { |
87 » » return nil, err | 89 » » return nil, fmt.Errorf("can't get machine %d: %v", id, err) |
88 } | 90 } |
89 if !topology.HasMachine(key) { | 91 if !topology.HasMachine(key) { |
90 return nil, fmt.Errorf("machine %d not found", id) | 92 return nil, fmt.Errorf("machine %d not found", id) |
91 } | 93 } |
92 return &Machine{s, key}, nil | 94 return &Machine{s, key}, nil |
93 } | 95 } |
94 | 96 |
95 // AllMachines returns all machines in the environment. | 97 // AllMachines returns all machines in the environment. |
96 func (s *State) AllMachines() ([]*Machine, error) { | 98 func (s *State) AllMachines() ([]*Machine, error) { |
97 topology, err := readTopology(s.zk) | 99 topology, err := readTopology(s.zk) |
98 if err != nil { | 100 if err != nil { |
99 » » return nil, err | 101 » » return nil, fmt.Errorf("can't get all machines: %v", err) |
100 } | 102 } |
101 machines := []*Machine{} | 103 machines := []*Machine{} |
102 for _, key := range topology.MachineKeys() { | 104 for _, key := range topology.MachineKeys() { |
103 machines = append(machines, &Machine{s, key}) | 105 machines = append(machines, &Machine{s, key}) |
104 } | 106 } |
105 return machines, nil | 107 return machines, nil |
106 } | 108 } |
107 | 109 |
108 // AddCharm adds the ch charm with curl to the state. | 110 // AddCharm adds the ch charm with curl to the state. |
109 // bundleUrl must be set to a URL where the bundle for ch | 111 // bundleUrl must be set to a URL where the bundle for ch |
110 // may be downloaded from. | 112 // may be downloaded from. |
111 // On success the newly added charm state is returned. | 113 // On success the newly added charm state is returned. |
112 func (s *State) AddCharm(ch charm.Charm, curl *charm.URL, bundleURL *url.URL, bu ndleSha256 string) (*Charm, error) { | 114 func (s *State) AddCharm(ch charm.Charm, curl *charm.URL, bundleURL *url.URL, bu ndleSha256 string) (stch *Charm, err error) { |
115 » defer errorContext(&err, "can't add charm %q: %v", curl) | |
113 data := &charmData{ | 116 data := &charmData{ |
114 Meta: ch.Meta(), | 117 Meta: ch.Meta(), |
115 Config: ch.Config(), | 118 Config: ch.Config(), |
116 BundleURL: bundleURL.String(), | 119 BundleURL: bundleURL.String(), |
117 BundleSha256: bundleSha256, | 120 BundleSha256: bundleSha256, |
118 } | 121 } |
119 yaml, err := goyaml.Marshal(data) | 122 yaml, err := goyaml.Marshal(data) |
120 if err != nil { | 123 if err != nil { |
121 » » return nil, err | 124 » » return |
122 } | 125 } |
123 path, err := charmPath(curl) | 126 path, err := charmPath(curl) |
124 if err != nil { | 127 if err != nil { |
125 » » return nil, err | 128 » » return |
126 } | 129 } |
127 _, err = s.zk.Create(path, string(yaml), 0, zkPermAll) | 130 _, err = s.zk.Create(path, string(yaml), 0, zkPermAll) |
128 if err != nil { | 131 if err != nil { |
129 » » return nil, err | 132 » » return |
130 } | 133 } |
131 » return newCharm(s, curl, data) | 134 » stch, err = newCharm(s, curl, data) |
niemeyer
2012/06/13 12:32:38
Please revert. The original version is fine.
TheMue
2012/06/13 12:54:34
Done.
| |
135 » if err != nil { | |
136 » » return | |
137 » } | |
138 » return stch, nil | |
132 } | 139 } |
133 | 140 |
134 // Charm returns a charm by the given id. | 141 // Charm returns a charm by the given id. |
135 func (s *State) Charm(curl *charm.URL) (*Charm, error) { | 142 func (s *State) Charm(curl *charm.URL) (stch *Charm, err error) { |
143 » defer errorContext(&err, "can't get charm %q: %v", curl) | |
136 path, err := charmPath(curl) | 144 path, err := charmPath(curl) |
137 if err != nil { | 145 if err != nil { |
138 » » return nil, err | 146 » » return |
139 } | 147 } |
140 yaml, _, err := s.zk.Get(path) | 148 yaml, _, err := s.zk.Get(path) |
141 if zookeeper.IsError(err, zookeeper.ZNONODE) { | 149 if zookeeper.IsError(err, zookeeper.ZNONODE) { |
142 » » return nil, fmt.Errorf("charm not found: %q", curl) | 150 » » return |
143 } | 151 } |
144 if err != nil { | 152 if err != nil { |
145 » » return nil, err | 153 » » return |
146 } | 154 } |
147 data := &charmData{} | 155 data := &charmData{} |
148 » if err := goyaml.Unmarshal([]byte(yaml), data); err != nil { | 156 » if err = goyaml.Unmarshal([]byte(yaml), data); err != nil { |
149 » » return nil, err | 157 » » return |
150 } | 158 } |
151 » return newCharm(s, curl, data) | 159 » stch, err = newCharm(s, curl, data) |
niemeyer
2012/06/13 12:32:38
Ditto.
TheMue
2012/06/13 12:54:34
Done.
| |
160 » if err != nil { | |
161 » » return | |
162 » } | |
163 » return stch, nil | |
152 } | 164 } |
153 | 165 |
154 // AddService creates a new service state with the given unique name | 166 // AddService creates a new service state with the given unique name |
155 // and the charm state. | 167 // and the charm state. |
156 func (s *State) AddService(name string, ch *Charm) (*Service, error) { | 168 func (s *State) AddService(name string, ch *Charm) (service *Service, err error) { |
169 » defer errorContext(&err, "can't add service %q: %v", name) | |
157 details := map[string]interface{}{"charm": ch.URL().String()} | 170 details := map[string]interface{}{"charm": ch.URL().String()} |
158 yaml, err := goyaml.Marshal(details) | 171 yaml, err := goyaml.Marshal(details) |
159 if err != nil { | 172 if err != nil { |
160 » » return nil, err | 173 » » return |
161 } | 174 } |
162 path, err := s.zk.Create("/services/service-", string(yaml), zookeeper.S EQUENCE, zkPermAll) | 175 path, err := s.zk.Create("/services/service-", string(yaml), zookeeper.S EQUENCE, zkPermAll) |
163 if err != nil { | 176 if err != nil { |
164 » » return nil, err | 177 » » return |
165 } | 178 } |
166 key := strings.Split(path, "/")[2] | 179 key := strings.Split(path, "/")[2] |
167 » service := &Service{s, key, name} | 180 » service = &Service{s, key, name} |
168 // Create an empty configuration node. | 181 // Create an empty configuration node. |
169 _, err = createConfigNode(s.zk, service.zkConfigPath(), map[string]inter face{}{}) | 182 _, err = createConfigNode(s.zk, service.zkConfigPath(), map[string]inter face{}{}) |
170 if err != nil { | 183 if err != nil { |
171 » » return nil, err | 184 » » return |
niemeyer
2012/06/13 12:32:38
Please revert all of these changes. The original "
TheMue
2012/06/13 12:54:34
Done.
| |
172 } | 185 } |
173 // Create a parent node for the service units | 186 // Create a parent node for the service units |
174 _, err = s.zk.Create(service.zkPath()+"/units", "", 0, zkPermAll) | 187 _, err = s.zk.Create(service.zkPath()+"/units", "", 0, zkPermAll) |
175 if err != nil { | 188 if err != nil { |
176 » » return nil, err | 189 » » return |
177 } | 190 } |
178 addService := func(t *topology) error { | 191 addService := func(t *topology) error { |
179 if _, err := t.ServiceKey(name); err == nil { | 192 if _, err := t.ServiceKey(name); err == nil { |
180 // No error, so service name already in use. | 193 // No error, so service name already in use. |
181 » » » return fmt.Errorf("service name %q is already in use", n ame) | 194 » » » return fmt.Errorf("service name is already in use") |
182 } | 195 } |
183 return t.AddService(key, name) | 196 return t.AddService(key, name) |
184 } | 197 } |
185 if err = retryTopologyChange(s.zk, addService); err != nil { | 198 if err = retryTopologyChange(s.zk, addService); err != nil { |
186 » » return nil, err | 199 » » return |
187 } | 200 } |
188 return service, nil | 201 return service, nil |
189 } | 202 } |
190 | 203 |
191 // RemoveService removes a service from the state. It will | 204 // RemoveService removes a service from the state. It will |
192 // also remove all its units and break any of its existing | 205 // also remove all its units and break any of its existing |
193 // relations. | 206 // relations. |
194 func (s *State) RemoveService(svc *Service) error { | 207 func (s *State) RemoveService(svc *Service) (err error) { |
208 » defer errorContext(&err, "can't remove service %q: %v", svc.Name()) | |
195 // TODO Remove relations first, to prevent spurious hook execution. | 209 // TODO Remove relations first, to prevent spurious hook execution. |
196 | 210 |
197 // Remove the units. | 211 // Remove the units. |
198 units, err := svc.AllUnits() | 212 units, err := svc.AllUnits() |
199 if err != nil { | 213 if err != nil { |
200 » » return err | 214 » » return |
201 } | 215 } |
202 for _, unit := range units { | 216 for _, unit := range units { |
203 if err = svc.RemoveUnit(unit); err != nil { | 217 if err = svc.RemoveUnit(unit); err != nil { |
204 » » » return err | 218 » » » return fmt.Errorf("can't remove unit %q: %v", unit.Name( ), err) |
niemeyer
2012/06/13 12:32:38
No need to adorn it further. RemoveUnit itself wil
TheMue
2012/06/13 12:54:34
Done.
| |
205 } | 219 } |
206 } | 220 } |
207 // Remove the service from the topology. | 221 // Remove the service from the topology. |
208 removeService := func(t *topology) error { | 222 removeService := func(t *topology) error { |
209 if !t.HasService(svc.key) { | 223 if !t.HasService(svc.key) { |
210 return stateChanged | 224 return stateChanged |
211 } | 225 } |
212 t.RemoveService(svc.key) | 226 t.RemoveService(svc.key) |
213 return nil | 227 return nil |
214 } | 228 } |
215 if err = retryTopologyChange(s.zk, removeService); err != nil { | 229 if err = retryTopologyChange(s.zk, removeService); err != nil { |
216 » » return err | 230 » » return |
217 } | 231 } |
218 » return zkRemoveTree(s.zk, svc.zkPath()) | 232 » if err = zkRemoveTree(s.zk, svc.zkPath()); err != nil { |
niemeyer
2012/06/13 12:32:38
Please revert.
TheMue
2012/06/13 12:54:34
Done.
| |
233 » » return | |
234 » } | |
235 » return nil | |
219 } | 236 } |
220 | 237 |
221 // Service returns a service state by name. | 238 // Service returns a service state by name. |
222 func (s *State) Service(name string) (*Service, error) { | 239 func (s *State) Service(name string) (*Service, error) { |
223 topology, err := readTopology(s.zk) | 240 topology, err := readTopology(s.zk) |
224 if err != nil { | 241 if err != nil { |
225 » » return nil, err | 242 » » return nil, fmt.Errorf("can't get service %q: %v", name, err) |
226 } | 243 } |
227 key, err := topology.ServiceKey(name) | 244 key, err := topology.ServiceKey(name) |
228 if err != nil { | 245 if err != nil { |
229 return nil, err | 246 return nil, err |
niemeyer
2012/06/13 12:32:38
This error may come out as "can't find service key
TheMue
2012/06/13 12:54:34
Done.
| |
230 } | 247 } |
231 return &Service{s, key, name}, nil | 248 return &Service{s, key, name}, nil |
232 } | 249 } |
233 | 250 |
234 // AllServices returns all deployed services in the environment. | 251 // AllServices returns all deployed services in the environment. |
235 func (s *State) AllServices() ([]*Service, error) { | 252 func (s *State) AllServices() (services []*Service, err error) { |
253 » defer errorContext(&err, "can't get all services: %v") | |
236 topology, err := readTopology(s.zk) | 254 topology, err := readTopology(s.zk) |
237 if err != nil { | 255 if err != nil { |
238 » » return nil, err | 256 » » return |
239 } | 257 } |
240 » services := []*Service{} | 258 » services = []*Service{} |
241 for _, key := range topology.ServiceKeys() { | 259 for _, key := range topology.ServiceKeys() { |
242 » » name, err := topology.ServiceName(key) | 260 » » var name string |
niemeyer
2012/06/13 12:32:38
Please revert and have "return nil, err" below.
TheMue
2012/06/13 12:54:34
Done.
| |
261 » » name, err = topology.ServiceName(key) | |
243 if err != nil { | 262 if err != nil { |
244 » » » return nil, err | 263 » » » return |
245 } | 264 } |
246 services = append(services, &Service{s, key, name}) | 265 services = append(services, &Service{s, key, name}) |
247 } | 266 } |
248 return services, nil | 267 return services, nil |
249 } | 268 } |
250 | 269 |
251 // Unit returns a unit by name. | 270 // Unit returns a unit by name. |
252 func (s *State) Unit(name string) (*Unit, error) { | 271 func (s *State) Unit(name string) (unit *Unit, err error) { |
272 » defer errorContext(&err, "can't get unit %q: %v", name) | |
253 serviceName, _, err := parseUnitName(name) | 273 serviceName, _, err := parseUnitName(name) |
254 if err != nil { | 274 if err != nil { |
255 » » return nil, err | 275 » » return |
256 } | 276 } |
257 service, err := s.Service(serviceName) | 277 service, err := s.Service(serviceName) |
258 if err != nil { | 278 if err != nil { |
259 » » return nil, err | 279 » » return |
260 } | 280 } |
261 return service.Unit(name) | 281 return service.Unit(name) |
262 } | 282 } |
263 | 283 |
264 // addRelationNode creates the relation node. | 284 // addRelationNode creates the relation node. |
265 func (s *State) addRelationNode(scope RelationScope) (string, error) { | 285 func (s *State) addRelationNode(scope RelationScope) (string, error) { |
266 path, err := s.zk.Create("/relations/relation-", "", zookeeper.SEQUENCE, zkPermAll) | 286 path, err := s.zk.Create("/relations/relation-", "", zookeeper.SEQUENCE, zkPermAll) |
267 if err != nil { | 287 if err != nil { |
268 return "", err | 288 return "", err |
269 } | 289 } |
270 relationKey := strings.Split(path, "/")[2] | 290 relationKey := strings.Split(path, "/")[2] |
271 // Create the settings node only if the scope is global. | 291 // Create the settings node only if the scope is global. |
272 // In case of container scoped relations the creation per | 292 // In case of container scoped relations the creation per |
273 // container occurs in ServiceRelation.AddUnit. | 293 // container occurs in ServiceRelation.AddUnit. |
274 if scope == ScopeGlobal { | 294 if scope == ScopeGlobal { |
275 _, err = s.zk.Create(path+"/settings", "", 0, zkPermAll) | 295 _, err = s.zk.Create(path+"/settings", "", 0, zkPermAll) |
276 if err != nil { | 296 if err != nil { |
277 return "", err | 297 return "", err |
278 } | 298 } |
279 } | 299 } |
280 return relationKey, nil | 300 return relationKey, nil |
281 } | 301 } |
282 | 302 |
283 // addRelationEndpointNode creates the endpoint role node below its relation nod e· | 303 // addRelationEndpointNode creates the endpoint role node below its relation nod e· |
284 // for the given relation endpoint. | 304 // for the given relation endpoint. |
285 func (s *State) addRelationEndpointNode(relationKey string, endpoint RelationEnd point) error { | 305 func (s *State) addRelationEndpointNode(relationKey string, endpoint RelationEnd point) error { |
286 path := fmt.Sprintf("/relations/%s/%s", relationKey, string(endpoint.Rel ationRole)) | 306 path := fmt.Sprintf("/relations/%s/%s", relationKey, string(endpoint.Rel ationRole)) |
287 » _, err := s.zk.Create(path, "", 0, zkPermAll) | 307 » if _, err := s.zk.Create(path, "", 0, zkPermAll); err != nil { |
niemeyer
2012/06/13 12:32:38
Please revert.
TheMue
2012/06/13 12:54:34
Done.
| |
288 » return err | 308 » » return err |
309 » } | |
310 » return nil | |
289 } | 311 } |
290 | 312 |
291 // AddRelation creates a new relation with the given endpoints.·· | 313 // AddRelation creates a new relation with the given endpoints.·· |
292 func (s *State) AddRelation(endpoints ...RelationEndpoint) (*Relation, []*Servic eRelation, error) { | 314 func (s *State) AddRelation(endpoints ...RelationEndpoint) (rel *Relation, svcre ls []*ServiceRelation, err error) { |
315 » defer errorContext(&err, "can't add relation: %v") | |
293 switch len(endpoints) { | 316 switch len(endpoints) { |
294 case 1: | 317 case 1: |
295 if endpoints[0].RelationRole != RolePeer { | 318 if endpoints[0].RelationRole != RolePeer { |
296 » » » return nil, nil, fmt.Errorf("can't add non-peer relation with a single service") | 319 » » » return nil, nil, fmt.Errorf("non-peer relation with a si ngle service") |
297 } | 320 } |
298 case 2: | 321 case 2: |
299 if !endpoints[0].CanRelateTo(&endpoints[1]) { | 322 if !endpoints[0].CanRelateTo(&endpoints[1]) { |
300 » » » return nil, nil, fmt.Errorf("can't add relation between %s and %s", endpoints[0], endpoints[1]) | 323 » » » return nil, nil, fmt.Errorf("relation between %s and %s is invalid", endpoints[0], endpoints[1]) |
301 } | 324 } |
302 default: | 325 default: |
303 » » return nil, nil, fmt.Errorf("can't add relations between %d serv ices", len(endpoints)) | 326 » » return nil, nil, fmt.Errorf("relations between %d services are i nvalid", len(endpoints)) |
304 } | 327 } |
305 t, err := readTopology(s.zk) | 328 t, err := readTopology(s.zk) |
306 if err != nil { | 329 if err != nil { |
307 » » return nil, nil, err | 330 » » return |
308 } | 331 } |
309 // Check if the relation already exists. | 332 // Check if the relation already exists. |
310 relationKey, err := t.RelationKey(endpoints...) | 333 relationKey, err := t.RelationKey(endpoints...) |
311 if err != nil { | 334 if err != nil { |
312 if _, ok := err.(*NoRelationError); !ok { | 335 if _, ok := err.(*NoRelationError); !ok { |
313 » » » return nil, nil, err | 336 » » » return |
314 } | 337 } |
315 } | 338 } |
316 if relationKey != "" { | 339 if relationKey != "" { |
317 return nil, nil, fmt.Errorf("relation already exists") | 340 return nil, nil, fmt.Errorf("relation already exists") |
318 } | 341 } |
319 scope := ScopeGlobal | 342 scope := ScopeGlobal |
320 for _, endpoint := range endpoints { | 343 for _, endpoint := range endpoints { |
321 if endpoint.RelationScope == ScopeContainer { | 344 if endpoint.RelationScope == ScopeContainer { |
322 scope = ScopeContainer | 345 scope = ScopeContainer |
323 break | 346 break |
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
366 service := &topoRelationService{ | 389 service := &topoRelationService{ |
367 RelationRole: serviceRelation.RelationRole(), | 390 RelationRole: serviceRelation.RelationRole(), |
368 RelationName: serviceRelation.RelationName(), | 391 RelationName: serviceRelation.RelationName(), |
369 } | 392 } |
370 relation.Services[serviceRelation.serviceKey] = service | 393 relation.Services[serviceRelation.serviceKey] = service |
371 } | 394 } |
372 return t.AddRelation(relationKey, relation) | 395 return t.AddRelation(relationKey, relation) |
373 } | 396 } |
374 err = retryTopologyChange(s.zk, addRelation) | 397 err = retryTopologyChange(s.zk, addRelation) |
375 if err != nil { | 398 if err != nil { |
376 » » return nil, nil, err | 399 » » return |
377 } | 400 } |
378 return &Relation{s, relationKey}, serviceRelations, nil | 401 return &Relation{s, relationKey}, serviceRelations, nil |
379 } | 402 } |
380 | 403 |
381 // RemoveRelation removes the relation. | 404 // RemoveRelation removes the relation. |
382 func (s *State) RemoveRelation(relation *Relation) error { | 405 func (s *State) RemoveRelation(relation *Relation) error { |
383 removeRelation := func(t *topology) error { | 406 removeRelation := func(t *topology) error { |
384 » » _, err := t.Relation(relation.key) | 407 » » if _, err := t.Relation(relation.key); err != nil { |
385 » » if err != nil { | 408 » » » return err |
386 » » » return fmt.Errorf("can't remove relation: %v", err) | |
387 } | 409 } |
388 return t.RemoveRelation(relation.key) | 410 return t.RemoveRelation(relation.key) |
389 } | 411 } |
390 » // TODO: Improve high-level errors, no passing of low-level· | 412 » if err := retryTopologyChange(s.zk, removeRelation); err != nil { |
391 » // errors directly to the caller. | 413 » » return fmt.Errorf("can't remove relation: %v", err) |
392 » return retryTopologyChange(s.zk, removeRelation) | 414 » } |
415 » return nil | |
393 } | 416 } |
OLD | NEW |