Beispiel #1
0
def deduct_credit(user_name):
    # For expServer to invoke - it only has access to deduct credit.
    # No other configurable params - to avoid potential securty issue with juypter
    # To-do auth logic to make sure the caller is updating his credit only
    user_info = get_user_info(dynamodb_client, user_name, user_table)
    if 'Item' in user_info and 'cfn_id' in user_info['Item']:
        cfn_id = user_info['Item']['cfn_id']['S']
    else:
        return _make_reply(
            _http_status(user_info), {
                'status': Status.NO_STACK,
                'error': '%s does not have a stack' % user_name
            })
    stack_info = get_stack_info(cfn_client, cfn_id)
    if 'errorCode' in stack_info:
        return _make_reply(
            stack_info['errorCode'], {
                'status': Status.STACK_NOT_FOUND,
                'error': 'Stack %s not found' % cfn_id
            })
    elif 'size' not in stack_info or 'type' not in stack_info or stack_info[
            'size'] == 0:
        return _make_reply(200, {
            'status': Status.NO_RUNNING_CLUSTER,
            'error': 'No running cluster'
        })
    credit_change = str(-1 * get_price(stack_info['type'], stack_info['size']))
    return update_credit(user_name, credit_change)
Beispiel #2
0
def stop_cluster(user_name):
    user_info = get_user_info(dynamodb_client, user_name, user_table)
    if 'Item' not in user_info:
        return _make_reply(_http_status(user_info), {
            "status": Status.USER_NOT_FOUND,
            "error": "%s does not exist" % user_name
        })
    if 'cfn_id' not in user_info['Item']:
        return _make_reply(_http_status(user_info), {
            'status': Status.NO_STACK,
            'error': '%s does not have a stack' % user_name
        })
    cfn_id = user_info['Item']['cfn_id']['S']
    stack_params = get_stack_params(cfn_client, cfn_id)
    for param in stack_params:
        if param['ParameterKey'] == 'ClusterSize':
            param.update(ParameterValue='0')

        if param['ParameterKey'] == 'AdminPassword':
            param.pop('ParameterValue', None)
            param['UsePreviousValue']=True

    response = cfn_client.update_stack(
        StackName = cfn_id,
        UsePreviousTemplate = True,
        Parameters = stack_params,
        Capabilities=IamCapabilities,
        RoleARN=cfn_role_arn
    )
    return _make_reply(_http_status(response), {'status': Status.OK})
Beispiel #3
0
def lambda_handler(event, context):
    try:
        path = event['path']
        headers = event['headers']
        headers_origin = '*'
        headers_cookies = None
        for key, headerLine in headers.items():
            if (key.lower() == "origin"):
                headers_origin = headerLine
            if (key.lower() == "cookie"):
                headers_cookies = headerLine
        if headers_origin == '*':
            data = json.loads(event['body'])
            if 'username' not in data or \
               'instanceId' not in data or \
               validate_user_instance(ec2_client,
                                      data['username'],
                                      data['instanceId']) != True:
                return _make_reply(401, {
                    'status': Status.AUTH_ERROR,
                    'error': 'Authentication failed'
                }, headers_origin)

        elif re.match('^https://\w+.'+domain, headers_origin, re.M|re.I):
            if (event['httpMethod'] == 'OPTIONS'):
                return _make_options_reply(200,  headers_origin)
            data = json.loads(event['body'])
            credential, username = check_user_credential(dynamodb_client,
                                                         session_table,
                                                         creds_table,
                                                         headers_cookies)
            if credential is None or username != data['username']:
                return _make_reply(401, {
                    'status': Status.AUTH_ERROR,
                    'error': "Authentication Failed"
                }, headers_origin)
        else:
            return _make_reply(403, "Forbidden",  headers_origin)

        if path == '/cluster/start':
            reply = start_cluster(data['username'], data['clusterParams'])
        elif path == '/cluster/stop':
            reply = stop_cluster(data['username'])
        elif path == '/cluster/get':
            reply = get_cluster(data['username'])
        else:
            reply = _make_reply(400, "Invalid endpoint: %s" % path)

    except Exception as e:
        traceback.print_exc()
        reply = _make_reply(400, "Exception has occurred: {}".format(e))
    reply = _replace_headers_origin(reply, headers_origin)
    return reply
Beispiel #4
0
def lambda_handler(event, context):
    try:
        path = event['path']

        if path == '/config':
            reply = _make_reply(200, {
                'config': configResult
            })
        else:
            reply = _make_reply(400, "Invalid endpoint: %s" % path)
    except Exception as e:
        traceback.print_exc()
        reply = _make_reply(400, "Exception has occurred: {}".format(e))
    return reply
Beispiel #5
0
def delete_file(delete_params):
    user_name = delete_params['username']
    file_name = delete_params['fileName']
    bucket_resp = get_bucket(user_name)
    if type(bucket_resp) != str:
        return bucket_resp
    s3_client = boto3.client('s3', region_name=region)
    s3_client.delete_object(Bucket=bucket_resp, Key=file_name)
    return _make_reply(200, {'status': Status.OK})
Beispiel #6
0
def lambda_handler(event, context):
    try:
        path = event['path']
        headers = event['headers']
        headers_origin = '*'
        headers_cookies = None
        for key, headerLine in headers.items():
            if (key.lower() == "origin"):
                headers_origin = headerLine
            if (key.lower() == "cookie"):
                headers_cookies = headerLine
        if re.match('^https://\w+.' + domain, headers_origin, re.M | re.I):
            if (event['httpMethod'] == 'OPTIONS'):
                return _make_options_reply(200, headers_origin)

            data = json.loads(event['body'])
            credential, username = check_user_credential(
                dynamodb_client, session_table, creds_table, headers_cookies)
            if credential == None or username != data['username']:
                return _make_reply(401, {
                    'status': Status.AUTH_ERROR,
                    'error': "Authentication Failed"
                }, headers_origin)
        else:
            return _make_reply(403, {'error': "Forbidden"}, headers_origin)

        if path == '/s3/uploadurl':
            reply = get_upload_file_url(data)
        elif path == '/s3/delete':
            reply = delete_file(data)
        elif path == '/s3/describe':
            reply = bucket_info(data['username'])
        elif path == '/s3/corsconfig':
            reply = put_cors_config(data['username'])
        else:
            reply = _make_reply(400, {'error': "Invalid endpoint: %s" % path})

    except Exception as e:
        traceback.print_exc()
        reply = _make_reply(400,
                            {'error': "Exception has occurred: {}".format(e)})
    reply = _replace_headers_origin(reply, headers_origin)
    return reply
Beispiel #7
0
def get_bucket(user_name):
    response = get_user_info(dynamodb_client, user_name, user_table)
    if 'Item' not in response:
        return _make_reply(
            _http_status(response), {
                'status': Status.USER_NOT_FOUND,
                'error': "%s does not exist" % user_name
            })
    cfn_id = response['Item']['cfn_id']['S']
    stack_info = get_stack_info(cfn_client, cfn_id)
    if 'errorCode' in stack_info:
        return _make_reply(
            stack_info['errorCode'], {
                'status': Status.STACK_NOT_FOUND,
                'error': 'Stack %s not found' % cfn_id
            })
    if 's3_url' not in stack_info:
        return _make_reply(
            200, {
                'status': Status.S3_BUCKET_NOT_EXIST,
                'error': 'Cloud not find s3 given stack %s' % cfn_id
            })
    return stack_info['s3_url']
Beispiel #8
0
def get_credit(user_name):
    response = dynamodb_client.query(
        TableName=billing_table,
        ScanIndexForward=True,
        ProjectionExpression='credit_change',
        KeyConditionExpression='user_name = :uname',
        ExpressionAttributeValues={':uname': {
            'S': user_name
        }})
    credit = 0
    if 'Items' in response and len(response['Items']) > 0:
        for row in response['Items']:
            credit += float(row['credit_change']['N'])
    else:
        return _make_reply(
            _http_status(response), {
                'status': Status.NO_CREDIT_HISTORY,
                'error': 'No credit history for user: %s' % user_name
            })

    while 'LastEvaluatedKey' in response:
        response = dynamodb_client.query(
            TableName=billing_table,
            ScanIndexForward=True,
            ExclusiveStartKey=response['LastEvaluatedKey'],
            ProjectionExpression='credit_change',
            KeyConditionExpression='user_name = :uname',
            ExpressionAttributeValues={':uname': {
                'S': user_name
            }})
        if 'Items' in response and len(response['Items']) > 0:
            for row in response['Items']:
                credit += float(row['credit_change']['N'])
    return _make_reply(_http_status(response), {
        'status': Status.OK,
        'credits': credit,
    })
Beispiel #9
0
def update_credit(user_name, credit_change):
    transaction = {
        'user_name': {
            'S': user_name
        },
        'timestamp': {
            'N': str(round(time.time() * 1000))
        },
        'credit_change': {
            'N': credit_change
        }
    }
    response = dynamodb_client.put_item(TableName=billing_table,
                                        Item=transaction)
    return _make_reply(_http_status(response), {'status': Status.OK})
Beispiel #10
0
def get_upload_file_url(upload_params):
    user_name = upload_params['username']
    file_name = upload_params['fileName']
    fields = upload_params['fields']
    conditions = upload_params['conditions']
    bucket_resp = get_bucket(user_name)
    if type(bucket_resp) != str:
        return bucket_resp
    expiration = 3600
    s3_client = boto3.client('s3', region_name=region)
    res_dict = s3_client.generate_presigned_post(bucket_resp,
                                                 file_name,
                                                 Fields=fields,
                                                 Conditions=conditions,
                                                 ExpiresIn=expiration)
    return _make_reply(200, {'status': Status.OK, 'responseDict': res_dict})
Beispiel #11
0
def put_cors_config(user_name):
    # Hard code it here
    cors_config = {
        "CORSRules": [{
            "AllowedHeaders": ["*"],
            "AllowedMethods": ["POST"],
            "AllowedOrigins": ["*"],
            "MaxAgeSeconds": 3000
        }]
    }
    bucket_resp = get_bucket(user_name)
    if type(bucket_resp) != str:
        return bucket_resp
    s3_client = boto3.client('s3', region_name=region)
    s3_client.put_bucket_cors(Bucket=bucket_resp,
                              CORSConfiguration=cors_config)
    return _make_reply(200, {'status': Status.OK})
Beispiel #12
0
def get_cluster(user_name):
    user_info = get_user_info(dynamodb_client, user_name, user_table)
    if 'Item' not in user_info:
        response = init_user(dynamodb_client, user_name, default_credit, user_table, billing_table)
        return _make_reply(_http_status(response), {
            'status': Status.OK,
            'isPending': False
        })
    elif 'cfn_id' not in user_info['Item']:
        return  _make_reply(200, {
            'status': Status.OK,
            'isPending': False
        })
    cfn_id = user_info['Item']['cfn_id']['S']
    stack_info = get_stack_info(cfn_client, cfn_id)
    if 'errorCode' in stack_info:
        if _http_status(reset_user_cfn(dynamodb_client, user_name, user_table)) != 200:
            error = 'Stack %s not found and failed to clean user table' % cfn_id
        else:
            error = 'Stack %s not found' % cfn_id
        return _make_reply(stack_info['errorCode'], {
            'status': Status.STACK_NOT_FOUND,
            'error': error
        })
    # To-do more detailed stack status
    else:
        # in progresss
        if stack_info['stack_status'].endswith('IN_PROGRESS'):
            return _make_reply(200, {
                'status': Status.OK,
                'isPending': True,
                'isStarting': False if stack_info['size'] == 0 else True
            })
        #updated completed, then check cluster status
        elif stack_info['stack_status'] == 'UPDATE_COMPLETE':
            cluster_status = check_cluster_status(user_name, stack_info)
            credit_change = str(-1 * get_price(stack_info['type'], stack_info['size']))
            return _make_reply(200, cluster_status)
        #error(more detailed failure check)
        else:
            return _make_reply(200, {
                'status': Status.STACK_ERROR,
                'error': 'Stack has error: %s' % stack_info['stack_status'],
            })
Beispiel #13
0
def start_cluster(user_name, cluster_params):
    # if the user has a cfn stack
    response = get_user_info(dynamodb_client, user_name, user_table)
    if 'Item' not in response:
        return _make_reply(_http_status(response), {
            'status': Status.USER_NOT_FOUND,
            'error': '%s does not exist' % user_name
        })
    user_info = response['Item']
    parameters = []
    is_new = False # whether this is a new user
    tags = cfn_id = cluster_type = response = None
    if 'cfn_id' in user_info:
        cfn_id = user_info['cfn_id']['S']
    else:
        #or we give him an available one
        stack_info = get_available_stack(user_name)
        if stack_info is None:
            return _make_reply(200, {
                'status': Status.NO_AVAILABLE_STACK,
                'error': 'No available stack at this moment'
            })
        cfn_id = stack_info['cfn_id']
        tags = stack_info['tags']
        is_new = True

    if 'type' in cluster_params and cluster_params['type'] in cluster_type_table:
        cluster_type = cluster_type_table[cluster_params['type']]
    else:
        # default to use 'XS'
        cluster_type = cluster_type_table['XS']
    stack_params = get_stack_params(cfn_client, cfn_id)

    for param in stack_params:
        if param['ParameterKey'] == 'ClusterSize':
            param.update(ParameterValue=cluster_type['clusterSize'])

        if param['ParameterKey'] == 'InstanceType':
            param.update(ParameterValue=cluster_type['instanceType'])

        if param['ParameterKey'] == 'ImageId' and 'AMI' in cluster_params:
            param.update(ParameterValue=cluster_params['AMI'])

        if param['ParameterKey'] == 'AdminPassword':
            param.pop('ParameterValue', None)
            param['UsePreviousValue']=True

    is_test_cluster = check_test_cluster(cfn_id)
    if is_test_cluster is None:
        error = 'Stack %s not found' % cfn_id
        return _make_reply(200, {
                'status': Status.STACK_NOT_FOUND,
                'error': error
            })
    elif is_test_cluster:
        if is_new == False:
            response = cfn_client.update_stack(
                StackName=cfn_id,
                UsePreviousTemplate=True,
                Parameters=stack_params,
                Capabilities=IamCapabilities,
                RoleARN=cfn_role_arn
            )
        else:
            cfn_client.update_stack(
                StackName=cfn_id,
                UsePreviousTemplate=True,
                Parameters=stack_params ,
                Capabilities=IamCapabilities,
                RoleARN=cfn_role_arn,
                Tags=tags
            )
            updates = {
                'cfn_id': {
                    'S': cfn_id
                }
            }
            response = update_user_info(dynamodb_client, user_info, updates, user_table)
    else:
        template = ssm_client.get_parameter(Name=ssm_key)['Parameter']['Value']
        if is_new == False:
            response = cfn_client.update_stack(
                StackName=cfn_id,
                TemplateURL=template,
                UsePreviousTemplate=False,
                Parameters=stack_params,
                Capabilities=IamCapabilities,
                RoleARN=cfn_role_arn
            )
        else:
            cfn_client.update_stack(
                StackName=cfn_id,
                TemplateURL=template,
                UsePreviousTemplate=False,
                Parameters=stack_params ,
                Capabilities=IamCapabilities,
                RoleARN=cfn_role_arn,
                Tags=tags
            )
            updates = {
                'cfn_id': {
                    'S': cfn_id
                }
            }
            response = update_user_info(dynamodb_client, user_info, updates, user_table)


    return _make_reply(_http_status(response), {
        'status': Status.OK
    })
Beispiel #14
0
def bucket_info(user_name):
    bucket_resp = get_bucket(user_name)
    if type(bucket_resp) != str:
        return bucket_resp
    return _make_reply(200, {'status': Status.OK, 'bucketName': bucket_resp})