github.com/niedbalski/juju@v0.0.0-20190215020005-8ff100488e47/apiserver/facades/agent/resourceshookcontext/unitfacade.go (about) 1 // Copyright 2017 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package resourceshookcontext 5 6 import ( 7 "github.com/juju/errors" 8 "gopkg.in/juju/names.v2" 9 10 "github.com/juju/juju/apiserver/common" 11 "github.com/juju/juju/apiserver/facade" 12 "github.com/juju/juju/apiserver/params" 13 "github.com/juju/juju/resource" 14 "github.com/juju/juju/resource/api" 15 "github.com/juju/juju/state" 16 ) 17 18 // NewHookContextFacade adapts NewUnitFacade for facade registration. 19 func NewHookContextFacade(st *state.State, unit *state.Unit) (interface{}, error) { 20 res, err := st.Resources() 21 if err != nil { 22 return nil, errors.Trace(err) 23 } 24 return NewUnitFacade(&resourcesUnitDataStore{res, unit}), nil 25 } 26 27 // NewStateFacade provides the signature to register this resource facade 28 func NewStateFacade(ctx facade.Context) (*UnitFacade, error) { 29 authorizer := ctx.Auth() 30 st := ctx.State() 31 32 if !authorizer.AuthUnitAgent() && !authorizer.AuthApplicationAgent() { 33 return nil, common.ErrPerm 34 } 35 36 var ( 37 unit *state.Unit 38 err error 39 ) 40 switch tag := authorizer.GetAuthTag().(type) { 41 case names.UnitTag: 42 unit, err = st.Unit(tag.Id()) 43 if err != nil { 44 return nil, errors.Trace(err) 45 } 46 case names.ApplicationTag: 47 // Allow application access for K8s units. As they are all homogeneous any of the units will suffice. 48 app, err := st.Application(tag.Id()) 49 if err != nil { 50 return nil, errors.Trace(err) 51 } 52 allUnits, err := app.AllUnits() 53 if err != nil { 54 return nil, errors.Trace(err) 55 } 56 if len(allUnits) <= 0 { 57 return nil, errors.Errorf("failed to get units for app: %s", app.Name()) 58 } 59 unit = allUnits[0] 60 default: 61 return nil, errors.Errorf("expected names.UnitTag or names.ApplicationTag, got %T", tag) 62 } 63 64 res, err := st.Resources() 65 if err != nil { 66 return nil, errors.Trace(err) 67 } 68 return NewUnitFacade(&resourcesUnitDataStore{res, unit}), nil 69 } 70 71 // resourcesUnitDatastore is a shim to elide serviceName from 72 // ListResources. 73 type resourcesUnitDataStore struct { 74 resources state.Resources 75 unit *state.Unit 76 } 77 78 // ListResources implements resource/api/private/server.UnitDataStore. 79 func (ds *resourcesUnitDataStore) ListResources() (resource.ApplicationResources, error) { 80 return ds.resources.ListResources(ds.unit.ApplicationName()) 81 } 82 83 // UnitDataStore exposes the data storage functionality needed here. 84 // All functionality is tied to the unit's application. 85 type UnitDataStore interface { 86 // ListResources lists all the resources for the application. 87 ListResources() (resource.ApplicationResources, error) 88 } 89 90 // NewUnitFacade returns the resources portion of the uniter's API facade. 91 func NewUnitFacade(dataStore UnitDataStore) *UnitFacade { 92 return &UnitFacade{ 93 DataStore: dataStore, 94 } 95 } 96 97 // UnitFacade is the resources portion of the uniter's API facade. 98 type UnitFacade struct { 99 //DataStore is the data store used by the facade. 100 DataStore UnitDataStore 101 } 102 103 // GetResourceInfo returns the resource info for each of the given 104 // resource names (for the implicit application). If any one is missing then 105 // the corresponding result is set with errors.NotFound. 106 func (uf UnitFacade) GetResourceInfo(args params.ListUnitResourcesArgs) (params.UnitResourcesResult, error) { 107 var r params.UnitResourcesResult 108 r.Resources = make([]params.UnitResourceResult, len(args.ResourceNames)) 109 110 resources, err := uf.DataStore.ListResources() 111 if err != nil { 112 r.Error = common.ServerError(err) 113 return r, nil 114 } 115 116 for i, name := range args.ResourceNames { 117 res, ok := lookUpResource(name, resources.Resources) 118 if !ok { 119 r.Resources[i].Error = common.ServerError(errors.NotFoundf("resource %q", name)) 120 continue 121 } 122 123 r.Resources[i].Resource = api.Resource2API(res) 124 } 125 return r, nil 126 } 127 128 func lookUpResource(name string, resources []resource.Resource) (resource.Resource, bool) { 129 for _, res := range resources { 130 if name == res.Name { 131 return res, true 132 } 133 } 134 return resource.Resource{}, false 135 }