~nskaggs/+junk/xenial-test

« back to all changes in this revision

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

  • Committer: Nicholas Skaggs
  • Date: 2016-10-24 20:56:05 UTC
  • Revision ID: nicholas.skaggs@canonical.com-20161024205605-z8lta0uvuhtxwzwl
Initi with beta15

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
// Copyright 2015 Canonical Ltd.
 
2
// Licensed under the AGPLv3, see LICENCE file for details.
 
3
 
 
4
// Package uniter implements the API interface used by the uniter worker.
 
5
 
 
6
package uniter
 
7
 
 
8
import (
 
9
        "fmt"
 
10
 
 
11
        "github.com/juju/errors"
 
12
        "github.com/juju/loggo"
 
13
        "gopkg.in/juju/charm.v6-unstable"
 
14
        "gopkg.in/juju/names.v2"
 
15
 
 
16
        "github.com/juju/juju/apiserver/common"
 
17
        "github.com/juju/juju/apiserver/facade"
 
18
        leadershipapiserver "github.com/juju/juju/apiserver/leadership"
 
19
        "github.com/juju/juju/apiserver/meterstatus"
 
20
        "github.com/juju/juju/apiserver/params"
 
21
        "github.com/juju/juju/core/leadership"
 
22
        "github.com/juju/juju/network"
 
23
        "github.com/juju/juju/state"
 
24
        "github.com/juju/juju/state/multiwatcher"
 
25
        "github.com/juju/juju/state/watcher"
 
26
)
 
27
 
 
28
var logger = loggo.GetLogger("juju.apiserver.uniter")
 
29
 
 
30
func init() {
 
31
        common.RegisterStandardFacade("Uniter", 4, NewUniterAPIV4)
 
32
}
 
33
 
 
34
// UniterAPIV3 implements the API version 3, used by the uniter worker.
 
35
type UniterAPIV3 struct {
 
36
        *common.LifeGetter
 
37
        *StatusAPI
 
38
        *common.DeadEnsurer
 
39
        *common.AgentEntityWatcher
 
40
        *common.APIAddresser
 
41
        *common.ModelWatcher
 
42
        *common.RebootRequester
 
43
        *leadershipapiserver.LeadershipSettingsAccessor
 
44
        meterstatus.MeterStatus
 
45
 
 
46
        st            *state.State
 
47
        auth          facade.Authorizer
 
48
        resources     facade.Resources
 
49
        accessUnit    common.GetAuthFunc
 
50
        accessService common.GetAuthFunc
 
51
        unit          *state.Unit
 
52
        accessMachine common.GetAuthFunc
 
53
        StorageAPI
 
54
}
 
55
 
 
56
// NewUniterAPIV4 creates a new instance of the Uniter API, version 3.
 
57
func NewUniterAPIV4(st *state.State, resources facade.Resources, authorizer facade.Authorizer) (*UniterAPIV3, error) {
 
58
        if !authorizer.AuthUnitAgent() {
 
59
                return nil, common.ErrPerm
 
60
        }
 
61
        var unit *state.Unit
 
62
        var err error
 
63
        switch tag := authorizer.GetAuthTag().(type) {
 
64
        case names.UnitTag:
 
65
                unit, err = st.Unit(tag.Id())
 
66
                if err != nil {
 
67
                        return nil, errors.Trace(err)
 
68
                }
 
69
        default:
 
70
                return nil, errors.Errorf("expected names.UnitTag, got %T", tag)
 
71
        }
 
72
        accessUnit := func() (common.AuthFunc, error) {
 
73
                return authorizer.AuthOwner, nil
 
74
        }
 
75
        accessService := func() (common.AuthFunc, error) {
 
76
                switch tag := authorizer.GetAuthTag().(type) {
 
77
                case names.UnitTag:
 
78
                        entity, err := st.Unit(tag.Id())
 
79
                        if err != nil {
 
80
                                return nil, errors.Trace(err)
 
81
                        }
 
82
                        applicationName := entity.ApplicationName()
 
83
                        applicationTag := names.NewApplicationTag(applicationName)
 
84
                        return func(tag names.Tag) bool {
 
85
                                return tag == applicationTag
 
86
                        }, nil
 
87
                default:
 
88
                        return nil, errors.Errorf("expected names.UnitTag, got %T", tag)
 
89
                }
 
90
        }
 
91
        accessMachine := func() (common.AuthFunc, error) {
 
92
                switch tag := authorizer.GetAuthTag().(type) {
 
93
                case names.UnitTag:
 
94
                        entity, err := st.Unit(tag.Id())
 
95
                        if err != nil {
 
96
                                return nil, errors.Trace(err)
 
97
                        }
 
98
                        machineId, err := entity.AssignedMachineId()
 
99
                        if err != nil {
 
100
                                return nil, errors.Trace(err)
 
101
                        }
 
102
                        machineTag := names.NewMachineTag(machineId)
 
103
                        return func(tag names.Tag) bool {
 
104
                                return tag == machineTag
 
105
                        }, nil
 
106
                default:
 
107
                        return nil, errors.Errorf("expected names.UnitTag, got %T", tag)
 
108
                }
 
109
        }
 
110
        storageAPI, err := newStorageAPI(getStorageState(st), resources, accessUnit)
 
111
        if err != nil {
 
112
                return nil, err
 
113
        }
 
114
        msAPI, err := meterstatus.NewMeterStatusAPI(st, resources, authorizer)
 
115
        if err != nil {
 
116
                return nil, errors.Annotate(err, "could not create meter status API handler")
 
117
        }
 
118
        accessUnitOrService := common.AuthEither(accessUnit, accessService)
 
119
        return &UniterAPIV3{
 
120
                LifeGetter:                 common.NewLifeGetter(st, accessUnitOrService),
 
121
                DeadEnsurer:                common.NewDeadEnsurer(st, accessUnit),
 
122
                AgentEntityWatcher:         common.NewAgentEntityWatcher(st, resources, accessUnitOrService),
 
123
                APIAddresser:               common.NewAPIAddresser(st, resources),
 
124
                ModelWatcher:               common.NewModelWatcher(st, resources, authorizer),
 
125
                RebootRequester:            common.NewRebootRequester(st, accessMachine),
 
126
                LeadershipSettingsAccessor: leadershipSettingsAccessorFactory(st, resources, authorizer),
 
127
                MeterStatus:                msAPI,
 
128
                // TODO(fwereade): so *every* unit should be allowed to get/set its
 
129
                // own status *and* its service's? This is not a pleasing arrangement.
 
130
                StatusAPI: NewStatusAPI(st, accessUnitOrService),
 
131
 
 
132
                st:            st,
 
133
                auth:          authorizer,
 
134
                resources:     resources,
 
135
                accessUnit:    accessUnit,
 
136
                accessService: accessService,
 
137
                accessMachine: accessMachine,
 
138
                unit:          unit,
 
139
                StorageAPI:    *storageAPI,
 
140
        }, nil
 
141
}
 
142
 
 
143
// AllMachinePorts returns all opened port ranges for each given
 
144
// machine (on all networks).
 
145
func (u *UniterAPIV3) AllMachinePorts(args params.Entities) (params.MachinePortsResults, error) {
 
146
        result := params.MachinePortsResults{
 
147
                Results: make([]params.MachinePortsResult, len(args.Entities)),
 
148
        }
 
149
        canAccess, err := u.accessMachine()
 
150
        if err != nil {
 
151
                return params.MachinePortsResults{}, err
 
152
        }
 
153
        for i, entity := range args.Entities {
 
154
                result.Results[i] = u.getOneMachinePorts(canAccess, entity.Tag)
 
155
        }
 
156
        return result, nil
 
157
}
 
158
 
 
159
// AssignedMachine returns the machine tag for each given unit tag, or
 
160
// an error satisfying params.IsCodeNotAssigned when a unit has no
 
161
// assigned machine.
 
162
func (u *UniterAPIV3) AssignedMachine(args params.Entities) (params.StringResults, error) {
 
163
        result := params.StringResults{
 
164
                Results: make([]params.StringResult, len(args.Entities)),
 
165
        }
 
166
        canAccess, err := u.accessUnit()
 
167
        if err != nil {
 
168
                return params.StringResults{}, err
 
169
        }
 
170
        for i, entity := range args.Entities {
 
171
                tag, err := names.ParseUnitTag(entity.Tag)
 
172
                if err != nil {
 
173
                        result.Results[i].Error = common.ServerError(common.ErrPerm)
 
174
                        continue
 
175
                }
 
176
                if !canAccess(tag) {
 
177
                        result.Results[i].Error = common.ServerError(common.ErrPerm)
 
178
                        continue
 
179
                }
 
180
                unit, err := u.getUnit(tag)
 
181
                if err != nil {
 
182
                        result.Results[i].Error = common.ServerError(err)
 
183
                        continue
 
184
                }
 
185
                machineId, err := unit.AssignedMachineId()
 
186
                if err != nil {
 
187
                        result.Results[i].Error = common.ServerError(err)
 
188
                } else {
 
189
                        result.Results[i].Result = names.NewMachineTag(machineId).String()
 
190
                }
 
191
        }
 
192
        return result, nil
 
193
}
 
194
 
 
195
func (u *UniterAPIV3) getMachine(tag names.MachineTag) (*state.Machine, error) {
 
196
        return u.st.Machine(tag.Id())
 
197
}
 
198
 
 
199
func (u *UniterAPIV3) getOneMachinePorts(canAccess common.AuthFunc, machineTag string) params.MachinePortsResult {
 
200
        tag, err := names.ParseMachineTag(machineTag)
 
201
        if err != nil {
 
202
                return params.MachinePortsResult{Error: common.ServerError(common.ErrPerm)}
 
203
        }
 
204
        if !canAccess(tag) {
 
205
                return params.MachinePortsResult{Error: common.ServerError(common.ErrPerm)}
 
206
        }
 
207
        machine, err := u.getMachine(tag)
 
208
        if err != nil {
 
209
                return params.MachinePortsResult{Error: common.ServerError(err)}
 
210
        }
 
211
        allPorts, err := machine.AllPorts()
 
212
        if err != nil {
 
213
                return params.MachinePortsResult{Error: common.ServerError(err)}
 
214
        }
 
215
        var resultPorts []params.MachinePortRange
 
216
        for _, ports := range allPorts {
 
217
                // AllPortRanges gives a map, but apis require a stable order
 
218
                // for results, so sort the port ranges.
 
219
                portRangesToUnits := ports.AllPortRanges()
 
220
                portRanges := make([]network.PortRange, 0, len(portRangesToUnits))
 
221
                for portRange := range portRangesToUnits {
 
222
                        portRanges = append(portRanges, portRange)
 
223
                }
 
224
                network.SortPortRanges(portRanges)
 
225
                for _, portRange := range portRanges {
 
226
                        unitName := portRangesToUnits[portRange]
 
227
                        resultPorts = append(resultPorts, params.MachinePortRange{
 
228
                                UnitTag:   names.NewUnitTag(unitName).String(),
 
229
                                PortRange: params.FromNetworkPortRange(portRange),
 
230
                        })
 
231
                }
 
232
        }
 
233
        return params.MachinePortsResult{
 
234
                Ports: resultPorts,
 
235
        }
 
236
}
 
237
 
 
238
// PublicAddress returns the public address for each given unit, if set.
 
239
func (u *UniterAPIV3) PublicAddress(args params.Entities) (params.StringResults, error) {
 
240
        result := params.StringResults{
 
241
                Results: make([]params.StringResult, len(args.Entities)),
 
242
        }
 
243
        canAccess, err := u.accessUnit()
 
244
        if err != nil {
 
245
                return params.StringResults{}, err
 
246
        }
 
247
        for i, entity := range args.Entities {
 
248
                tag, err := names.ParseUnitTag(entity.Tag)
 
249
                if err != nil {
 
250
                        result.Results[i].Error = common.ServerError(common.ErrPerm)
 
251
                        continue
 
252
                }
 
253
                err = common.ErrPerm
 
254
                if canAccess(tag) {
 
255
                        var unit *state.Unit
 
256
                        unit, err = u.getUnit(tag)
 
257
                        if err == nil {
 
258
                                var address network.Address
 
259
                                address, err = unit.PublicAddress()
 
260
                                if err == nil {
 
261
                                        result.Results[i].Result = address.Value
 
262
                                } else if network.IsNoAddressError(err) {
 
263
                                        err = common.NoAddressSetError(tag, "public")
 
264
                                }
 
265
                        }
 
266
                }
 
267
                result.Results[i].Error = common.ServerError(err)
 
268
        }
 
269
        return result, nil
 
270
}
 
271
 
 
272
// PrivateAddress returns the private address for each given unit, if set.
 
273
func (u *UniterAPIV3) PrivateAddress(args params.Entities) (params.StringResults, error) {
 
274
        result := params.StringResults{
 
275
                Results: make([]params.StringResult, len(args.Entities)),
 
276
        }
 
277
        canAccess, err := u.accessUnit()
 
278
        if err != nil {
 
279
                return params.StringResults{}, err
 
280
        }
 
281
        for i, entity := range args.Entities {
 
282
                tag, err := names.ParseUnitTag(entity.Tag)
 
283
                if err != nil {
 
284
                        result.Results[i].Error = common.ServerError(common.ErrPerm)
 
285
                        continue
 
286
                }
 
287
                err = common.ErrPerm
 
288
                if canAccess(tag) {
 
289
                        var unit *state.Unit
 
290
                        unit, err = u.getUnit(tag)
 
291
                        if err == nil {
 
292
                                var address network.Address
 
293
                                address, err = unit.PrivateAddress()
 
294
                                if err == nil {
 
295
                                        result.Results[i].Result = address.Value
 
296
                                } else if network.IsNoAddressError(err) {
 
297
                                        err = common.NoAddressSetError(tag, "private")
 
298
                                }
 
299
                        }
 
300
                }
 
301
                result.Results[i].Error = common.ServerError(err)
 
302
        }
 
303
        return result, nil
 
304
}
 
305
 
 
306
// TODO(ericsnow) Factor out the common code amongst the many methods here.
 
307
 
 
308
var getZone = func(st *state.State, tag names.Tag) (string, error) {
 
309
        unit, err := st.Unit(tag.Id())
 
310
        if err != nil {
 
311
                return "", errors.Trace(err)
 
312
        }
 
313
        zone, err := unit.AvailabilityZone()
 
314
        return zone, errors.Trace(err)
 
315
}
 
316
 
 
317
// AvailabilityZone returns the availability zone for each given unit, if applicable.
 
318
func (u *UniterAPIV3) AvailabilityZone(args params.Entities) (params.StringResults, error) {
 
319
        var results params.StringResults
 
320
 
 
321
        canAccess, err := u.accessUnit()
 
322
        if err != nil {
 
323
                return results, errors.Trace(err)
 
324
        }
 
325
 
 
326
        // Prep the results.
 
327
        results = params.StringResults{
 
328
                Results: make([]params.StringResult, len(args.Entities)),
 
329
        }
 
330
 
 
331
        // Collect the zones. No zone will be collected for any entity where
 
332
        // the tag is invalid or not authorized. Instead the corresponding
 
333
        // result will be updated with the error.
 
334
        for i, entity := range args.Entities {
 
335
                tag, err := names.ParseUnitTag(entity.Tag)
 
336
                if err != nil {
 
337
                        results.Results[i].Error = common.ServerError(common.ErrPerm)
 
338
                        continue
 
339
                }
 
340
                err = common.ErrPerm
 
341
                if canAccess(tag) {
 
342
                        var zone string
 
343
                        zone, err = getZone(u.st, tag)
 
344
                        if err == nil {
 
345
                                results.Results[i].Result = zone
 
346
                        }
 
347
                }
 
348
                results.Results[i].Error = common.ServerError(err)
 
349
        }
 
350
 
 
351
        return results, nil
 
352
}
 
353
 
 
354
// Resolved returns the current resolved setting for each given unit.
 
355
func (u *UniterAPIV3) Resolved(args params.Entities) (params.ResolvedModeResults, error) {
 
356
        result := params.ResolvedModeResults{
 
357
                Results: make([]params.ResolvedModeResult, len(args.Entities)),
 
358
        }
 
359
        canAccess, err := u.accessUnit()
 
360
        if err != nil {
 
361
                return params.ResolvedModeResults{}, err
 
362
        }
 
363
        for i, entity := range args.Entities {
 
364
                tag, err := names.ParseUnitTag(entity.Tag)
 
365
                if err != nil {
 
366
                        result.Results[i].Error = common.ServerError(common.ErrPerm)
 
367
                        continue
 
368
                }
 
369
                err = common.ErrPerm
 
370
                if canAccess(tag) {
 
371
                        var unit *state.Unit
 
372
                        unit, err = u.getUnit(tag)
 
373
                        if err == nil {
 
374
                                result.Results[i].Mode = params.ResolvedMode(unit.Resolved())
 
375
                        }
 
376
                }
 
377
                result.Results[i].Error = common.ServerError(err)
 
378
        }
 
379
        return result, nil
 
380
}
 
381
 
 
382
// ClearResolved removes any resolved setting from each given unit.
 
383
func (u *UniterAPIV3) ClearResolved(args params.Entities) (params.ErrorResults, error) {
 
384
        result := params.ErrorResults{
 
385
                Results: make([]params.ErrorResult, len(args.Entities)),
 
386
        }
 
387
        canAccess, err := u.accessUnit()
 
388
        if err != nil {
 
389
                return params.ErrorResults{}, err
 
390
        }
 
391
        for i, entity := range args.Entities {
 
392
                tag, err := names.ParseUnitTag(entity.Tag)
 
393
                if err != nil {
 
394
                        result.Results[i].Error = common.ServerError(common.ErrPerm)
 
395
                        continue
 
396
                }
 
397
                err = common.ErrPerm
 
398
                if canAccess(tag) {
 
399
                        var unit *state.Unit
 
400
                        unit, err = u.getUnit(tag)
 
401
                        if err == nil {
 
402
                                err = unit.ClearResolved()
 
403
                        }
 
404
                }
 
405
                result.Results[i].Error = common.ServerError(err)
 
406
        }
 
407
        return result, nil
 
408
}
 
409
 
 
410
// GetPrincipal returns the result of calling PrincipalName() and
 
411
// converting it to a tag, on each given unit.
 
412
func (u *UniterAPIV3) GetPrincipal(args params.Entities) (params.StringBoolResults, error) {
 
413
        result := params.StringBoolResults{
 
414
                Results: make([]params.StringBoolResult, len(args.Entities)),
 
415
        }
 
416
        canAccess, err := u.accessUnit()
 
417
        if err != nil {
 
418
                return params.StringBoolResults{}, err
 
419
        }
 
420
        for i, entity := range args.Entities {
 
421
                tag, err := names.ParseUnitTag(entity.Tag)
 
422
                if err != nil {
 
423
                        result.Results[i].Error = common.ServerError(common.ErrPerm)
 
424
                        continue
 
425
                }
 
426
                err = common.ErrPerm
 
427
                if canAccess(tag) {
 
428
                        var unit *state.Unit
 
429
                        unit, err = u.getUnit(tag)
 
430
                        if err == nil {
 
431
                                principal, ok := unit.PrincipalName()
 
432
                                if principal != "" {
 
433
                                        result.Results[i].Result = names.NewUnitTag(principal).String()
 
434
                                }
 
435
                                result.Results[i].Ok = ok
 
436
                        }
 
437
                }
 
438
                result.Results[i].Error = common.ServerError(err)
 
439
        }
 
440
        return result, nil
 
441
}
 
442
 
 
443
// Destroy advances all given Alive units' lifecycles as far as
 
444
// possible. See state/Unit.Destroy().
 
445
func (u *UniterAPIV3) Destroy(args params.Entities) (params.ErrorResults, error) {
 
446
        result := params.ErrorResults{
 
447
                Results: make([]params.ErrorResult, len(args.Entities)),
 
448
        }
 
449
        canAccess, err := u.accessUnit()
 
450
        if err != nil {
 
451
                return params.ErrorResults{}, err
 
452
        }
 
453
        for i, entity := range args.Entities {
 
454
                tag, err := names.ParseUnitTag(entity.Tag)
 
455
                if err != nil {
 
456
                        result.Results[i].Error = common.ServerError(common.ErrPerm)
 
457
                        continue
 
458
                }
 
459
                err = common.ErrPerm
 
460
                if canAccess(tag) {
 
461
                        var unit *state.Unit
 
462
                        unit, err = u.getUnit(tag)
 
463
                        if err == nil {
 
464
                                err = unit.Destroy()
 
465
                        }
 
466
                }
 
467
                result.Results[i].Error = common.ServerError(err)
 
468
        }
 
469
        return result, nil
 
470
}
 
471
 
 
472
// DestroyAllSubordinates destroys all subordinates of each given unit.
 
473
func (u *UniterAPIV3) DestroyAllSubordinates(args params.Entities) (params.ErrorResults, error) {
 
474
        result := params.ErrorResults{
 
475
                Results: make([]params.ErrorResult, len(args.Entities)),
 
476
        }
 
477
        canAccess, err := u.accessUnit()
 
478
        if err != nil {
 
479
                return params.ErrorResults{}, err
 
480
        }
 
481
        for i, entity := range args.Entities {
 
482
                tag, err := names.ParseUnitTag(entity.Tag)
 
483
                if err != nil {
 
484
                        result.Results[i].Error = common.ServerError(common.ErrPerm)
 
485
                        continue
 
486
                }
 
487
                err = common.ErrPerm
 
488
                if canAccess(tag) {
 
489
                        var unit *state.Unit
 
490
                        unit, err = u.getUnit(tag)
 
491
                        if err == nil {
 
492
                                err = u.destroySubordinates(unit)
 
493
                        }
 
494
                }
 
495
                result.Results[i].Error = common.ServerError(err)
 
496
        }
 
497
        return result, nil
 
498
}
 
499
 
 
500
// HasSubordinates returns the whether each given unit has any subordinates.
 
501
func (u *UniterAPIV3) HasSubordinates(args params.Entities) (params.BoolResults, error) {
 
502
        result := params.BoolResults{
 
503
                Results: make([]params.BoolResult, len(args.Entities)),
 
504
        }
 
505
        canAccess, err := u.accessUnit()
 
506
        if err != nil {
 
507
                return params.BoolResults{}, err
 
508
        }
 
509
        for i, entity := range args.Entities {
 
510
                tag, err := names.ParseUnitTag(entity.Tag)
 
511
                if err != nil {
 
512
                        result.Results[i].Error = common.ServerError(common.ErrPerm)
 
513
                        continue
 
514
                }
 
515
                err = common.ErrPerm
 
516
                if canAccess(tag) {
 
517
                        var unit *state.Unit
 
518
                        unit, err = u.getUnit(tag)
 
519
                        if err == nil {
 
520
                                subordinates := unit.SubordinateNames()
 
521
                                result.Results[i].Result = len(subordinates) > 0
 
522
                        }
 
523
                }
 
524
                result.Results[i].Error = common.ServerError(err)
 
525
        }
 
526
        return result, nil
 
527
}
 
528
 
 
529
// CharmModifiedVersion returns the most CharmModifiedVersion for all given
 
530
// units or services.
 
531
func (u *UniterAPIV3) CharmModifiedVersion(args params.Entities) (params.IntResults, error) {
 
532
        results := params.IntResults{
 
533
                Results: make([]params.IntResult, len(args.Entities)),
 
534
        }
 
535
 
 
536
        accessUnitOrService := common.AuthEither(u.accessUnit, u.accessService)
 
537
        canAccess, err := accessUnitOrService()
 
538
        if err != nil {
 
539
                return results, err
 
540
        }
 
541
        for i, entity := range args.Entities {
 
542
                ver, err := u.charmModifiedVersion(entity.Tag, canAccess)
 
543
                if err != nil {
 
544
                        results.Results[i].Error = common.ServerError(err)
 
545
                        continue
 
546
                }
 
547
                results.Results[i].Result = ver
 
548
        }
 
549
        return results, nil
 
550
}
 
551
 
 
552
func (u *UniterAPIV3) charmModifiedVersion(tagStr string, canAccess func(names.Tag) bool) (int, error) {
 
553
        tag, err := names.ParseTag(tagStr)
 
554
        if err != nil {
 
555
                return -1, common.ErrPerm
 
556
        }
 
557
        if !canAccess(tag) {
 
558
                return -1, common.ErrPerm
 
559
        }
 
560
        unitOrService, err := u.st.FindEntity(tag)
 
561
        if err != nil {
 
562
                return -1, err
 
563
        }
 
564
        var service *state.Application
 
565
        switch entity := unitOrService.(type) {
 
566
        case *state.Application:
 
567
                service = entity
 
568
        case *state.Unit:
 
569
                service, err = entity.Application()
 
570
                if err != nil {
 
571
                        return -1, err
 
572
                }
 
573
        default:
 
574
                return -1, errors.BadRequestf("type %t does not have a CharmModifiedVersion", entity)
 
575
        }
 
576
        return service.CharmModifiedVersion(), nil
 
577
}
 
578
 
 
579
// CharmURL returns the charm URL for all given units or services.
 
580
func (u *UniterAPIV3) CharmURL(args params.Entities) (params.StringBoolResults, error) {
 
581
        result := params.StringBoolResults{
 
582
                Results: make([]params.StringBoolResult, len(args.Entities)),
 
583
        }
 
584
        accessUnitOrService := common.AuthEither(u.accessUnit, u.accessService)
 
585
        canAccess, err := accessUnitOrService()
 
586
        if err != nil {
 
587
                return params.StringBoolResults{}, err
 
588
        }
 
589
        for i, entity := range args.Entities {
 
590
                tag, err := names.ParseTag(entity.Tag)
 
591
                if err != nil {
 
592
                        result.Results[i].Error = common.ServerError(common.ErrPerm)
 
593
                        continue
 
594
                }
 
595
                err = common.ErrPerm
 
596
                if canAccess(tag) {
 
597
                        var unitOrService state.Entity
 
598
                        unitOrService, err = u.st.FindEntity(tag)
 
599
                        if err == nil {
 
600
                                charmURLer := unitOrService.(interface {
 
601
                                        CharmURL() (*charm.URL, bool)
 
602
                                })
 
603
                                curl, ok := charmURLer.CharmURL()
 
604
                                if curl != nil {
 
605
                                        result.Results[i].Result = curl.String()
 
606
                                        result.Results[i].Ok = ok
 
607
                                }
 
608
                        }
 
609
                }
 
610
                result.Results[i].Error = common.ServerError(err)
 
611
        }
 
612
        return result, nil
 
613
}
 
614
 
 
615
// SetCharmURL sets the charm URL for each given unit. An error will
 
616
// be returned if a unit is dead, or the charm URL is not know.
 
617
func (u *UniterAPIV3) SetCharmURL(args params.EntitiesCharmURL) (params.ErrorResults, error) {
 
618
        result := params.ErrorResults{
 
619
                Results: make([]params.ErrorResult, len(args.Entities)),
 
620
        }
 
621
        canAccess, err := u.accessUnit()
 
622
        if err != nil {
 
623
                return params.ErrorResults{}, err
 
624
        }
 
625
        for i, entity := range args.Entities {
 
626
                tag, err := names.ParseUnitTag(entity.Tag)
 
627
                if err != nil {
 
628
                        result.Results[i].Error = common.ServerError(common.ErrPerm)
 
629
                        continue
 
630
                }
 
631
                err = common.ErrPerm
 
632
                if canAccess(tag) {
 
633
                        var unit *state.Unit
 
634
                        unit, err = u.getUnit(tag)
 
635
                        if err == nil {
 
636
                                var curl *charm.URL
 
637
                                curl, err = charm.ParseURL(entity.CharmURL)
 
638
                                if err == nil {
 
639
                                        err = unit.SetCharmURL(curl)
 
640
                                }
 
641
                        }
 
642
                }
 
643
                result.Results[i].Error = common.ServerError(err)
 
644
        }
 
645
        return result, nil
 
646
}
 
647
 
 
648
// WorkloadVersion returns the workload version for all given units or services.
 
649
func (u *UniterAPIV3) WorkloadVersion(args params.Entities) (params.StringResults, error) {
 
650
        result := params.StringResults{
 
651
                Results: make([]params.StringResult, len(args.Entities)),
 
652
        }
 
653
        canAccess, err := u.accessUnit()
 
654
        if err != nil {
 
655
                return params.StringResults{}, err
 
656
        }
 
657
        for i, entity := range args.Entities {
 
658
                resultItem := &result.Results[i]
 
659
                tag, err := names.ParseUnitTag(entity.Tag)
 
660
                if err != nil {
 
661
                        resultItem.Error = common.ServerError(err)
 
662
                        continue
 
663
                }
 
664
                if !canAccess(tag) {
 
665
                        resultItem.Error = common.ServerError(common.ErrPerm)
 
666
                        continue
 
667
                }
 
668
                unit, err := u.getUnit(tag)
 
669
                if err != nil {
 
670
                        resultItem.Error = common.ServerError(err)
 
671
                        continue
 
672
                }
 
673
                version, err := unit.WorkloadVersion()
 
674
                if err != nil {
 
675
                        resultItem.Error = common.ServerError(err)
 
676
                        continue
 
677
                }
 
678
                resultItem.Result = version
 
679
        }
 
680
        return result, nil
 
681
}
 
682
 
 
683
// SetWorkloadVersion sets the workload version for each given unit. An error will
 
684
// be returned if a unit is dead.
 
685
func (u *UniterAPIV3) SetWorkloadVersion(args params.EntityWorkloadVersions) (params.ErrorResults, error) {
 
686
        result := params.ErrorResults{
 
687
                Results: make([]params.ErrorResult, len(args.Entities)),
 
688
        }
 
689
        canAccess, err := u.accessUnit()
 
690
        if err != nil {
 
691
                return params.ErrorResults{}, err
 
692
        }
 
693
        for i, entity := range args.Entities {
 
694
                resultItem := &result.Results[i]
 
695
                tag, err := names.ParseUnitTag(entity.Tag)
 
696
                if err != nil {
 
697
                        resultItem.Error = common.ServerError(err)
 
698
                        continue
 
699
                }
 
700
                if !canAccess(tag) {
 
701
                        resultItem.Error = common.ServerError(common.ErrPerm)
 
702
                        continue
 
703
                }
 
704
                unit, err := u.getUnit(tag)
 
705
                if err != nil {
 
706
                        resultItem.Error = common.ServerError(err)
 
707
                        continue
 
708
                }
 
709
                err = unit.SetWorkloadVersion(entity.WorkloadVersion)
 
710
                if err != nil {
 
711
                        resultItem.Error = common.ServerError(err)
 
712
                }
 
713
        }
 
714
        return result, nil
 
715
}
 
716
 
 
717
// OpenPorts sets the policy of the port range with protocol to be
 
718
// opened, for all given units.
 
719
func (u *UniterAPIV3) OpenPorts(args params.EntitiesPortRanges) (params.ErrorResults, error) {
 
720
        result := params.ErrorResults{
 
721
                Results: make([]params.ErrorResult, len(args.Entities)),
 
722
        }
 
723
        canAccess, err := u.accessUnit()
 
724
        if err != nil {
 
725
                return params.ErrorResults{}, err
 
726
        }
 
727
        for i, entity := range args.Entities {
 
728
                tag, err := names.ParseUnitTag(entity.Tag)
 
729
                if err != nil {
 
730
                        result.Results[i].Error = common.ServerError(common.ErrPerm)
 
731
                        continue
 
732
                }
 
733
                err = common.ErrPerm
 
734
                if canAccess(tag) {
 
735
                        var unit *state.Unit
 
736
                        unit, err = u.getUnit(tag)
 
737
                        if err == nil {
 
738
                                err = unit.OpenPorts(entity.Protocol, entity.FromPort, entity.ToPort)
 
739
                        }
 
740
                }
 
741
                result.Results[i].Error = common.ServerError(err)
 
742
        }
 
743
        return result, nil
 
744
}
 
745
 
 
746
// ClosePorts sets the policy of the port range with protocol to be
 
747
// closed, for all given units.
 
748
func (u *UniterAPIV3) ClosePorts(args params.EntitiesPortRanges) (params.ErrorResults, error) {
 
749
        result := params.ErrorResults{
 
750
                Results: make([]params.ErrorResult, len(args.Entities)),
 
751
        }
 
752
        canAccess, err := u.accessUnit()
 
753
        if err != nil {
 
754
                return params.ErrorResults{}, err
 
755
        }
 
756
        for i, entity := range args.Entities {
 
757
                tag, err := names.ParseUnitTag(entity.Tag)
 
758
                if err != nil {
 
759
                        result.Results[i].Error = common.ServerError(common.ErrPerm)
 
760
                        continue
 
761
                }
 
762
                err = common.ErrPerm
 
763
                if canAccess(tag) {
 
764
                        var unit *state.Unit
 
765
                        unit, err = u.getUnit(tag)
 
766
                        if err == nil {
 
767
                                err = unit.ClosePorts(entity.Protocol, entity.FromPort, entity.ToPort)
 
768
                        }
 
769
                }
 
770
                result.Results[i].Error = common.ServerError(err)
 
771
        }
 
772
        return result, nil
 
773
}
 
774
 
 
775
// WatchConfigSettings returns a NotifyWatcher for observing changes
 
776
// to each unit's service configuration settings. See also
 
777
// state/watcher.go:Unit.WatchConfigSettings().
 
778
func (u *UniterAPIV3) WatchConfigSettings(args params.Entities) (params.NotifyWatchResults, error) {
 
779
        result := params.NotifyWatchResults{
 
780
                Results: make([]params.NotifyWatchResult, len(args.Entities)),
 
781
        }
 
782
        canAccess, err := u.accessUnit()
 
783
        if err != nil {
 
784
                return params.NotifyWatchResults{}, err
 
785
        }
 
786
        for i, entity := range args.Entities {
 
787
                tag, err := names.ParseUnitTag(entity.Tag)
 
788
                if err != nil {
 
789
                        result.Results[i].Error = common.ServerError(common.ErrPerm)
 
790
                        continue
 
791
                }
 
792
                err = common.ErrPerm
 
793
                watcherId := ""
 
794
                if canAccess(tag) {
 
795
                        watcherId, err = u.watchOneUnitConfigSettings(tag)
 
796
                }
 
797
                result.Results[i].NotifyWatcherId = watcherId
 
798
                result.Results[i].Error = common.ServerError(err)
 
799
        }
 
800
        return result, nil
 
801
}
 
802
 
 
803
// WatchActionNotifications returns a StringsWatcher for observing
 
804
// incoming action calls to a unit. See also state/watcher.go
 
805
// Unit.WatchActionNotifications(). This method is called from
 
806
// api/uniter/uniter.go WatchActionNotifications().
 
807
func (u *UniterAPIV3) WatchActionNotifications(args params.Entities) (params.StringsWatchResults, error) {
 
808
        tagToActionReceiver := common.TagToActionReceiverFn(u.st.FindEntity)
 
809
        watchOne := common.WatchOneActionReceiverNotifications(tagToActionReceiver, u.resources.Register)
 
810
        canAccess, err := u.accessUnit()
 
811
        if err != nil {
 
812
                return params.StringsWatchResults{}, err
 
813
        }
 
814
        return common.WatchActionNotifications(args, canAccess, watchOne), nil
 
815
}
 
816
 
 
817
// ConfigSettings returns the complete set of service charm config
 
818
// settings available to each given unit.
 
819
func (u *UniterAPIV3) ConfigSettings(args params.Entities) (params.ConfigSettingsResults, error) {
 
820
        result := params.ConfigSettingsResults{
 
821
                Results: make([]params.ConfigSettingsResult, len(args.Entities)),
 
822
        }
 
823
        canAccess, err := u.accessUnit()
 
824
        if err != nil {
 
825
                return params.ConfigSettingsResults{}, err
 
826
        }
 
827
        for i, entity := range args.Entities {
 
828
                tag, err := names.ParseUnitTag(entity.Tag)
 
829
                if err != nil {
 
830
                        result.Results[i].Error = common.ServerError(common.ErrPerm)
 
831
                        continue
 
832
                }
 
833
                err = common.ErrPerm
 
834
                if canAccess(tag) {
 
835
                        var unit *state.Unit
 
836
                        unit, err = u.getUnit(tag)
 
837
                        if err == nil {
 
838
                                var settings charm.Settings
 
839
                                settings, err = unit.ConfigSettings()
 
840
                                if err == nil {
 
841
                                        result.Results[i].Settings = params.ConfigSettings(settings)
 
842
                                }
 
843
                        }
 
844
                }
 
845
                result.Results[i].Error = common.ServerError(err)
 
846
        }
 
847
        return result, nil
 
848
}
 
849
 
 
850
// WatchApplicationRelations returns a StringsWatcher, for each given
 
851
// service, that notifies of changes to the lifecycles of relations
 
852
// involving that service.
 
853
func (u *UniterAPIV3) WatchApplicationRelations(args params.Entities) (params.StringsWatchResults, error) {
 
854
        result := params.StringsWatchResults{
 
855
                Results: make([]params.StringsWatchResult, len(args.Entities)),
 
856
        }
 
857
        canAccess, err := u.accessService()
 
858
        if err != nil {
 
859
                return params.StringsWatchResults{}, err
 
860
        }
 
861
        for i, entity := range args.Entities {
 
862
                tag, err := names.ParseApplicationTag(entity.Tag)
 
863
                if err != nil {
 
864
                        result.Results[i].Error = common.ServerError(common.ErrPerm)
 
865
                        continue
 
866
                }
 
867
                err = common.ErrPerm
 
868
                if canAccess(tag) {
 
869
                        result.Results[i], err = u.watchOneServiceRelations(tag)
 
870
                }
 
871
                result.Results[i].Error = common.ServerError(err)
 
872
        }
 
873
        return result, nil
 
874
}
 
875
 
 
876
// CharmArchiveSha256 returns the SHA256 digest of the charm archive
 
877
// (bundle) data for each charm url in the given parameters.
 
878
func (u *UniterAPIV3) CharmArchiveSha256(args params.CharmURLs) (params.StringResults, error) {
 
879
        result := params.StringResults{
 
880
                Results: make([]params.StringResult, len(args.URLs)),
 
881
        }
 
882
        for i, arg := range args.URLs {
 
883
                curl, err := charm.ParseURL(arg.URL)
 
884
                if err != nil {
 
885
                        err = common.ErrPerm
 
886
                } else {
 
887
                        var sch *state.Charm
 
888
                        sch, err = u.st.Charm(curl)
 
889
                        if errors.IsNotFound(err) {
 
890
                                err = common.ErrPerm
 
891
                        }
 
892
                        if err == nil {
 
893
                                result.Results[i].Result = sch.BundleSha256()
 
894
                        }
 
895
                }
 
896
                result.Results[i].Error = common.ServerError(err)
 
897
        }
 
898
        return result, nil
 
899
}
 
900
 
 
901
// Relation returns information about all given relation/unit pairs,
 
902
// including their id, key and the local endpoint.
 
903
func (u *UniterAPIV3) Relation(args params.RelationUnits) (params.RelationResults, error) {
 
904
        result := params.RelationResults{
 
905
                Results: make([]params.RelationResult, len(args.RelationUnits)),
 
906
        }
 
907
        canAccess, err := u.accessUnit()
 
908
        if err != nil {
 
909
                return params.RelationResults{}, err
 
910
        }
 
911
        for i, rel := range args.RelationUnits {
 
912
                relParams, err := u.getOneRelation(canAccess, rel.Relation, rel.Unit)
 
913
                if err == nil {
 
914
                        result.Results[i] = relParams
 
915
                }
 
916
                result.Results[i].Error = common.ServerError(err)
 
917
        }
 
918
        return result, nil
 
919
}
 
920
 
 
921
// Actions returns the Actions by Tags passed and ensures that the Unit asking
 
922
// for them is the same Unit that has the Actions.
 
923
func (u *UniterAPIV3) Actions(args params.Entities) (params.ActionResults, error) {
 
924
        canAccess, err := u.accessUnit()
 
925
        if err != nil {
 
926
                return params.ActionResults{}, err
 
927
        }
 
928
 
 
929
        actionFn := common.AuthAndActionFromTagFn(canAccess, u.st.ActionByTag)
 
930
        return common.Actions(args, actionFn), nil
 
931
}
 
932
 
 
933
// BeginActions marks the actions represented by the passed in Tags as running.
 
934
func (u *UniterAPIV3) BeginActions(args params.Entities) (params.ErrorResults, error) {
 
935
        canAccess, err := u.accessUnit()
 
936
        if err != nil {
 
937
                return params.ErrorResults{}, err
 
938
        }
 
939
 
 
940
        actionFn := common.AuthAndActionFromTagFn(canAccess, u.st.ActionByTag)
 
941
        return common.BeginActions(args, actionFn), nil
 
942
}
 
943
 
 
944
// FinishActions saves the result of a completed Action
 
945
func (u *UniterAPIV3) FinishActions(args params.ActionExecutionResults) (params.ErrorResults, error) {
 
946
        canAccess, err := u.accessUnit()
 
947
        if err != nil {
 
948
                return params.ErrorResults{}, err
 
949
        }
 
950
 
 
951
        actionFn := common.AuthAndActionFromTagFn(canAccess, u.st.ActionByTag)
 
952
        return common.FinishActions(args, actionFn), nil
 
953
}
 
954
 
 
955
// RelationById returns information about all given relations,
 
956
// specified by their ids, including their key and the local
 
957
// endpoint.
 
958
func (u *UniterAPIV3) RelationById(args params.RelationIds) (params.RelationResults, error) {
 
959
        result := params.RelationResults{
 
960
                Results: make([]params.RelationResult, len(args.RelationIds)),
 
961
        }
 
962
        for i, relId := range args.RelationIds {
 
963
                relParams, err := u.getOneRelationById(relId)
 
964
                if err == nil {
 
965
                        result.Results[i] = relParams
 
966
                }
 
967
                result.Results[i].Error = common.ServerError(err)
 
968
        }
 
969
        return result, nil
 
970
}
 
971
 
 
972
// JoinedRelations returns the tags of all relations for which each supplied unit
 
973
// has entered scope. It should be called RelationsInScope, but it's not convenient
 
974
// to make that change until we have versioned APIs.
 
975
func (u *UniterAPIV3) JoinedRelations(args params.Entities) (params.StringsResults, error) {
 
976
        result := params.StringsResults{
 
977
                Results: make([]params.StringsResult, len(args.Entities)),
 
978
        }
 
979
        if len(args.Entities) == 0 {
 
980
                return result, nil
 
981
        }
 
982
        canRead, err := u.accessUnit()
 
983
        if err != nil {
 
984
                return params.StringsResults{}, err
 
985
        }
 
986
        for i, entity := range args.Entities {
 
987
                tag, err := names.ParseUnitTag(entity.Tag)
 
988
                if err != nil {
 
989
                        result.Results[i].Error = common.ServerError(common.ErrPerm)
 
990
                        continue
 
991
                }
 
992
                err = common.ErrPerm
 
993
                if canRead(tag) {
 
994
                        var unit *state.Unit
 
995
                        unit, err = u.getUnit(tag)
 
996
                        if err == nil {
 
997
                                result.Results[i].Result, err = relationsInScopeTags(unit)
 
998
                        }
 
999
                }
 
1000
                result.Results[i].Error = common.ServerError(err)
 
1001
        }
 
1002
        return result, nil
 
1003
}
 
1004
 
 
1005
// CurrentModel returns the name and UUID for the current juju model.
 
1006
func (u *UniterAPIV3) CurrentModel() (params.ModelResult, error) {
 
1007
        result := params.ModelResult{}
 
1008
        env, err := u.st.Model()
 
1009
        if err == nil {
 
1010
                result.Name = env.Name()
 
1011
                result.UUID = env.UUID()
 
1012
        }
 
1013
        return result, err
 
1014
}
 
1015
 
 
1016
// ProviderType returns the provider type used by the current juju
 
1017
// model.
 
1018
//
 
1019
// TODO(dimitern): Refactor the uniter to call this instead of calling
 
1020
// ModelConfig() just to get the provider type. Once we have machine
 
1021
// addresses, this might be completely unnecessary though.
 
1022
func (u *UniterAPIV3) ProviderType() (params.StringResult, error) {
 
1023
        result := params.StringResult{}
 
1024
        cfg, err := u.st.ModelConfig()
 
1025
        if err == nil {
 
1026
                result.Result = cfg.Type()
 
1027
        }
 
1028
        return result, err
 
1029
}
 
1030
 
 
1031
// EnterScope ensures each unit has entered its scope in the relation,
 
1032
// for all of the given relation/unit pairs. See also
 
1033
// state.RelationUnit.EnterScope().
 
1034
func (u *UniterAPIV3) EnterScope(args params.RelationUnits) (params.ErrorResults, error) {
 
1035
        result := params.ErrorResults{
 
1036
                Results: make([]params.ErrorResult, len(args.RelationUnits)),
 
1037
        }
 
1038
        canAccess, err := u.accessUnit()
 
1039
        if err != nil {
 
1040
                return params.ErrorResults{}, err
 
1041
        }
 
1042
        for i, arg := range args.RelationUnits {
 
1043
                tag, err := names.ParseUnitTag(arg.Unit)
 
1044
                if err != nil {
 
1045
                        result.Results[i].Error = common.ServerError(common.ErrPerm)
 
1046
                        continue
 
1047
                }
 
1048
                relUnit, err := u.getRelationUnit(canAccess, arg.Relation, tag)
 
1049
                if err == nil {
 
1050
                        // Construct the settings, passing the unit's
 
1051
                        // private address (we already know it).
 
1052
                        privateAddress, _ := relUnit.PrivateAddress()
 
1053
                        settings := map[string]interface{}{
 
1054
                                "private-address": privateAddress.Value,
 
1055
                        }
 
1056
                        err = relUnit.EnterScope(settings)
 
1057
                }
 
1058
                result.Results[i].Error = common.ServerError(err)
 
1059
        }
 
1060
        return result, nil
 
1061
}
 
1062
 
 
1063
// LeaveScope signals each unit has left its scope in the relation,
 
1064
// for all of the given relation/unit pairs. See also
 
1065
// state.RelationUnit.LeaveScope().
 
1066
func (u *UniterAPIV3) LeaveScope(args params.RelationUnits) (params.ErrorResults, error) {
 
1067
        result := params.ErrorResults{
 
1068
                Results: make([]params.ErrorResult, len(args.RelationUnits)),
 
1069
        }
 
1070
        canAccess, err := u.accessUnit()
 
1071
        if err != nil {
 
1072
                return params.ErrorResults{}, err
 
1073
        }
 
1074
        for i, arg := range args.RelationUnits {
 
1075
                unit, err := names.ParseUnitTag(arg.Unit)
 
1076
                if err != nil {
 
1077
                        result.Results[i].Error = common.ServerError(common.ErrPerm)
 
1078
                        continue
 
1079
                }
 
1080
                relUnit, err := u.getRelationUnit(canAccess, arg.Relation, unit)
 
1081
                if err == nil {
 
1082
                        err = relUnit.LeaveScope()
 
1083
                }
 
1084
                result.Results[i].Error = common.ServerError(err)
 
1085
        }
 
1086
        return result, nil
 
1087
}
 
1088
 
 
1089
// ReadSettings returns the local settings of each given set of
 
1090
// relation/unit.
 
1091
func (u *UniterAPIV3) ReadSettings(args params.RelationUnits) (params.SettingsResults, error) {
 
1092
        result := params.SettingsResults{
 
1093
                Results: make([]params.SettingsResult, len(args.RelationUnits)),
 
1094
        }
 
1095
        canAccess, err := u.accessUnit()
 
1096
        if err != nil {
 
1097
                return params.SettingsResults{}, err
 
1098
        }
 
1099
        for i, arg := range args.RelationUnits {
 
1100
                unit, err := names.ParseUnitTag(arg.Unit)
 
1101
                if err != nil {
 
1102
                        result.Results[i].Error = common.ServerError(common.ErrPerm)
 
1103
                        continue
 
1104
                }
 
1105
                relUnit, err := u.getRelationUnit(canAccess, arg.Relation, unit)
 
1106
                if err == nil {
 
1107
                        var settings *state.Settings
 
1108
                        settings, err = relUnit.Settings()
 
1109
                        if err == nil {
 
1110
                                result.Results[i].Settings, err = convertRelationSettings(settings.Map())
 
1111
                        }
 
1112
                }
 
1113
                result.Results[i].Error = common.ServerError(err)
 
1114
        }
 
1115
        return result, nil
 
1116
}
 
1117
 
 
1118
// ReadRemoteSettings returns the remote settings of each given set of
 
1119
// relation/local unit/remote unit.
 
1120
func (u *UniterAPIV3) ReadRemoteSettings(args params.RelationUnitPairs) (params.SettingsResults, error) {
 
1121
        result := params.SettingsResults{
 
1122
                Results: make([]params.SettingsResult, len(args.RelationUnitPairs)),
 
1123
        }
 
1124
        canAccess, err := u.accessUnit()
 
1125
        if err != nil {
 
1126
                return params.SettingsResults{}, err
 
1127
        }
 
1128
        for i, arg := range args.RelationUnitPairs {
 
1129
                unit, err := names.ParseUnitTag(arg.LocalUnit)
 
1130
                if err != nil {
 
1131
                        result.Results[i].Error = common.ServerError(common.ErrPerm)
 
1132
                        continue
 
1133
                }
 
1134
                relUnit, err := u.getRelationUnit(canAccess, arg.Relation, unit)
 
1135
                if err == nil {
 
1136
                        // TODO(dfc) rework this logic
 
1137
                        remoteUnit := ""
 
1138
                        remoteUnit, err = u.checkRemoteUnit(relUnit, arg.RemoteUnit)
 
1139
                        if err == nil {
 
1140
                                var settings map[string]interface{}
 
1141
                                settings, err = relUnit.ReadSettings(remoteUnit)
 
1142
                                if err == nil {
 
1143
                                        result.Results[i].Settings, err = convertRelationSettings(settings)
 
1144
                                }
 
1145
                        }
 
1146
                }
 
1147
                result.Results[i].Error = common.ServerError(err)
 
1148
        }
 
1149
        return result, nil
 
1150
}
 
1151
 
 
1152
// UpdateSettings persists all changes made to the local settings of
 
1153
// all given pairs of relation and unit. Keys with empty values are
 
1154
// considered a signal to delete these values.
 
1155
func (u *UniterAPIV3) UpdateSettings(args params.RelationUnitsSettings) (params.ErrorResults, error) {
 
1156
        result := params.ErrorResults{
 
1157
                Results: make([]params.ErrorResult, len(args.RelationUnits)),
 
1158
        }
 
1159
        canAccess, err := u.accessUnit()
 
1160
        if err != nil {
 
1161
                return params.ErrorResults{}, err
 
1162
        }
 
1163
        for i, arg := range args.RelationUnits {
 
1164
                unit, err := names.ParseUnitTag(arg.Unit)
 
1165
                if err != nil {
 
1166
                        result.Results[i].Error = common.ServerError(common.ErrPerm)
 
1167
                        continue
 
1168
                }
 
1169
                relUnit, err := u.getRelationUnit(canAccess, arg.Relation, unit)
 
1170
                if err == nil {
 
1171
                        var settings *state.Settings
 
1172
                        settings, err = relUnit.Settings()
 
1173
                        if err == nil {
 
1174
                                for k, v := range arg.Settings {
 
1175
                                        if v == "" {
 
1176
                                                settings.Delete(k)
 
1177
                                        } else {
 
1178
                                                settings.Set(k, v)
 
1179
                                        }
 
1180
                                }
 
1181
                                _, err = settings.Write()
 
1182
                        }
 
1183
                }
 
1184
                result.Results[i].Error = common.ServerError(err)
 
1185
        }
 
1186
        return result, nil
 
1187
}
 
1188
 
 
1189
// WatchRelationUnits returns a RelationUnitsWatcher for observing
 
1190
// changes to every unit in the supplied relation that is visible to
 
1191
// the supplied unit. See also state/watcher.go:RelationUnit.Watch().
 
1192
func (u *UniterAPIV3) WatchRelationUnits(args params.RelationUnits) (params.RelationUnitsWatchResults, error) {
 
1193
        result := params.RelationUnitsWatchResults{
 
1194
                Results: make([]params.RelationUnitsWatchResult, len(args.RelationUnits)),
 
1195
        }
 
1196
        canAccess, err := u.accessUnit()
 
1197
        if err != nil {
 
1198
                return params.RelationUnitsWatchResults{}, err
 
1199
        }
 
1200
        for i, arg := range args.RelationUnits {
 
1201
                unit, err := names.ParseUnitTag(arg.Unit)
 
1202
                if err != nil {
 
1203
                        result.Results[i].Error = common.ServerError(common.ErrPerm)
 
1204
                        continue
 
1205
                }
 
1206
                relUnit, err := u.getRelationUnit(canAccess, arg.Relation, unit)
 
1207
                if err == nil {
 
1208
                        result.Results[i], err = u.watchOneRelationUnit(relUnit)
 
1209
                }
 
1210
                result.Results[i].Error = common.ServerError(err)
 
1211
        }
 
1212
        return result, nil
 
1213
}
 
1214
 
 
1215
// WatchUnitAddresses returns a NotifyWatcher for observing changes
 
1216
// to each unit's addresses.
 
1217
func (u *UniterAPIV3) WatchUnitAddresses(args params.Entities) (params.NotifyWatchResults, error) {
 
1218
        result := params.NotifyWatchResults{
 
1219
                Results: make([]params.NotifyWatchResult, len(args.Entities)),
 
1220
        }
 
1221
        canAccess, err := u.accessUnit()
 
1222
        if err != nil {
 
1223
                return params.NotifyWatchResults{}, err
 
1224
        }
 
1225
        for i, entity := range args.Entities {
 
1226
                unit, err := names.ParseUnitTag(entity.Tag)
 
1227
                if err != nil {
 
1228
                        result.Results[i].Error = common.ServerError(common.ErrPerm)
 
1229
                        continue
 
1230
                }
 
1231
                err = common.ErrPerm
 
1232
                watcherId := ""
 
1233
                if canAccess(unit) {
 
1234
                        watcherId, err = u.watchOneUnitAddresses(unit)
 
1235
                }
 
1236
                result.Results[i].NotifyWatcherId = watcherId
 
1237
                result.Results[i].Error = common.ServerError(err)
 
1238
        }
 
1239
        return result, nil
 
1240
}
 
1241
 
 
1242
func (u *UniterAPIV3) getUnit(tag names.UnitTag) (*state.Unit, error) {
 
1243
        return u.st.Unit(tag.Id())
 
1244
}
 
1245
 
 
1246
func (u *UniterAPIV3) getService(tag names.ApplicationTag) (*state.Application, error) {
 
1247
        return u.st.Application(tag.Id())
 
1248
}
 
1249
 
 
1250
func (u *UniterAPIV3) getRelationUnit(canAccess common.AuthFunc, relTag string, unitTag names.UnitTag) (*state.RelationUnit, error) {
 
1251
        rel, unit, err := u.getRelationAndUnit(canAccess, relTag, unitTag)
 
1252
        if err != nil {
 
1253
                return nil, err
 
1254
        }
 
1255
        return rel.Unit(unit)
 
1256
}
 
1257
 
 
1258
func (u *UniterAPIV3) getOneRelationById(relId int) (params.RelationResult, error) {
 
1259
        nothing := params.RelationResult{}
 
1260
        rel, err := u.st.Relation(relId)
 
1261
        if errors.IsNotFound(err) {
 
1262
                return nothing, common.ErrPerm
 
1263
        } else if err != nil {
 
1264
                return nothing, err
 
1265
        }
 
1266
        tag := u.auth.GetAuthTag()
 
1267
        switch tag.(type) {
 
1268
        case names.UnitTag:
 
1269
                // do nothing
 
1270
        default:
 
1271
                panic("authenticated entity is not a unit")
 
1272
        }
 
1273
        unit, err := u.st.FindEntity(tag)
 
1274
        if err != nil {
 
1275
                return nothing, err
 
1276
        }
 
1277
        // Use the currently authenticated unit to get the endpoint.
 
1278
        result, err := u.prepareRelationResult(rel, unit.(*state.Unit))
 
1279
        if err != nil {
 
1280
                // An error from prepareRelationResult means the authenticated
 
1281
                // unit's service is not part of the requested
 
1282
                // relation. That's why it's appropriate to return ErrPerm
 
1283
                // here.
 
1284
                return nothing, common.ErrPerm
 
1285
        }
 
1286
        return result, nil
 
1287
}
 
1288
 
 
1289
func (u *UniterAPIV3) getRelationAndUnit(canAccess common.AuthFunc, relTag string, unitTag names.UnitTag) (*state.Relation, *state.Unit, error) {
 
1290
        tag, err := names.ParseRelationTag(relTag)
 
1291
        if err != nil {
 
1292
                return nil, nil, common.ErrPerm
 
1293
        }
 
1294
        rel, err := u.st.KeyRelation(tag.Id())
 
1295
        if errors.IsNotFound(err) {
 
1296
                return nil, nil, common.ErrPerm
 
1297
        } else if err != nil {
 
1298
                return nil, nil, err
 
1299
        }
 
1300
        if !canAccess(unitTag) {
 
1301
                return nil, nil, common.ErrPerm
 
1302
        }
 
1303
        unit, err := u.getUnit(unitTag)
 
1304
        return rel, unit, err
 
1305
}
 
1306
 
 
1307
func (u *UniterAPIV3) prepareRelationResult(rel *state.Relation, unit *state.Unit) (params.RelationResult, error) {
 
1308
        nothing := params.RelationResult{}
 
1309
        ep, err := rel.Endpoint(unit.ApplicationName())
 
1310
        if err != nil {
 
1311
                // An error here means the unit's service is not part of the
 
1312
                // relation.
 
1313
                return nothing, err
 
1314
        }
 
1315
        return params.RelationResult{
 
1316
                Id:   rel.Id(),
 
1317
                Key:  rel.String(),
 
1318
                Life: params.Life(rel.Life().String()),
 
1319
                Endpoint: multiwatcher.Endpoint{
 
1320
                        ApplicationName: ep.ApplicationName,
 
1321
                        Relation:        multiwatcher.NewCharmRelation(ep.Relation),
 
1322
                },
 
1323
        }, nil
 
1324
}
 
1325
 
 
1326
func (u *UniterAPIV3) getOneRelation(canAccess common.AuthFunc, relTag, unitTag string) (params.RelationResult, error) {
 
1327
        nothing := params.RelationResult{}
 
1328
        tag, err := names.ParseUnitTag(unitTag)
 
1329
        if err != nil {
 
1330
                return nothing, common.ErrPerm
 
1331
        }
 
1332
        rel, unit, err := u.getRelationAndUnit(canAccess, relTag, tag)
 
1333
        if err != nil {
 
1334
                return nothing, err
 
1335
        }
 
1336
        return u.prepareRelationResult(rel, unit)
 
1337
}
 
1338
 
 
1339
func (u *UniterAPIV3) destroySubordinates(principal *state.Unit) error {
 
1340
        subordinates := principal.SubordinateNames()
 
1341
        for _, subName := range subordinates {
 
1342
                unit, err := u.getUnit(names.NewUnitTag(subName))
 
1343
                if err != nil {
 
1344
                        return err
 
1345
                }
 
1346
                if err = unit.Destroy(); err != nil {
 
1347
                        return err
 
1348
                }
 
1349
        }
 
1350
        return nil
 
1351
}
 
1352
 
 
1353
func (u *UniterAPIV3) watchOneServiceRelations(tag names.ApplicationTag) (params.StringsWatchResult, error) {
 
1354
        nothing := params.StringsWatchResult{}
 
1355
        service, err := u.getService(tag)
 
1356
        if err != nil {
 
1357
                return nothing, err
 
1358
        }
 
1359
        watch := service.WatchRelations()
 
1360
        // Consume the initial event and forward it to the result.
 
1361
        if changes, ok := <-watch.Changes(); ok {
 
1362
                return params.StringsWatchResult{
 
1363
                        StringsWatcherId: u.resources.Register(watch),
 
1364
                        Changes:          changes,
 
1365
                }, nil
 
1366
        }
 
1367
        return nothing, watcher.EnsureErr(watch)
 
1368
}
 
1369
 
 
1370
func (u *UniterAPIV3) watchOneUnitConfigSettings(tag names.UnitTag) (string, error) {
 
1371
        unit, err := u.getUnit(tag)
 
1372
        if err != nil {
 
1373
                return "", err
 
1374
        }
 
1375
        watch, err := unit.WatchConfigSettings()
 
1376
        if err != nil {
 
1377
                return "", err
 
1378
        }
 
1379
        // Consume the initial event. Technically, API
 
1380
        // calls to Watch 'transmit' the initial event
 
1381
        // in the Watch response. But NotifyWatchers
 
1382
        // have no state to transmit.
 
1383
        if _, ok := <-watch.Changes(); ok {
 
1384
                return u.resources.Register(watch), nil
 
1385
        }
 
1386
        return "", watcher.EnsureErr(watch)
 
1387
}
 
1388
 
 
1389
func (u *UniterAPIV3) watchOneUnitAddresses(tag names.UnitTag) (string, error) {
 
1390
        unit, err := u.getUnit(tag)
 
1391
        if err != nil {
 
1392
                return "", err
 
1393
        }
 
1394
        machineId, err := unit.AssignedMachineId()
 
1395
        if err != nil {
 
1396
                return "", err
 
1397
        }
 
1398
        machine, err := u.st.Machine(machineId)
 
1399
        if err != nil {
 
1400
                return "", err
 
1401
        }
 
1402
        watch := machine.WatchAddresses()
 
1403
        // Consume the initial event. Technically, API
 
1404
        // calls to Watch 'transmit' the initial event
 
1405
        // in the Watch response. But NotifyWatchers
 
1406
        // have no state to transmit.
 
1407
        if _, ok := <-watch.Changes(); ok {
 
1408
                return u.resources.Register(watch), nil
 
1409
        }
 
1410
        return "", watcher.EnsureErr(watch)
 
1411
}
 
1412
 
 
1413
func (u *UniterAPIV3) watchOneRelationUnit(relUnit *state.RelationUnit) (params.RelationUnitsWatchResult, error) {
 
1414
        watch := relUnit.Watch()
 
1415
        // Consume the initial event and forward it to the result.
 
1416
        if changes, ok := <-watch.Changes(); ok {
 
1417
                return params.RelationUnitsWatchResult{
 
1418
                        RelationUnitsWatcherId: u.resources.Register(watch),
 
1419
                        Changes:                changes,
 
1420
                }, nil
 
1421
        }
 
1422
        return params.RelationUnitsWatchResult{}, watcher.EnsureErr(watch)
 
1423
}
 
1424
 
 
1425
func (u *UniterAPIV3) checkRemoteUnit(relUnit *state.RelationUnit, remoteUnitTag string) (string, error) {
 
1426
        // Make sure the unit is indeed remote.
 
1427
        if remoteUnitTag == u.auth.GetAuthTag().String() {
 
1428
                return "", common.ErrPerm
 
1429
        }
 
1430
        // Check remoteUnit is indeed related. Note that we don't want to actually get
 
1431
        // the *Unit, because it might have been removed; but its relation settings will
 
1432
        // persist until the relation itself has been removed (and must remain accessible
 
1433
        // because the local unit's view of reality may be time-shifted).
 
1434
        tag, err := names.ParseUnitTag(remoteUnitTag)
 
1435
        if err != nil {
 
1436
                return "", common.ErrPerm
 
1437
        }
 
1438
        remoteUnitName := tag.Id()
 
1439
        remoteServiceName, err := names.UnitApplication(remoteUnitName)
 
1440
        if err != nil {
 
1441
                return "", common.ErrPerm
 
1442
        }
 
1443
        rel := relUnit.Relation()
 
1444
        _, err = rel.RelatedEndpoints(remoteServiceName)
 
1445
        if err != nil {
 
1446
                return "", common.ErrPerm
 
1447
        }
 
1448
        return remoteUnitName, nil
 
1449
}
 
1450
 
 
1451
func convertRelationSettings(settings map[string]interface{}) (params.Settings, error) {
 
1452
        result := make(params.Settings)
 
1453
        for k, v := range settings {
 
1454
                // All relation settings should be strings.
 
1455
                sval, ok := v.(string)
 
1456
                if !ok {
 
1457
                        return nil, fmt.Errorf("unexpected relation setting %q: expected string, got %T", k, v)
 
1458
                }
 
1459
                result[k] = sval
 
1460
        }
 
1461
        return result, nil
 
1462
}
 
1463
 
 
1464
func relationsInScopeTags(unit *state.Unit) ([]string, error) {
 
1465
        relations, err := unit.RelationsInScope()
 
1466
        if err != nil {
 
1467
                return nil, err
 
1468
        }
 
1469
        tags := make([]string, len(relations))
 
1470
        for i, relation := range relations {
 
1471
                tags[i] = relation.Tag().String()
 
1472
        }
 
1473
        return tags, nil
 
1474
}
 
1475
 
 
1476
func leadershipSettingsAccessorFactory(
 
1477
        st *state.State,
 
1478
        resources facade.Resources,
 
1479
        auth facade.Authorizer,
 
1480
) *leadershipapiserver.LeadershipSettingsAccessor {
 
1481
        registerWatcher := func(serviceId string) (string, error) {
 
1482
                service, err := st.Application(serviceId)
 
1483
                if err != nil {
 
1484
                        return "", err
 
1485
                }
 
1486
                w := service.WatchLeaderSettings()
 
1487
                if _, ok := <-w.Changes(); ok {
 
1488
                        return resources.Register(w), nil
 
1489
                }
 
1490
                return "", watcher.EnsureErr(w)
 
1491
        }
 
1492
        getSettings := func(serviceId string) (map[string]string, error) {
 
1493
                service, err := st.Application(serviceId)
 
1494
                if err != nil {
 
1495
                        return nil, err
 
1496
                }
 
1497
                return service.LeaderSettings()
 
1498
        }
 
1499
        writeSettings := func(token leadership.Token, serviceId string, settings map[string]string) error {
 
1500
                service, err := st.Application(serviceId)
 
1501
                if err != nil {
 
1502
                        return err
 
1503
                }
 
1504
                return service.UpdateLeaderSettings(token, settings)
 
1505
        }
 
1506
        return leadershipapiserver.NewLeadershipSettingsAccessor(
 
1507
                auth,
 
1508
                registerWatcher,
 
1509
                getSettings,
 
1510
                st.LeadershipChecker().LeadershipCheck,
 
1511
                writeSettings,
 
1512
        )
 
1513
}
 
1514
 
 
1515
// AddMetricBatches adds the metrics for the specified unit.
 
1516
func (u *UniterAPIV3) AddMetricBatches(args params.MetricBatchParams) (params.ErrorResults, error) {
 
1517
        result := params.ErrorResults{
 
1518
                Results: make([]params.ErrorResult, len(args.Batches)),
 
1519
        }
 
1520
        canAccess, err := u.accessUnit()
 
1521
        if err != nil {
 
1522
                logger.Warningf("failed to check unit access: %v", err)
 
1523
                return params.ErrorResults{}, common.ErrPerm
 
1524
        }
 
1525
        for i, batch := range args.Batches {
 
1526
                tag, err := names.ParseUnitTag(batch.Tag)
 
1527
                if err != nil {
 
1528
                        result.Results[i].Error = common.ServerError(err)
 
1529
                        continue
 
1530
                }
 
1531
                if !canAccess(tag) {
 
1532
                        result.Results[i].Error = common.ServerError(common.ErrPerm)
 
1533
                        continue
 
1534
                }
 
1535
                metrics := make([]state.Metric, len(batch.Batch.Metrics))
 
1536
                for j, metric := range batch.Batch.Metrics {
 
1537
                        metrics[j] = state.Metric{
 
1538
                                Key:   metric.Key,
 
1539
                                Value: metric.Value,
 
1540
                                Time:  metric.Time,
 
1541
                        }
 
1542
                }
 
1543
                _, err = u.st.AddMetrics(state.BatchParam{
 
1544
                        UUID:     batch.Batch.UUID,
 
1545
                        Created:  batch.Batch.Created,
 
1546
                        CharmURL: batch.Batch.CharmURL,
 
1547
                        Metrics:  metrics,
 
1548
                        Unit:     tag,
 
1549
                })
 
1550
                result.Results[i].Error = common.ServerError(err)
 
1551
        }
 
1552
        return result, nil
 
1553
}
 
1554
 
 
1555
// NetworkConfig returns information about all given relation/unit pairs,
 
1556
// including their id, key and the local endpoint.
 
1557
func (u *UniterAPIV3) NetworkConfig(args params.UnitsNetworkConfig) (params.UnitNetworkConfigResults, error) {
 
1558
        result := params.UnitNetworkConfigResults{
 
1559
                Results: make([]params.UnitNetworkConfigResult, len(args.Args)),
 
1560
        }
 
1561
 
 
1562
        canAccess, err := u.accessUnit()
 
1563
        if err != nil {
 
1564
                return params.UnitNetworkConfigResults{}, err
 
1565
        }
 
1566
 
 
1567
        for i, arg := range args.Args {
 
1568
                netConfig, err := u.getOneNetworkConfig(canAccess, arg.UnitTag, arg.BindingName)
 
1569
                if err == nil {
 
1570
                        result.Results[i].Config = netConfig
 
1571
                } else {
 
1572
                        result.Results[i].Error = common.ServerError(err)
 
1573
                }
 
1574
        }
 
1575
        return result, nil
 
1576
}
 
1577
 
 
1578
func (u *UniterAPIV3) getOneNetworkConfig(canAccess common.AuthFunc, unitTagArg, bindingName string) ([]params.NetworkConfig, error) {
 
1579
        unitTag, err := names.ParseUnitTag(unitTagArg)
 
1580
        if err != nil {
 
1581
                return nil, errors.Trace(err)
 
1582
        }
 
1583
 
 
1584
        if bindingName == "" {
 
1585
                return nil, errors.Errorf("binding name cannot be empty")
 
1586
        }
 
1587
 
 
1588
        if !canAccess(unitTag) {
 
1589
                return nil, common.ErrPerm
 
1590
        }
 
1591
 
 
1592
        unit, err := u.getUnit(unitTag)
 
1593
        if err != nil {
 
1594
                return nil, errors.Trace(err)
 
1595
        }
 
1596
 
 
1597
        service, err := unit.Application()
 
1598
        if err != nil {
 
1599
                return nil, errors.Trace(err)
 
1600
        }
 
1601
 
 
1602
        bindings, err := service.EndpointBindings()
 
1603
        if err != nil {
 
1604
                return nil, errors.Trace(err)
 
1605
        }
 
1606
        boundSpace, known := bindings[bindingName]
 
1607
        if !known {
 
1608
                return nil, errors.Errorf("binding name %q not defined by the unit's charm", bindingName)
 
1609
        }
 
1610
 
 
1611
        machineID, err := unit.AssignedMachineId()
 
1612
        if err != nil {
 
1613
                return nil, errors.Trace(err)
 
1614
        }
 
1615
 
 
1616
        machine, err := u.st.Machine(machineID)
 
1617
        if err != nil {
 
1618
                return nil, errors.Trace(err)
 
1619
        }
 
1620
 
 
1621
        var results []params.NetworkConfig
 
1622
        if boundSpace == "" {
 
1623
                logger.Debugf(
 
1624
                        "endpoint %q not explicitly bound to a space, using preferred private address for machine %q",
 
1625
                        bindingName, machineID,
 
1626
                )
 
1627
 
 
1628
                privateAddress, err := machine.PrivateAddress()
 
1629
                if err != nil {
 
1630
                        return nil, errors.Annotatef(err, "getting machine %q preferred private address", machineID)
 
1631
                }
 
1632
 
 
1633
                results = append(results, params.NetworkConfig{
 
1634
                        Address: privateAddress.Value,
 
1635
                })
 
1636
                return results, nil
 
1637
        } else {
 
1638
                logger.Debugf("endpoint %q is explicitly bound to space %q", bindingName, boundSpace)
 
1639
        }
 
1640
 
 
1641
        // TODO(dimitern): Use NetworkInterfaces() instead later, this is just for
 
1642
        // the PoC to enable minimal network-get implementation returning just the
 
1643
        // primary address.
 
1644
        //
 
1645
        // LKK Card: https://canonical.leankit.com/Boards/View/101652562/119258804
 
1646
        addresses, err := machine.AllAddresses()
 
1647
        if err != nil {
 
1648
                return nil, errors.Annotate(err, "cannot get devices addresses")
 
1649
        }
 
1650
        logger.Infof(
 
1651
                "geting network config for machine %q with addresses %+v, hosting unit %q of application %q, with bindings %+v",
 
1652
                machineID, addresses, unit.Name(), service.Name(), bindings,
 
1653
        )
 
1654
 
 
1655
        for _, addr := range addresses {
 
1656
                subnet, err := addr.Subnet()
 
1657
                if errors.IsNotFound(err) {
 
1658
                        logger.Debugf("skipping %s: not linked to a known subnet (%v)", addr, err)
 
1659
                        continue
 
1660
                } else if err != nil {
 
1661
                        return nil, errors.Annotatef(err, "cannot get subnet for address %q", addr)
 
1662
                }
 
1663
 
 
1664
                if space := subnet.SpaceName(); space != boundSpace {
 
1665
                        logger.Debugf("skipping %s: want bound to space %q, got space %q", addr, boundSpace, space)
 
1666
                        continue
 
1667
                }
 
1668
                logger.Debugf("endpoint %q bound to space %q has address %q", bindingName, boundSpace, addr)
 
1669
 
 
1670
                // TODO(dimitern): Fill in the rest later (see linked LKK card above).
 
1671
                results = append(results, params.NetworkConfig{
 
1672
                        Address: addr.Value(),
 
1673
                })
 
1674
        }
 
1675
 
 
1676
        return results, nil
 
1677
}