def command_update_resource_limits(args):
    "Implements the update_resource_limits subcommand"

    oauth2_instance = oauth2.build_oauth2(args)
    auth = oauth2_instance.build_authorizer()

    s = requests.Session()
    s.auth = auth

    course_branch_id = (args.course.replace("~", "!~")
                        if "authoringBranch~" in args.course else args.course)
    course_branch_item = '%s~%s' % (course_branch_id, args.item)

    params = 'id=%s&partId=%s' % (course_branch_item, args.part)

    body = {
        "reservedCpu":
        (int(args.grader_cpu) * 1024 if args.grader_cpu is not None else None),
        "reservedMemory": (int(args.grader_memory_limit)
                           if args.grader_memory_limit is not None else None),
        "wallClockTimeout":
        (int(args.grader_timeout) if args.grader_timeout is not None else None)
    }
    result = s.post(args.updateGraderResourceLimits_endpoint,
                    params=params,
                    json=body)
    if result.status_code == 404:
        logging.error(
            '\nUnable to find the part or grader with ' +
            'part id %s in item %s in course %s.\n'
            'Status Code: 404 \n'
            'URL: %s \n'
            'Response: %s\n', args.part, args.item, args.course, result.url,
            result.text)
        return 1
    elif result.status_code != 200:
        logging.error(
            '\nUnable to update grader resources.\n'
            'CourseId: %s\n'
            'ItemId: %s\n'
            'PartId: %s\n'
            'Status Code: %d\n'
            'URL: %s\n'
            'Response: %s\n', args.course, args.item, args.part,
            result.status_code, result.url, result.text)
        return 1
    print('\nUpdated resource Limits for grader with ' +
          'part id %s in item %s in course %s:\n'
          'New Reserved CPU (vCPUs): %s\n'
          'New Reserved Memory (MiB): %s\n'
          'New Wall Clock Timeout (s): %s\n' %
          (args.part, args.item, args.course,
           (int(result.json()['reservedCpu']) / 1024 if 'reservedCpu' in
            result.json() else 'Cpu limit not set - default is 1 vCPU'),
           (result.json()['reservedMemory'] if 'reservedMemory' in
            result.json() else 'Memory limit not set - default is 4096 MiB'),
           (result.json()['wallClockTimeout'] if 'wallClockTimeout' in
            result.json() else 'Timeout not set - default is 1200 seconds')))
    return 0
def test_compute_cache_filname_expanded_path():
    args = argparse.Namespace()
    args.client_id = 'client_id'
    args.client_secret = 'fake-secret'
    args.scopes = 'fake scopes'
    cfg = configparser.ConfigParser()
    cfg.add_section('oauth2')
    cfg.set('oauth2', 'token_cache', '~/.coursera/oauth2_cache.pickle')
    computed = oauth2.build_oauth2(args, cfg).token_cache_file
    assert '~' not in computed, 'Computed contained "~": %s' % computed
def test_compute_cache_filename():
    args = argparse.Namespace()
    args.client_id = 'client_id'
    args.client_secret = 'fake-secret'
    args.scopes = 'fake scopes'
    cfg = configparser.ConfigParser()
    cfg.add_section('oauth2')
    cfg.set('oauth2', 'token_cache', '/tmp/configured_cache')
    assert oauth2.build_oauth2(args, cfg).token_cache_file == \
        '/tmp/configured_cache'
Beispiel #4
0
def check_auth(args):
    """
    Checks coursera_autograder's connectivity to the coursera.org API servers
    """
    oauth2_instance = oauth2.build_oauth2(args)
    auth = oauth2_instance.build_authorizer()
    my_profile_url = (
        'https://api.coursera.org/api/externalBasicProfiles.v1?'
        'q=me&fields=name'
    )
    r = requests.get(my_profile_url, auth=auth)
    if r.status_code != 200:
        logging.error('Received response code %s from the basic profile API.',
                      r.status_code)
        logging.debug('Response body:\n%s', r.text)
        sys.exit(1)
    try:
        external_id = r.json()['elements'][0]['id']
    except:
        logging.error(
            'Could not parse the external id out of the response body %s',
            r.text)
        external_id = None

    try:
        name = r.json()['elements'][0]['name']
    except:
        logging.error(
            'Could not parse the name out of the response body %s',
            r.text)
        name = None

    if not args.quiet or args.quiet == 0:
        print('Name: %s' % name)
        print('External ID: %s' % external_id)

    if name is None or external_id is None:
        sys.exit(1)
Beispiel #5
0
def command_get_status(args):
    "Implements the get_status subcommand"

    oauth2_instance = oauth2.build_oauth2(args)
    auth = oauth2_instance.build_authorizer()

    s = requests.Session()
    s.auth = auth

    course_branch_id = (args.course.replace("~", "!~")
                        if "authoringBranch~" in args.course else args.course)
    course_grader_id = '%s~%s' % (course_branch_id, args.graderId)

    result = s.get('%s%s' % (args.getGraderStatus_endpoint, course_grader_id))
    if result.status_code == 404:
        logging.error(
            '\nUnable to find grader with id %s in course %s.\n'
            'Status Code: 404 \n'
            'URL: %s \n'
            'Response: %s\n', args.graderId, args.course, result.url,
            result.text)
        return 1
    elif result.status_code != 200:
        logging.error(
            '\nUnable to get grader status.\n'
            'CourseId: %s\n'
            'GraderId: %s\n'
            'Status Code: %d \n'
            'URL: %s \n'
            'Response: %s\n', args.course, args.graderId, result.status_code,
            result.url, result.text)
        return 1

    status = result.json()['elements'][0]['status']
    print('\nGrader status: %s\n' % (status))
    return 0
Beispiel #6
0
def display_auth_cache(args):
    '''
    Writes to the screen the state of the authentication cache. (For debugging
    authentication issues.) BEWARE: DO NOT email the output of this command!!!
    You must keep the tokens secure. Treat them as passwords.
    '''
    oauth2_instance = oauth2.build_oauth2(args)
    if not args.quiet or args.quiet == 0:
        token = oauth2_instance.token_cache['token']
        if not args.no_truncate and token is not None:
            token = token[:10] + '...'
        print("Auth token: %s" % token)

        expires_time = oauth2_instance.token_cache['expires']
        expires_in = int((expires_time - time.time()) * 10) / 10.0
        print("Auth token expires in: %s seconds." % expires_in)

        if 'refresh' in oauth2_instance.token_cache:
            refresh = oauth2_instance.token_cache['refresh']
            if not args.no_truncate and refresh is not None:
                refresh = refresh[:10] + '...'
            print("Refresh token: %s" % refresh)
        else:
            print("No refresh token found.")
Beispiel #7
0
def command_list_graders(args):
    "Implements the list subcommand"

    oauth2_instance = oauth2.build_oauth2(args)
    auth = oauth2_instance.build_authorizer()

    s = requests.Session()
    s.auth = auth

    result = s.get('%s%s' % (args.listGrader_endpoint, args.course))
    if result.status_code == 404:
        logging.error(
            '\nUnable to locate course with id %s.\n'
            'Status Code: 404 \n'
            'URL: %s \n'
            'Response: %s\n', args.course, result.url, result.text)
        return 1
    elif result.status_code != 200:
        logging.error(
            '\nUnable to list graders.\n'
            'CourseId: %s\n'
            'Status Code: %d \n'
            'URL: %s \n'
            'Response: %s\n', args.course, result.status_code, result.url,
            result.text)
        return 1

    elements = result.json()['elements']
    print('Graders associated with course id %s:\n' % args.course)
    for element in elements:
        course_grader_id = element['id']
        grader = course_grader_id.split('~')[-1]
        filename = element['filename']
        print('Filename: %s\nGraderId: %s\n' % (filename, grader))

    return 0
def command_upload(args):
    "Implements the upload subcommand"

    validate_memory_based_on_cpu(args.grader_cpu, args.grader_memory_limit)

    d = utils.docker_client(args)
    image = (args.imageZipFile, os.path.basename(args.imageZipFile))

    oauth2_instance = oauth2.build_oauth2(args)
    auth = oauth2_instance.build_authorizer()
    # TODO: use transloadit's signatures for upload signing.
    # authorization = authorize_upload(args, auth)

    # Generate a random uuid for upload.
    upload_id = uuid.uuid4().hex
    transloadit_host = idle_transloadit_server(args)
    upload_url = 'https://%(host)s/assemblies/%(id)s' % {
        'host': transloadit_host,
        'id': upload_id,
    }
    if args.upload_to_requestbin is not None:
        upload_url = 'http://requestb.in/%s' % args.upload_to_requestbin

    if not args.quiet or args.quiet == 0:
        sys.stdout.write(
            'About to upload to server:\n\t%(transloadit_host)s\n'
            'with upload id:\n\t%(upload_id)s\nStatus API:\n'
            '\t%(upload_url)s\nUploading...' % {
                'transloadit_host': transloadit_host,
                'upload_id': upload_id,
                'upload_url': upload_url,
            })
        sys.stdout.flush()
    p = multiprocessing.Process(target=upload, args=(args, upload_url, image))
    p.daemon = True  # Auto-kill when the main process exits.
    p.start()
    time.sleep(20)  # Yield control to the child process to kick off upload.

    upload_information = None

    while p.is_alive():
        upload_information = poll_transloadit(args, upload_url)
        if upload_information is not None:
            logging.warn(
                'Upload information retrieved before upload completed??! %s',
                upload_information)
            break
        time.sleep(10)  # 10 seconds

    p.join(1)  # Join to clean up zombie.

    # TODO: make time waiting for transloadit to finish processing configurable
    for i in range(300):
        upload_information = poll_transloadit(args, upload_url)
        if upload_information is not None:
            break
        time.sleep(5)

    if upload_information is None:
        logging.error(
            'Upload did not complete within expected time limits. Upload '
            'URL: %s', upload_url)
        return 1
    # Register the grader with Coursera to initiate the image cleaning process
    logging.debug('Grader upload info is: %s', upload_information)

    # Rebuild an authorizer to ensure it's fresh and not expired
    auth = oauth2_instance.build_authorizer()
    grader_id = register_grader(auth,
                                args,
                                bucket=upload_information[0],
                                key=upload_information[1])

    return update_assignments(auth, grader_id, args)