def do_GET(self): """Respond to a GET request. Returns: None """ db_con = None try: db_con = datastore.DatabaseConnection() except datastore.DatabaseReadError: return self.server_error('Unable to connect to database.') #Match path to processing function urlparsed = urlparse(self.path) if urlparsed.path not in FUNCTIONS: return self.invalid_request( 'Path specified is not in the list of valid paths.') try: FUNCTIONS[urlparsed.path](self, parse_qs(urlparsed.query), db_con) except Exception, err: err_msg = 'Uncaught error exception' if DEBUG_MODE: err_msg += ": {0}".format(err) err_msg += str(traceback.format_exc()) return self.invalid_request(err_msg)
def _main(): server_class = BaseHTTPServer.HTTPServer httpd = server_class((HOST_NAME, PORT_NUMBER), MyHandler) msg = "Server Starts - {0}:{1}".format(HOST_NAME, PORT_NUMBER) common.log(msg=msg, level=logging.INFO) print time.asctime(), msg #confirm db is accessible and properly initialized try: datastore.DatabaseConnection() except datastore.DatabaseReadError: httpd.server_close() msg = 'Error: Webserver unable to access database. Exiting.' common.log(msg=msg, level=logging.CRITICAL) sys.exit(msg) try: httpd.serve_forever() except KeyboardInterrupt: pass httpd.server_close() msg = "Server Stops - {0}:{1}".format(HOST_NAME, PORT_NUMBER) common.log(msg=msg, level=logging.INFO) print time.asctime(), msg
def run(db_con=None): """Fetch notification requests from queue and process them. Returns: None Raises: NotificationSendError if notification not sent successfully """ if db_con is None: db_con = datastore.DatabaseConnection() notif_req = None while True: print "DEBUG" try: notif_req = db_con.pop_notif() except datastore.EmptyQueueError: info_message = "No requests remain in the queue. Done." print info_message common.log(msg=info_message, level=logging.INFO) return except datastore.DatabaseReadError, err: #TODO: handle raise datastore.DatabaseReadError(err) except datastore.DatabaseWriteError, err: #TODO: handle raise datastore.DatabaseWriteError(err)
def process_notification(handler, arguments, db_con=None): """Process a request for a notification. TODO: Add handling of 'topic' argument Args: handler (BaseHTTPServer.BaseHTTPRequestHandler): The handler handling the HTTP request tp notify. arguments (dict): The parsed version of the HTTP query extracted from the URL following '?' db_con (Optional[datastore.DatabaseConnection]): A connection to the database that handles the notification queue. Arguments are url-decoded (including UTF-8 encoding) before being added to a sending queue. Returns: None """ assert isinstance(handler, BaseHTTPServer.BaseHTTPRequestHandler) assert isinstance(arguments, dict) assert isinstance(db_con, datastore.DatabaseConnection) or db_con is None if db_con is None: try: db_con = datastore.DatabaseConnection() except datastore.DatabaseReadError: return handler.server_error('Unable to connect to database.') #ensure required args are included for required_arg in NOTIFY_REQUIRED_ARGS: if required_arg not in arguments: return handler.invalid_request( "Missing argument '{0}' from arguments".format(required_arg)) #handle URL encoding for key, val_list in arguments.items(): val = val_list[0] #only use first value for specified GET param arguments[key] = urllib.unquote(val).decode('utf8') if DEBUG_MODE: print "DEBUG: key={0} val={1}".format(key, val) #validate channel if arguments['channel'] not in SUPPORTED_CHANNELS: return handler.invalid_request('Invalid channel specified') #try to set up notification request object notif = common.NotificationRequest() try: notif.set_channel(SUPPORTED_CHANNELS[arguments['channel']]) except AssertionError: return handler.invalid_request('Channel not supported') try: notif.add_recipient(arguments['recipient']) except AssertionError, err: err_msg = 'Invalid recipient' if DEBUG_MODE: err_msg += " ({0})".format(err) return handler.invalid_request(err_msg)
def process_secrets(handler, arguments, db_con=None): """Process a request to get app secrets. Returns: None """ assert isinstance(handler, BaseHTTPServer.BaseHTTPRequestHandler) assert isinstance(arguments, dict) assert isinstance(db_con, datastore.DatabaseConnection) or db_con is None if db_con is None: try: db_con = datastore.DatabaseConnection() except datastore.DatabaseReadError: return handler.server_error('Unable to connect to database.') new_app_id = datastore.generate_app_id() new_app_secret = datastore.generate_app_secret() return handler.response_secrets(new_app_id, new_app_secret)
def process_store(handler, arguments, db_con=None): """Process a request to store a key/val pair in db Returns: None """ assert isinstance(handler, BaseHTTPServer.BaseHTTPRequestHandler) assert isinstance(arguments, dict) assert isinstance(db_con, datastore.DatabaseConnection) or db_con is None if db_con is None: try: db_con = datastore.DatabaseConnection() except datastore.DatabaseReadError: return handler.server_error('Unable to connect to database.') #ensure required args are present for required_arg in STORE_REQUIRED_ARGS: if required_arg not in arguments: return handler.invalid_request( "Missing argument '{0}' from arguments".format(required_arg)) #handle URL encoding for key, val_list in arguments.items(): val = val_list[0] #only use first value for specified GET param arguments[key] = urllib.unquote(val).decode('utf8') if DEBUG_MODE: print "DEBUG: URL params: {0}={1}".format(key, val) #validate args try: arguments['app_id'] = str(arguments['app_id']) common.b64decode(arguments['app_id']) assert arguments['app_id'] != '' arguments['app_secret'] = str(arguments['app_secret']) common.b64decode(arguments['app_secret']) assert arguments['app_id'] != '' arguments['key'] = str(arguments['key']) arguments['value'] = str(arguments['value']) except (AssertionError, TypeError), err: if DEBUG_MODE: print 'One of the arguments failed validation: {0}'.format(err) handler.invalid_request('Invalid app_id or app_secret')
def process_start_digest(handler, arguments, db_con=None): """Process a request to start a digest alert. A digest alert accumulates multiple messages into a batch and then sends a summary in a single alert message to the recipient on a regular basis. If no messages have been accumulated during that time period, an alert is sent indicating that no messages were accumulated. Args: handler (BaseHTTPServer.BaseHTTPRequestHandler): The handler handling the HTTP request tp notify. arguments (dict): The parsed version of the HTTP query extracted from the URL following '?' db_con (Optional[datastore.DatabaseConnection]): A connection to the database that handles the notification queue. Returns: None """ assert isinstance(handler, BaseHTTPServer.BaseHTTPRequestHandler) assert isinstance(arguments, dict) assert isinstance(db_con, datastore.DatabaseConnection) or db_con is None if db_con is None: try: db_con = datastore.DatabaseConnection() except datastore.DatabaseReadError: return handler.server_error('Unable to connect to database.') #ensure required args are included for required_arg in START_DIGEST_REQUIRED_ARGS: if required_arg not in arguments: return handler.invalid_request( "Missing argument '{0}' from arguments".format(required_arg)) #handle URL encoding for key, val_list in arguments.items(): val = val_list[0] #only use first value for specified GET param arguments[key] = urllib.unquote(val).decode('utf8') if DEBUG_MODE: print "DEBUG: key={0} val={1}".format(key, val)
def get_value(key, app_id=None, app_secret=None): """Fetch configuration value stored for key Args: key (str): The plaintext key that you want to look up app_id (Optional[str]): If specified, the base64-encoded id assigned to the app that wants to query its data app_secret (Optional[str]): If specified, the base64-encoded secret assigned to the app that wants to query its data. This is a decryption key. Raises: KeyNotStoredAndNoFallbackError """ assert isinstance(key, str) if app_id is not None and app_secret is not None: assert isinstance(app_id, str) assert isinstance(app_secret, str) common.b64decode(app_id) common.b64decode(app_secret) with datastore.DatabaseConnection() as db_con: try: return db_con.get_key_val(app_id, app_secret, key) except datastore.DecryptionFailError: pass #try fallback if key in KEY_FALLBACKS.keys(): val = os.getenv(KEY_FALLBACKS[key], None) if val is not None: return val err_msg = "Unable to acquire value for '{0}'".format(key) if key in KEY_FALLBACKS.keys(): err_msg = ''.join([err_msg, ' (set environment variable {0})'.format(KEY_FALLBACKS[key])]) raise KeyNotStoredAndNoFallbackError(err_msg)