예제 #1
0
파일: repo_mirror.py 프로젝트: kleesc/quay
def set_mirroring_robot(repository, robot):
    """
    Sets the mirroring robot for the repository.
    """
    assert robot.robot
    namespace, _ = parse_robot_username(robot.username)
    if namespace != repository.namespace_user.username:
        raise DataModelException("Cannot use robot for mirroring")

    mirror = get_mirror(repository)
    mirror.internal_robot = robot
    mirror.save()
예제 #2
0
def find_matching_team_invite(code, user_obj):
    """ Finds a team invite with the given code that applies to the given user and returns it or
      raises a DataModelException if not found. """
    found = lookup_team_invite(code)

    # If the invite is for a specific user, we have to confirm that here.
    if found.user is not None and found.user != user_obj:
        message = """This invite is intended for user "%s".
                 Please login to that account and try again.""" % found.user.username
        raise DataModelException(message)

    return found
예제 #3
0
파일: repository.py 프로젝트: wjjmjh/quay
def create_email_authorization_for_repo(namespace_name, repository_name,
                                        email):
    try:
        repo = _basequery.get_existing_repository(namespace_name,
                                                  repository_name)
    except Repository.DoesNotExist:
        raise DataModelException("Invalid repository %s/%s" %
                                 (namespace_name, repository_name))

    return RepositoryAuthorizedEmail.create(repository=repo,
                                            email=email,
                                            confirmed=False)
예제 #4
0
    def delete_tag(self, repository_ref, tag_name):
        """
    Deletes the latest, *active* tag with the given name in the repository.
    """
        deleted_tag = oci.tag.delete_tag(repository_ref._db_id, tag_name)
        if deleted_tag is None:
            # TODO: This is only needed because preoci raises an exception. Remove and fix
            # expected status codes once PreOCIModel is gone.
            msg = ('Invalid repository tag \'%s\' on repository' % tag_name)
            raise DataModelException(msg)

        return Tag.for_tag(deleted_tag)
예제 #5
0
파일: team.py 프로젝트: sabre1041/quay-1
def confirm_team_invite(code, user_obj):
    """
    Confirms the given team invite code for the given user by adding the user to the team and
    deleting the code.

    Raises a DataModelException if the code was not found or does not apply to the given user. If
    the user is invited to two or more teams under the same organization, they are automatically
    confirmed for all of them.
    """
    found = find_matching_team_invite(code, user_obj)

    # Find all matching invitations for the user under the organization.
    code_found = False
    for invite in find_organization_invites(found.team.organization, user_obj):
        # Add the user to the team.
        try:
            code_found = True
            add_user_to_team(user_obj, invite.team)
        except UserAlreadyInTeam:
            # Ignore.
            pass

        # Delete the invite and return the team.
        invite.delete_instance()

    if not code_found:
        if found.user:
            message = ("""This invite is intended for user "%s".
                   Please login to that account and try again.""" %
                       found.user.username)
            raise DataModelException(message)
        else:
            message = ("""This invite is intended for email "%s".
                   Please login to that account and try again.""" %
                       found.email)
            raise DataModelException(message)

    team = found.team
    inviter = found.inviter
    return (team, inviter)
예제 #6
0
def _logs_query(
    selections,
    start_time=None,
    end_time=None,
    performer=None,
    repository=None,
    namespace=None,
    ignore=None,
    model=LogEntry3,
    id_range=None,
    namespace_id=None,
):
    """ Returns a query for selecting logs from the table, with various options and filters. """
    if namespace is not None:
        assert namespace_id is None

    if namespace_id is not None:
        assert namespace is None

    assert (start_time is not None and end_time is not None) or (id_range
                                                                 is not None)
    joined = model.select(*selections).switch(model)

    if id_range is not None:
        joined = joined.where(model.id >= id_range[0], model.id <= id_range[1])
    else:
        joined = joined.where(model.datetime >= start_time,
                              model.datetime < end_time)

    if repository:
        joined = joined.where(model.repository == repository)

    if performer:
        joined = joined.where(model.performer == performer)

    if namespace and not repository:
        namespace_user = user.get_user_or_org(namespace)
        if namespace_user is None:
            raise DataModelException("Invalid namespace requested: %s" %
                                     namespace)

        joined = joined.where(model.account == namespace_user.id)

    if namespace_id is not None and not repository:
        joined = joined.where(model.account == namespace_id)

    if ignore:
        kind_map = get_log_entry_kinds()
        ignore_ids = [kind_map[kind_name] for kind_name in ignore]
        joined = joined.where(~(model.kind << ignore_ids))

    return joined
예제 #7
0
파일: tag.py 프로젝트: zhill/quay
def _get_repo_tag_image(tag_name, include_storage, modifier):
    query = Image.select().join(RepositoryTag)

    if include_storage:
        query = (Image.select(
            Image,
            ImageStorage).join(ImageStorage).switch(Image).join(RepositoryTag))

    images = _tag_alive(modifier(query.where(RepositoryTag.name == tag_name)))
    if not images:
        raise DataModelException("Unable to find image for tag.")
    else:
        return images[0]
예제 #8
0
    def delete_tag(self, repository_ref, tag_name):
        """
        Deletes the latest, *active* tag with the given name in the repository.
        """
        with db_disallow_replica_use():
            deleted_tag = oci.tag.delete_tag(repository_ref._db_id, tag_name)
            if deleted_tag is None:
                # TODO: This is only needed because preoci raises an exception. Remove and fix
                # expected status codes once PreOCIModel is gone.
                msg = "Invalid repository tag '%s' on repository" % tag_name
                raise DataModelException(msg)

            return Tag.for_tag(deleted_tag, self._legacy_image_id_handler)
예제 #9
0
파일: permission.py 프로젝트: zhill/quay
def set_user_repo_permission(username, namespace_name, repository_name,
                             role_name):
    if username == namespace_name:
        raise DataModelException("Namespace owner must always be admin.")

    try:
        user = User.get(User.username == username)
    except User.DoesNotExist:
        raise DataModelException("Invalid username: %s" % username)

    if user.robot:
        parts = parse_robot_username(user.username)
        if not parts:
            raise DataModelException("Invalid robot: %s" % username)

        robot_namespace, _ = parts
        if robot_namespace != namespace_name:
            raise DataModelException("Cannot add robot %s under namespace %s" %
                                     (username, namespace_name))

    return __set_entity_repo_permission(user, "user", namespace_name,
                                        repository_name, role_name)
예제 #10
0
def change_user_tag_expiration(user, tag_expiration_s):
    """
    Changes the tag expiration on the given user/org.

    Note that the specified expiration must be within the configured TAG_EXPIRATION_OPTIONS or this
    method will raise a DataModelException.
    """
    allowed_options = [_convert_to_s(o) for o in config.app_config["TAG_EXPIRATION_OPTIONS"]]
    if tag_expiration_s not in allowed_options:
        raise DataModelException("Invalid tag expiration option")

    user.removed_tag_expiration_s = tag_expiration_s
    user.save()
예제 #11
0
파일: image.py 프로젝트: quay/quay
def set_image_metadata(
    docker_image_id,
    namespace_name,
    repository_name,
    created_date_str,
    comment,
    command,
    v1_json_metadata,
    parent=None,
):
    """
    Sets metadata that is specific to how a binary piece of storage fits into the layer tree.
    """
    with db_transaction():
        try:
            fetched = (
                Image.select(Image, ImageStorage)
                .join(Repository)
                .join(Namespace, on=(Repository.namespace_user == Namespace.id))
                .switch(Image)
                .join(ImageStorage)
                .where(
                    Repository.name == repository_name,
                    Namespace.username == namespace_name,
                    Image.docker_image_id == docker_image_id,
                )
                .get()
            )
        except Image.DoesNotExist:
            raise DataModelException("No image with specified id and repository")

        fetched.created = datetime.now()
        if created_date_str is not None:
            try:
                fetched.created = dateutil.parser.parse(created_date_str).replace(tzinfo=None)
            except:
                # parse raises different exceptions, so we cannot use a specific kind of handler here.
                pass

        # We cleanup any old checksum in case it's a retry after a fail
        fetched.v1_checksum = None
        fetched.comment = comment
        fetched.command = command
        fetched.v1_json_metadata = v1_json_metadata

        if parent:
            fetched.ancestors = "%s%s/" % (parent.ancestors, parent.id)
            fetched.parent = parent

        fetched.save()
        return fetched
예제 #12
0
def create_user_noverify(username, email, email_required=True, prompts=tuple(),
                         is_possible_abuser=False):
  if email_required:
    if not validate_email(email):
      raise InvalidEmailAddressException('Invalid email address: %s' % email)
  else:
    # If email addresses are not required and none was specified, then we just use a unique
    # ID to ensure that the database consistency check remains intact.
    email = email or str(uuid.uuid4())

  (username_valid, username_issue) = validate_username(username)
  if not username_valid:
    raise InvalidUsernameException('Invalid namespace %s: %s' % (username, username_issue))

  try:
    existing = User.get((User.username == username) | (User.email == email))
    logger.info('Existing user with same username or email.')

    # A user already exists with either the same username or email
    if existing.username == username:
      assert not existing.robot

      msg = 'Username has already been taken by an organization and cannot be reused: %s' % username
      if not existing.organization:
        msg = 'Username has already been taken by user cannot be reused: %s' % username

      raise InvalidUsernameException(msg)

    raise InvalidEmailAddressException('Email has already been used: %s' % email)
  except User.DoesNotExist:
    # This is actually the happy path
    logger.debug('Email and username are unique!')

  # Create the user.
  try:
    default_expr_s = _convert_to_s(config.app_config['DEFAULT_TAG_EXPIRATION'])
    default_max_builds = config.app_config.get('DEFAULT_NAMESPACE_MAXIMUM_BUILD_COUNT')
    threat_max_builds = config.app_config.get('THREAT_NAMESPACE_MAXIMUM_BUILD_COUNT')

    if is_possible_abuser and threat_max_builds is not None:
      default_max_builds = threat_max_builds

    new_user = User.create(username=username, email=email, removed_tag_expiration_s=default_expr_s,
                           maximum_queued_builds_count=default_max_builds)
    for prompt in prompts:
      create_user_prompt(new_user, prompt)

    return new_user
  except Exception as ex:
    raise DataModelException(ex.message)
예제 #13
0
파일: team.py 프로젝트: sabre1041/quay-1
def remove_user_from_team(org_name, team_name, username, removed_by_username):
    Org = User.alias()
    joined = TeamMember.select().join(User).switch(TeamMember).join(Team)
    with_role = joined.join(TeamRole)
    with_org = with_role.switch(Team).join(Org,
                                           on=(Org.id == Team.organization))
    found = list(
        with_org.where(User.username == username, Org.username == org_name,
                       Team.name == team_name))

    if not found:
        raise DataModelException("User %s does not belong to team %s" %
                                 (username, team_name))

    if username == removed_by_username:
        admin_team_query = __get_user_admin_teams(org_name, username)
        admin_team_names = {team.name for team in admin_team_query}
        if team_name in admin_team_names and len(admin_team_names) <= 1:
            msg = "User cannot remove themselves from their only admin team."
            raise DataModelException(msg)

    user_in_team = found[0]
    user_in_team.delete_instance()
예제 #14
0
파일: tag.py 프로젝트: zhill/quay
def store_tag_manifest_for_testing(namespace_name, repository_name, tag_name,
                                   manifest, leaf_layer_id, storage_id_map):
    """ Stores a tag manifest for a specific tag name in the database. Returns the TagManifest
      object, as well as a boolean indicating whether the TagManifest was created.
  """
    try:
        repo = _basequery.get_existing_repository(namespace_name,
                                                  repository_name)
    except Repository.DoesNotExist:
        raise DataModelException("Invalid repository %s/%s" %
                                 (namespace_name, repository_name))

    return store_tag_manifest_for_repo(repo.id, tag_name, manifest,
                                       leaf_layer_id, storage_id_map)
예제 #15
0
def get_user_starred_repositories(user, kind_filter="image"):
    """ Retrieves all of the repositories a user has starred. """
    try:
        repo_kind = Repository.kind.get_id(kind_filter)
    except RepositoryKind.DoesNotExist:
        raise DataModelException("Unknown kind of repository")

    query = (Repository.select(
        Repository, User, Visibility,
        Repository.id.alias("rid")).join(Star).switch(Repository).join(
            User).switch(Repository).join(Visibility).where(
                Star.user == user, Repository.kind == repo_kind))

    return query
예제 #16
0
파일: user.py 프로젝트: zhill/quay
def confirm_user_email(token):
    # TODO(remove-unenc): Remove allow_public_only once migrated.
    allow_public_only = ActiveDataMigration.has_flag(
        ERTMigrationFlags.READ_OLD_FIELDS)
    result = decode_public_private_token(token,
                                         allow_public_only=allow_public_only)
    if not result:
        raise DataModelException("Invalid email confirmation code")

    try:
        code = EmailConfirmation.get(
            EmailConfirmation.code == result.public_code,
            EmailConfirmation.email_confirm == True)
    except EmailConfirmation.DoesNotExist:
        raise DataModelException("Invalid email confirmation code")

    if result.private_token and not code.verification_code.matches(
            result.private_token):
        raise DataModelException("Invalid email confirmation code")

    user = code.user
    user.verified = True

    old_email = None
    new_email = code.new_email
    if new_email and new_email != old_email:
        if find_user_by_email(new_email):
            raise DataModelException("E-mail address already used")

        old_email = user.email
        user.email = new_email

    with db_transaction():
        user.save()
        code.delete_instance()

    return user, new_email, old_email
예제 #17
0
def confirm_email_authorization_for_repo(code):
    try:
        found = (RepositoryAuthorizedEmail.select(
            RepositoryAuthorizedEmail, Repository,
            Namespace).join(Repository).join(
                Namespace, on=(Repository.namespace_user == Namespace.id)
            ).where(RepositoryAuthorizedEmail.code == code).where(
                Repository.state != RepositoryState.MARKED_FOR_DELETION).get())
    except RepositoryAuthorizedEmail.DoesNotExist:
        raise DataModelException("Invalid confirmation code.")

    found.confirmed = True
    found.save()

    return found
예제 #18
0
파일: team.py 프로젝트: sabre1041/quay-1
def set_team_org_permission(team, team_role_name, set_by_username):
    if team.role.name == "admin" and team_role_name != "admin":
        # We need to make sure we're not removing the users only admin role
        user_admin_teams = __get_user_admin_teams(team.organization.username,
                                                  set_by_username)
        admin_team_set = {admin_team.name for admin_team in user_admin_teams}
        if team.name in admin_team_set and len(admin_team_set) <= 1:
            msg = ("Cannot remove admin from team '%s' because calling user " +
                   "would no longer have admin on org '%s'") % (
                       team.name, team.organization.username)
            raise DataModelException(msg)

    new_role = TeamRole.get(TeamRole.name == team_role_name)
    team.role = new_role
    team.save()
    return team
예제 #19
0
파일: tag.py 프로젝트: zhill/quay
def create_or_update_tag(namespace_name,
                         repository_name,
                         tag_name,
                         tag_docker_image_id,
                         reversion=False,
                         now_ms=None):
    try:
        repo = _basequery.get_existing_repository(namespace_name,
                                                  repository_name)
    except Repository.DoesNotExist:
        raise DataModelException("Invalid repository %s/%s" %
                                 (namespace_name, repository_name))

    return create_or_update_tag_for_repo(repo.id,
                                         tag_name,
                                         tag_docker_image_id,
                                         reversion=reversion,
                                         now_ms=now_ms)
예제 #20
0
def create_robot(robot_shortname,
                 parent,
                 description="",
                 unstructured_metadata=None):
    (username_valid, username_issue) = validate_username(robot_shortname)
    if not username_valid:
        raise InvalidRobotException(
            "The name for the robot '%s' is invalid: %s" %
            (robot_shortname, username_issue))

    username = format_robot_username(parent.username, robot_shortname)

    try:
        User.get(User.username == username)

        msg = "Existing robot with name: %s" % username
        logger.debug(msg)
        raise InvalidRobotException(msg)
    except User.DoesNotExist:
        pass

    service = LoginService.get(name="quayrobot")
    try:
        with db_transaction():
            created = User.create(username=username,
                                  email=str(uuid.uuid4()),
                                  robot=True)
            token = random_string_generator(length=64)()
            RobotAccountToken.create(robot_account=created,
                                     token=token,
                                     fully_migrated=True)
            FederatedLogin.create(user=created,
                                  service=service,
                                  service_ident="robot:%s" % created.id)
            RobotAccountMetadata.create(
                robot_account=created,
                description=description[0:255],
                unstructured_json=unstructured_metadata or {},
            )
            return created, token
    except Exception as ex:
        raise DataModelException(ex)
예제 #21
0
def calculate_image_aggregate_size(ancestors_str, image_size, parent_image):
    ancestors = ancestors_str.split("/")[1:-1]
    if not ancestors:
        return image_size

    if parent_image is None:
        raise DataModelException("Could not load parent image")

    ancestor_size = parent_image.aggregate_size
    if ancestor_size is not None:
        return ancestor_size + image_size

    # Fallback to a slower path if the parent doesn't have an aggregate size saved.
    # TODO: remove this code if/when we do a full backfill.
    ancestor_size = (ImageStorage.select(fn.Sum(ImageStorage.image_size)).join(
        Image).where(Image.id << ancestors).scalar())
    if ancestor_size is None:
        return None

    return ancestor_size + image_size
예제 #22
0
파일: tag.py 프로젝트: zhangli19817/quay
def restore_tag_to_manifest(repo_obj, tag_name, manifest_digest):
    """
    Restores a tag to a specific manifest digest.
    """
    with db_transaction():
        # Verify that the manifest digest already existed under this repository under the
        # tag.
        try:
            tag_manifest = (TagManifest.select(
                TagManifest, RepositoryTag,
                Image).join(RepositoryTag).join(Image).where(
                    RepositoryTag.repository == repo_obj).where(
                        RepositoryTag.name == tag_name).where(
                            TagManifest.digest == manifest_digest).get())
        except TagManifest.DoesNotExist:
            raise DataModelException(
                "Cannot restore to unknown or invalid digest")

        # Lookup the existing image, if any.
        try:
            existing_image = get_repo_tag_image(repo_obj, tag_name)
        except DataModelException:
            existing_image = None

        docker_image_id = tag_manifest.tag.image.docker_image_id
        oci_manifest = None
        try:
            oci_manifest = Manifest.get(repository=repo_obj,
                                        digest=manifest_digest)
        except Manifest.DoesNotExist:
            pass

        # Change the tag and tag manifest to point to the updated image.
        updated_tag = create_or_update_tag_for_repo(repo_obj,
                                                    tag_name,
                                                    docker_image_id,
                                                    reversion=True,
                                                    oci_manifest=oci_manifest)
        tag_manifest.tag = updated_tag
        tag_manifest.save()
        return existing_image
예제 #23
0
파일: team.py 프로젝트: sabre1041/quay-1
def remove_team(org_name, team_name, removed_by_username):
    joined = Team.select(Team, TeamRole).join(User).switch(Team).join(TeamRole)

    found = list(
        joined.where(User.organization == True, User.username == org_name,
                     Team.name == team_name))
    if not found:
        raise InvalidTeamException("Team '%s' is not a team in org '%s'" %
                                   (team_name, org_name))

    team = found[0]
    if team.role.name == "admin":
        admin_teams = list(
            __get_user_admin_teams(org_name, removed_by_username))
        if len(admin_teams) <= 1:
            # The team we are trying to remove is the only admin team containing this user.
            msg = "Deleting team '%s' would remove admin ability for user '%s' in organization '%s'"
            raise DataModelException(
                msg % (team_name, removed_by_username, org_name))

    team.delete_instance(recursive=True, delete_nullable=True)
예제 #24
0
파일: tag.py 프로젝트: zhill/quay
def delete_tag(namespace_name, repository_name, tag_name, now_ms=None):
    now_ms = now_ms or get_epoch_timestamp_ms()
    now_ts = int(now_ms / 1000)

    with db_transaction():
        try:
            query = _tag_alive(
                RepositoryTag.select(
                    RepositoryTag, Repository).join(Repository).join(
                        Namespace,
                        on=(Repository.namespace_user == Namespace.id)).where(
                            Repository.name == repository_name,
                            Namespace.username == namespace_name,
                            RepositoryTag.name == tag_name,
                        ),
                now_ts,
            )
            found = db_for_update(query).get()
        except RepositoryTag.DoesNotExist:
            msg = "Invalid repository tag '%s' on repository '%s/%s'" % (
                tag_name,
                namespace_name,
                repository_name,
            )
            raise DataModelException(msg)

        found.lifetime_end_ts = now_ts
        found.save()

        try:
            oci_tag_query = TagToRepositoryTag.select().where(
                TagToRepositoryTag.repository_tag == found)
            oci_tag = db_for_update(oci_tag_query).get().tag
            oci_tag.lifetime_end_ms = now_ms
            oci_tag.save()
        except TagToRepositoryTag.DoesNotExist:
            pass

        return found
예제 #25
0
파일: storage.py 프로젝트: sabre1041/quay-1
def set_image_storage_metadata(
    docker_image_id, namespace_name, repository_name, image_size, uncompressed_size
):
    """
    Sets metadata that is specific to the binary storage of the data, irrespective of how it is used
    in the layer tree.
    """
    if image_size is None:
        raise DataModelException("Empty image size field")

    try:
        image = (
            Image.select(Image, ImageStorage)
            .join(Repository)
            .join(Namespace, on=(Repository.namespace_user == Namespace.id))
            .switch(Image)
            .join(ImageStorage)
            .where(
                Repository.name == repository_name,
                Namespace.username == namespace_name,
                Image.docker_image_id == docker_image_id,
            )
            .get()
        )
    except ImageStorage.DoesNotExist:
        raise InvalidImageException("No image with specified id and repository")

    # We MUST do this here, it can't be done in the corresponding image call because the storage
    # has not yet been pushed
    image.aggregate_size = _basequery.calculate_image_aggregate_size(
        image.ancestors, image_size, image.parent
    )
    image.save()

    image.storage.image_size = image_size
    image.storage.uncompressed_size = uncompressed_size
    image.storage.save()
    return image.storage
예제 #26
0
파일: log.py 프로젝트: sabre1041/quay-1
def _latest_logs_query(
    selections,
    performer=None,
    repository=None,
    namespace=None,
    ignore=None,
    model=LogEntry3,
    size=None,
):
    """
    Returns a query for selecting the latest logs from the table, with various options and filters.
    """
    query = model.select(*selections).switch(model)

    if repository:
        query = query.where(model.repository == repository)

    if performer:
        query = query.where(model.repository == repository)

    if namespace and not repository:
        namespace_user = user.get_user_or_org(namespace)
        if namespace_user is None:
            raise DataModelException("Invalid namespace requested")

        query = query.where(model.account == namespace_user.id)

    if ignore:
        kind_map = get_log_entry_kinds()
        ignore_ids = [kind_map[kind_name] for kind_name in ignore]
        query = query.where(~(model.kind << ignore_ids))

    query = query.order_by(model.datetime.desc(), model.id)

    if size:
        query = query.limit(size)

    return query
예제 #27
0
def convert_user_to_organization(user_obj, admin_user):
    if user_obj.robot:
        raise DataModelException("Cannot convert a robot into an organization")

    with db_transaction():
        # Change the user to an organization and disable this account for login.
        user_obj.organization = True
        user_obj.password_hash = None
        user_obj.save()

        # Clear any federated auth pointing to this user.
        FederatedLogin.delete().where(FederatedLogin.user == user_obj).execute()

        # Delete any user-specific permissions on repositories.
        (RepositoryPermission.delete().where(RepositoryPermission.user == user_obj).execute())

        # Create a team for the owners
        owners_team = team.create_team("owners", user_obj, "admin")

        # Add the user who will admin the org to the owners team
        team.add_user_to_team(admin_user, owners_team)

        return user_obj
예제 #28
0
def mark_namespace_for_deletion(user, queues, namespace_gc_queue, force=False):
    """
    Marks a namespace (as referenced by the given user) for deletion.

    A queue item will be added to delete the namespace's repositories and storage, while the
    namespace itself will be renamed, disabled, and delinked from other tables.
    """
    if not user.enabled:
        return None

    if not force and not user.organization:
        # Ensure that the user is not the sole admin for any organizations. If so, then the user
        # cannot be deleted before those organizations are deleted or reassigned.
        organizations = get_solely_admined_organizations(user)
        if len(organizations) > 0:
            message = (
                "Cannot delete %s as you are the only admin for organizations: "
                % user.username)
            for index, org in enumerate(organizations):
                if index > 0:
                    message = message + ", "

                message = message + org.username

            raise DataModelException(message)

    # Delete all queue items for the user.
    for queue in queues:
        queue.delete_namespaced_items(user.username)

    # Delete non-repository related items. This operation is very quick, so we can do so here.
    _delete_user_linked_data(user)

    with db_transaction():
        original_username = user.username
        user = db_for_update(User.select().where(User.id == user.id)).get()

        # Mark the namespace as deleted and ready for GC.
        try:
            marker = DeletedNamespace.create(
                namespace=user,
                original_username=original_username,
                original_email=user.email)
        except IntegrityError:
            return

        # Disable the namespace itself, and replace its various unique fields with UUIDs.
        user.enabled = False
        user.username = str(uuid4())
        user.email = str(uuid4())
        user.save()

    # Add a queueitem to delete the namespace.
    marker.queue_id = namespace_gc_queue.put(
        [str(user.id)],
        json.dumps({
            "marker_id": marker.id,
            "original_username": original_username,
        }),
    )
    marker.save()
    return marker.id
예제 #29
0
파일: tag.py 프로젝트: zhill/quay
def create_or_update_tag_for_repo(repository_id,
                                  tag_name,
                                  tag_docker_image_id,
                                  reversion=False,
                                  oci_manifest=None,
                                  now_ms=None):
    now_ms = now_ms or get_epoch_timestamp_ms()
    now_ts = int(now_ms / 1000)

    with db_transaction():
        try:
            tag = db_for_update(
                _tag_alive(
                    RepositoryTag.select().where(
                        RepositoryTag.repository == repository_id,
                        RepositoryTag.name == tag_name),
                    now_ts,
                )).get()
            tag.lifetime_end_ts = now_ts
            tag.save()

            # Check for an OCI tag.
            try:
                oci_tag = db_for_update(
                    Tag.select().join(TagToRepositoryTag).where(
                        TagToRepositoryTag.repository_tag == tag)).get()
                oci_tag.lifetime_end_ms = now_ms
                oci_tag.save()
            except Tag.DoesNotExist:
                pass
        except RepositoryTag.DoesNotExist:
            pass
        except IntegrityError:
            msg = "Tag with name %s was stale when we tried to update it; Please retry the push"
            raise StaleTagException(msg % tag_name)

        try:
            image_obj = Image.get(Image.docker_image_id == tag_docker_image_id,
                                  Image.repository == repository_id)
        except Image.DoesNotExist:
            raise DataModelException("Invalid image with id: %s" %
                                     tag_docker_image_id)

        try:
            created = RepositoryTag.create(
                repository=repository_id,
                image=image_obj,
                name=tag_name,
                lifetime_start_ts=now_ts,
                reversion=reversion,
            )
            if oci_manifest:
                # Create the OCI tag as well.
                oci_tag = Tag.create(
                    repository=repository_id,
                    manifest=oci_manifest,
                    name=tag_name,
                    lifetime_start_ms=now_ms,
                    reversion=reversion,
                    tag_kind=Tag.tag_kind.get_id("tag"),
                )
                TagToRepositoryTag.create(tag=oci_tag,
                                          repository_tag=created,
                                          repository=repository_id)

            return created
        except IntegrityError:
            msg = "Tag with name %s and lifetime start %s already exists"
            raise TagAlreadyCreatedException(msg % (tag_name, now_ts))