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 }