launchpad.net/~rogpeppe/juju-core/500-errgo-fix@v0.0.0-20140213181702-000000002356/state/apiserver/firewaller/firewaller.go (about) 1 // Copyright 2012, 2013 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 package firewaller 4 5 import ( 6 "launchpad.net/errgo/errors" 7 "launchpad.net/juju-core/names" 8 "launchpad.net/juju-core/state" 9 "launchpad.net/juju-core/state/api/params" 10 "launchpad.net/juju-core/state/apiserver/common" 11 ) 12 13 var mask = errors.Mask 14 15 // FirewallerAPI provides access to the Firewaller API facade. 16 type FirewallerAPI struct { 17 *common.LifeGetter 18 *common.EnvironWatcher 19 *common.AgentEntityWatcher 20 *common.UnitsWatcher 21 *common.EnvironMachinesWatcher 22 *common.InstanceIdGetter 23 24 st *state.State 25 resources *common.Resources 26 authorizer common.Authorizer 27 accessUnit common.GetAuthFunc 28 accessService common.GetAuthFunc 29 } 30 31 // NewFirewallerAPI creates a new server-side FirewallerAPI facade. 32 func NewFirewallerAPI( 33 st *state.State, 34 resources *common.Resources, 35 authorizer common.Authorizer, 36 ) (*FirewallerAPI, error) { 37 if !authorizer.AuthEnvironManager() { 38 // Firewaller must run as environment manager. 39 return nil, common.ErrPerm 40 } 41 // Set up the various authorization checkers. 42 accessUnit := getAuthFuncForTagKind(names.UnitTagKind) 43 accessService := getAuthFuncForTagKind(names.ServiceTagKind) 44 accessMachine := getAuthFuncForTagKind(names.MachineTagKind) 45 accessEnviron := getAuthFuncForTagKind("") 46 accessUnitOrService := common.AuthEither(accessUnit, accessService) 47 accessUnitServiceOrMachine := common.AuthEither(accessUnitOrService, accessMachine) 48 49 // Life() is supported for units, services or machines. 50 lifeGetter := common.NewLifeGetter( 51 st, 52 accessUnitServiceOrMachine, 53 ) 54 // EnvironConfig() and WatchForEnvironConfigChanges() are allowed 55 // with unrestriced access. 56 environWatcher := common.NewEnvironWatcher( 57 st, 58 resources, 59 accessEnviron, 60 accessEnviron, 61 ) 62 // Watch() is supported for units or services. 63 entityWatcher := common.NewAgentEntityWatcher( 64 st, 65 resources, 66 accessUnitOrService, 67 ) 68 // WatchUnits() is supported for machines. 69 unitsWatcher := common.NewUnitsWatcher(st, 70 resources, 71 accessMachine, 72 ) 73 // WatchEnvironMachines() is allowed with unrestricted access. 74 machinesWatcher := common.NewEnvironMachinesWatcher( 75 st, 76 resources, 77 accessEnviron, 78 ) 79 // InstanceId() is supported for machines. 80 instanceIdGetter := common.NewInstanceIdGetter( 81 st, 82 accessMachine, 83 ) 84 return &FirewallerAPI{ 85 LifeGetter: lifeGetter, 86 EnvironWatcher: environWatcher, 87 AgentEntityWatcher: entityWatcher, 88 UnitsWatcher: unitsWatcher, 89 EnvironMachinesWatcher: machinesWatcher, 90 InstanceIdGetter: instanceIdGetter, 91 st: st, 92 resources: resources, 93 authorizer: authorizer, 94 accessUnit: accessUnit, 95 accessService: accessService, 96 }, nil 97 } 98 99 // OpenedPorts returns the list of opened ports for each given unit. 100 func (f *FirewallerAPI) OpenedPorts(args params.Entities) (params.PortsResults, error) { 101 result := params.PortsResults{ 102 Results: make([]params.PortsResult, len(args.Entities)), 103 } 104 canAccess, err := f.accessUnit() 105 if err != nil { 106 return params.PortsResults{}, mask(err) 107 } 108 for i, entity := range args.Entities { 109 var unit *state.Unit 110 unit, err = f.getUnit(canAccess, entity.Tag) 111 if err == nil { 112 result.Results[i].Ports = unit.OpenedPorts() 113 } 114 result.Results[i].Error = common.ServerError(err) 115 } 116 return result, nil 117 } 118 119 // GetExposed returns the exposed flag value for each given service. 120 func (f *FirewallerAPI) GetExposed(args params.Entities) (params.BoolResults, error) { 121 result := params.BoolResults{ 122 Results: make([]params.BoolResult, len(args.Entities)), 123 } 124 canAccess, err := f.accessService() 125 if err != nil { 126 return params.BoolResults{}, mask(err) 127 } 128 for i, entity := range args.Entities { 129 var service *state.Service 130 service, err = f.getService(canAccess, entity.Tag) 131 if err == nil { 132 result.Results[i].Result = service.IsExposed() 133 } 134 result.Results[i].Error = common.ServerError(err) 135 } 136 return result, nil 137 } 138 139 // GetAssignedMachine returns the assigned machine tag (if any) for 140 // each given unit. 141 func (f *FirewallerAPI) GetAssignedMachine(args params.Entities) (params.StringResults, error) { 142 result := params.StringResults{ 143 Results: make([]params.StringResult, len(args.Entities)), 144 } 145 canAccess, err := f.accessUnit() 146 if err != nil { 147 return params.StringResults{}, mask(err) 148 } 149 for i, entity := range args.Entities { 150 var unit *state.Unit 151 unit, err = f.getUnit(canAccess, entity.Tag) 152 if err == nil { 153 var machineId string 154 machineId, err = unit.AssignedMachineId() 155 if err == nil { 156 result.Results[i].Result = names.MachineTag(machineId) 157 } 158 } 159 result.Results[i].Error = common.ServerError(err) 160 } 161 return result, nil 162 } 163 164 func (f *FirewallerAPI) getEntity(canAccess common.AuthFunc, tag string) (state.Entity, error) { 165 if !canAccess(tag) { 166 return nil, common.ErrPerm 167 } 168 return f.st.FindEntity(tag) 169 } 170 171 func (f *FirewallerAPI) getUnit(canAccess common.AuthFunc, tag string) (*state.Unit, error) { 172 entity, err := f.getEntity(canAccess, tag) 173 if err != nil { 174 // The authorization function guarantees that the tag represents a 175 // unit. 176 return nil, mask(err, errors.Any) 177 } 178 179 return entity.(*state.Unit), nil 180 } 181 182 func (f *FirewallerAPI) getService(canAccess common.AuthFunc, tag string) (*state.Service, error) { 183 entity, err := f.getEntity(canAccess, tag) 184 if err != nil { 185 // The authorization function guarantees that the tag represents a 186 // service. 187 return nil, mask(err, errors.Any) 188 } 189 190 return entity.(*state.Service), nil 191 } 192 193 // getAuthFuncForTagKind returns a GetAuthFunc which creates an 194 // AuthFunc allowing only the given tag kind and denies all 195 // others. In the special case where a single empty string is given, 196 // it's assumed only environment tags are allowed, but not specified 197 // (for now). 198 func getAuthFuncForTagKind(kind string) common.GetAuthFunc { 199 return func() (common.AuthFunc, error) { 200 return func(tag string) bool { 201 if tag == "" { 202 // Assume an empty tag means a missing environment tag. 203 return kind == "" 204 } 205 // Allow only the given tag kind. 206 _, _, err := names.ParseTag(tag, kind) 207 if err != nil { 208 return false 209 } 210 return true 211 }, nil 212 } 213 }