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  }