github.com/niedbalski/juju@v0.0.0-20190215020005-8ff100488e47/apiserver/facades/client/annotations/client.go (about) 1 // Copyright 2015 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package annotations 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/permission" 14 "github.com/juju/juju/state" 15 ) 16 17 var getState = func(st *state.State, m *state.Model) annotationAccess { 18 return stateShim{st, m} 19 } 20 21 // Annotations defines the methods on the service API end point. 22 type Annotations interface { 23 Get(args params.Entities) params.AnnotationsGetResults 24 Set(args params.AnnotationsSet) params.ErrorResults 25 } 26 27 // API implements the service interface and is the concrete 28 // implementation of the api end point. 29 type API struct { 30 access annotationAccess 31 authorizer facade.Authorizer 32 } 33 34 // NewAPI returns a new charm annotator API facade. 35 func NewAPI( 36 st *state.State, 37 resources facade.Resources, 38 authorizer facade.Authorizer, 39 ) (*API, error) { 40 if !authorizer.AuthClient() { 41 return nil, common.ErrPerm 42 } 43 m, err := st.Model() 44 if err != nil { 45 return nil, errors.Trace(err) 46 } 47 48 return &API{ 49 access: getState(st, m), 50 authorizer: authorizer, 51 }, nil 52 } 53 54 func (api *API) checkCanRead() error { 55 canRead, err := api.authorizer.HasPermission(permission.ReadAccess, api.access.ModelTag()) 56 if err != nil { 57 return errors.Trace(err) 58 } 59 if !canRead { 60 return common.ErrPerm 61 } 62 return nil 63 } 64 65 func (api *API) checkCanWrite() error { 66 canWrite, err := api.authorizer.HasPermission(permission.WriteAccess, api.access.ModelTag()) 67 if err != nil { 68 return errors.Trace(err) 69 } 70 if !canWrite { 71 return common.ErrPerm 72 } 73 return nil 74 } 75 76 // Get returns annotations for given entities. 77 // If annotations cannot be retrieved for a given entity, an error is returned. 78 // Each entity is treated independently and, hence, will fail or succeed independently. 79 func (api *API) Get(args params.Entities) params.AnnotationsGetResults { 80 if err := api.checkCanRead(); err != nil { 81 result := make([]params.AnnotationsGetResult, len(args.Entities)) 82 for i := range result { 83 result[i].Error = params.ErrorResult{Error: common.ServerError(err)} 84 } 85 return params.AnnotationsGetResults{Results: result} 86 } 87 88 entityResults := []params.AnnotationsGetResult{} 89 for _, entity := range args.Entities { 90 anEntityResult := params.AnnotationsGetResult{EntityTag: entity.Tag} 91 if annts, err := api.getEntityAnnotations(entity.Tag); err != nil { 92 anEntityResult.Error = params.ErrorResult{annotateError(err, entity.Tag, "getting")} 93 } else { 94 anEntityResult.Annotations = annts 95 } 96 entityResults = append(entityResults, anEntityResult) 97 } 98 return params.AnnotationsGetResults{Results: entityResults} 99 } 100 101 // Set stores annotations for given entities 102 func (api *API) Set(args params.AnnotationsSet) params.ErrorResults { 103 if err := api.checkCanWrite(); err != nil { 104 errorResults := make([]params.ErrorResult, len(args.Annotations)) 105 for i := range errorResults { 106 errorResults[i].Error = common.ServerError(err) 107 } 108 return params.ErrorResults{Results: errorResults} 109 } 110 setErrors := []params.ErrorResult{} 111 for _, entityAnnotation := range args.Annotations { 112 err := api.setEntityAnnotations(entityAnnotation.EntityTag, entityAnnotation.Annotations) 113 if err != nil { 114 setErrors = append(setErrors, 115 params.ErrorResult{Error: annotateError(err, entityAnnotation.EntityTag, "setting")}) 116 } 117 } 118 return params.ErrorResults{Results: setErrors} 119 } 120 121 func annotateError(err error, tag, op string) *params.Error { 122 return common.ServerError( 123 errors.Trace( 124 errors.Annotatef( 125 err, "while %v annotations to %q", op, tag))) 126 } 127 128 func (api *API) getEntityAnnotations(entityTag string) (map[string]string, error) { 129 tag, err := names.ParseTag(entityTag) 130 if err != nil { 131 return nil, errors.Trace(err) 132 } 133 entity, err := api.findEntity(tag) 134 if err != nil { 135 return nil, errors.Trace(err) 136 } 137 annotations, err := api.access.Annotations(entity) 138 if err != nil { 139 return nil, errors.Trace(err) 140 } 141 return annotations, nil 142 } 143 144 func (api *API) findEntity(tag names.Tag) (state.GlobalEntity, error) { 145 entity0, err := api.access.FindEntity(tag) 146 if err != nil { 147 if errors.IsNotFound(err) { 148 return nil, common.ErrPerm 149 } 150 return nil, err 151 } 152 entity, ok := entity0.(state.GlobalEntity) 153 if !ok { 154 return nil, common.NotSupportedError(tag, "annotations") 155 } 156 return entity, nil 157 } 158 159 func (api *API) setEntityAnnotations(entityTag string, annotations map[string]string) error { 160 tag, err := names.ParseTag(entityTag) 161 if err != nil { 162 return errors.Trace(err) 163 } 164 entity, err := api.findEntity(tag) 165 if err != nil { 166 return errors.Trace(err) 167 } 168 return api.access.SetAnnotations(entity, annotations) 169 }