-
-
from pyaspects.weaver import weave_class_method
from PLC.Method import Method
from aspects.omfaspects import OMFAspect
-
-
+from aspects.ratelimitaspects import RateLimitAspect
def apply_omf_aspect():
# track all PLC methods to add OMF hooks
weave_class_method(OMFAspect(), Method, "__call__")
-
+ weave_class_method(RateLimitAspect(), Method, "__call__")
def apply_debugger_aspect():
# just log all method calls w/ their parameters
--- /dev/null
+from PLC.Config import Config
+from PLC.Faults import *
+
+from datetime import datetime, timedelta
+from pyaspects.meta import MetaAspect
+import memcache
+
+class BaseRateLimit(object):
+
+ def __init__(self):
+ self.config = Config("/etc/planetlab/plc_config")
+
+ self.prefix = "ratelimit"
+ self.minutes = 3 # The time period
+ self.requests = 10 # Number of allowed requests in that time period
+ self.expire_after = (self.minutes + 1) * 60
+
+ def before(self, wobj, data, *args, **kwargs):
+ # ratelimit_128.112.139.115_201011091532 = 1
+ # ratelimit_128.112.139.115_201011091533 = 14
+ # ratelimit_128.112.139.115_201011091534 = 11
+ # Now, on every request we work out the keys for the past five minutes and use get_multi to retrieve them.
+ # If the sum of those counters exceeds the maximum allowed for that time period, we block the request.
+
+ api_method_name = wobj.name
+ api_method_source = wobj.source
+
+ if api_method_source == None or api_method_source[0] == self.config.PLC_API_HOST:
+ return
+
+ mc = memcache.Client(['%s:11211'] % self.config.PLC_API_HOST)
+ now = datetime.now()
+ current_key = '%s_%s_%s' % (self.prefix, api_method_source[0], now.strftime('%Y%m%d%H%M'))
+
+ keys_to_check = ['%s_%s_%s' % (self.prefix, api_method_source[0], (now - timedelta(minutes = minute)).strftime('%Y%m%d%H%M')) for minute in range(self.minutes + 1)]
+
+ try:
+ mc.incr(current_key)
+ except ValueError:
+ mc.set(current_key, 1, time=self.expire_after)
+
+ result = mc.get_multi(keys_to_check)
+ total_requests = 0
+ for i in result:
+ total_requests += result[i]
+
+ if total_requests > self.requests:
+ raise PLCPermissionDenied, "Maximum allowed number of API calls exceeded"
+
+ def after(self, wobj, data, *args, **kwargs):
+ return
+
+class RateLimitAspect_class(BaseRateLimit):
+ __metaclass__ = MetaAspect
+ name = "ratelimitaspect_class"
+
+ def __init__(self):
+ BaseRateLimit.__init__(self)
+
+ def before(self, wobj, data, *args, **kwargs):
+ BaseRateLimit.before(self, wobj, data, *args, **kwargs)
+
+ def after(self, wobj, data, *args, **kwargs):
+ BaseRateLimit.after(self, wobj, data, *args, **kwargs)
+
+RateLimitAspect = RateLimitAspect_class