Example #1
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})
Example #2
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)
Example #3
0
def get_stack_info(client, cfn_id):
    cluster_url = None
    try:
        response = client.describe_stacks(StackName=cfn_id)
    except Exception as e:
        return {'errorCode': 400}
    if 'Stacks' not in response or len(response['Stacks']) == 0:
        return {'errorCode': _http_status(response)}
    stack_info = response['Stacks'][0]
    ret_struct = {}
    for param in stack_info['Parameters']:
        if 'ParameterValue' in param:
            if param['ParameterKey'] == 'InstanceType':
                ret_struct['type'] = param['ParameterValue']
            elif param['ParameterKey'] == 'ClusterSize':
                ret_struct['size'] = int(param['ParameterValue'])
    for output in stack_info['Outputs']:
        if output['OutputKey'] == 'S3Bucket':
            ret_struct['s3_url'] = output['OutputValue']
        elif output['OutputKey'] == 'VanityURL':
            ret_struct['cluster_url'] = output['OutputValue']
        elif 'cluster_url' not in ret_struct and output['OutputKey'] == 'URL':
            ret_struct['cluster_url'] = output['OutputValue']
    ret_struct['stack_status'] = stack_info['StackStatus']
    return ret_struct
Example #4
0
def get_stack_params(client, cfn_id):
    try:
        response = client.describe_stacks(StackName=cfn_id)
    except Exception as e:
        return {'errorCode': 400}
    if 'Stacks' not in response or len(response['Stacks']) == 0:
        return {'errorCode': _http_status(response)}
    stack_params = response['Stacks'][0]['Parameters']
    return stack_params
Example #5
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'],
            })
Example #6
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,
    })
Example #7
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})
Example #8
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']
Example #9
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
    })