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