Skip to content
Merged
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
3 changes: 2 additions & 1 deletion src/gardenlinux/oci/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,9 @@
"""

from .container import Container
from .image_manifest import ImageManifest
from .index import Index
from .layer import Layer
from .manifest import Manifest

__all__ = ["Container", "Index", "Layer", "Manifest"]
__all__ = ["Container", "ImageManifest", "Index", "Layer", "Manifest"]
96 changes: 84 additions & 12 deletions src/gardenlinux/oci/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,26 +31,28 @@ def cli():
help="Container Name",
)
@click.option(
"--version",
required=True,
type=click.Path(),
help="Version of image",
"--cname", required=True, type=click.Path(), help="Canonical Name of Image"
)
@click.option(
"--commit",
"--arch",
required=False,
type=click.Path(),
default=None,
help="Commit of image",
help="Target Image CPU Architecture",
)
@click.option(
"--arch",
required=True,
"--version",
required=False,
type=click.Path(),
help="Target Image CPU Architecture",
default=None,
help="Version of image",
)
@click.option(
"--cname", required=True, type=click.Path(), help="Canonical Name of Image"
"--commit",
required=False,
type=click.Path(),
default=None,
help="Commit of image",
)
@click.option("--dir", "directory", required=True, help="path to the build artifacts")
@click.option(
Expand All @@ -76,10 +78,10 @@ def cli():
)
def push_manifest(
container,
cname,
arch,
version,
commit,
arch,
cname,
directory,
cosign_file,
manifest_file,
Expand Down Expand Up @@ -107,6 +109,76 @@ def push_manifest(
print(manifest.digest, file=open(cosign_file, "w"))


@cli.command()
@click.option(
"--container",
required=True,
type=click.Path(),
help="Container Name",
)
@click.option(
"--cname",
required=False,
type=click.Path(),
default=None,
help="Canonical Name of Image",
)
@click.option(
"--arch",
required=False,
type=click.Path(),
default=None,
help="Target Image CPU Architecture",
)
@click.option(
"--version",
required=False,
type=click.Path(),
default=None,
help="Version of image",
)
@click.option(
"--commit",
required=False,
type=click.Path(),
default=None,
help="Commit of image",
)
@click.option(
"--insecure",
default=False,
help="Use HTTP to communicate with the registry",
)
@click.option(
"--tag",
required=True,
multiple=True,
help="Tag to push the manifest with",
)
def push_manifest_tags(
container,
cname,
arch,
version,
commit,
insecure,
tag,
):
"""
Push artifacts and the manifest from a directory to a registry.

:since: 0.10.0
"""

container = Container(
f"{container}:{version}",
insecure=insecure,
)

manifest = container.read_or_generate_manifest(cname, arch, version, commit)
container.push_manifest_for_tags(manifest, tag)


@cli.command()
@click.option(
"--container",
Expand Down
118 changes: 81 additions & 37 deletions src/gardenlinux/oci/container.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@

from .index import Index
from .layer import Layer
from .image_manifest import ImageManifest
from .manifest import Manifest
from .schemas import index as IndexSchema

Expand Down Expand Up @@ -83,11 +84,21 @@ def __init__(
self._container_version = container_data[1]

container_url_data = urlsplit(self._container_url)
self._token = None

if token is None:
token = getenv("GL_CLI_REGISTRY_TOKEN")

if token is not None:
auth_backend = "token"
self._token = b64encode(token.encode("utf-8")).decode("utf-8")
else:
auth_backend = "basic"

Registry.__init__(
self,
hostname=container_url_data.netloc,
auth_backend="token",
auth_backend=auth_backend,
insecure=insecure,
)

Expand All @@ -97,11 +108,7 @@ def __init__(
self._container_name = container_url_data.path[1:]
self._logger = logger

if token is None:
token = getenv("GL_CLI_REGISTRY_TOKEN")

if token is not None:
self._token = b64encode(token.encode("utf-8")).decode("utf-8")
if self._token is not None:
self.auth.set_token_auth(self._token)
else:
# Authentication credentials from environment
Expand All @@ -117,17 +124,7 @@ def __init__(
except Exception as login_error:
self._logger.error(f"Login error: {str(login_error)}")

def generate_index(self):
"""
Generates an OCI image index

:return: (object) OCI image index
:since: 0.7.0
"""

return Index()

def generate_manifest(
def generate_image_manifest(
self,
cname: str,
architecture: Optional[str] = None,
Expand All @@ -145,7 +142,7 @@ def generate_manifest(
:param feature_set: The expanded list of the included features of this manifest

:return: (object) OCI image manifest
:since: 0.7.0
:since: 0.10.0
"""

cname_object = CName(cname, architecture, version)
Expand All @@ -162,15 +159,13 @@ def generate_manifest(
if commit is None:
commit = ""

manifest = Manifest()
manifest = ImageManifest()

manifest["annotations"] = {}
manifest["annotations"]["version"] = version
manifest["annotations"]["cname"] = cname
manifest["annotations"]["architecture"] = architecture
manifest["annotations"]["feature_set"] = feature_set
manifest["annotations"]["flavor"] = f"{cname_object.flavor}-{architecture}"
manifest["annotations"]["commit"] = commit
manifest.version = version
manifest.cname = cname
manifest.arch = architecture
manifest.feature_set = feature_set
manifest.commit = commit

description = (
f"Image: {cname} "
Expand All @@ -189,6 +184,43 @@ def generate_manifest(

return manifest

def generate_index(self):
"""
Generates an OCI image index

:return: (object) OCI image index
:since: 0.7.0
"""

return Index()

def generate_manifest(
self,
version: Optional[str] = None,
commit: Optional[str] = None,
):
"""
Generates an OCI manifest

:param cname: Canonical name of the manifest
:param architecture: Target architecture of the manifest
:param version: Artifacts version of the manifest
:param commit: The commit hash of the manifest
:param feature_set: The expanded list of the included features of this manifest

:return: (object) OCI manifest
:since: 0.9.2
"""

manifest = Manifest()

manifest.version = version
manifest.commit = commit

manifest.config_from_dict({}, {})

return manifest

def _get_index_without_response_parsing(self):
"""
Return the response of an OCI image index request.
Expand Down Expand Up @@ -520,14 +552,14 @@ def read_or_generate_index(self):

def read_or_generate_manifest(
self,
cname: str,
cname: Optional[str] = None,
architecture: Optional[str] = None,
version: Optional[str] = None,
commit: Optional[str] = None,
feature_set: Optional[str] = None,
) -> Manifest:
"""
Reads from registry or generates the OCI image manifest.
Reads from registry or generates the OCI manifest.

:param cname: Canonical name of the manifest
:param architecture: Target architecture of the manifest
Expand All @@ -539,19 +571,31 @@ def read_or_generate_manifest(
:since: 0.7.0
"""

if architecture is None:
architecture = CName(cname, architecture, version).arch
if cname is None:
manifest_type = Manifest

response = self._get_manifest_without_response_parsing(
f"{self._container_version}-{cname}-{architecture}"
)
response = self._get_manifest_without_response_parsing(
self._container_version
)
else:
manifest_type = ImageManifest

if architecture is None:
architecture = CName(cname, architecture, version).arch

response = self._get_manifest_without_response_parsing(
f"{self._container_version}-{cname}-{architecture}"
)

if response.ok:
manifest = Manifest(**response.json())
manifest = manifest_type(**response.json())
elif response.status_code == 404:
manifest = self.generate_manifest(
cname, architecture, version, commit, feature_set
)
if cname is None:
manifest = self.generate_manifest(version, commit)
else:
manifest = self.generate_image_manifest(
cname, architecture, version, commit, feature_set
)
else:
response.raise_for_status()

Expand Down
Loading