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