github.com/altoros/juju-vmware@v0.0.0-20150312064031-f19ae857ccca/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) oneMachineInfo(id string) ([]params.NetworkInfo, 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  	info := make([]params.NetworkInfo, 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  		info[i] = params.NetworkInfo{
    95  			MACAddress:    iface.MACAddress(),
    96  			CIDR:          nw.CIDR(),
    97  			NetworkName:   iface.NetworkName(),
    98  			ProviderId:    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 info, nil
   107  }
   108  
   109  // Networks returns the list of networks with related interfaces for a given set of machines.
   110  func (n *NetworkerAPI) MachineNetworkInfo(args params.Entities) (params.MachineNetworkInfoResults, error) {
   111  	result := params.MachineNetworkInfoResults{
   112  		Results: make([]params.MachineNetworkInfoResult, len(args.Entities)),
   113  	}
   114  	canAccess, err := n.getAuthFunc()
   115  	if err != nil {
   116  		return result, err
   117  	}
   118  	for i, entity := range args.Entities {
   119  		tag, err := names.ParseTag(entity.Tag)
   120  		if err != nil {
   121  			result.Results[i].Error = common.ServerError(common.ErrPerm)
   122  			continue
   123  		}
   124  
   125  		if !canAccess(tag) {
   126  			err = common.ErrPerm
   127  		} else {
   128  			tag, ok := tag.(names.MachineTag)
   129  			if ok {
   130  				id := tag.Id()
   131  				result.Results[i].Info, err = n.oneMachineInfo(id)
   132  			}
   133  		}
   134  		result.Results[i].Error = common.ServerError(err)
   135  	}
   136  	return result, nil
   137  }
   138  
   139  func (n *NetworkerAPI) watchOneMachineInterfaces(id string) (string, error) {
   140  	machine, err := n.st.Machine(id)
   141  	if err != nil {
   142  		return "", err
   143  	}
   144  	watch := machine.WatchInterfaces()
   145  	// Consume the initial event.
   146  	if _, ok := <-watch.Changes(); ok {
   147  		return n.resources.Register(watch), nil
   148  	}
   149  	return "", watcher.EnsureErr(watch)
   150  }
   151  
   152  // WatchInterfaces returns a NotifyWatcher for observing changes
   153  // to each unit's service configuration settings.
   154  func (n *NetworkerAPI) WatchInterfaces(args params.Entities) (params.NotifyWatchResults, error) {
   155  	result := params.NotifyWatchResults{
   156  		Results: make([]params.NotifyWatchResult, len(args.Entities)),
   157  	}
   158  	canAccess, err := n.getAuthFunc()
   159  	if err != nil {
   160  		return result, err
   161  	}
   162  	for i, entity := range args.Entities {
   163  		tag, err := names.ParseTag(entity.Tag)
   164  		if err != nil {
   165  			result.Results[i].Error = common.ServerError(common.ErrPerm)
   166  			continue
   167  		}
   168  		if !canAccess(tag) {
   169  			err = common.ErrPerm
   170  		} else {
   171  			tag, ok := tag.(names.MachineTag)
   172  			if ok {
   173  				id := tag.Id()
   174  				result.Results[i].NotifyWatcherId, err = n.watchOneMachineInterfaces(id)
   175  			}
   176  		}
   177  		result.Results[i].Error = common.ServerError(err)
   178  	}
   179  	return result, nil
   180  }