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 }