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