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  }