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  }