~nskaggs/+junk/juju-packaging-test

« back to all changes in this revision

Viewing changes to src/github.com/juju/juju/api/uniter/uniter.go

  • Committer: Nicholas Skaggs
  • Date: 2016-10-27 20:23:11 UTC
  • Revision ID: nicholas.skaggs@canonical.com-20161027202311-sux4jk2o73p1d6rg
Re-add src

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
// Copyright 2013 Canonical Ltd.
 
2
// Licensed under the AGPLv3, see LICENCE file for details.
 
3
 
 
4
package uniter
 
5
 
 
6
import (
 
7
        "fmt"
 
8
 
 
9
        "github.com/juju/errors"
 
10
        "github.com/juju/names"
 
11
        "gopkg.in/juju/charm.v6-unstable"
 
12
 
 
13
        "github.com/juju/juju/api/base"
 
14
        "github.com/juju/juju/api/common"
 
15
        apiwatcher "github.com/juju/juju/api/watcher"
 
16
        "github.com/juju/juju/apiserver/params"
 
17
        "github.com/juju/juju/network"
 
18
        "github.com/juju/juju/watcher"
 
19
)
 
20
 
 
21
const uniterFacade = "Uniter"
 
22
 
 
23
// State provides access to the Uniter API facade.
 
24
type State struct {
 
25
        *common.ModelWatcher
 
26
        *common.APIAddresser
 
27
        *StorageAccessor
 
28
 
 
29
        LeadershipSettings *LeadershipSettingsAccessor
 
30
        facade             base.FacadeCaller
 
31
        // unitTag contains the authenticated unit's tag.
 
32
        unitTag names.UnitTag
 
33
}
 
34
 
 
35
// newStateForVersion creates a new client-side Uniter facade for the
 
36
// given version.
 
37
func newStateForVersion(
 
38
        caller base.APICaller,
 
39
        authTag names.UnitTag,
 
40
        version int,
 
41
) *State {
 
42
        facadeCaller := base.NewFacadeCallerForVersion(
 
43
                caller,
 
44
                uniterFacade,
 
45
                version,
 
46
        )
 
47
        state := &State{
 
48
                ModelWatcher:    common.NewModelWatcher(facadeCaller),
 
49
                APIAddresser:    common.NewAPIAddresser(facadeCaller),
 
50
                StorageAccessor: NewStorageAccessor(facadeCaller),
 
51
                facade:          facadeCaller,
 
52
                unitTag:         authTag,
 
53
        }
 
54
 
 
55
        newWatcher := func(result params.NotifyWatchResult) watcher.NotifyWatcher {
 
56
                return apiwatcher.NewNotifyWatcher(caller, result)
 
57
        }
 
58
        state.LeadershipSettings = NewLeadershipSettingsAccessor(
 
59
                facadeCaller.FacadeCall,
 
60
                newWatcher,
 
61
                ErrIfNotVersionFn(2, state.BestAPIVersion()),
 
62
        )
 
63
        return state
 
64
}
 
65
 
 
66
func newStateForVersionFn(version int) func(base.APICaller, names.UnitTag) *State {
 
67
        return func(caller base.APICaller, authTag names.UnitTag) *State {
 
68
                return newStateForVersion(caller, authTag, version)
 
69
        }
 
70
}
 
71
 
 
72
// newStateV3 creates a new client-side Uniter facade, version 3.
 
73
var newStateV3 = newStateForVersionFn(3)
 
74
 
 
75
// NewState creates a new client-side Uniter facade.
 
76
// Defined like this to allow patching during tests.
 
77
var NewState = newStateV3
 
78
 
 
79
// BestAPIVersion returns the API version that we were able to
 
80
// determine is supported by both the client and the API Server.
 
81
func (st *State) BestAPIVersion() int {
 
82
        return st.facade.BestAPIVersion()
 
83
}
 
84
 
 
85
// Facade returns the current facade.
 
86
func (st *State) Facade() base.FacadeCaller {
 
87
        return st.facade
 
88
}
 
89
 
 
90
// life requests the lifecycle of the given entity from the server.
 
91
func (st *State) life(tag names.Tag) (params.Life, error) {
 
92
        return common.Life(st.facade, tag)
 
93
}
 
94
 
 
95
// relation requests relation information from the server.
 
96
func (st *State) relation(relationTag, unitTag names.Tag) (params.RelationResult, error) {
 
97
        nothing := params.RelationResult{}
 
98
        var result params.RelationResults
 
99
        args := params.RelationUnits{
 
100
                RelationUnits: []params.RelationUnit{
 
101
                        {Relation: relationTag.String(), Unit: unitTag.String()},
 
102
                },
 
103
        }
 
104
        err := st.facade.FacadeCall("Relation", args, &result)
 
105
        if err != nil {
 
106
                return nothing, err
 
107
        }
 
108
        if len(result.Results) != 1 {
 
109
                return nothing, fmt.Errorf("expected 1 result, got %d", len(result.Results))
 
110
        }
 
111
        if err := result.Results[0].Error; err != nil {
 
112
                return nothing, err
 
113
        }
 
114
        return result.Results[0], nil
 
115
}
 
116
 
 
117
// getOneAction retrieves a single Action from the controller.
 
118
func (st *State) getOneAction(tag *names.ActionTag) (params.ActionsQueryResult, error) {
 
119
        nothing := params.ActionsQueryResult{}
 
120
 
 
121
        args := params.Entities{
 
122
                Entities: []params.Entity{
 
123
                        {Tag: tag.String()},
 
124
                },
 
125
        }
 
126
 
 
127
        var results params.ActionsQueryResults
 
128
        err := st.facade.FacadeCall("Actions", args, &results)
 
129
        if err != nil {
 
130
                return nothing, err
 
131
        }
 
132
 
 
133
        if len(results.Results) > 1 {
 
134
                return nothing, fmt.Errorf("expected only 1 action query result, got %d", len(results.Results))
 
135
        }
 
136
 
 
137
        // handle server errors
 
138
        result := results.Results[0]
 
139
        if err := result.Error; err != nil {
 
140
                return nothing, err
 
141
        }
 
142
 
 
143
        return result, nil
 
144
}
 
145
 
 
146
// Unit provides access to methods of a state.Unit through the facade.
 
147
func (st *State) Unit(tag names.UnitTag) (*Unit, error) {
 
148
        life, err := st.life(tag)
 
149
        if err != nil {
 
150
                return nil, err
 
151
        }
 
152
        return &Unit{
 
153
                tag:  tag,
 
154
                life: life,
 
155
                st:   st,
 
156
        }, nil
 
157
}
 
158
 
 
159
// Service returns a service state by tag.
 
160
func (st *State) Service(tag names.ServiceTag) (*Service, error) {
 
161
        life, err := st.life(tag)
 
162
        if err != nil {
 
163
                return nil, err
 
164
        }
 
165
        return &Service{
 
166
                tag:  tag,
 
167
                life: life,
 
168
                st:   st,
 
169
        }, nil
 
170
}
 
171
 
 
172
// ProviderType returns a provider type used by the current juju model.
 
173
//
 
174
// TODO(dimitern): We might be able to drop this, once we have machine
 
175
// addresses implemented fully. See also LP bug 1221798.
 
176
func (st *State) ProviderType() (string, error) {
 
177
        var result params.StringResult
 
178
        err := st.facade.FacadeCall("ProviderType", nil, &result)
 
179
        if err != nil {
 
180
                return "", err
 
181
        }
 
182
        if err := result.Error; err != nil {
 
183
                return "", err
 
184
        }
 
185
        return result.Result, nil
 
186
}
 
187
 
 
188
// Charm returns the charm with the given URL.
 
189
func (st *State) Charm(curl *charm.URL) (*Charm, error) {
 
190
        if curl == nil {
 
191
                return nil, fmt.Errorf("charm url cannot be nil")
 
192
        }
 
193
        return &Charm{
 
194
                st:   st,
 
195
                curl: curl,
 
196
        }, nil
 
197
}
 
198
 
 
199
// Relation returns the existing relation with the given tag.
 
200
func (st *State) Relation(relationTag names.RelationTag) (*Relation, error) {
 
201
        result, err := st.relation(relationTag, st.unitTag)
 
202
        if err != nil {
 
203
                return nil, err
 
204
        }
 
205
        return &Relation{
 
206
                id:   result.Id,
 
207
                tag:  relationTag,
 
208
                life: result.Life,
 
209
                st:   st,
 
210
        }, nil
 
211
}
 
212
 
 
213
// Action returns the Action with the given tag.
 
214
func (st *State) Action(tag names.ActionTag) (*Action, error) {
 
215
        result, err := st.getOneAction(&tag)
 
216
        if err != nil {
 
217
                return nil, err
 
218
        }
 
219
        return &Action{
 
220
                name:   result.Action.Action.Name,
 
221
                params: result.Action.Action.Parameters,
 
222
        }, nil
 
223
}
 
224
 
 
225
// ActionBegin marks an action as running.
 
226
func (st *State) ActionBegin(tag names.ActionTag) error {
 
227
        var outcome params.ErrorResults
 
228
 
 
229
        args := params.Entities{
 
230
                Entities: []params.Entity{
 
231
                        {Tag: tag.String()},
 
232
                },
 
233
        }
 
234
 
 
235
        err := st.facade.FacadeCall("BeginActions", args, &outcome)
 
236
        if err != nil {
 
237
                return err
 
238
        }
 
239
        if len(outcome.Results) != 1 {
 
240
                return fmt.Errorf("expected 1 result, got %d", len(outcome.Results))
 
241
        }
 
242
        result := outcome.Results[0]
 
243
        if result.Error != nil {
 
244
                return result.Error
 
245
        }
 
246
        return nil
 
247
}
 
248
 
 
249
// ActionFinish captures the structured output of an action.
 
250
func (st *State) ActionFinish(tag names.ActionTag, status string, results map[string]interface{}, message string) error {
 
251
        var outcome params.ErrorResults
 
252
 
 
253
        args := params.ActionExecutionResults{
 
254
                Results: []params.ActionExecutionResult{
 
255
                        {
 
256
                                ActionTag: tag.String(),
 
257
                                Status:    status,
 
258
                                Results:   results,
 
259
                                Message:   message,
 
260
                        },
 
261
                },
 
262
        }
 
263
 
 
264
        err := st.facade.FacadeCall("FinishActions", args, &outcome)
 
265
        if err != nil {
 
266
                return err
 
267
        }
 
268
        if len(outcome.Results) != 1 {
 
269
                return fmt.Errorf("expected 1 result, got %d", len(outcome.Results))
 
270
        }
 
271
        result := outcome.Results[0]
 
272
        if result.Error != nil {
 
273
                return result.Error
 
274
        }
 
275
        return nil
 
276
}
 
277
 
 
278
// RelationById returns the existing relation with the given id.
 
279
func (st *State) RelationById(id int) (*Relation, error) {
 
280
        var results params.RelationResults
 
281
        args := params.RelationIds{
 
282
                RelationIds: []int{id},
 
283
        }
 
284
        err := st.facade.FacadeCall("RelationById", args, &results)
 
285
        if err != nil {
 
286
                return nil, err
 
287
        }
 
288
        if len(results.Results) != 1 {
 
289
                return nil, fmt.Errorf("expected 1 result, got %d", len(results.Results))
 
290
        }
 
291
        result := results.Results[0]
 
292
        if err := result.Error; err != nil {
 
293
                return nil, err
 
294
        }
 
295
        relationTag := names.NewRelationTag(result.Key)
 
296
        return &Relation{
 
297
                id:   result.Id,
 
298
                tag:  relationTag,
 
299
                life: result.Life,
 
300
                st:   st,
 
301
        }, nil
 
302
}
 
303
 
 
304
// Model returns the model entity.
 
305
func (st *State) Model() (*Model, error) {
 
306
        var result params.ModelResult
 
307
        err := st.facade.FacadeCall("CurrentModel", nil, &result)
 
308
        if err != nil {
 
309
                return nil, err
 
310
        }
 
311
        if err := result.Error; err != nil {
 
312
                return nil, err
 
313
        }
 
314
        return &Model{
 
315
                name: result.Name,
 
316
                uuid: result.UUID,
 
317
        }, nil
 
318
}
 
319
 
 
320
// AllMachinePorts returns all port ranges currently open on the given
 
321
// machine, mapped to the tags of the unit that opened them and the
 
322
// relation that applies.
 
323
func (st *State) AllMachinePorts(machineTag names.MachineTag) (map[network.PortRange]params.RelationUnit, error) {
 
324
        if st.BestAPIVersion() < 1 {
 
325
                // AllMachinePorts() was introduced in UniterAPIV1.
 
326
                return nil, errors.NotImplementedf("AllMachinePorts() (need V1+)")
 
327
        }
 
328
        var results params.MachinePortsResults
 
329
        args := params.Entities{
 
330
                Entities: []params.Entity{{Tag: machineTag.String()}},
 
331
        }
 
332
        err := st.facade.FacadeCall("AllMachinePorts", args, &results)
 
333
        if err != nil {
 
334
                return nil, err
 
335
        }
 
336
        if len(results.Results) != 1 {
 
337
                return nil, fmt.Errorf("expected 1 result, got %d", len(results.Results))
 
338
        }
 
339
        result := results.Results[0]
 
340
        if result.Error != nil {
 
341
                return nil, result.Error
 
342
        }
 
343
        portsMap := make(map[network.PortRange]params.RelationUnit)
 
344
        for _, ports := range result.Ports {
 
345
                portRange := ports.PortRange.NetworkPortRange()
 
346
                portsMap[portRange] = params.RelationUnit{
 
347
                        Unit:     ports.UnitTag,
 
348
                        Relation: ports.RelationTag,
 
349
                }
 
350
        }
 
351
        return portsMap, nil
 
352
}
 
353
 
 
354
// WatchRelationUnits returns a watcher that notifies of changes to the
 
355
// counterpart units in the relation for the given unit.
 
356
func (st *State) WatchRelationUnits(
 
357
        relationTag names.RelationTag,
 
358
        unitTag names.UnitTag,
 
359
) (watcher.RelationUnitsWatcher, error) {
 
360
        var results params.RelationUnitsWatchResults
 
361
        args := params.RelationUnits{
 
362
                RelationUnits: []params.RelationUnit{{
 
363
                        Relation: relationTag.String(),
 
364
                        Unit:     unitTag.String(),
 
365
                }},
 
366
        }
 
367
        err := st.facade.FacadeCall("WatchRelationUnits", args, &results)
 
368
        if err != nil {
 
369
                return nil, err
 
370
        }
 
371
        if len(results.Results) != 1 {
 
372
                return nil, fmt.Errorf("expected 1 result, got %d", len(results.Results))
 
373
        }
 
374
        result := results.Results[0]
 
375
        if result.Error != nil {
 
376
                return nil, result.Error
 
377
        }
 
378
        w := apiwatcher.NewRelationUnitsWatcher(st.facade.RawAPICaller(), result)
 
379
        return w, nil
 
380
}
 
381
 
 
382
// ErrIfNotVersionFn returns a function which can be used to check for
 
383
// the minimum supported version, and, if appropriate, generate an
 
384
// error.
 
385
func ErrIfNotVersionFn(minVersion int, bestApiVersion int) func(string) error {
 
386
        return func(fnName string) error {
 
387
                if minVersion <= bestApiVersion {
 
388
                        return nil
 
389
                }
 
390
                return errors.NotImplementedf("%s(...) requires v%d+", fnName, minVersion)
 
391
        }
 
392
}