Ejemplo n.º 1
0
def AddDockerTag(args):
    """Adds a Docker tag."""
    src_image, version_or_tag = _ParseDockerImage(args.DOCKER_IMAGE,
                                                  _INVALID_DOCKER_IMAGE_ERROR)
    if version_or_tag is None:
        raise ar_exceptions.InvalidInputValueError(_INVALID_DOCKER_IMAGE_ERROR)

    dest_image, tag = _ParseDockerTag(args.DOCKER_TAG)

    if src_image.GetPackageName() != dest_image.GetPackageName():
        raise ar_exceptions.InvalidInputValueError(
            "Image {}\ndoes not match image {}".format(
                src_image.GetDockerString(), dest_image.GetDockerString()))

    client = ar_requests.GetClient()
    messages = ar_requests.GetMessages()
    docker_version = version_or_tag
    if isinstance(version_or_tag, DockerTag):
        docker_version = DockerVersion(
            version_or_tag.image,
            ar_requests.GetVersionFromTag(client, messages,
                                          version_or_tag.GetTagName()))

    try:
        ar_requests.GetTag(client, messages, tag.GetTagName())
    except api_exceptions.HttpNotFoundError:
        ar_requests.CreateDockerTag(client, messages, tag, docker_version)
    else:
        ar_requests.DeleteTag(client, messages, tag.GetTagName())
        ar_requests.CreateDockerTag(client, messages, tag, docker_version)

    log.status.Print("Added tag [{}] to image [{}].".format(
        tag.GetDockerString(), args.DOCKER_IMAGE))
Ejemplo n.º 2
0
def _ValidateAndGetDockerVersion(version_or_tag):
    """Validates a version_or_tag and returns the validated DockerVersion object.

  Args:
    version_or_tag: a docker version or a docker tag.

  Returns:
    a DockerVersion object.

  Raises:
    ar_exceptions.InvalidInputValueError if version_or_tag is not valid.
  """
    try:
        if isinstance(version_or_tag, DockerVersion):
            # We have all the information about the docker digest.
            # Call the API to make sure it exists.
            ar_requests.GetVersion(ar_requests.GetClient(),
                                   ar_requests.GetMessages(),
                                   version_or_tag.GetVersionName())
            return version_or_tag
        elif isinstance(version_or_tag, DockerTag):
            digest = ar_requests.GetVersionFromTag(ar_requests.GetClient(),
                                                   ar_requests.GetMessages(),
                                                   version_or_tag.GetTagName())
            docker_version = DockerVersion(version_or_tag.image, digest)
            return docker_version
        else:
            raise ar_exceptions.InvalidInputValueError(
                _INVALID_DOCKER_IMAGE_ERROR)
    except api_exceptions.HttpNotFoundError:
        raise ar_exceptions.InvalidInputValueError(_DOCKER_IMAGE_NOT_FOUND)
Ejemplo n.º 3
0
def _ParseDockerImage(img_str, err_msg):
    """Validates and parses an image string into a DockerImage.

  Args:
    img_str: str, User input docker formatted string.
    err_msg: str, Error message to return to user.

  Raises:
    ar_exceptions.InvalidInputValueError if user input is invalid.
    ar_exceptions.UnsupportedLocationError if provided location is invalid.

  Returns:
    A DockerImage, and a DockerTag or a DockerVersion.
  """
    try:
        docker_repo = _ParseInput(img_str)
    except ar_exceptions.InvalidInputValueError:
        raise ar_exceptions.InvalidInputValueError(_INVALID_DOCKER_IMAGE_ERROR)

    img_by_digest_match = re.match(DOCKER_IMG_BY_DIGEST_REGEX, img_str)
    if img_by_digest_match:
        docker_img = DockerImage(docker_repo, img_by_digest_match.group("img"))
        return docker_img, DockerVersion(docker_img,
                                         img_by_digest_match.group("digest"))
    img_by_tag_match = re.match(DOCKER_IMG_BY_TAG_REGEX, img_str)
    if img_by_tag_match:
        docker_img = DockerImage(docker_repo, img_by_tag_match.group("img"))
        return docker_img, DockerTag(docker_img, img_by_tag_match.group("tag"))
    whole_img_match = re.match(DOCKER_IMG_REGEX, img_str)
    if whole_img_match:
        return DockerImage(docker_repo,
                           whole_img_match.group("img").strip("/")), None
    raise ar_exceptions.InvalidInputValueError(err_msg)
Ejemplo n.º 4
0
def ValidateGcrRepo(repo_name, repo_format, location, docker_format):
    """Validates input for a gcr.io repository."""
    expected_location = _ALLOWED_GCR_REPO_LOCATION.get(repo_name, "")
    if location != expected_location:
        raise ar_exceptions.InvalidInputValueError(
            _INVALID_REPO_LOCATION_ERROR.format(repo_name, expected_location))
    if repo_format != docker_format:
        raise ar_exceptions.InvalidInputValueError(
            _INVALID_GCR_REPO_FORMAT_ERROR.format(repo_name))
Ejemplo n.º 5
0
def _ParseDockerImagePath(img_path):
    """Validates and parses an image path into a DockerImage or a DockerRepo."""
    if not img_path:
        return _GetDefaultResources()

    resource_val_list = list(filter(None, img_path.split("/")))
    try:
        docker_repo = _ParseInput(img_path)
    except ar_exceptions.InvalidInputValueError:
        raise ar_exceptions.InvalidInputValueError(_INVALID_IMAGE_PATH_ERROR)

    if len(resource_val_list) == 3:
        return docker_repo
    elif len(resource_val_list) > 3:
        return DockerImage(docker_repo, "/".join(resource_val_list[3:]))
    raise ar_exceptions.InvalidInputValueError(_INVALID_IMAGE_PATH_ERROR)
Ejemplo n.º 6
0
def _ValidateDockerRepo(repo_name):
    repo = ar_requests.GetRepository(repo_name)
    messages = ar_requests.GetMessages()
    if repo.format != messages.Repository.FormatValueValuesEnum.DOCKER:
        raise ar_exceptions.InvalidInputValueError(
            "Invalid repository type {}. The `artifacts docker` command group can "
            "only be used on Docker repositories.".format(repo.format))
Ejemplo n.º 7
0
def GetNpmSettingsSnippet(args):
    """Forms an npm settings snippet to add to the .npmrc file.

  Args:
    args: an argparse namespace. All the arguments that were provided to this
      command invocation.

  Returns:
    An npm settings snippet.
  """
    messages = ar_requests.GetMessages()
    location, repo_path = _GetLocationAndRepoPath(
        args, messages.Repository.FormatValueValuesEnum.NPM)
    registry_path = "{location}-npm.pkg.dev/{repo_path}/".format(
        **{
            "location": location,
            "repo_path": repo_path
        })
    configured_registry = "registry"
    if args.scope:
        if not args.scope.startswith("@") or len(args.scope) <= 1:
            raise ar_exceptions.InvalidInputValueError(
                "Scope name must start with \"@\" and be longer than 1 character."
            )
        configured_registry = args.scope + ":" + configured_registry

    data = {
        "configured_registry": configured_registry,
        "registry_path": registry_path,
        "repo_path": repo_path
    }

    sa_creds = _GetServiceAccountCreds(args)
    if sa_creds:
        npm_setting_template = """\
# Insert following snippet into your .npmrc

{configured_registry}=https://{registry_path}
//{registry_path}:_password="******"
//{registry_path}:username=_json_key_base64
//{registry_path}:[email protected]
//{registry_path}:always-auth=true
"""
        data["password"] = base64.b64encode(
            sa_creds.encode("utf-8")).decode("utf-8")
    else:
        npm_setting_template = """\
# Insert following snippet into your .npmrc

{configured_registry}=https://{registry_path}
//{registry_path}:_authToken=""
//{registry_path}:always-auth=true
"""

    return npm_setting_template.format(**data)
Ejemplo n.º 8
0
def AppendRepoDataToRequest(repo_ref, repo_args, request):
    """Adds repository data to CreateRepositoryRequest."""
    repo_name = repo_ref.repositoriesId
    if repo_name in _ALLOWED_GCR_REPO_LOCATION:
        location = _ALLOWED_GCR_REPO_LOCATION.get(repo_name, "")
        if location != GetLocation(repo_args):
            raise ar_exceptions.InvalidInputValueError(
                _INVALID_REPO_LOCATION_ERROR.format(repo_name, location))
    elif not _IsValidRepoName(repo_ref.repositoriesId):
        raise ar_exceptions.InvalidInputValueError(_INVALID_REPO_NAME_ERROR)

    messages = _GetMessagesForResource(repo_ref)
    repo_format = messages.Repository.FormatValueValuesEnum(
        repo_args.repository_format.upper())
    if repo_format != messages.Repository.FormatValueValuesEnum.DOCKER:
        log.status.Print("Note: Language package support is in Alpha.\n")

    request.repository.name = repo_ref.RelativeName()
    request.repositoryId = repo_ref.repositoriesId
    return request
Ejemplo n.º 9
0
def _GetDefaultResources():
    """Gets default config values for project, location, and repository."""
    project = properties.VALUES.core.project.Get()
    location = properties.VALUES.artifacts.location.Get()
    repo = properties.VALUES.artifacts.repository.Get()
    if not project or not location or not repo:
        raise ar_exceptions.InvalidInputValueError(
            _INVALID_DEFAULT_DOCKER_STRING_ERROR.format(**{
                "project": project,
                "location": location,
                "repo": repo,
            }))
    return DockerRepo(project, location, repo)
Ejemplo n.º 10
0
def _GetLocationRepoPathAndMavenConfig(args, repo_format):
  """Get resource values and validate user input."""
  repo = _GetRequiredRepoValue(args)
  project = _GetRequiredProjectValue(args)
  location = _GetRequiredLocationValue(args)
  repo_path = project + "/" + repo
  repo = ar_requests.GetRepository(
      "projects/{}/locations/{}/repositories/{}".format(project, location,
                                                        repo))
  if repo.format != repo_format:
    raise ar_exceptions.InvalidInputValueError(
        "Invalid repository type {}. Valid type is {}.".format(
            repo.format, repo_format))
  return location, repo_path, repo.mavenConfig
Ejemplo n.º 11
0
def _GetDockerDigest(version_or_tag):
    """Retrieves the docker digest information.

  Args:
    version_or_tag: an object of DockerVersion or DockerTag

  Returns:
    A dictionary of information about the given docker image.
  """
    docker_version = version_or_tag
    try:
        if isinstance(version_or_tag, DockerVersion):
            # We have all the information about the docker digest.
            # Call the API to make sure it exists.
            ar_requests.GetVersion(ar_requests.GetClient(),
                                   ar_requests.GetMessages(),
                                   version_or_tag.GetVersionName())
        elif isinstance(version_or_tag, DockerTag):
            digest = ar_requests.GetVersionFromTag(ar_requests.GetClient(),
                                                   ar_requests.GetMessages(),
                                                   version_or_tag.GetTagName())
            docker_version = DockerVersion(version_or_tag.image, digest)
        else:
            raise ar_exceptions.InvalidInputValueError(
                _INVALID_DOCKER_IMAGE_ERROR)
    except api_exceptions.HttpNotFoundError:
        raise ar_exceptions.InvalidInputValueError(_DOCKER_IMAGE_NOT_FOUND)
    return {
        "digest":
        docker_version.digest,
        "fully_qualified_digest":
        docker_version.GetDockerString(),
        "registry":
        "{}-docker.pkg.dev".format(docker_version.image.docker_repo.location),
        "repository":
        docker_version.image.docker_repo.repo,
    }
Ejemplo n.º 12
0
def _ParseDockerTag(tag):
    """Validates and parses a tag string.

  Args:
    tag: str, User input Docker tag string.

  Raises:
    ar_exceptions.InvalidInputValueError if user input is invalid.
    ar_exceptions.UnsupportedLocationError if provided location is invalid.

  Returns:
    A DockerImage and a DockerTag.
  """
    try:
        docker_repo = _ParseInput(tag)
    except ar_exceptions.InvalidInputValueError:
        raise ar_exceptions.InvalidInputValueError(_INVALID_DOCKER_TAG_ERROR)

    img_by_tag_match = re.match(DOCKER_IMG_BY_TAG_REGEX, tag)
    if img_by_tag_match:
        docker_img = DockerImage(docker_repo, img_by_tag_match.group("img"))
        return docker_img, DockerTag(docker_img, img_by_tag_match.group("tag"))
    else:
        raise ar_exceptions.InvalidInputValueError(_INVALID_DOCKER_TAG_ERROR)
Ejemplo n.º 13
0
def AppendRepoDataToRequest(repo_ref, repo_args, request):
    """Adds repository data to CreateRepositoryRequest."""
    repo_name = repo_ref.repositoriesId
    location = GetLocation(repo_args)
    messages = _GetMessagesForResource(repo_ref)
    docker_format = messages.Repository.FormatValueValuesEnum.DOCKER
    repo_format = messages.Repository.FormatValueValuesEnum(
        repo_args.repository_format.upper())
    if repo_name in _ALLOWED_GCR_REPO_LOCATION:
        ValidateGcrRepo(repo_name, repo_format, location, docker_format)
    elif not _IsValidRepoName(repo_ref.repositoriesId):
        raise ar_exceptions.InvalidInputValueError(_INVALID_REPO_NAME_ERROR)

    request.repository.name = repo_ref.RelativeName()
    request.repositoryId = repo_ref.repositoriesId
    return request
Ejemplo n.º 14
0
def AppendRepoDataToRequest(repo_ref, repo_args, request):
    """Adds repository data to CreateRepositoryRequest."""
    if not _IsValidRepoName(repo_ref.repositoriesId):
        raise ar_exceptions.InvalidInputValueError(_INVALID_REPO_NAME_ERROR)
    if not _IsValidLocation(repo_args.location):
        raise ar_exceptions.UnsupportedLocationError(
            "{} is not a valid location. Valid locations are [{}].".format(
                repo_args.location, ", ".join(_VALID_LOCATIONS)))
    messages = _GetMessagesForResource(repo_ref)
    repo = messages.Repository(
        name=repo_ref.RelativeName(),
        description=repo_args.description,
        format=messages.Repository.FormatValueValuesEnum(
            repo_args.repository_format.upper()))
    request.repository = repo
    request.repositoryId = repo_ref.repositoriesId
    return request
Ejemplo n.º 15
0
def AppendRepoDataToRequest(repo_ref, repo_args, request):
  """Adds repository data to CreateRepositoryRequest."""
  if not _IsValidRepoName(repo_ref.repositoriesId):
    raise ar_exceptions.InvalidInputValueError(_INVALID_REPO_NAME_ERROR)
  messages = _GetMessagesForResource(repo_ref)
  repo_format = messages.Repository.FormatValueValuesEnum(
      repo_args.repository_format.upper())
  if repo_format in [
      messages.Repository.FormatValueValuesEnum.MAVEN,
      messages.Repository.FormatValueValuesEnum.NPM,
  ]:
    log.status.Print("Note: Language package support is in Alpha.\n")
  if repo_format == messages.Repository.FormatValueValuesEnum.APT:
    log.status.Print("Note: APT package support is in Alpha.\n")

  request.repository.name = repo_ref.RelativeName()
  request.repositoryId = repo_ref.repositoriesId
  return request
Ejemplo n.º 16
0
def GetNpmSettingsSnippet(args):
    """Forms an npm settings snippet to add to the .npmrc file.

  Args:
    args: an argparse namespace. All the arguments that were provided to this
      command invocation.

  Returns:
    An npm settings snippet.
  """
    messages = ar_requests.GetMessages()
    location, repo_path = _GetLocationAndRepoPath(
        args, messages.Repository.FormatValueValuesEnum.NPM)
    registry_path = "{location}-npm.pkg.dev/{repo_path}/".format(
        **{
            "location": location,
            "repo_path": repo_path
        })
    configured_registry = "registry"
    if args.scope:
        if not args.scope.startswith("@") or len(args.scope) <= 1:
            raise ar_exceptions.InvalidInputValueError(
                "Scope name must start with '@' and be longer than 1 character."
            )
        configured_registry = args.scope + ":" + configured_registry

    npm_setting_template = """\
Please insert following snippet into your .npmrc

======================================================
{configured_registry}=https://{registry_path}
//{registry_path}:_password=""
//{registry_path}:username=oauth2accesstoken
//{registry_path}:[email protected]
//{registry_path}:always-auth=true
======================================================
"""

    data = {
        "configured_registry": configured_registry,
        "registry_path": registry_path,
        "repo_path": repo_path,
    }
    return npm_setting_template.format(**data)
Ejemplo n.º 17
0
def _GetLocationAndRepoPath(args, repo_format):
    """Get resource values and validate user input."""
    repo = _GetRequiredRepoValue(args)
    project = _GetRequiredProjectValue(args)
    location = _GetRequiredLocationValue(args)
    repo_path = project + "/" + repo
    location_list = ar_requests.ListLocations(project)
    if location.lower() not in location_list:
        raise ar_exceptions.UnsupportedLocationError(
            "{} is not a valid location. Valid locations are [{}].".format(
                location, ", ".join(location_list)))
    repo = ar_requests.GetRepository(
        "projects/{}/locations/{}/repositories/{}".format(
            project, location, repo))
    if repo.format != repo_format:
        raise ar_exceptions.InvalidInputValueError(
            "Invalid repository type {}. Valid type is {}.".format(
                repo.format, repo_format))
    return location, repo_path
Ejemplo n.º 18
0
def _ParseInput(input_str):
    """Parses user input into project, location, and repository values.

  Args:
    input_str: str, user input. Ex: us-docker.pkg.dev/my-proj/my-repo/my-img

  Raises:
    ar_exceptions.InvalidInputValueError if user input is invalid.
    ar_exceptions.UnsupportedLocationError if provided location is invalid.

  Returns:
    A DockerRepo.
  """
    matches = re.match(DOCKER_REPO_REGEX, input_str)
    if not matches:
        raise ar_exceptions.InvalidInputValueError()
    location = matches.group("location")
    project_id = matches.group("project")
    return DockerRepo(project_id, location, matches.group("repo"))
Ejemplo n.º 19
0
def GetNpmSettingsSnippet(args):
  """Forms an npm settings snippet to add to the .npmrc file.

  Args:
    args: an argparse namespace. All the arguments that were provided to this
      command invocation.

  Returns:
    An npm settings snippet.
  """
  messages = ar_requests.GetMessages()
  location, repo_path = _GetLocationAndRepoPath(
      args, messages.Repository.FormatValueValuesEnum.NPM)
  registry_path = "{location}-npm.pkg.dev/{repo_path}/".format(**{
      "location": location,
      "repo_path": repo_path
  })
  configured_registry = "registry"
  if args.scope:
    if not args.scope.startswith("@") or len(args.scope) <= 1:
      raise ar_exceptions.InvalidInputValueError(
          "Scope name must start with \"@\" and be longer than 1 character.")
    configured_registry = args.scope + ":" + configured_registry

  data = {
      "configured_registry": configured_registry,
      "registry_path": registry_path,
      "repo_path": repo_path
  }

  sa_creds = _GetServiceAccountCreds(args)
  if sa_creds:
    npm_setting_template = npm.SERVICE_ACCOUNT_TEMPLATE
    data["password"] = base64.b64encode(
        sa_creds.encode("utf-8")).decode("utf-8")
  else:
    npm_setting_template = npm.NO_SERVICE_ACCOUNT_TEMPLATE
  return npm_setting_template.format(**data)
Ejemplo n.º 20
0
def _ParseInput(input_str):
    """Parses user input into project, location, and repository values.

  Args:
    input_str: str, user input. Ex: us-docker.pkg.dev/my-proj/my-repo/my-img

  Raises:
    ar_exceptions.InvalidInputValueError if user input is invalid.
    ar_exceptions.UnsupportedLocationError if provided location is invalid.

  Returns:
    A DockerRepo.
  """
    matches = re.match(DOCKER_REPO_REGEX, input_str)
    if not matches:
        raise ar_exceptions.InvalidInputValueError()
    location = matches.group("location")
    if not util.IsValidLocation(location):
        raise ar_exceptions.UnsupportedLocationError(
            "{} is not a valid location. Valid locations are [{}].".format(
                location, ", ".join(util.GetLocationList())))
    return DockerRepo(matches.group("project"), location,
                      matches.group("repo"))
Ejemplo n.º 21
0
def _GetRequiredLocationValue(args):
    if not args.location and not properties.VALUES.artifacts.location.Get():
        raise ar_exceptions.InvalidInputValueError(_LOCATION_NOT_FOUND_ERROR)
    return ar_util.GetLocation(args)
Ejemplo n.º 22
0
def _GetRequiredRepoValue(args):
    if not args.repository and not properties.VALUES.artifacts.repository.Get(
    ):
        raise ar_exceptions.InvalidInputValueError(_REPO_NOT_FOUND_ERROR)
    return ar_util.GetRepo(args)
Ejemplo n.º 23
0
def _GetRequiredProjectValue(args):
    if not args.project and not properties.VALUES.core.project.Get():
        raise ar_exceptions.InvalidInputValueError(_PROJECT_NOT_FOUND_ERROR)
    return ar_util.GetProject(args)
def ListFiles(args):
    """Lists files in a given project.

  Args:
    args: User input arguments.

  Returns:
    List of files.
  """
    client = ar_requests.GetClient()
    messages = ar_requests.GetMessages()
    project = GetProject(args)
    location = args.location or properties.VALUES.artifacts.location.Get()
    repo = GetRepo(args)
    package = args.package
    version = args.version
    tag = args.tag
    page_size = args.page_size
    arg_filters = ""

    # Parse fully qualified path in package argument
    if package:
        if re.match(
                r"projects\/.*\/locations\/.*\/repositories\/.*\/packages\/.*",
                package):
            params = package.replace("projects/", "", 1).replace(
                "/locations/", " ",
                1).replace("/repositories/", " ",
                           1).replace("/packages/", " ", 1).split(" ")
            project, location, repo, package = [
                params[i] for i in range(len(params))
            ]

    # Escape slashes in package name
    if package:
        package = package.replace("/", "%2F")

    # Retrieve version from tag name
    if version and tag:
        raise ar_exceptions.InvalidInputValueError(
            "Specify either --version or --tag with --package argument.")
    if package and tag:
        tag_path = resources.Resource.RelativeName(
            resources.REGISTRY.Create(
                "artifactregistry.projects.locations.repositories.packages.tags",
                projectsId=project,
                locationsId=location,
                repositoriesId=repo,
                packagesId=package,
                tagsId=tag))
        version = ar_requests.GetVersionFromTag(client, messages, tag_path)

    if package and version:
        version_path = resources.Resource.RelativeName(
            resources.REGISTRY.Create(
                "artifactregistry.projects.locations.repositories.packages.versions",
                projectsId=project,
                locationsId=location,
                repositoriesId=repo,
                packagesId=package,
                versionsId=version))
        arg_filters = 'owner="{}"'.format(version_path)
    elif package:
        package_path = resources.Resource.RelativeName(
            resources.REGISTRY.Create(
                "artifactregistry.projects.locations.repositories.packages",
                projectsId=project,
                locationsId=location,
                repositoriesId=repo,
                packagesId=package))
        arg_filters = 'owner="{}"'.format(package_path)
    elif version or tag:
        raise ar_exceptions.InvalidInputValueError(
            "Package name is required when specifying version or tag.")

    repo_path = resources.Resource.RelativeName(
        resources.REGISTRY.Create(
            "artifactregistry.projects.locations.repositories",
            projectsId=project,
            locationsId=location,
            repositoriesId=repo))
    files = ar_requests.ListFiles(client, messages, repo_path, arg_filters,
                                  page_size)

    for file in files:
        file.name = resources.REGISTRY.ParseRelativeName(
            file.name,
            collection="artifactregistry.projects.locations.repositories.files"
        ).filesId.replace("%2F", "/")

    return files