github.com/cloud-green/juju@v0.0.0-20151002100041-a00291338d3d/apiserver/firewaller/firewaller.go (about)

     1  // Copyright 2014 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package firewaller
     5  
     6  import (
     7  	"github.com/juju/errors"
     8  	"github.com/juju/names"
     9  
    10  	"github.com/juju/juju/apiserver/common"
    11  	"github.com/juju/juju/apiserver/params"
    12  	"github.com/juju/juju/network"
    13  	"github.com/juju/juju/state"
    14  	"github.com/juju/juju/state/watcher"
    15  )
    16  
    17  func init() {
    18  	// Version 0 is no longer supported.
    19  	common.RegisterStandardFacade("Firewaller", 1, NewFirewallerAPI)
    20  }
    21  
    22  // FirewallerAPI provides access to the Firewaller API facade.
    23  type FirewallerAPI struct {
    24  	*common.LifeGetter
    25  	*common.EnvironWatcher
    26  	*common.AgentEntityWatcher
    27  	*common.UnitsWatcher
    28  	*common.EnvironMachinesWatcher
    29  	*common.InstanceIdGetter
    30  
    31  	st            *state.State
    32  	resources     *common.Resources
    33  	authorizer    common.Authorizer
    34  	accessUnit    common.GetAuthFunc
    35  	accessService common.GetAuthFunc
    36  	accessMachine common.GetAuthFunc
    37  	accessEnviron common.GetAuthFunc
    38  }
    39  
    40  // NewFirewallerAPI creates a new server-side FirewallerAPI facade.
    41  func NewFirewallerAPI(
    42  	st *state.State,
    43  	resources *common.Resources,
    44  	authorizer common.Authorizer,
    45  ) (*FirewallerAPI, error) {
    46  	if !authorizer.AuthEnvironManager() {
    47  		// Firewaller must run as environment manager.
    48  		return nil, common.ErrPerm
    49  	}
    50  	// Set up the various authorization checkers.
    51  	accessEnviron := common.AuthFuncForTagKind(names.EnvironTagKind)
    52  	accessUnit := common.AuthFuncForTagKind(names.UnitTagKind)
    53  	accessService := common.AuthFuncForTagKind(names.ServiceTagKind)
    54  	accessMachine := common.AuthFuncForTagKind(names.MachineTagKind)
    55  	accessUnitOrService := common.AuthEither(accessUnit, accessService)
    56  	accessUnitServiceOrMachine := common.AuthEither(accessUnitOrService, accessMachine)
    57  
    58  	// Life() is supported for units, services or machines.
    59  	lifeGetter := common.NewLifeGetter(
    60  		st,
    61  		accessUnitServiceOrMachine,
    62  	)
    63  	// EnvironConfig() and WatchForEnvironConfigChanges() are allowed
    64  	// with unrestriced access.
    65  	environWatcher := common.NewEnvironWatcher(
    66  		st,
    67  		resources,
    68  		authorizer,
    69  	)
    70  	// Watch() is supported for services only.
    71  	entityWatcher := common.NewAgentEntityWatcher(
    72  		st,
    73  		resources,
    74  		accessService,
    75  	)
    76  	// WatchUnits() is supported for machines.
    77  	unitsWatcher := common.NewUnitsWatcher(st,
    78  		resources,
    79  		accessMachine,
    80  	)
    81  	// WatchEnvironMachines() is allowed with unrestricted access.
    82  	machinesWatcher := common.NewEnvironMachinesWatcher(
    83  		st,
    84  		resources,
    85  		authorizer,
    86  	)
    87  	// InstanceId() is supported for machines.
    88  	instanceIdGetter := common.NewInstanceIdGetter(
    89  		st,
    90  		accessMachine,
    91  	)
    92  
    93  	return &FirewallerAPI{
    94  		LifeGetter:             lifeGetter,
    95  		EnvironWatcher:         environWatcher,
    96  		AgentEntityWatcher:     entityWatcher,
    97  		UnitsWatcher:           unitsWatcher,
    98  		EnvironMachinesWatcher: machinesWatcher,
    99  		InstanceIdGetter:       instanceIdGetter,
   100  		st:                     st,
   101  		resources:              resources,
   102  		authorizer:             authorizer,
   103  		accessUnit:             accessUnit,
   104  		accessService:          accessService,
   105  		accessMachine:          accessMachine,
   106  		accessEnviron:          accessEnviron,
   107  	}, nil
   108  }
   109  
   110  // WatchOpenedPorts returns a new StringsWatcher for each given
   111  // environment tag.
   112  func (f *FirewallerAPI) WatchOpenedPorts(args params.Entities) (params.StringsWatchResults, error) {
   113  	result := params.StringsWatchResults{
   114  		Results: make([]params.StringsWatchResult, len(args.Entities)),
   115  	}
   116  	if len(args.Entities) == 0 {
   117  		return result, nil
   118  	}
   119  	canWatch, err := f.accessEnviron()
   120  	if err != nil {
   121  		return params.StringsWatchResults{}, errors.Trace(err)
   122  	}
   123  	for i, entity := range args.Entities {
   124  		tag, err := names.ParseTag(entity.Tag)
   125  		if err != nil {
   126  			result.Results[i].Error = common.ServerError(common.ErrPerm)
   127  			continue
   128  		}
   129  		if !canWatch(tag) {
   130  			result.Results[i].Error = common.ServerError(common.ErrPerm)
   131  			continue
   132  		}
   133  		watcherId, initial, err := f.watchOneEnvironOpenedPorts(tag)
   134  		if err != nil {
   135  			result.Results[i].Error = common.ServerError(err)
   136  			continue
   137  		}
   138  		result.Results[i].StringsWatcherId = watcherId
   139  		result.Results[i].Changes = initial
   140  	}
   141  	return result, nil
   142  }
   143  
   144  func (f *FirewallerAPI) watchOneEnvironOpenedPorts(tag names.Tag) (string, []string, error) {
   145  	// NOTE: tag is ignored, as there is only one environment in the
   146  	// state DB. Once this changes, change the code below accordingly.
   147  	watch := f.st.WatchOpenedPorts()
   148  	// Consume the initial event and forward it to the result.
   149  	if changes, ok := <-watch.Changes(); ok {
   150  		return f.resources.Register(watch), changes, nil
   151  	}
   152  	return "", nil, watcher.EnsureErr(watch)
   153  }
   154  
   155  // GetMachinePorts returns the port ranges opened on a machine for the
   156  // specified network as a map mapping port ranges to the tags of the
   157  // units that opened them.
   158  func (f *FirewallerAPI) GetMachinePorts(args params.MachinePortsParams) (params.MachinePortsResults, error) {
   159  	result := params.MachinePortsResults{
   160  		Results: make([]params.MachinePortsResult, len(args.Params)),
   161  	}
   162  	canAccess, err := f.accessMachine()
   163  	if err != nil {
   164  		return params.MachinePortsResults{}, err
   165  	}
   166  	for i, param := range args.Params {
   167  		machineTag, err := names.ParseMachineTag(param.MachineTag)
   168  		if err != nil {
   169  			result.Results[i].Error = common.ServerError(common.ErrPerm)
   170  			continue
   171  		}
   172  		networkTag, err := names.ParseNetworkTag(param.NetworkTag)
   173  		if err != nil {
   174  			result.Results[i].Error = common.ServerError(common.ErrPerm)
   175  			continue
   176  		}
   177  		machine, err := f.getMachine(canAccess, machineTag)
   178  		if err != nil {
   179  			result.Results[i].Error = common.ServerError(err)
   180  			continue
   181  		}
   182  		ports, err := machine.OpenedPorts(networkTag.Id())
   183  		if err != nil {
   184  			result.Results[i].Error = common.ServerError(err)
   185  			continue
   186  		}
   187  		if ports != nil {
   188  			portRangeMap := ports.AllPortRanges()
   189  			var portRanges []network.PortRange
   190  			for portRange := range portRangeMap {
   191  				portRanges = append(portRanges, portRange)
   192  			}
   193  			network.SortPortRanges(portRanges)
   194  
   195  			for _, portRange := range portRanges {
   196  				unitTag := names.NewUnitTag(portRangeMap[portRange]).String()
   197  				result.Results[i].Ports = append(result.Results[i].Ports,
   198  					params.MachinePortRange{
   199  						UnitTag:   unitTag,
   200  						PortRange: params.FromNetworkPortRange(portRange),
   201  					})
   202  			}
   203  		}
   204  	}
   205  	return result, nil
   206  }
   207  
   208  // GetMachineActiveNetworks returns the tags of the all networks the
   209  // each given machine has open ports on.
   210  func (f *FirewallerAPI) GetMachineActiveNetworks(args params.Entities) (params.StringsResults, error) {
   211  	result := params.StringsResults{
   212  		Results: make([]params.StringsResult, len(args.Entities)),
   213  	}
   214  	canAccess, err := f.accessMachine()
   215  	if err != nil {
   216  		return params.StringsResults{}, err
   217  	}
   218  	for i, entity := range args.Entities {
   219  		machineTag, err := names.ParseMachineTag(entity.Tag)
   220  		if err != nil {
   221  			result.Results[i].Error = common.ServerError(common.ErrPerm)
   222  			continue
   223  		}
   224  		machine, err := f.getMachine(canAccess, machineTag)
   225  		if err != nil {
   226  			result.Results[i].Error = common.ServerError(err)
   227  			continue
   228  		}
   229  		ports, err := machine.AllPorts()
   230  		if err != nil {
   231  			result.Results[i].Error = common.ServerError(err)
   232  			continue
   233  		}
   234  		for _, port := range ports {
   235  			networkTag := names.NewNetworkTag(port.NetworkName()).String()
   236  			result.Results[i].Result = append(result.Results[i].Result, networkTag)
   237  		}
   238  	}
   239  	return result, nil
   240  }
   241  
   242  // GetExposed returns the exposed flag value for each given service.
   243  func (f *FirewallerAPI) GetExposed(args params.Entities) (params.BoolResults, error) {
   244  	result := params.BoolResults{
   245  		Results: make([]params.BoolResult, len(args.Entities)),
   246  	}
   247  	canAccess, err := f.accessService()
   248  	if err != nil {
   249  		return params.BoolResults{}, err
   250  	}
   251  	for i, entity := range args.Entities {
   252  		tag, err := names.ParseServiceTag(entity.Tag)
   253  		if err != nil {
   254  			result.Results[i].Error = common.ServerError(common.ErrPerm)
   255  			continue
   256  		}
   257  		service, err := f.getService(canAccess, tag)
   258  		if err == nil {
   259  			result.Results[i].Result = service.IsExposed()
   260  		}
   261  		result.Results[i].Error = common.ServerError(err)
   262  	}
   263  	return result, nil
   264  }
   265  
   266  // GetAssignedMachine returns the assigned machine tag (if any) for
   267  // each given unit.
   268  func (f *FirewallerAPI) GetAssignedMachine(args params.Entities) (params.StringResults, error) {
   269  	result := params.StringResults{
   270  		Results: make([]params.StringResult, len(args.Entities)),
   271  	}
   272  	canAccess, err := f.accessUnit()
   273  	if err != nil {
   274  		return params.StringResults{}, err
   275  	}
   276  	for i, entity := range args.Entities {
   277  		tag, err := names.ParseUnitTag(entity.Tag)
   278  		if err != nil {
   279  			result.Results[i].Error = common.ServerError(common.ErrPerm)
   280  			continue
   281  		}
   282  		unit, err := f.getUnit(canAccess, tag)
   283  		if err == nil {
   284  			var machineId string
   285  			machineId, err = unit.AssignedMachineId()
   286  			if err == nil {
   287  				result.Results[i].Result = names.NewMachineTag(machineId).String()
   288  			}
   289  		}
   290  		result.Results[i].Error = common.ServerError(err)
   291  	}
   292  	return result, nil
   293  }
   294  
   295  func (f *FirewallerAPI) getEntity(canAccess common.AuthFunc, tag names.Tag) (state.Entity, error) {
   296  	if !canAccess(tag) {
   297  		return nil, common.ErrPerm
   298  	}
   299  	return f.st.FindEntity(tag)
   300  }
   301  
   302  func (f *FirewallerAPI) getUnit(canAccess common.AuthFunc, tag names.UnitTag) (*state.Unit, error) {
   303  	entity, err := f.getEntity(canAccess, tag)
   304  	if err != nil {
   305  		return nil, err
   306  	}
   307  	// The authorization function guarantees that the tag represents a
   308  	// unit.
   309  	return entity.(*state.Unit), nil
   310  }
   311  
   312  func (f *FirewallerAPI) getService(canAccess common.AuthFunc, tag names.ServiceTag) (*state.Service, error) {
   313  	entity, err := f.getEntity(canAccess, tag)
   314  	if err != nil {
   315  		return nil, err
   316  	}
   317  	// The authorization function guarantees that the tag represents a
   318  	// service.
   319  	return entity.(*state.Service), nil
   320  }
   321  
   322  func (f *FirewallerAPI) getMachine(canAccess common.AuthFunc, tag names.MachineTag) (*state.Machine, error) {
   323  	entity, err := f.getEntity(canAccess, tag)
   324  	if err != nil {
   325  		return nil, err
   326  	}
   327  	// The authorization function guarantees that the tag represents a
   328  	// machine.
   329  	return entity.(*state.Machine), nil
   330  }