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 }