def listSideTags(basetag=None, user=None, queryOpts=None):
    """List all sidetags with additional filters

    :param basetag: filter by basteag id or name
    :type basetag: int or str
    :param user: filter by userid or username
    :type user: int or str
    :param queryOpts: additional query options
                      {countOnly, order, offset, limit}
    :type queryOpts: dict

    :returns: list of dicts: id, name, user_id, user_name
    """
    # te1.sidetag
    # te2.user_id
    # te3.basetag
    if user is not None:
        user_id = str(get_user(user, strict=True)["id"])
    else:
        user_id = None
    if basetag is not None:
        basetag_id = get_tag(basetag, strict=True)["id"]
    else:
        basetag_id = None

    joins = [
        "LEFT JOIN tag_extra AS te1 ON tag.id = te1.tag_id",
        "LEFT JOIN tag_extra AS te2 ON tag.id = te2.tag_id",
        "LEFT JOIN users ON CAST(te2.value AS INTEGER) = users.id",
    ]
    clauses = [
        "te1.active IS TRUE",
        "te1.key = 'sidetag'",
        "te1.value = 'true'",
        "te2.active IS TRUE",
        "te2.key = 'sidetag_user_id'"
    ]
    if user_id:
        clauses.append("te2.value = %(user_id)s")
    if basetag_id:
        joins.append("LEFT JOIN tag_inheritance ON tag.id = tag_inheritance.tag_id")
        clauses.extend(
            [
                "tag_inheritance.active IS TRUE",
                "tag_inheritance.parent_id = %(basetag_id)s",
            ]
        )

    query = QueryProcessor(
        tables=["tag"],
        clauses=clauses,
        columns=["tag.id", "tag.name", "te2.value", "users.name"],
        aliases=["id", "name", "user_id", "user_name"],
        joins=joins,
        values={"basetag_id": basetag_id, "user_id": user_id},
        opts=queryOpts,
    )
    return query.execute()
Example #2
0
def createSideTag(basetag, debuginfo=False):
    """Create a side tag.

    :param basetag: name or ID of base tag
    :type basetag: str or int

    :param debuginfo: should buildroot repos contain debuginfo?
    :type debuginfo: bool
    """

    # Any logged-in user is able to request creation of side tags,
    # as long the request meets the policy.
    context.session.assertLogin()
    user = get_user(context.session.user_id, strict=True)

    basetag = get_tag(basetag, strict=True)

    query = QueryProcessor(
        tables=["tag_extra"],
        clauses=[
            "key='sidetag_user_id'", "value=%(user_id)s", "active IS TRUE"
        ],
        columns=["COUNT(*)"],
        aliases=["user_tags"],
        values={"user_id": str(user["id"])},
    )
    user_tags = query.executeOne()
    if user_tags is None:
        # should not ever happen
        raise koji.GenericError("Unknown db error")

    # Policy is a very flexible mechanism, that can restrict for which
    # tags sidetags can be created, or which users can create sidetags etc.
    assert_policy("sidetag", {
        "tag": basetag["id"],
        "number_of_tags": user_tags["user_tags"]
    })

    # ugly, it will waste one number in tag_id_seq, but result will match with
    # id assigned by _create_tag
    tag_id = nextval("tag_id_seq") + 1
    sidetag_name = "%s-side-%s" % (basetag["name"], tag_id)
    extra = {
        "sidetag": True,
        "sidetag_user": user["name"],
        "sidetag_user_id": user["id"],
    }
    if debuginfo:
        extra['with_debuginfo'] = True
    sidetag_id = _create_tag(
        sidetag_name,
        parent=basetag["id"],
        arches=basetag["arches"],
        extra=extra,
    )
    _create_build_target(sidetag_name, sidetag_id, sidetag_id)

    return {"name": sidetag_name, "id": sidetag_id}
Example #3
0
def editSideTag(sidetag,
                debuginfo=None,
                rpm_macros=None,
                remove_rpm_macros=None):
    """Restricted ability to modify sidetags, parent tag must have:
    sidetag_debuginfo_allowed: 1
    sidetag_rpm_macros_allowed: 1
    in extra, if modifying functions should work. For blocking/unblocking
    further policy must be compatible with these operations.

    :param sidetag: sidetag id or name
    :type sidetag: int or str
    :param debuginfo: set or disable debuginfo repo generation
    :type debuginfo: bool
    :param rpm_macros: add/update rpms macros in extra
    :type rpm_macros: dict
    :param remove_rpm_macros: remove rpm macros from extra
    :type remove_rpm_macros: list of str
    """

    context.session.assertLogin()
    user = get_user(context.session.user_id, strict=True)
    sidetag = get_tag(sidetag, strict=True)

    # sanity/access
    is_sidetag(sidetag, raise_error=True)
    is_sidetag_owner(sidetag, user, raise_error=True)

    parent_id = readInheritanceData(sidetag['id'])[0]['parent_id']
    parent = get_tag(parent_id)

    if debuginfo is not None and not parent['extra'].get(
            'sidetag_debuginfo_allowed'):
        raise koji.GenericError(
            "Debuginfo setting is not allowed in parent tag.")

    if (rpm_macros is not None or remove_rpm_macros is not None) \
            and not parent['extra'].get('sidetag_rpm_macros_allowed'):
        raise koji.GenericError(
            "RPM macros change is not allowed in parent tag.")

    kwargs = {'extra': {}}
    if debuginfo is not None:
        kwargs['extra']['with_debuginfo'] = bool(debuginfo)
    if rpm_macros is not None:
        for macro, value in rpm_macros.items():
            kwargs['extra']['rpm.macro.%s' % macro] = value
    if remove_rpm_macros is not None:
        kwargs['remove_extra'] = [
            'rpm.macro.%s' % m for m in remove_rpm_macros
        ]

    _edit_tag(sidetag['id'], **kwargs)
def removeSideTag(sidetag):
    """Remove a side tag

    :param sidetag: id or name of sidetag
    :type sidetag: int or str
    """
    context.session.assertLogin()
    user = get_user(context.session.user_id, strict=True)
    sidetag = get_tag(sidetag, strict=True)

    # sanity/access
    is_sidetag(sidetag, raise_error=True)
    is_sidetag_owner(sidetag, user, raise_error=True)

    _remove_sidetag(sidetag)
Example #5
0
def get_message_body(topic, *args, **kws):
    msg = {}

    if topic == 'package.list.change':
        msg['tag'] = kws['tag']['name']
        msg['package'] = kws['package']['name']
    elif topic == 'task.state.change':
        msg['method'] = kws['info']['method']
        msg['attribute'] = kws['attribute']
        msg['old'] = kws['old']
        msg['new'] = kws['new']
        msg['owner'] = kojihub.get_user(kws['info']['owner'])['name']
        msg['id'] = kws['info']['id']
    elif topic == 'build.state.change':
        info = kws['info']
        msg['name'] = info['name']
        msg['version'] = info['version']
        msg['release'] = info['release']
        msg['attribute'] = kws['attribute']
        msg['old'] = kws['old']
        msg['new'] = kws['new']
    elif topic == 'import':
        msg['type'] = kws['type']
    elif topic in ('tag', 'untag'):
        msg['tag'] = kws['tag']['name']
        build = kws['build']
        msg['name'] = build['name']
        msg['version'] = build['version']
        msg['release'] = build['release']
        msg['user'] = kws['user']['name']
    elif topic == 'repo.init':
        msg['tag'] = kws['tag']['name']
    elif topic == 'repo.done':
        msg['tag'] = kws['repo']['tag_name']

    return msg
def get_message_body(topic, *args, **kws):
    msg = {}

    if topic == 'package.list.change':
        msg['tag'] = kws['tag']['name']
        msg['package'] = kws['package']['name']
    elif topic == 'task.state.change':
        info = kws['info']

        # Stuff in information about descendant tasks
        task = kojihub.Task(info['id'])
        info['children'] = task.getChildren()

        # Send the whole info dict along because it might have useful info.
        # For instance, it contains the mention of what format createAppliance
        # is using (raw or qcow2).
        msg['info'] = info
        msg['method'] = kws['info']['method']
        msg['attribute'] = kws['attribute']
        msg['old'] = kws['old']
        msg['new'] = kws['new']
        msg['id'] = kws['info']['id']

        # extract a useful identifier from the request string
        request = kws.get('info', {}).get('request', ['/'])
        msg['srpm'] = request[0].split('/')[-1]

        if 'owner_name' in info:
            msg['owner'] = info['owner_name']
        elif 'owner_id' in info:
            msg['owner'] = kojihub.get_user(info['owner_id'])['name']
        elif 'owner' in info:
            msg['owner'] = kojihub.get_user(info['owner'])['name']
        else:
            msg['owner'] = None

    elif topic == 'build.state.change':
        info = kws['info']
        msg['name'] = info['name']
        msg['version'] = info['version']
        msg['release'] = info['release']
        msg['attribute'] = kws['attribute']
        msg['old'] = kws['old']
        msg['new'] = kws['new']
        msg['build_id'] = info.get('id', None)
        msg['task_id'] = info.get('task_id', None)

        if msg['task_id']:
            task = kojihub.Task(msg['task_id'])
            msg['request'] = task.getRequest()
        else:
            msg['request'] = None

        if 'owner_name' in info:
            msg['owner'] = info['owner_name']
        elif 'owner_id' in info:
            msg['owner'] = kojihub.get_user(info['owner_id'])['name']
        elif 'owner' in info:
            msg['owner'] = kojihub.get_user(info['owner'])['name']
        else:
            msg['owner'] = None

    elif topic == 'import':
        # TODO -- import is currently unused.
        # Should we remove it?
        msg['type'] = kws['type']
    elif topic in ('tag', 'untag'):
        msg['tag'] = kws['tag']['name']
        build = kws['build']
        msg['name'] = build['name']
        msg['version'] = build['version']
        msg['release'] = build['release']
        msg['user'] = kws['user']['name']
        msg['owner'] = kojihub.get_user(kws['build']['owner_id'])['name']
        msg['tag_id'] = kws['tag']['id']
        msg['build_id'] = kws['build']['id']
    elif topic == 'repo.init':
        msg['tag'] = kws['tag']['name']
        msg['tag_id'] = kws['tag']['id']
        msg['repo_id'] = kws['repo_id']
    elif topic == 'repo.done':
        msg['tag'] = kws['repo']['tag_name']
        msg['tag_id'] = kws['repo']['tag_id']
        msg['repo_id'] = kws['repo']['id']
    elif topic == 'rpm.sign':
        if 'attribute' in kws:
            # v1.10.1 and earlier
            msg['attribute'] = kws['attribute']
            msg['old'] = kws['old']
            msg['new'] = kws['new']
            msg['info'] = kws['info']
        else:
            # v1.11.0 (and maybe higher, but who knows)
            msg['sigkey'] = kws['sigkey']
            msg['sighash'] = kws['sighash']
            msg['build'] = kws['build']
            msg['rpm'] = kws['rpm']

    return msg
def get_message_body(topic, *args, **kws):
    msg = {}

    if topic == 'package.list.change':
        msg['tag'] = kws['tag']['name']
        msg['package'] = kws['package']['name']
        msg['action'] = kws['action']
        if 'owner' in kws:
            msg['owner'] = kojihub.get_user(kws['owner'])['name']
        else:
            msg['owner'] = None
        msg['block'] = kws.get('block', None)
        msg['extra_arches'] = kws.get('extra_arches', None)
        msg['force'] = kws.get('force', None)
        msg['update'] = kws.get('update', None)
    elif topic == 'task.state.change':
        info = kws['info']

        # Stuff in information about descendant tasks
        task = kojihub.Task(info['id'])
        info['children'] = task.getChildren()

        # Send the whole info dict along because it might have useful info.
        # For instance, it contains the mention of what format createAppliance
        # is using (raw or qcow2).
        msg['info'] = info
        msg['method'] = kws['info']['method']
        msg['attribute'] = kws['attribute']
        msg['old'] = kws['old']
        msg['new'] = kws['new']
        msg['id'] = kws['info']['id']

        # extract a useful identifier from the request string
        request = kws.get('info', {}).get('request', ['/'])
        msg['srpm'] = request[0].split('/')[-1]

        if 'owner_name' in info:
            msg['owner'] = info['owner_name']
        elif 'owner_id' in info:
            msg['owner'] = kojihub.get_user(info['owner_id'])['name']
        elif 'owner' in info:
            msg['owner'] = kojihub.get_user(info['owner'])['name']
        else:
            msg['owner'] = None

    elif topic == 'build.state.change':
        info = kws['info']
        msg['name'] = info['name']
        msg['version'] = info['version']
        msg['release'] = info['release']
        msg['epoch'] = info.get('epoch')
        msg['attribute'] = kws['attribute']
        msg['old'] = kws['old']
        msg['new'] = kws['new']
        msg['build_id'] = info.get('id', None)
        msg['task_id'] = info.get('task_id', None)

        if msg['task_id']:
            task = kojihub.Task(msg['task_id'])
            msg['request'] = task.getRequest()
        else:
            msg['request'] = None

        if 'owner_name' in info:
            msg['owner'] = info['owner_name']
        elif 'owner_id' in info:
            msg['owner'] = kojihub.get_user(info['owner_id'])['name']
        elif 'owner' in info:
            msg['owner'] = kojihub.get_user(info['owner'])['name']
        else:
            msg['owner'] = None

    elif topic == 'import':
        # TODO -- import is currently unused.
        # Should we remove it?
        msg['type'] = kws['type']
    elif topic in ('tag', 'untag'):
        msg['tag'] = kws['tag']['name']
        build = kws['build']
        msg['name'] = build['name']
        msg['version'] = build['version']
        msg['release'] = build['release']
        msg['user'] = kws['user']['name']
        msg['owner'] = kojihub.get_user(kws['build']['owner_id'])['name']
        msg['tag_id'] = kws['tag']['id']
        msg['build_id'] = kws['build']['id']
    elif topic == 'repo.init':
        msg['tag'] = kws['tag']['name']
        msg['tag_id'] = kws['tag']['id']
        msg['repo_id'] = kws['repo_id']
    elif topic == 'repo.done':
        msg['tag'] = kws['repo']['tag_name']
        msg['tag_id'] = kws['repo']['tag_id']
        msg['repo_id'] = kws['repo']['id']
    elif topic == 'rpm.sign':
        if 'attribute' in kws:
            # v1.10.1 and earlier
            msg['attribute'] = kws['attribute']
            msg['old'] = kws['old']
            msg['new'] = kws['new']
            msg['info'] = kws['info']
        else:
            # v1.11.0 (and maybe higher, but who knows)
            msg['sigkey'] = kws['sigkey']
            msg['sighash'] = kws['sighash']
            msg['build'] = kws['build']
            msg['rpm'] = kws['rpm']

    return msg
Example #8
0
def createSideTag(basetag, debuginfo=False, suffix=None):
    """Create a side tag.

    :param basetag: name or ID of base tag
    :type basetag: str or int

    :param debuginfo: should buildroot repos contain debuginfo?
    :type debuginfo: bool

    :param suffix: suffix which will be appended to generated sidetag name
                   List of allowed suffixes needs to be defined in config.
    :type suffix: str

    :returns dict: sidetag name + id
    """

    if suffix and suffix not in ALLOWED_SUFFIXES:
        raise koji.GenericError("%s suffix is not allowed for sidetag" % suffix)

    # Any logged-in user is able to request creation of side tags,
    # as long the request meets the policy.
    context.session.assertLogin()
    user = get_user(context.session.user_id, strict=True)

    basetag = get_tag(basetag, strict=True)

    query = QueryProcessor(
        tables=["tag_extra"],
        clauses=["key='sidetag_user_id'", "value=%(user_id)s", "active IS TRUE"],
        columns=["COUNT(*)"],
        aliases=["user_tags"],
        values={"user_id": str(user["id"])},
    )
    user_tags = query.executeOne()
    if user_tags is None:
        # should not ever happen
        raise koji.GenericError("Unknown db error")

    # Policy is a very flexible mechanism, that can restrict for which
    # tags sidetags can be created, or which users can create sidetags etc.
    assert_policy(
        "sidetag", {"tag": basetag["id"], "number_of_tags": user_tags["user_tags"]}
    )

    # ugly, it will waste one number in tag_id_seq, but result will match with
    # id assigned by _create_tag
    tag_id = nextval("tag_id_seq") + 1
    sidetag_name = NAME_TEMPLATE.format(basetag=basetag["name"], tag_id=tag_id)
    if suffix:
        sidetag_name += '-%s' % suffix
    extra = {
        "sidetag": True,
        "sidetag_user": user["name"],
        "sidetag_user_id": user["id"],
    }
    if debuginfo:
        extra['with_debuginfo'] = True
    sidetag_id = _create_tag(
        sidetag_name,
        parent=basetag["id"],
        arches=basetag["arches"],
        extra=extra,
    )
    _create_build_target(sidetag_name, sidetag_id, sidetag_id)

    return {"name": sidetag_name, "id": sidetag_id}