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

     1  // Copyright 2014 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package networker
     5  
     6  import (
     7  	"github.com/juju/loggo"
     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/state"
    13  	"github.com/juju/juju/state/watcher"
    14  )
    15  
    16  func init() {
    17  	// TODO: When the client can handle new versions, this should really be
    18  	// registered as version 1, since it was not present in the API in Juju
    19  	// 1.18
    20  	common.RegisterStandardFacade("Networker", 0, NewNetworkerAPI)
    21  }
    22  
    23  var logger = loggo.GetLogger("juju.apiserver.networker")
    24  
    25  // NetworkerAPI provides access to the Networker API facade.
    26  type NetworkerAPI struct {
    27  	st          *state.State
    28  	resources   *common.Resources
    29  	authorizer  common.Authorizer
    30  	getAuthFunc common.GetAuthFunc
    31  }
    32  
    33  // NewNetworkerAPI creates a new server-side Networker API facade.
    34  func NewNetworkerAPI(
    35  	st *state.State,
    36  	resources *common.Resources,
    37  	authorizer common.Authorizer,
    38  ) (*NetworkerAPI, error) {
    39  	if !authorizer.AuthMachineAgent() {
    40  		return nil, common.ErrPerm
    41  	}
    42  	getAuthFunc := func() (common.AuthFunc, error) {
    43  		authEntityTag := authorizer.GetAuthTag()
    44  
    45  		return func(tag names.Tag) bool {
    46  			if tag == authEntityTag {
    47  				// A machine agent can always access its own machine.
    48  				return true
    49  			}
    50  			if _, ok := tag.(names.MachineTag); !ok {
    51  				// Only machine tags are allowed.
    52  				return false
    53  			}
    54  			id := tag.Id()
    55  			for parentId := state.ParentId(id); parentId != ""; parentId = state.ParentId(parentId) {
    56  				// Until a top-level machine is reached.
    57  
    58  				// TODO (thumper): remove the names.Tag conversion when gccgo
    59  				// implements concrete-type-to-interface comparison correctly.
    60  				if names.Tag(names.NewMachineTag(parentId)) == authEntityTag {
    61  					// All containers with the authenticated machine as a
    62  					// parent are accessible by it.
    63  					return true
    64  				}
    65  			}
    66  			// Not found authorized machine agent among ancestors of the current one.
    67  			return false
    68  		}, nil
    69  	}
    70  
    71  	return &NetworkerAPI{
    72  		st:          st,
    73  		resources:   resources,
    74  		authorizer:  authorizer,
    75  		getAuthFunc: getAuthFunc,
    76  	}, nil
    77  }
    78  
    79  func (n *NetworkerAPI) oneMachineConfig(id string) ([]params.NetworkConfig, error) {
    80  	machine, err := n.st.Machine(id)
    81  	if err != nil {
    82  		return nil, err
    83  	}
    84  	ifaces, err := machine.NetworkInterfaces()
    85  	if err != nil {
    86  		return nil, err
    87  	}
    88  	configs := make([]params.NetworkConfig, len(ifaces))
    89  	for i, iface := range ifaces {
    90  		nw, err := n.st.Network(iface.NetworkName())
    91  		if err != nil {
    92  			return nil, err
    93  		}
    94  		configs[i] = params.NetworkConfig{
    95  			MACAddress:    iface.MACAddress(),
    96  			CIDR:          nw.CIDR(),
    97  			NetworkName:   iface.NetworkName(),
    98  			ProviderId:    string(nw.ProviderId()),
    99  			VLANTag:       nw.VLANTag(),
   100  			InterfaceName: iface.RawInterfaceName(),
   101  			Disabled:      iface.IsDisabled(),
   102  			// TODO(dimitern) Add the rest of the fields, once we
   103  			// store them in state.
   104  		}
   105  	}
   106  	return configs, nil
   107  }
   108  
   109  // MachineNetworkInfo returns the list of networks with related interfaces for a
   110  // given set of machines.
   111  // DEPRECATED: Use MachineNetworkConfig() instead.
   112  func (n *NetworkerAPI) MachineNetworkInfo(args params.Entities) (params.MachineNetworkConfigResults, error) {
   113  	return n.MachineNetworkConfig(args)
   114  }
   115  
   116  // MachineNetworkConfig returns the list of networks with related interfaces
   117  // for a given set of machines.
   118  func (n *NetworkerAPI) MachineNetworkConfig(args params.Entities) (params.MachineNetworkConfigResults, error) {
   119  	result := params.MachineNetworkConfigResults{
   120  		Results: make([]params.MachineNetworkConfigResult, len(args.Entities)),
   121  	}
   122  	canAccess, err := n.getAuthFunc()
   123  	if err != nil {
   124  		return result, err
   125  	}
   126  	for i, entity := range args.Entities {
   127  		tag, err := names.ParseTag(entity.Tag)
   128  		if err != nil {
   129  			result.Results[i].Error = common.ServerError(common.ErrPerm)
   130  			continue
   131  		}
   132  
   133  		if !canAccess(tag) {
   134  			err = common.ErrPerm
   135  		} else {
   136  			tag, ok := tag.(names.MachineTag)
   137  			if ok {
   138  				id := tag.Id()
   139  				result.Results[i].Config, err = n.oneMachineConfig(id)
   140  			}
   141  		}
   142  		result.Results[i].Error = common.ServerError(err)
   143  	}
   144  	return result, nil
   145  }
   146  
   147  func (n *NetworkerAPI) watchOneMachineInterfaces(id string) (string, error) {
   148  	machine, err := n.st.Machine(id)
   149  	if err != nil {
   150  		return "", err
   151  	}
   152  	watch := machine.WatchInterfaces()
   153  	// Consume the initial event.
   154  	if _, ok := <-watch.Changes(); ok {
   155  		return n.resources.Register(watch), nil
   156  	}
   157  	return "", watcher.EnsureErr(watch)
   158  }
   159  
   160  // WatchInterfaces returns a NotifyWatcher for observing changes
   161  // to each unit's service configuration settings.
   162  func (n *NetworkerAPI) WatchInterfaces(args params.Entities) (params.NotifyWatchResults, error) {
   163  	result := params.NotifyWatchResults{
   164  		Results: make([]params.NotifyWatchResult, len(args.Entities)),
   165  	}
   166  	canAccess, err := n.getAuthFunc()
   167  	if err != nil {
   168  		return result, err
   169  	}
   170  	for i, entity := range args.Entities {
   171  		tag, err := names.ParseTag(entity.Tag)
   172  		if err != nil {
   173  			result.Results[i].Error = common.ServerError(common.ErrPerm)
   174  			continue
   175  		}
   176  		if !canAccess(tag) {
   177  			err = common.ErrPerm
   178  		} else {
   179  			tag, ok := tag.(names.MachineTag)
   180  			if ok {
   181  				id := tag.Id()
   182  				result.Results[i].NotifyWatcherId, err = n.watchOneMachineInterfaces(id)
   183  			}
   184  		}
   185  		result.Results[i].Error = common.ServerError(err)
   186  	}
   187  	return result, nil
   188  }