from PLC.Config import Config
from PLC.Faults import PLCPermissionDenied
+from PLC.Nodes import Node, Nodes
+from PLC.Persons import Person, Persons
+from PLC.Sessions import Session, Sessions
+
from datetime import datetime, timedelta
from pyaspects.meta import MetaAspect
import memcache
+import os
+import sys
+import socket
+
class BaseRateLimit(object):
def __init__(self):
log.write("%s - %s\n" % (date, line))
log.flush()
+ def mail(self, to):
+ sendmail = os.popen("/usr/sbin/sendmail -N never -t -f%s" % self.config.PLC_MAIL_SUPPORT_ADDRESS, "w")
+
+ subject = "[PLCAPI] Maximum allowed number of API calls exceeded"
+
+ header = {'from': "%s Support <%s>" % (self.config.PLC_NAME, self.config.PLC_MAIL_SUPPORT_ADDRESS),
+ 'to': "%s, %s" % (to, self.config.PLC_MAIL_SUPPORT_ADDRESS),
+ 'version': sys.version.split(" ")[0],
+ 'subject': subject}
+
+ body = "Maximum allowed number of API calls exceeded for the user %s within the last %s minutes." % (to, self.minutes)
+
+ # Write headers
+ sendmail.write(
+"""
+Content-type: text/plain
+From: %(from)s
+Reply-To: %(from)s
+To: %(to)s
+X-Mailer: Python/%(version)s
+Subject: %(subject)s
+
+""".lstrip() % header)
+
+ # Write body
+ sendmail.write(body)
+ # Done
+ sendmail.close()
+
def before(self, wobj, data, *args, **kwargs):
# ratelimit_128.112.139.115_201011091532 = 1
# ratelimit_128.112.139.115_201011091533 = 14
except:
return
+ # decode api_method_caller
if api_method == "session":
- api_method_caller = args[0]["session"]
+ api_method_caller = Sessions(wobj.api, {'session_id': args[0]["session"]})
+ if api_method_caller == []:
+ return
+ elif api_method_caller[0]["person_id"] != None:
+ api_method_caller = Persons(wobj.api, api_method_caller[0]["person_id"])[0]["email"]
+ elif api_method_caller[0]["node_id"] != None:
+ api_method_caller = Nodes(wobj.api, api_method_caller[0]["node_id"])[0]["hostname"]
+ else:
+ api_method_caller = args[0]["session"]
elif api_method == "password" or api_method == "capability":
api_method_caller = args[0]["Username"]
elif api_method == "gpg":
else:
api_method_caller = "unknown"
- if api_method_source == None or api_method_source[0] == self.config.PLC_API_IP or api_method_source[0] in self.whitelist:
+ # excludes
+ if api_method_source == None or api_method_source[0] == socket.gethostbyname(self.config.PLC_API_HOST) or api_method_source[0] in self.whitelist:
return
+ # sanity check
if api_method_caller == None:
self.log("%s called from %s with Username = None?" % (api_method_name, api_method_source[0]))
return
+ # normalize unicode string otherwise memcache throws an exception
+ api_method_caller = str(api_method_caller)
+
mc = memcache.Client(["%s:11211" % self.config.PLC_API_HOST])
now = datetime.now()
- current_key = "%s_%s_%s_%s" % (self.prefix, api_method_caller, api_method_source[0], now.strftime("%Y%m%d%H%M"))
+ current_key = "%s_%s_%s_%s" % (self.prefix, api_method_caller, api_method_source[0], now.strftime("%Y%m%d%H%M"))
keys_to_check = ["%s_%s_%s_%s" % (self.prefix, api_method_caller, api_method_source[0], (now - timedelta(minutes = minute)).strftime("%Y%m%d%H%M")) for minute in range(self.minutes + 1)]
try:
if value == None:
mc.set(current_key, 1, time=self.expire_after)
- result = mc.get_multi(keys_to_check)
+ results = mc.get_multi(keys_to_check)
total_requests = 0
- for i in result:
- total_requests += result[i]
+ for i in results:
+ total_requests += results[i]
if total_requests > self.requests:
self.log("%s - %s" % (api_method_source[0], api_method_caller))
+
+ caller_key = "%s_%s" % (self.prefix, api_method_caller)
+ if mc.get(caller_key) == None:
+ mc.set(caller_key, 1, time = self.expire_after)
+ if (api_method == "session" and api_method_caller.__contains__("@")) or (api_method == "password" or api_method == "capability"):
+ self.mail(api_method_caller)
+
raise PLCPermissionDenied, "Maximum allowed number of API calls exceeded"
def after(self, wobj, data, *args, **kwargs):