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