github.com/mattyw/juju@v0.0.0-20140610034352-732aecd63861/state/apiserver/firewaller/firewaller.go (about)

     1  // Copyright 2012, 2013 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  package firewaller
     4  
     5  import (
     6  	"github.com/juju/names"
     7  
     8  	"github.com/juju/juju/state"
     9  	"github.com/juju/juju/state/api/params"
    10  	"github.com/juju/juju/state/apiserver/common"
    11  )
    12  
    13  // FirewallerAPI provides access to the Firewaller API facade.
    14  type FirewallerAPI struct {
    15  	*common.LifeGetter
    16  	*common.EnvironWatcher
    17  	*common.AgentEntityWatcher
    18  	*common.UnitsWatcher
    19  	*common.EnvironMachinesWatcher
    20  	*common.InstanceIdGetter
    21  
    22  	st            *state.State
    23  	resources     *common.Resources
    24  	authorizer    common.Authorizer
    25  	accessUnit    common.GetAuthFunc
    26  	accessService common.GetAuthFunc
    27  }
    28  
    29  // NewFirewallerAPI creates a new server-side FirewallerAPI facade.
    30  func NewFirewallerAPI(
    31  	st *state.State,
    32  	resources *common.Resources,
    33  	authorizer common.Authorizer,
    34  ) (*FirewallerAPI, error) {
    35  	if !authorizer.AuthEnvironManager() {
    36  		// Firewaller must run as environment manager.
    37  		return nil, common.ErrPerm
    38  	}
    39  	// Set up the various authorization checkers.
    40  	accessUnit := getAuthFuncForTagKind(names.UnitTagKind)
    41  	accessService := getAuthFuncForTagKind(names.ServiceTagKind)
    42  	accessMachine := getAuthFuncForTagKind(names.MachineTagKind)
    43  	accessEnviron := getAuthFuncForTagKind("")
    44  	accessUnitOrService := common.AuthEither(accessUnit, accessService)
    45  	accessUnitServiceOrMachine := common.AuthEither(accessUnitOrService, accessMachine)
    46  
    47  	// Life() is supported for units, services or machines.
    48  	lifeGetter := common.NewLifeGetter(
    49  		st,
    50  		accessUnitServiceOrMachine,
    51  	)
    52  	// EnvironConfig() and WatchForEnvironConfigChanges() are allowed
    53  	// with unrestriced access.
    54  	environWatcher := common.NewEnvironWatcher(
    55  		st,
    56  		resources,
    57  		accessEnviron,
    58  		accessEnviron,
    59  	)
    60  	// Watch() is supported for units or services.
    61  	entityWatcher := common.NewAgentEntityWatcher(
    62  		st,
    63  		resources,
    64  		accessUnitOrService,
    65  	)
    66  	// WatchUnits() is supported for machines.
    67  	unitsWatcher := common.NewUnitsWatcher(st,
    68  		resources,
    69  		accessMachine,
    70  	)
    71  	// WatchEnvironMachines() is allowed with unrestricted access.
    72  	machinesWatcher := common.NewEnvironMachinesWatcher(
    73  		st,
    74  		resources,
    75  		accessEnviron,
    76  	)
    77  	// InstanceId() is supported for machines.
    78  	instanceIdGetter := common.NewInstanceIdGetter(
    79  		st,
    80  		accessMachine,
    81  	)
    82  	return &FirewallerAPI{
    83  		LifeGetter:             lifeGetter,
    84  		EnvironWatcher:         environWatcher,
    85  		AgentEntityWatcher:     entityWatcher,
    86  		UnitsWatcher:           unitsWatcher,
    87  		EnvironMachinesWatcher: machinesWatcher,
    88  		InstanceIdGetter:       instanceIdGetter,
    89  		st:                     st,
    90  		resources:              resources,
    91  		authorizer:             authorizer,
    92  		accessUnit:             accessUnit,
    93  		accessService:          accessService,
    94  	}, nil
    95  }
    96  
    97  // OpenedPorts returns the list of opened ports for each given unit.
    98  func (f *FirewallerAPI) OpenedPorts(args params.Entities) (params.PortsResults, error) {
    99  	result := params.PortsResults{
   100  		Results: make([]params.PortsResult, len(args.Entities)),
   101  	}
   102  	canAccess, err := f.accessUnit()
   103  	if err != nil {
   104  		return params.PortsResults{}, err
   105  	}
   106  	for i, entity := range args.Entities {
   107  		var unit *state.Unit
   108  		unit, err = f.getUnit(canAccess, entity.Tag)
   109  		if err == nil {
   110  			result.Results[i].Ports = unit.OpenedPorts()
   111  		}
   112  		result.Results[i].Error = common.ServerError(err)
   113  	}
   114  	return result, nil
   115  }
   116  
   117  // GetExposed returns the exposed flag value for each given service.
   118  func (f *FirewallerAPI) GetExposed(args params.Entities) (params.BoolResults, error) {
   119  	result := params.BoolResults{
   120  		Results: make([]params.BoolResult, len(args.Entities)),
   121  	}
   122  	canAccess, err := f.accessService()
   123  	if err != nil {
   124  		return params.BoolResults{}, err
   125  	}
   126  	for i, entity := range args.Entities {
   127  		var service *state.Service
   128  		service, err = f.getService(canAccess, entity.Tag)
   129  		if err == nil {
   130  			result.Results[i].Result = service.IsExposed()
   131  		}
   132  		result.Results[i].Error = common.ServerError(err)
   133  	}
   134  	return result, nil
   135  }
   136  
   137  // GetAssignedMachine returns the assigned machine tag (if any) for
   138  // each given unit.
   139  func (f *FirewallerAPI) GetAssignedMachine(args params.Entities) (params.StringResults, error) {
   140  	result := params.StringResults{
   141  		Results: make([]params.StringResult, len(args.Entities)),
   142  	}
   143  	canAccess, err := f.accessUnit()
   144  	if err != nil {
   145  		return params.StringResults{}, err
   146  	}
   147  	for i, entity := range args.Entities {
   148  		var unit *state.Unit
   149  		unit, err = f.getUnit(canAccess, entity.Tag)
   150  		if err == nil {
   151  			var machineId string
   152  			machineId, err = unit.AssignedMachineId()
   153  			if err == nil {
   154  				result.Results[i].Result = names.MachineTag(machineId)
   155  			}
   156  		}
   157  		result.Results[i].Error = common.ServerError(err)
   158  	}
   159  	return result, nil
   160  }
   161  
   162  func (f *FirewallerAPI) getEntity(canAccess common.AuthFunc, tag string) (state.Entity, error) {
   163  	if !canAccess(tag) {
   164  		return nil, common.ErrPerm
   165  	}
   166  	return f.st.FindEntity(tag)
   167  }
   168  
   169  func (f *FirewallerAPI) getUnit(canAccess common.AuthFunc, tag string) (*state.Unit, error) {
   170  	entity, err := f.getEntity(canAccess, tag)
   171  	if err != nil {
   172  		return nil, err
   173  	}
   174  	// The authorization function guarantees that the tag represents a
   175  	// unit.
   176  	return entity.(*state.Unit), nil
   177  }
   178  
   179  func (f *FirewallerAPI) getService(canAccess common.AuthFunc, tag string) (*state.Service, error) {
   180  	entity, err := f.getEntity(canAccess, tag)
   181  	if err != nil {
   182  		return nil, err
   183  	}
   184  	// The authorization function guarantees that the tag represents a
   185  	// service.
   186  	return entity.(*state.Service), nil
   187  }
   188  
   189  // getAuthFuncForTagKind returns a GetAuthFunc which creates an
   190  // AuthFunc allowing only the given tag kind and denies all
   191  // others. In the special case where a single empty string is given,
   192  // it's assumed only environment tags are allowed, but not specified
   193  // (for now).
   194  func getAuthFuncForTagKind(kind string) common.GetAuthFunc {
   195  	return func() (common.AuthFunc, error) {
   196  		return func(tag string) bool {
   197  			if tag == "" {
   198  				// Assume an empty tag means a missing environment tag.
   199  				return kind == ""
   200  			}
   201  			// Allow only the given tag kind.
   202  			_, _, err := names.ParseTag(tag, kind)
   203  			if err != nil {
   204  				return false
   205  			}
   206  			return true
   207  		}, nil
   208  	}
   209  }