Example #1
0
def create_topics(user):
    values = flask.request.json
    check_json_is_valid(create_topic_schema, values)
    values.update(v1_utils.common_values_dict())

    if user.is_not_super_admin() and user.is_not_epm() and user.is_not_feeder(
    ):  # noqa
        raise dci_exc.Unauthorized()

    # todo(yassine): enabled when client updated.
    # if values['component_types'] == []:
    #     raise dci_exc.DCIException('component_types should not be void')

    query = _TABLE.insert().values(**values)

    try:
        flask.g.db_conn.execute(query)
    except sa_exc.IntegrityError:
        raise dci_exc.DCICreationConflict(_TABLE.name, 'name')

    result = json.dumps({'topic': values})
    return flask.Response(result,
                          201,
                          headers={'ETag': values['etag']},
                          content_type='application/json')
Example #2
0
def update_product(user, product_id):
    # get If-Match header
    if_match_etag = utils.check_and_get_etag(flask.request.headers)
    values = flask.request.json
    check_json_is_valid(update_product_schema, values)

    if user.is_not_super_admin():
        raise dci_exc.Unauthorized()

    v1_utils.verify_existence_and_get(product_id, _TABLE)

    values['etag'] = utils.gen_etag()
    where_clause = sql.and_(_TABLE.c.etag == if_match_etag,
                            _TABLE.c.id == product_id)
    query = _TABLE.update().returning(*_TABLE.columns).\
        where(where_clause).values(**values)

    result = flask.g.db_conn.execute(query)
    if not result.rowcount:
        raise dci_exc.DCIConflict('Product update error', product_id)

    return flask.Response(json.dumps({'product': result.fetchone()}),
                          200,
                          headers={'ETag': values['etag']},
                          content_type='application/json')
Example #3
0
def create_feeders(user):
    values = flask.request.json
    check_json_is_valid(create_feeder_schema, values)
    values.update(v1_utils.common_values_dict())

    if user.is_not_epm() and user.is_not_super_admin():
        raise dci_exc.Unauthorized()

    values.update({
        # XXX(fc): this should be populated as a default value from the
        # model, but we don't return values from the database :(
        'api_secret': signature.gen_secret(),
        'data': values.get('data', {}),
    })

    query = _TABLE.insert().values(**values)

    try:
        flask.g.db_conn.execute(query)
    except sa_exc.IntegrityError:
        raise dci_exc.DCICreationConflict(_TABLE.name, 'name')

    return flask.Response(json.dumps({'feeder': values}),
                          201,
                          headers={'ETag': values['etag']},
                          content_type='application/json')
Example #4
0
def put_user(user, user_id):
    values = flask.request.json
    check_json_is_valid(update_user_schema, values)
    if_match_etag = utils.check_and_get_etag(flask.request.headers)

    # to update a user the caller must be a super admin
    if user.is_not_super_admin():
        raise dci_exc.Unauthorized()

    values['etag'] = utils.gen_etag()

    if 'password' in values:
        values['password'] = auth.hash_password(values.get('password'))

    where_clause = sql.and_(_TABLE.c.etag == if_match_etag,
                            _TABLE.c.id == user_id)
    query = _TABLE.update().returning(*_TABLE.columns).\
        where(where_clause).values(**values)

    result = flask.g.db_conn.execute(query)
    if not result.rowcount:
        raise dci_exc.DCIConflict('User', user_id)

    _result = dict(result.fetchone())
    del _result['password']

    return flask.Response(json.dumps({'user': _result}),
                          200,
                          headers={'ETag': values['etag']},
                          content_type='application/json')
def update_components(user, c_id):
    component = v1_utils.verify_existence_and_get(c_id, _TABLE)
    if_match_etag = utils.check_and_get_etag(flask.request.headers)

    topic = v1_utils.verify_existence_and_get(component['topic_id'],
                                              models.TOPICS)
    export_control.verify_access_to_topic(user, topic)

    values = flask.request.json
    check_json_is_valid(update_component_schema, values)
    values['etag'] = utils.gen_etag()

    where_clause = sql.and_(
        _TABLE.c.etag == if_match_etag,
        _TABLE.c.id == c_id
    )

    query = _TABLE.update().returning(*_TABLE.columns).where(where_clause).\
        values(**values)

    result = flask.g.db_conn.execute(query)
    if not result.rowcount:
        raise dci_exc.DCIConflict('Component', c_id)

    return flask.Response(
        json.dumps({'component': result.fetchone()}), 200,
        headers={'ETag': values['etag']}, content_type='application/json'
    )
Example #6
0
def upload_certification(user, file_id):
    data = flask.request.json
    check_json_is_valid(file_upload_certification_schema, data)

    file = get_file_object(file_id)
    file_descriptor = get_file_descriptor(file)
    file_content = file_descriptor.read()

    username = data['username']
    password = data['password']
    conf = dci_config.CONFIG
    proxy = ServerProxy(conf['CERTIFICATION_URL'])
    certification_details = proxy.Cert.getOpenStack_4_7({
        'username':
        username,
        'password':
        password,
        'certification_id':
        data['certification_id']
    })
    certification = build_certification(username, password,
                                        certification_details['cert_nid'],
                                        file['name'], file_content)
    proxy.Cert.uploadTestLog(certification)
    return flask.Response(None, 204, content_type='application/json')
Example #7
0
def create_users(user):
    values = flask.request.json
    check_json_is_valid(create_user_schema, values)
    values.update(v1_utils.common_values_dict())

    if user.is_not_super_admin():
        raise dci_exc.Unauthorized()

    values.update({
        'password': auth.hash_password(values.get('password')),
        'fullname': values.get('fullname', values['name']),
        'timezone': values.get('timezone', 'UTC'),
        'sso_username': None
    })

    query = _TABLE.insert().values(**values)

    try:
        flask.g.db_conn.execute(query)
    except sa_exc.IntegrityError:
        raise dci_exc.DCICreationConflict(_TABLE.name, 'name')

    # remove the password in the result for security reasons
    del values['password']

    return flask.Response(json.dumps({'user': values}),
                          201,
                          headers={'ETag': values['etag']},
                          content_type='application/json')
Example #8
0
def attach_issue(resource_id, table, user_id):
    data = flask.request.json
    check_json_is_valid(issue_schema, data)
    issue = _get_or_create_issue(data)

    # Second, insert a join record in the JOIN_JOBS_ISSUES or
    # JOIN_COMPONENTS_ISSUES database.
    if table.name == 'jobs':
        join_table = models.JOIN_JOBS_ISSUES
    else:
        join_table = models.JOIN_COMPONENTS_ISSUES

    key = '%s_id' % table.name[0:-1]
    query = join_table.insert().values({
        'user_id': user_id,
        'issue_id': issue['id'],
        key: resource_id
    })

    try:
        flask.g.db_conn.execute(query)
    except sa_exc.IntegrityError:
        raise dci_exc.DCICreationConflict(join_table.name,
                                          '%s, issue_id' % key)

    result = json.dumps({'issue': dict(issue)})
    return flask.Response(result, 201, content_type='application/json')
Example #9
0
def test_check_json_is_valid():
    schema = {"type": "object", "properties": {"name": Properties.string}}
    try:
        check_json_is_valid(schema, {"name": "foo"})
    except DCIException:
        pytest.fail(
            "check_json_is_valid raises DCIException and it should not")
Example #10
0
def put_feeder(user, f_id):
    if_match_etag = utils.check_and_get_etag(flask.request.headers)
    values = flask.request.json
    check_json_is_valid(update_feeder_schema, values)
    feeder = v1_utils.verify_existence_and_get(f_id, _TABLE)

    if not user.is_in_team(feeder['team_id']):
        raise dci_exc.Unauthorized()

    values['etag'] = utils.gen_etag()
    where_clause = sql.and_(_TABLE.c.etag == if_match_etag,
                            _TABLE.c.state != 'archived', _TABLE.c.id == f_id)

    query = (_TABLE.update().returning(
        *_TABLE.columns).where(where_clause).values(**values))

    result = flask.g.db_conn.execute(query)
    if not result.rowcount:
        raise dci_exc.DCIConflict('Feeder', f_id)

    _result = dict(result.fetchone())
    del _result['api_secret']

    return flask.Response(json.dumps({'feeder': _result}),
                          200,
                          headers={'ETag': values['etag']},
                          content_type='application/json')
Example #11
0
def create_jobs(user):
    values = flask.request.json
    check_json_is_valid(create_job_schema, values)
    values.update(v1_utils.common_values_dict())

    components_ids = values.pop('components')

    if user.is_not_remoteci():
        raise dci_exc.DCIException('Only remoteci can create job')

    topic_id = values.get('topic_id')
    topic = v1_utils.verify_existence_and_get(topic_id, models.TOPICS)
    export_control.verify_access_to_topic(user, topic)
    previous_job_id = values.get('previous_job_id')
    if previous_job_id:
        v1_utils.verify_existence_and_get(previous_job_id, _TABLE)

    values.update({
        'status':
        'new',
        'remoteci_id':
        user.id,
        'topic_id':
        topic_id,
        'user_agent':
        flask.request.environ.get('HTTP_USER_AGENT'),
        'client_version':
        flask.request.environ.get('HTTP_CLIENT_VERSION'),
        'previous_job_id':
        previous_job_id,
        'team_id':
        user.teams_ids[0],
        'product_id':
        topic['product_id'],
        'duration':
        0
    })

    # create the job and feed the jobs_components table
    with flask.g.db_conn.begin():
        query = _TABLE.insert().values(**values)
        flask.g.db_conn.execute(query)

        jobs_components_to_insert = []
        for cmpt_id in components_ids:
            v1_utils.verify_existence_and_get(cmpt_id, models.COMPONENTS)
            jobs_components_to_insert.append({
                'job_id': values['id'],
                'component_id': cmpt_id
            })
        if jobs_components_to_insert:
            flask.g.db_conn.execute(models.JOIN_JOBS_COMPONENTS.insert(),
                                    jobs_components_to_insert)

    return flask.Response(json.dumps({'job': values}),
                          201,
                          headers={'ETag': values['etag']},
                          content_type='application/json')
Example #12
0
def create_issue(user):
    data = flask.request.json
    check_json_is_valid(issue_test_schema, data)
    issue = _get_or_create_issue(data)
    result = json.dumps({'issue': dict(issue)})
    return flask.Response(result,
                          201,
                          headers={'ETag': issue['etag']},
                          content_type='application/json')
Example #13
0
def test_create_user_schema_required_value(user_json):
    with pytest.raises(DCIException) as e:
        check_json_is_valid(create_user_schema, {})
    result = e.value
    assert result.status_code == 400
    assert len(result.payload["errors"]) == len(user_json.keys())
    errors = "\n".join(result.payload["errors"])
    for key in user_json.keys():
        assert "'%s' is a required property" % key in errors
Example #14
0
def create_new_upgrade_job_from_an_existing_job(user):
    """Create a new job in the 'next topic' of the topic of
    the provided job_id."""
    values = flask.request.json
    check_json_is_valid(upgrade_job_schema, values)

    values.update({
        'id': utils.gen_uuid(),
        'created_at': get_utc_now().isoformat(),
        'updated_at': get_utc_now().isoformat(),
        'etag': utils.gen_etag(),
        'status': 'new'
    })

    original_job_id = values.pop('job_id')
    original_job = v1_utils.verify_existence_and_get(original_job_id,
                                                     models.JOBS)
    if user.is_not_in_team(original_job['team_id']) and user.is_not_epm():
        raise dci_exc.Unauthorized()

    # get the remoteci
    remoteci_id = str(original_job['remoteci_id'])
    remoteci = v1_utils.verify_existence_and_get(remoteci_id, models.REMOTECIS)
    values.update({'remoteci_id': remoteci_id})

    # get the associated topic
    topic_id = str(original_job['topic_id'])
    topic = v1_utils.verify_existence_and_get(topic_id, models.TOPICS)

    values.update({
        'user_agent':
        flask.request.environ.get('HTTP_USER_AGENT'),
        'client_version':
        flask.request.environ.get('HTTP_CLIENT_VERSION'),
    })

    next_topic_id = topic['next_topic_id']

    if not next_topic_id:
        raise dci_exc.DCIException("topic %s does not contains a next topic" %
                                   topic_id)
    topic = v1_utils.verify_existence_and_get(next_topic_id, models.TOPICS)
    product_id = topic['product_id']

    # instantiate a new job in the next_topic_id
    # todo(yassine): make possible the upgrade to choose specific components
    values = _build_job(product_id,
                        next_topic_id,
                        remoteci, [],
                        values,
                        previous_job_id=original_job_id)

    return flask.Response(json.dumps({'job': values}),
                          201,
                          headers={'ETag': values['etag']},
                          content_type='application/json')
Example #15
0
def test_check_json_is_valid_check_positive_or_null_integer_type():
    schema = {
        "type": "object",
        "properties": {
            "positive_or_null_integer": Properties.positive_or_null_integer
        },
        "required": ["positive_or_null_integer"],
    }
    try:
        check_json_is_valid(schema, {"positive_or_null_integer": 0})
    except DCIException:
        pytest.fail("positive_or_null_integer() is invalid")
Example #16
0
def test_update_user_schema():
    try:
        check_json_is_valid(
            update_user_schema, {
                "id": "909b4ad1-1c38-4fc3-9454-57dc6d80b44d",
                "etag": "8407cdbf-04d1-4453-8d35-19e4425c535b",
                "name": "jdoe",
                "fullname": "John Doe",
                "email": "*****@*****.**",
            })
    except DCIException:
        pytest.fail("update_user_schema is invalid")
Example #17
0
def test_allow_none_values():
    schema = {
        "type": "object",
        "properties": {
            "foo": allow_none(Properties.uuid)
        },
        "required": [],
    }
    try:
        check_json_is_valid(schema, {"foo": None})
    except DCIException:
        pytest.fail("allow None for foo doesn't work")
def compare_performance(user):
    values = flask.request.json
    check_json_is_valid(performance_schema, values)
    base_job_id = values["base_job_id"]
    jobs_ids = values["jobs"]
    tests_filenames = _get_tests_filenames(base_job_id)
    res = []
    for tf in tests_filenames:
        baseline_tests, tests = _get_test_files(base_job_id, jobs_ids, tf)  # noqa
        baseline_tests_file_with_fd, tests_files_with_fds = _get_test_files_with_fds(baseline_tests, tests)  # noqa
        perf_res = get_performance_tests(baseline_tests_file_with_fd,
                                         tests_files_with_fds)
        res.append({tf: perf_res})
    return flask.jsonify({"performance": res}), 200
Example #19
0
def test_check_json_is_valid_required_field():
    schema = {
        "type": "object",
        "properties": {
            "name": Properties.string
        },
        "required": ["name"],
    }
    with pytest.raises(DCIException) as e:
        check_json_is_valid(schema, {})
    result = e.value
    assert result.status_code == 400
    assert len(result.payload["errors"]) == 1
    assert result.payload["errors"][0] == "'name' is a required property"
    assert result.message == "Request malformed"
Example #20
0
def add_test_to_issue(user, issue_id):
    values = flask.request.json
    check_json_is_valid(issue_test_schema, values)

    issue_id = v1_utils.verify_existence_and_get(issue_id, _TABLE, get_id=True)

    values['issue_id'] = issue_id
    v1_utils.verify_existence_and_get(values.get('test_id'),
                                      models.TESTS,
                                      get_id=True)
    q_insert = models.JOIN_ISSUES_TESTS.insert().values(**values)
    flask.g.db_conn.execute(q_insert)
    return flask.Response(json.dumps(values),
                          201,
                          content_type='application/json')
Example #21
0
def test_check_json_is_valid_no_additional_properties():
    schema = {
        "type": "object",
        "properties": {
            "name": Properties.string
        },
        "additionalProperties": False,
    }
    with pytest.raises(DCIException) as e:
        check_json_is_valid(schema, {"name": "foo", "age": 32})
    result = e.value
    assert result.status_code == 400
    assert len(result.payload["errors"]) == 1
    assert (result.payload["errors"][0] ==
            "Additional properties are not allowed ('age' was unexpected)")
    assert result.message == "Request malformed"
Example #22
0
def create_jobstates(user):
    values = flask.request.json
    check_json_is_valid(jobstate_schema, values)

    # if one create a 'failed' jobstates and the current state is either
    # 'run' or 'pre-run' then set the job to 'error' state
    job_id = values.get('job_id')
    job = v1_utils.verify_existence_and_get(job_id, models.JOBS)
    job = dict(job)
    if values.get('status') in ['failure', 'error']:
        if job['status'] in ['new', 'pre-run']:
            values['status'] = 'error'

    insert_jobstate(user, values)

    # Update job status
    job_duration = datetime.datetime.utcnow() - job['created_at']
    query_update_job = (models.JOBS.update().where(
        sql.and_(models.JOBS.c.id == job_id,
                 models.JOBS.c.status != values.get('status'))).values(
                     status=values.get('status'),
                     duration=job_duration.seconds))
    result = flask.g.db_conn.execute(query_update_job)

    # send notification in case of final jobstate status
    if result.rowcount and values.get('status') in models.FINAL_STATUSES:
        embeds = ['components', 'topic', 'remoteci', 'results']
        embeds_many = {
            'components': True,
            'topic': False,
            'remoteci': False,
            'results': True
        }

        job = base.get_resource_by_id(user,
                                      job,
                                      models.JOBS,
                                      embed_many=embeds_many,
                                      embeds=embeds,
                                      jsonify=False)
        job = dict(job)
        jobs_events.create_event(job['id'], values['status'], job['topic_id'])
        if values.get('status') in models.FINAL_FAILURE_STATUSES:
            notifications.dispatcher(job)

    result = json.dumps({'jobstate': values})
    return flask.Response(result, 201, content_type='application/json')
Example #23
0
def test_default_values_string_value():
    schema = {
        "type": "object",
        "properties": {
            "foo": with_default(Properties.string, "bar")
        },
        "required": [],
    }
    try:
        obj = {}
        check_json_is_valid(schema, obj)
        assert obj == {"foo": "bar"}
        obj = {"foo": "foo"}
        check_json_is_valid(schema, obj)
        assert obj == {"foo": "foo"}
    except DCIException:
        pytest.fail("default string value doesn't work")
Example #24
0
def test_default_values_boolean_value():
    schema = {
        "type": "object",
        "properties": {
            "foo": with_default(Properties.boolean, False)
        },
        "required": [],
    }
    try:
        obj = {}
        check_json_is_valid(schema, obj)
        assert obj == {"foo": False}
        obj = {"foo": True}
        check_json_is_valid(schema, obj)
        assert obj == {"foo": True}
    except DCIException:
        pytest.fail("default boolean value doesn't work")
def create_components(user):
    values = flask.request.json
    check_json_is_valid(create_component_schema, values)
    values.update(v1_utils.common_values_dict())

    if str(values['topic_id']) not in v1_utils.user_topic_ids(user):
        raise dci_exc.Unauthorized()

    query = _TABLE.insert().values(**values)

    try:
        flask.g.db_conn.execute(query)
    except sa_exc.IntegrityError:
        raise dci_exc.DCICreationConflict(_TABLE.name, 'name')

    result = json.dumps({'component': values})
    return flask.Response(result, 201, content_type='application/json')
Example #26
0
def test_default_values_none_value():
    schema = {
        "type": "object",
        "properties": {
            "foo": with_default(Properties.uuid, None)
        },
        "required": [],
    }
    try:
        obj = {}
        check_json_is_valid(schema, obj)
        assert obj == {"foo": None}
        obj = {"foo": "b82dca4a-0597-4c70-b90f-0c422fc05c38"}
        check_json_is_valid(schema, obj)
        assert obj == {"foo": "b82dca4a-0597-4c70-b90f-0c422fc05c38"}
    except DCIException:
        pytest.fail("default None value doesn't work")
Example #27
0
def test_default_values_array_value():
    schema = {
        "type": "object",
        "properties": {
            "foo": with_default(Properties.array, [])
        },
        "required": [],
    }
    try:
        obj = {}
        check_json_is_valid(schema, obj)
        assert obj == {"foo": []}
        obj = {"foo": ["bar"]}
        check_json_is_valid(schema, obj)
        assert obj == {"foo": ["bar"]}
    except DCIException:
        pytest.fail("default array value doesn't work")
Example #28
0
def test_check_json_is_valid_check_url_type():
    schema = {
        "type": "object",
        "properties": {
            "url": Properties.url
        },
        "required": ["url"],
    }
    try:
        check_json_is_valid(schema, {"url": "https://distributed-ci.io"})
    except DCIException:
        pytest.fail("url() is invalid")

    with pytest.raises(DCIException) as e:
        check_json_is_valid(schema, {"url": "not an url"})
    errors = e.value.payload["errors"]
    assert len(errors) == 1
    assert errors[0] == "url: 'not an url' is not a valid 'url'"
Example #29
0
def test_check_json_is_valid_check_string_type():
    schema = {
        "type": "object",
        "properties": {
            "name": Properties.string
        },
        "required": ["name"],
    }
    try:
        check_json_is_valid(schema, {"name": "good string"})
    except DCIException:
        pytest.fail("string() is invalid")

    with pytest.raises(DCIException) as e:
        check_json_is_valid(schema, {"name": None})
    errors = e.value.payload["errors"]
    assert len(errors) == 1
    assert errors[0] == "name: None is not of type 'string'"
Example #30
0
def test_check_json_is_valid_check_enum_type():
    schema = {
        "type": "object",
        "properties": {
            "status": Properties.enum(["success", "error"])
        },
        "required": ["status"],
    }
    try:
        check_json_is_valid(schema, {"status": "success"})
    except DCIException:
        pytest.fail("string() is invalid")

    with pytest.raises(DCIException) as e:
        check_json_is_valid(schema, {"status": "running"})
    errors = e.value.payload["errors"]
    assert len(errors) == 1
    assert errors[0] == "'running' is not one of ['success', 'error']"