Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add container build image commands #504

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGES/424.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Added container build image command.
5 changes: 5 additions & 0 deletions pulp-glue/pulp_glue/common/context.py
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,11 @@ def _patch_api_spec(self) -> None:
python_remote_serializer["properties"][prop]["items"] = {"type": "string"}
patched_python_remote_serializer["properties"][prop]["type"] = "array"
patched_python_remote_serializer["properties"][prop]["items"] = {"type": "string"}
if self.has_plugin(PluginRequirement("container", min="1.1.0")):
# TODO Add upper bound when fixed
oci_build_schema = api_spec["components"]["schemas"]["OCIBuildImage"]
oci_artifacts = oci_build_schema["properties"]["artifacts"]
oci_artifacts["type"] = "string"

@property
def domain_enabled(self) -> bool:
Expand Down
17 changes: 16 additions & 1 deletion pulp-glue/pulp_glue/container/context.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
from typing import Any, List, Optional
import json
from typing import Any, Dict, List, Optional

from pulp_glue.common.context import (
EntityDefinition,
Expand Down Expand Up @@ -128,6 +129,7 @@ class PulpContainerRepositoryContext(PulpContainerBaseRepositoryContext):
"pulpexport": [PluginRequirement("container", min="2.8.0")],
"tag": [PluginRequirement("container", min="2.3.0")],
"roles": [PluginRequirement("container", min="2.11.0")],
"build": [PluginRequirement("container", min="1.1.0")],
}

def modify(
Expand Down Expand Up @@ -167,6 +169,19 @@ def copy_manifest(
}
return self.call("copy_manifests", parameters={self.HREF: self.pulp_href}, body=body)

def build_image(
self,
container_artifact: str,
tag: Optional[str],
artifacts: Optional[Dict[str, str]],
) -> Any:
body = {"containerfile_artifact": container_artifact, "tag": tag, "artifacts": artifacts}
# TODO: Add plugin version check when schema is fixed
if artifacts:
body["artifacts"] = json.dumps(artifacts)
body = self.preprocess_body(body)
return self.call("build_image", parameters={self.HREF: self.pulp_href}, body=body)


class PulpContainerPushRepositoryContext(PulpContainerBaseRepositoryContext):
HREF = "container_container_push_repository_href"
Expand Down
95 changes: 93 additions & 2 deletions pulpcore/cli/container/repository.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,14 @@
import re
from typing import Any, Dict, List, Optional
from pathlib import Path
from typing import Any, Dict, List, Optional, Union

import click
from pulp_glue.common.context import EntityFieldDefinition, PulpRemoteContext, PulpRepositoryContext
from pulp_glue.common.context import (
EntityFieldDefinition,
PulpContext,
PulpRemoteContext,
PulpRepositoryContext,
)
from pulp_glue.common.i18n import get_translation
from pulp_glue.container.context import (
PulpContainerBaseRepositoryContext,
Expand All @@ -13,6 +19,7 @@
PulpContainerRepositoryContext,
PulpContainerTagContext,
)
from pulp_glue.core.context import PulpArtifactContext

from pulpcore.cli.common.generic import (
create_command,
Expand All @@ -21,7 +28,9 @@
label_command,
label_select_option,
list_command,
load_json_callback,
name_option,
pass_pulp_context,
pass_repository_context,
pulp_group,
pulp_labels_option,
Expand Down Expand Up @@ -53,6 +62,22 @@ def _tag_callback(ctx: click.Context, param: click.Parameter, value: str) -> str
return value


def _directory_or_json_callback(
ctx: click.Context, param: click.Parameter, value: Optional[str]
) -> Union[Dict[str, str], Path, None]:
if not value:
return None
uvalue: Union[Dict[str, str], Path]
try:
uvalue = load_json_callback(ctx, param, value)
except click.ClickException:
uvalue = Path(value)
if not uvalue.exists() or not uvalue.is_dir():
raise click.ClickException(_("{} is not a valid directory").format(value))

return uvalue


source_option = resource_option(
"--source",
default_plugin="container",
Expand Down Expand Up @@ -291,6 +316,72 @@ def copy_manifest(
)


def upload_file(pulp_ctx: PulpContext, file_location: str) -> str:
try:
with click.open_file(file_location, "rb") as fp:
artifact_ctx = PulpArtifactContext(pulp_ctx)
artifact_href = artifact_ctx.upload(fp)
except OSError:
raise click.ClickException(
_("Failed to load content from {file}").format(file=file_location)
)
click.echo(_("Uploaded file: {}").format(artifact_href))
return artifact_href # type: ignore


@repository.command(allowed_with_contexts=container_context)
@name_option
@href_option
@click.option(
"--containerfile",
help=_(
"An artifact href of an uploaded Containerfile. Can also be a local Containerfile to be"
" uploaded using @."
),
required=True,
)
@click.option("--tag", help=_("A tag name for the new image being built."))
@click.option(
"--artifacts",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

With a new release of pulp-container (coming in 1 month), we will no longer support this argument, see pulp/pulp_container#1687. Instead, we will start using file_repository_version as a build context.

Should we close this PR or are we going to address this change soon-ish? The feature is still shipped as a tech-preview. However, I do not think we should support workflows using the artifacts endpoint anymore due to pulp/pulpcore#5525.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I haven't touched this PR is a while, so maybe it's best to close it.

help=_(
"Directory of files to be uploaded and used during the build. Or a JSON string where each"
" key is an artifact href and the value is it's relative path (name) inside the "
"/pulp_working_directory of the build container executing the Containerfile."
),
callback=_directory_or_json_callback,
)
@pass_repository_context
@pass_pulp_context
def build_image(
pulp_ctx: PulpContext,
repository_ctx: PulpContainerRepositoryContext,
containerfile: str,
tag: Optional[str],
artifacts: Union[Dict[str, str], Path, None],
) -> None:
if not repository_ctx.capable("build"):
raise click.ClickException(_("Repository does not support image building."))

container_artifact_href: str
# Upload necessary files as artifacts if specified
if containerfile[0] == "@":
container_artifact_href = upload_file(pulp_ctx, containerfile[1:])
else:
artifact_ctx = PulpArtifactContext(pulp_ctx, pulp_href=containerfile)
container_artifact_href = artifact_ctx.pulp_href

if isinstance(artifacts, Path):
artifacts_path = artifacts
# Upload files in directory
artifacts = {}
for child in artifacts_path.rglob("*"):
if child.is_file():
artifact_href = upload_file(pulp_ctx, str(child))
artifacts[artifact_href] = str(child.relative_to(artifacts_path))

repository_ctx.build_image(container_artifact_href, tag, artifacts)


@repository.command(allowed_with_contexts=push_container_context)
@name_option
@href_option
Expand Down
5 changes: 5 additions & 0 deletions tests/assets/test_containerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
FROM busybox:latest
# Copy a file using COPY statement. Use the relative path specified in the 'artifacts' parameter.
COPY foo/bar/example.txt /tmp/inside-image.txt
# Print the content of the file when the container starts
CMD ["cat", "/tmp/inside-image.txt"]