Ejemplo n.º 1
0
def add_user(context, name):
    '''Adds new user to python shelve.

    Only accessible to ADMIN_USER.

    Args:
        context (dict): A dict of form {'caller': 'CALLER_NAME'}
        name (str): Name of the user to add

    Returns:
        String response on successly adding user

    Raises:
        ApiError: If user is not authorized to this resource

    ### Example (JSON-RPC request):
        {"jsonrpc": "2.0", "method":"add_user", "params": {"name": "USERNAME"},
        "id": "INTEGER/STRING"}
    '''
    if context['caller'] == ENV.ADMIN_USER:
        with shelve.open(ENV.SHELF_NAME, writeback=True) as shelf:
            if name not in shelf.get('users'):
                shelf['users'].append(name)
                return f'{name} added to shelf'
        return f'{name} already exists in shelf'
    raise ApiError('Unauthorized access', -32000, 'Restricted to admin user')
Ejemplo n.º 2
0
def get_all_users(context):
    '''Returns all the users stored in shelf.

    Only accessible to ADMIN_USER.

    Args:
        context (dict): A dict of form {'caller': 'CALLER_NAME'}

    Returns:
        All the users stored in shelf

    Raises:
        ApiError: If user is not authorized to this resource

    ### Example (JSON-RPC request):
        {"jsonrpc": "2.0", "method":"get_all_users", "id": "INTEGER/STRING"}
    '''
    if context['caller'] == ENV.ADMIN_USER:
        with shelve.open(ENV.SHELF_NAME, flag='r') as shelf:
            if shelf.get('users'):
                return shelf['users']
    raise ApiError('Unauthorized access', -32000, 'Restricted to admin user')
Ejemplo n.º 3
0
 def error():
     raise ApiError("Client Error")
Ejemplo n.º 4
0
 def error():
     raise ApiError("Client Error", code=123, data={"data": 42})
Ejemplo n.º 5
0
def to_done(context, issue_id):
    '''Validate and update fields across Jira, Gerrit and Polarion using \
    ADMIN_USER credentials.

    Args:
        context (dict): A dict of form {'caller': 'CALLER_NAME'}
        issue_id (str): Jira Issue ID for fields updation

    Raises:
        InvalidParamsError: If 'issue_id' param is missing from JSON-RPC \
        request.

    ### Example (JSON-RPC request):
        {"jsonrpc": "2.0", "method":"to_done", "params": {"issue_id":
        "JIRA_ISSUE_ID", "id": "INTEGER/STRING"}
    '''

    # Holds all the info required to perform below operations
    info_dict = {}

    # Jira
    try:
        issue = jira.issue(issue_id, fields='summary,comment,assignee')
    except JIRAError as err:
        raise ApiError('Jira Error', -32000,
                       f'{err.status_code}: {err.text}') from err

    if issue.fields.assignee.name != context['caller']:
        raise ApiError('Not an assignee', -3200,
                       'This issue is not assigned to you')

    summary = issue.fields.summary
    info_dict['pol_id'] = summary[0:summary.find('\t')]

    comment = issue.fields.comment.comments[-1].body
    # Expects comment body as below
    # rb: 12345
    # fn: test_function_1 test_function_2
    info_dict['rb'] = re.search(r'rb: (\d+)', comment).group(0)

    # One polarion test may correspond to many 'test_' functions in worst case
    temp_fns = re.findall(r'(test_\w+)', comment)
    if not (info_dict['rb'] and temp_fns):
        raise ApiError(
            'Malformed comment body', -32000, 'Comment expression '
            'should be of form: rb: 12345\nfn: test_func_1 test_func_2')

    # Gerrit
    resp = gerrit.get(f'/changes/?q={info_dict["rb"]}')
    if resp:
        info_dict['rb_status'] = resp[0]['status']
        change_id = resp[0]['change_id']
        info_dict['fn_path'] = []
    else:
        raise ApiError(
            'Gerrit error', -32000,
            f'No patch exists in Gerrit with id: {info_dict["rb"]}')

    # Take note of test_script and function name if it is actually merged
    if info_dict['rb_status'] == 'MERGED':
        resp = gerrit.get(f'/changes/{change_id}/revisions/current/files')

        for each_file in resp.keys():
            # Don't store 'COMMIT_MSG'
            if each_file.startswith('tests'):
                # Read it's content for 'test_' functions
                file_name = each_file.replace('/', '%2F')
                # TODO: Is there a way to query only test functions without
                # reading whole file?
                resp = (
                    gerrit.get(
                        f'/changes/{change_id}/revisions/current/files/{file_name}/content'  # noqa
                    ))
                if resp:
                    # Take note of all 'test_' functions in the file
                    all_fns = re.findall(r'def (test_\w+)', resp)
                    for fn in all_fns:
                        # Check 'test_' function from file matches any function
                        # given in Jira comment and take note of the file path
                        if fn in temp_fns:
                            info_dict['fn_path'].append((fn, each_file))
        if len(info_dict['fn_path']) != temp_fns:
            raise ApiError('Patch function doesn\'t exist', -32000,
                           f'{temp_fns} doesn\'t exist in {info_dict["rb"]}')
    else:
        raise ApiError('Gerrit error', -32000,
                       f'RB: {info_dict["rb"]} is not merged')

    # Polarion
    try:
        testcase = TestCase(work_item_id=info_dict['pol_id'])
    except Exception as excep:
        raise ApiError('Polarion error', -32000, str(excep)) from excep
    if testcase.caseautomation != 'automated':
        testcase.caseautomation = 'automated'
        setattr(testcase, 'testcase-automation_id',
                ' '.join(entry[0] for entry in info_dict['fn_path']))
        script_path = '\n'.join(
            POL_MARKUP.format(entry[1]) for entry in info_dict['fn_path'])
        testcase.automation_script = script_path
        try:
            testcase.update()
        except Exception as excep:
            raise ApiError('Polarion error', -32000, str(excep)) from excep
    else:
        raise ApiError(
            'Polarion error', -32000, f'{info_dict["id"]} is '
            'already marked as "automated" in Polarion')

    # Jira
    # Transistion to 'Done' state
    # Example: To get what transistions are possible for current Jira project
    # >>> trans = jira.transitions(issue)
    # >>> available = [(t['id'], t['name']) for t in trans]; print(available)
    # >>> [('21', 'In Progress'), ('31', 'Done'), ('51', 'To Do'), ('61', 'In
    # Review')]
    # >>> jira_state = [num[0] for num in available if num[1] == 'Done' ][0]
    try:
        jira.transition_issue(issue, '31')
    except JIRAError as err:
        raise ApiError(
            'Jira Error', -32000,
            ('Polarion fields are updated but mark Jira manually to '
             '"Done", error:' + str(err))) from err

    # Add JIRA comment with gathered info if update is successful
    body = '\n'.join(
        str(key) + ': ' + str(value) for key, value in info_dict.items()
        if key not in ('rb', 'pol_id'))
    body += f'\nGerrit: {ENV.GERRIT_URL}/{info_dict["rb"]}'
    body += f'\nPolarion: {ENV.POLARION_URL}/#/project/{ENV.POLARION_PROJECT}/workitem?id={info_dict["pol_id"]}'  # noqa
    body += '\nGerrit status is verified and Polarion fields are updated'

    try:
        jira.add_comment(issue, body)
    except JIRAError as err:
        raise ApiError(
            'Jira Error', -32000,
            ('Polarion and Jira fields are updated but unable to add Jira '
             'comment' + str(err))) from err

    return 'Gerrit fields are validated, Jira and Polarion fields are updated'
Ejemplo n.º 6
0
def get_token(name, jsessionid, skip_auth=False):
    '''Creates a token and returns to the caller.

    Generates a JWT token based on the info received. Cookie string will be \
    deleted after proving the user authenticity against jira server.

    Args:
        name (str): Name of the user requesting the token
        jsessionid (str): Cookie string recevied after authenticating \
        to '/rest/auth/latest/session' of Jira instance
        skip_auth (bool): Restricted to ADMIN_USER

    Raises:
        InvalidParamsError: If either 'name' or 'jsessionid' param missing \
        from JSON-RPC request
        ApiError: If the user isn't supposed to use this JSON-RPC service

    ### Example (JSON-RPC request):
        {"jsonrpc": "2.0", "method":"get_token", "params": {"name": "USERNAME",
        "jsessionid": "COOKIE_STRING"}, "id": "INTEGER/STRING"}
    '''

    with shelve.open(ENV.SHELF_NAME, flag='r') as shelf:
        if name not in shelf.get('users'):
            raise ApiError(
                'Unauthorized access', -32000,
                'Please contact admin for getting access to this service')

    if name == ENV.ADMIN_USER and skip_auth:
        # If ADMIN_USER doesn't want to be authenticated against jira
        pass
    else:
        # Authenticate user against Jira using the Cookie string
        auth_url = f'{ENV.JIRA_SERVER}/rest/auth/latest/session'
        cookies = {'JSESSIONID': jsessionid}
        resp = requests.get(auth_url,
                            cookies=cookies,
                            verify=ENV.JIRA_CERT_PATH)
        if resp:
            # Proving the identity using authenticated Jira cookie
            username = resp.json()['name']
            if name != username:
                raise ApiError(
                    'Unauthorized access', -32000,
                    f'Supplied "JSESSIONID" doesn\'t belong to {name}')

            # After authentication, logout the session which invalidates cookie
            del_ses = requests.delete(auth_url,
                                      cookies=cookies,
                                      verify=ENV.JIRA_CERT_PATH)
            if not del_ses:
                raise ApiError(
                    'Please logout of Jira once manually', -32000,
                    'Deletion of cookie failed and manual logout is needed')
        else:
            raise ApiError(
                'Invalid JSESSIONID supplied', -32000,
                f'Please contact {ENV.ADMIN_USER} for authenticating to '
                'JIRA correctly')

    # Generate and return JWT
    expiry = (datetime.datetime.utcnow() +
              datetime.timedelta(days=int(ENV.JWT_EXPIRY)))

    payload = {
        'exp': expiry,
        'sub': name,
    }
    return 'Token: ' + str(jwt.encode(payload, ENV.JWT_SECRET))