Beispiel #1
0
def get_command(remote_ip, **kw):
    """
    @param_post{remote_ip,string}
    @param_post{kw,dict} keyword params
    @returns{Command} next command from the que to the asking VM
    """
    vm = VM.get_by_ip(remote_ip)

    log.debug(0, "Get first command for %s" % vm.id)
    command = vm.command_set.filter(state=command_states['pending']).order_by('id')
    if len(command) == 0:
        return response('ctx_no_command')

    command = command[0]

    log.debug(0, "First command is %s" % command.id)
    command.state = command_states['executing']
    command.save()

    d = command.dict()

    r = response('ok', d)
    if int(kw.get('version', 0)) < VERSION:
        f = file(os.path.join(os.path.abspath(os.path.dirname(__file__)), 'actions.py'), 'r')
        r['actions_file'] = f.read()
        f.close()
    return r
Beispiel #2
0
 def lookup_by_name(self, first_name, last_name):
     """
     :return: a tuple of (user_id, is_err)
     If user is found, returns (user_id, False)
     If user is not found, this is not an error [returns (None, False)]
     """
     if not (first_name and last_name):
         return response(
             400, f'Missing name: "{first_name}" "{last_name}"'), True
     try:
         result = self.dynamo.query(
             ExpressionAttributeValues={
                 ':fn': {
                     'S': first_name
                 },
                 ':ln': {
                     'S': last_name
                 }
             },
             KeyConditionExpression='first_name = :fn AND last_name = :ln',
             TableName=self.tablename,
             IndexName='full_name-index')
         items = result['Items']
         if len(items) == 0:
             return (None, False)
         elif len(items) > 1:
             return response(
                 500,
                 f'More than one person named "{first_name}" "{last_name}"'
             ), True
         else:
             item = to_json(items[0])
             return item['user_id'], False
     except Exception:
         raise
def offer_get(event, context):
    item_id = event['pathParameters']['offer_id']
    item = OFFERS.get_by_id(item_id)
    if item:
        redact_name(item)
        return response(200, item)
    return response(404, 'Item not found')
Beispiel #4
0
def user_login(event, context):
    login_code = event['pathParameters'].get('login_code', None)
    if not login_code:
        return response(400, 'Missing login_code parameter')
    user = USER.lookup_by_login(login_code)
    if not user:
        return response(404, 'User not found')
    return response(200, user)
Beispiel #5
0
def user_get(event, context, user=None, admin=None):
    item_id = event['pathParameters']['user_id']
    if not (admin or (user and user['user_id'] == item_id)):
        return response(401, 'Unauthorized')
    item = USER.get_by_id(item_id)
    if item:
        return response(200, item)
    return response(404, 'Item not found')
def offer_delete(event, context, admin=None, user=None):
    item_id = event['pathParameters']['offer_id']
    item = OFFERS.get_by_id(item_id)
    if not item:
        return response(404, 'Item not found')
    if not (admin or (user and user['user_id'] == item['user_id'])):
        # authorized if you're an admin, or if you're the owner of the offer
        return response(401, 'Unauthorized')
    success = OFFERS.delete(item_id)
    return response(200, {'success': success})
def offer_update(event, context, user=None, admin=None):
    item_id = event['pathParameters']['offer_id']
    item = OFFERS.get_by_id(item_id)
    if not (admin or (user and user['user_id'] == item['user_id'])):
        # authorized if you're an admin, or if you're the owner of the offer
        return response(401, 'Unauthorized')
    if not item:
        return response(404, 'Item not found')
    put_data, err = safe_json(event['body'])
    if err:
        return put_data
    if OFFERS.update(item_id, put_data):
        return response(200, {'result': 'Successfully updated'})
Beispiel #8
0
def genericlog(log_enabled, pack_resp, is_user, is_clm_superuser, is_cm_superuser, fun, args, kwargs):
    """
    Generic log is called by actor decorators defined in src.clm.utils.decorators :
    - src.clm.utils.decorators.guest_log
    - src.clm.utils.decorators.user_log
    - src.clm.utils.decorators.admin_cm_log
    - src.clm.utils.decorators.admin_clm_log

    It calls decorated functions, additionally performing several tasks.

    Genericlog performes:

    -# <i>if decorated function requires user or admin privilidges</i>: <b>authorization</b>;
    -# <b>execution</b> of the decorated function;
    -# <b>debug log</b> of the arguments <i>depending on \c log_enabled and function's success</i>;
    -# <i>if exception is thrown</i>: <b>general exception log</b>.

    @returns{dict} response; fields:
    @dictkey{status,string} 'ok', if succeeded
    @dictkey{data,dict} response data
    """
    #===========================================================================
    # AUTORIZATION
    #===========================================================================
    name = '%s.%s' % (fun.__module__.replace('clm.views.', ''), fun.__name__)

    request = args[0]

    data = json.loads(request.body)
    #===========================================================================
    # LOG AGRUMENTS
    #===========================================================================
    gen_exception = False

    with transaction.commit_manually():
        try:
            # Execute function
            user_id = auth(is_user, is_clm_superuser, data)
            resp = fun(**data)
            if pack_resp and not hasattr(fun, 'packed'):  # if function is decorated by cm_request, 'packed' atribbute will be set - response is already packed by cm
                resp = response('ok', resp)
            transaction.commit()
        except CLMException, e:
            transaction.rollback()
            user_id = 0
            resp = e.response
        except Exception, e:
            transaction.rollback()
            gen_exception = True
            user_id = 0
            resp = response('clm_error', str(e))
Beispiel #9
0
def user_update(event, context, user=None, admin=None):
    item_id = event['pathParameters']['user_id']
    item, err = safe_json(event['body'])
    if err:
        return item
    if USER.update(item_id, item):
        return response(200, {'result': 'Successfully updated'})
Beispiel #10
0
        def wrapper(request, *args, **kwargs):
            data = request.GET.dict()
            data['remote_ip'] = request.META.get('REMOTE_ADDR')

            gen_exception = False
            log_enabled = kw.get('log', False)
            name = '%s.%s' % (fun.__module__.replace('cm.views.',
                                                     ''), fun.__name__)
            if log_enabled:
                log.debug(0, '=' * 100)
                log.debug(0, 'Function: %s' % name)
                log.debug(0, 'Args:\n%s' % json.dumps(data, indent=4))
            with transaction.commit_manually():
                try:
                    # Execute function
                    resp = fun(**data)
                    transaction.commit()
                except CMException, e:
                    transaction.rollback()
                    log.exception(0, 'CMException %s' % e)
                    resp = e.response
                except Exception, e:
                    transaction.rollback()
                    gen_exception = True
                    resp = response('cm_error', str(e))
Beispiel #11
0
    def hello(vm_ip, **args):
        """
        First function which must be called by VMs ctx module. It registers VM with status 'running ctx',
        also serves a special role when creating farms (tracking head, and worker nodes)

        @parameter{vm_ip,string}
        @parameter{args}
        """
        vm = VM.get_by_ip(vm_ip)
        log.debug(vm.user_id, "Hello from vm %d ip: %s" % (vm.id, vm_ip))

        vm.ctx_api_version = args.get('version', None)
        vm.state = vm_states['running ctx']

        if vm.ssh_username and vm.ssh_key:
            Command.execute('add_ssh_key',
                            vm.user_id,
                            vm.id,
                            user=vm.ssh_username,
                            ssh_key=vm.ssh_key)

        if vm.is_head():
            Command.register_head(vm)
        elif vm.is_farm():
            Command.register_node(vm)

        try:
            vm.save(update_fields=['state', 'ctx_api_version'])
        except Exception, e:
            log.error(
                vm.user_id,
                "Cannot update database for vm %d: %s" % (vm.id, e.message))
            return response('ctx_error',
                            "Cannot update database: %s" % e.message)
Beispiel #12
0
    def hello(vm_ip, **args):
        """
        First function which must be called by VMs ctx module. It registers VM with status 'running ctx',
        also serves a special role when creating farms (tracking head, and worker nodes)

        @parameter{vm_ip,string}
        @parameter{args}
        """
        vm = VM.get_by_ip(vm_ip)
        log.debug(vm.user_id, "Hello from vm %d ip: %s" % (vm.id, vm_ip))

        vm.ctx_api_version = args.get('version', None)
        vm.state = vm_states['running ctx']

        if vm.ssh_username and vm.ssh_key:
            Command.execute('add_ssh_key', vm.user_id, vm.id, user=vm.ssh_username, ssh_key=vm.ssh_key)

        if vm.is_head():
            Command.register_head(vm)
        elif vm.is_farm():
            Command.register_node(vm)

        try:
            vm.save(update_fields=['state', 'ctx_api_version'])
        except Exception, e:
            log.error(vm.user_id, "Cannot update database for vm %d: %s" % (vm.id, e.message))
            return response('ctx_error', "Cannot update database: %s" % e.message)
def offer_create_with_user(event, context):
    item, err = safe_json(event['body'])
    if err:
        return item
    result, is_err = OFFERS.create_with_user(item)
    if is_err:
        return result
    return response(200, result)
 def validate_for_create(self, item):
     """
     If item is valid, return it with is_error=False
     If there's an error, return the error response (as dict) along with is_error=True
     :param item: item to be validated
     :return: tuple of (object, is_error)
     """
     if self.partition_key in item:
         return response(400, 'Cannot supply item_id in request'), True
     return item, False
Beispiel #15
0
 def validate_for_create(self, item):
     """
     :return: tuple of (response, is_err)
     If response is an error, return it with is_err=True.
     If no error, response is the user_item, which can be
        a) if user already exists, user_item = {'user_id': <user_id>}
        b) if user doesn't exist, returns dict of user fields to create a new user
     """
     user_id = item.get('user_id', None)
     if user_id:
         # Supplied user_id -> look up values and return existing user
         result = self.get_by_id(user_id)
         if result:
             return result, False
         else:
             return response(404, f"User not found: {user_id}"), True
     # call base method
     item, is_err = super().validate_for_create(item)
     if is_err:
         return item
     first_name = item.get('first_name', None)
     last_name = item.get('last_name', None)
     user_id, is_err = self.lookup_by_name(first_name, last_name)
     if is_err:
         return user_id, True  # error while trying to look up user by name
     if user_id:
         return {'user_id': user_id}, False  # found existing user
     # will need to create a new user
     result = {'create_new_user': True}
     required_user_fields = [
         'first_name', 'last_name', 'parent_name', 'parent_phone',
         'parent_email'
     ]
     for field in required_user_fields:
         if field not in item:
             return response(400,
                             f'Missing required field: "{field}"'), True
         else:
             result[field] = item[field]
     return result, False
def order_create(event, context):
    """
    Event is a POST from Paypal's IPN (instant payment notification) callback
    containing all the details of a completed Paypal offer.
    """
    item = {i[0]: i[1] for i in parse_qsl(event['body'])}
    confirmation = get_paypal_confirmation(item)
    item['confirmation'] = confirmation
    if 'item_number' in item:
        # 'item_number' field contains offer_id. If present, insert it as a nested object
        offer_id = item['item_number']
        offer = OFFERS.get_by_id(offer_id)
        if offer:
            item['offer'] = offer
    new_key = ORDERS.create(item)
    return response(200, {'order_id': new_key})
    def create_with_user(self, item):
        """
        Like POST /offer, but also has user info in the event body
        :param item: form data with key/values for the offer and for the user
        :return: Returns tuple of (item, is_err):
           if result is an error, returns (err_response, True)
           if result is normal, returns   (result, False)
        """

        offer_item, err = self.validate_offer(item)
        if err:
            return offer_item, True

        user_item, is_err = USER.validate_for_create(item)
        if is_err:
            # if error, return it
            return user_item, True

        # user_item is either a reference to an existing user or a spec for a new user
        # only return a login_code if a new user has been created
        # user is the newly created user
        user = None
        if user_item.get('create_new_user', False):
            del user_item['create_new_user']
            user_id = USER.create(user_item)
            user = USER.get_by_id(user_id)
            login_code = user['login_code']
            user_item['login_code'] = login_code
        else:
            user_id = user_item.get('user_id', None)
            login_code = None
            if not user_id:
                return response(400, "Missing user_id"), True
        if not user:
            # if user is not freshly created, fetch their details
            user = USER.get_by_id(user_id)
        # populate offer with some user info
        offer_item['user_first_name'] = user['first_name']
        offer_item['user_last_name'] = user['last_name']
        offer_item['user_id'] = user_id
        offer_id = self.create(offer_item)
        result = {'user_id': user_id, 'offer_id': offer_id}
        # only return a login_code if a new user has been created
        if login_code:
            result['login_code'] = login_code
        self.send_confirmation_email(offer_item, user_item)
        return result, False
Beispiel #18
0
def hello(remote_ip, **kw):
    """
    REST stub for hello function

    @parameter{kw}
    @returns HTTP response
    """
    vm = VM.get_by_ip(remote_ip)
    log.info(vm.user_id, "vm  called hello")
    Command.hello(remote_ip)

    r = response('ok')
    if int(kw.get('version', 0)) < VERSION:
        f = file(os.path.join(os.path.abspath(os.path.dirname(__file__)), 'actions.py'), 'r')
        r['actions_file'] = f.read()
        f.close()
    return r
Beispiel #19
0
def hello(remote_ip, **kw):
    """
    REST stub for hello function

    @param_post{remote_ip,string}
    @param_post{kw}
    @returns HTTP response
    """
    vm = VM.get_by_ip(remote_ip)
    log.info(vm.user_id, "vm  called hello")
    Command.hello(remote_ip)

    r = response('ok')
    if int(kw.get('version', 0)) < VERSION:
        f = file(os.path.join(os.path.abspath(os.path.dirname(__file__)), 'actions.py'), 'r')
        r['actions_file'] = f.read()
        f.close()
    return r
 def validate_offer(self, item):
     """
     :return: tuple of (response, is_err)
     If is_err is True, response is an error
     """
     # optional field: 'offer_type_other'
     result = {'offer_type_other': item.get('offer_type_other', "<empty>")}
     fields = [
         'offer_type', 'offer_description', 'offer_unit', 'offer_per_hour'
     ]
     for field in fields:
         value = item.get(field, None)
         if value:
             result[field] = value
         else:
             msg = f'Missing some required fields in offer: missing "{field}"'
             return response(400, msg), True
     return result, False
Beispiel #21
0
    def wrapper(*args, **kwargs):
        args = list(args)
        args[0] = process_request(args[0])

        try:
            data = func(*args, **kwargs)
            if isinstance(data, HttpResponse):
                return data
            vars = {
                'status':'ok',
                'response': data
            }

        except ApiException as e:
            vars = {
                'status':'error',
                'error': e.message
            }
        return process_response(args[0], response(vars))
Beispiel #22
0
def finish_command(remote_ip, command_id, status, returns=None, **kw):
    """
    REST stub for finish_command

    @param_post{remote_ip,string}
    @param_post{command_id,string} hash string identyfing command
    @param_post{status,string}
    @param_post{returns,dict} dictionary containing VM returned values
    @param_post{kw,dict} keyword params
    """
    vm = VM.get_by_ip(remote_ip)

    if returns:
        returns = json.dumps(returns)

    log.debug(0, "Select command %s %s" % (command_id, status))
    try:
        command = vm.command_set.get(id=command_id)
    except Command.DoesNotExist:
        return

    log.debug(0, "Finish command %s" % command)
    if command is None:
        for c in Command.objects.all():
            log.debug(0, 'Finish - Available cmds id:%s,  state:%s, name:%s, vmid:%s' % (c.id, c.state, c.name, c.vm_id))
        return
    log.debug(vm.user_id, "command state %s" % command.state)

    command.response = returns
    command.state = command_states[status]
    log.debug(vm.user_id, "Finish command %s" % command.id)
    command.save()

    r = response('ok')
    if int(kw.get('version', 0)) < VERSION:
        f = file(os.path.join(os.path.abspath(os.path.dirname(__file__)), 'actions.py'), 'r')
        r['actions_file'] = f.read()
        f.close()
    return r
def offer_get_all(event, context, admin=None):
    items = OFFERS.get_all()
    # populate if missing names
    for item in items:
        user_id = item.get('user_id', None)
        user_first_name = item.get('user_first_name', None)
        user_last_name = item.get('user_last_name', None)
        if user_first_name and user_last_name and not admin:
            redact_name(item)
            continue
        if not user_id:
            # offer has no user_id, give up
            continue
        # need to look up user to get the info
        user = USER.get_by_id(user_id)
        if not user:
            # no user found, give up
            continue
        item['user_first_name'] = user['first_name']
        item['user_last_name'] = user['last_name']
        if not admin:
            redact_name(item)
    return response(200, {'result': items})
Beispiel #24
0
        def wrapper(request, *args, **kwargs):
            data = request.GET.dict()
            data['remote_ip'] = request.META.get('REMOTE_ADDR')

            gen_exception = False
            log_enabled = kw.get('log', False)
            name = '%s.%s' % (fun.__module__.replace('cm.views.', ''), fun.__name__)
            if log_enabled:
                log.debug(0, '=' * 100)
                log.debug(0, 'Function: %s' % name)
                log.debug(0, 'Args:\n%s' % json.dumps(data, indent=4))
            with transaction.commit_manually():
                try:
                    # Execute function
                    resp = fun(**data)
                    transaction.commit()
                except CMException, e:
                    transaction.rollback()
                    log.exception(0, 'CMException %s' % e)
                    resp = e.response
                except Exception, e:
                    transaction.rollback()
                    gen_exception = True
                    resp = response('cm_error', str(e))
Beispiel #25
0
 def response(self):
     """
     @returns{dict}
     common.response()
     """
     return response(str(self))
Beispiel #26
0
 def response(self):
     """
     @returns{dict} common.response() with the same status as this stringified exception
     """
     return response(str(self))
def order_get_all(event, context, admin=None, user=None):
    if not admin and not user:
        return response(401, "Unauthorized")
    items = ORDERS.get_all()
    return response(200, {'result': items})
Beispiel #28
0
def genericlog(log_enabled, is_user, is_admin_cm, need_ip, fun, args):
    """
    Generic log is called by actor decorators defined in src.clm.utils.decorators :
    - src.cm.utils.decorators.guest_log
    - src.cm.utils.decorators.user_log
    - src.cm.utils.decorators.admin_cm_log

    It calls decorated functions, additionally performing several tasks.

    Genericlog performes:

    -# <i>if decorated function requires user or admin privilidges</i>: <b>authorization</b>;
    -# <b>execution</b> of the decorated function;
    -# <i>if \c log_enabled=TRUE or if return status isn't 'ok'</i>: <b>debug log</b> of the \c user_id, function name and arguments;
    -# <i>if exception is thrown</i>: <b>general exception log</b>;
    -# <i>if return status isn't 'ok' or \c log_enabled:</i> <b>debug log</b> of the response.

    @returns{dict} HttpResponse response with content of JSON-ed tuple
    (status, data), where status should be "ok" if everything went fine.
    """
    #===========================================================================
    # AUTORIZATION
    #===========================================================================
    name = '%s.%s' % (fun.__module__.replace('cm.views.', ''), fun.__name__)

    request = args[0]
    data = json.loads(request.body)

    lock_name = None
    print data

    if is_user:
        if len(args) < 1:
            return response('cm_error', "missing arguments")

        caller_id = data['caller_id']

        if name in ('user.vm.create', 'user.farm.create', 'admin_cm.vm.create',
                    'admin_cm.farm.create'):
            lock_name = 'vmcreate'
            log.debug(caller_id, 'Try acquire lock vmcreate')
            locks[lock_name].acquire()
            log.debug(caller_id, 'Lock vmcreate acquired')

        if is_admin_cm:
            cm_password = data.pop('cm_password')
            try:
                Admin.check_password(caller_id, cm_password)
            except Exception:
                return HttpResponse(
                    json.dumps(response('user_permission'),
                               default=json_convert))
    else:
        caller_id = 0

    if need_ip:
        data['remote_ip'] = request.META.get('REMOTE_ADDR')

    #===========================================================================
    # LOG AGRUMENTS
    #===========================================================================
    gen_exception = False
    if log_enabled:
        log.debug(caller_id, '=' * 100)
        log.debug(caller_id, 'Function: %s' % name)
        log.debug(caller_id, 'Args:\n%s' % json.dumps(data, indent=4))

    with transaction.commit_manually():
        try:
            # Execute function
            resp = response('ok', fun(**data))
            transaction.commit()
        except CMException, e:
            transaction.rollback()
            log.exception(caller_id, 'CMException %s' % e)
            resp = e.response
        except Exception, e:
            transaction.rollback()
            gen_exception = True
            resp = response('cm_error', str(e))
Beispiel #29
0
 def response(self):
     """
     @returns{dict} common.response() with the same status as this stringified exception
     """
     return response(str(self))
Beispiel #30
0
def user_create(event, context):
    item, err = safe_json(event['body'])
    if err:
        return item
    new_key = USER.create(item)
    return response(200, {'user_id': new_key})
Beispiel #31
0
def genericlog(log_enabled, is_user, is_admin_cm, need_ip, fun, args):
    """
    Generic log is called by actor decorators defined in src.clm.utils.decorators :
    - src.cm.utils.decorators.guest_log
    - src.cm.utils.decorators.user_log
    - src.cm.utils.decorators.admin_cm_log

    It calls decorated functions, additionally performing several tasks.

    Genericlog performes:

    -# <i>if decorated function requires user or admin privilidges</i>: <b>authorization</b>;
    -# <b>execution</b> of the decorated function;
    -# <i>if \c log_enabled=TRUE or if return status isn't 'ok'</i>: <b>debug log</b> of the \c user_id, function name and arguments;
    -# <i>if exception is thrown</i>: <b>general exception log</b>;
    -# <i>if return status isn't 'ok' or \c log_enabled:</i> <b>debug log</b> of the response.

    @returns{dict} HttpResponse response with content of JSON-ed tuple
    (status, data), where status should be "ok" if everything went fine.
    """
    #===========================================================================
    # AUTORIZATION
    #===========================================================================
    name = '%s.%s' % (fun.__module__.replace('cm.views.', ''), fun.__name__)

    request = args[0]
    data = json.loads(request.body)

    lock_name = None
    print data

    if is_user:
        if len(args) < 1:
            return response('cm_error', "missing arguments")

        caller_id = data['caller_id']

        if name in ('user.vm.create', 'user.farm.create', 'admin_cm.vm.create', 'admin_cm.farm.create'):
            lock_name = 'vmcreate'
            log.debug(caller_id, 'Try acquire lock vmcreate')
            locks[lock_name].acquire()
            log.debug(caller_id, 'Lock vmcreate acquired')

        if is_admin_cm:
            cm_password = data.pop('cm_password')
            try:
                Admin.check_password(caller_id, cm_password)
            except Exception:
                return HttpResponse(json.dumps(response('user_permission'), default=json_convert))
    else:
        caller_id = 0

    if need_ip:
        data['remote_ip'] = request.META.get('REMOTE_ADDR')

    #===========================================================================
    # LOG AGRUMENTS
    #===========================================================================
    gen_exception = False
    if log_enabled:
        log.debug(caller_id, '=' * 100)
        log.debug(caller_id, 'Function: %s' % name)
        log.debug(caller_id, 'Args:\n%s' % json.dumps(data, indent=4))

    with transaction.commit_manually():
        try:
            # Execute function
            resp = response('ok', fun(**data))
            transaction.commit()
        except CMException, e:
            transaction.rollback()
            log.exception(caller_id, 'CMException %s' % e)
            resp = e.response
        except Exception, e:
            transaction.rollback()
            gen_exception = True
            resp = response('cm_error', str(e))
Beispiel #32
0
 def response(self):
     """
     @returns{dict}
     common.response()
     """
     return response(str(self))
Beispiel #33
0
def user_delete(event, context, admin=None):
    if not admin:
        return response(401, 'Unauthorized')
    item_id = event['pathParameters']['user_id']
    success = USER.delete(item_id)
    return response(200, {'success': success})
Beispiel #34
0
def user_get_all(event, context, admin=None):
    if not admin:
        return response(401, 'Unauthorized')
    items = USER.get_all()
    return response(200, {'result': items})