예제 #1
0
    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)
예제 #2
0
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
예제 #3
0
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)
예제 #4
0
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)
예제 #5
0
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)
예제 #6
0
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')
예제 #7
0
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)
예제 #8
0
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)