Skip to content

Commit

Permalink
Create oci_image_layout bazel rule.
Browse files Browse the repository at this point in the history
This commit creates a bazel rule that produces an OCI Image Format
directory based on a provided OCI Image index. The OCI Image Layout
is a standardized OCI format described in
https://github.com/opencontainers/image-spec/blob/main/image-layout.md.
  • Loading branch information
captainreality committed Jun 3, 2024
1 parent 4f54530 commit 0f02cd2
Show file tree
Hide file tree
Showing 5 changed files with 159 additions and 1 deletion.
46 changes: 46 additions & 0 deletions docs/docs.md
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,52 @@ Create a tarball and an OCI descriptor for it
| <a id="oci_image_layer-symlinks"></a>symlinks | Dictionary of symlink -&gt; target entries to place in the tarball | <a href="https://bazel.build/docs/skylark/lib/dict.html">Dictionary: String -> String</a> | optional | {} |


<a id="#oci_image_layout"></a>

## oci_image_layout

<pre>
oci_image_layout(<a href="#oci_image_layout-name">name</a>, <a href="#oci_image_layout-manifest">manifest</a>, <a href="#oci_image_layout-registry">registry</a>, <a href="#oci_image_layout-repository">repository</a>)
</pre>


Writes an OCI Image Index and related blobs to an OCI Image Format
directory. See https://github.com/opencontainers/image-spec/blob/main/image-layout.md
for the specification of the OCI Image Format directory. Local blobs are
used where available, and if a referenced blob is not present, it is
fetched from the provided OCI repository and placed in the output.

In order for this rule to work correctly in its current state, the
following flags must be provided to bazel:
--incompatible_strict_action_env=false
--spawn_strategy=local

The incompatible_strict_action_env flag is required because in order to
access the registry, a credential helper executable (named
docker-credential-<SOMETHING>) must be available so that ocitool can
execute it. The incompatible_strict_action_env flag makes the system
PATH available to bazel rules.

The spawn_strategy flag must be set to local because currently,
oci_image_index is only declaring the new JSON files it creates as
outputs; it's not declaring any manifests or layers from the images as
outputs. By default, Bazel only permits rules to access specifically
declared outputs of the rules direct dependencies. In order for this
rule to access the transitive set of outputs of all dependencies, we
must disable bazel's sandboxing by setting spawn_strategy=local.


**ATTRIBUTES**


| Name | Description | Type | Mandatory | Default |
| :------------- | :------------- | :------------- | :------------- | :------------- |
| <a id="oci_image_layout-name"></a>name | A unique name for this target. | <a href="https://bazel.build/docs/build-ref.html#name">Name</a> | required | |
| <a id="oci_image_layout-manifest"></a>manifest | An OCILayout index to be written to the OCI Image Format directory. | <a href="https://bazel.build/docs/build-ref.html#labels">Label</a> | optional | None |
| <a id="oci_image_layout-registry"></a>registry | A registry host that contains images referenced by the OCILayout index, if not present consult the toolchain. | String | optional | "" |
| <a id="oci_image_layout-repository"></a>repository | A repository that contains images referenced by the OCILayout index, if not present consult the toolchain. | String | optional | "" |


<a id="#oci_pull"></a>

## oci_pull
Expand Down
11 changes: 11 additions & 0 deletions oci/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ bzl_library(
visibility = ["//visibility:public"],
deps = [
":image",
":oci_image_layout",
":pull",
":push",
],
Expand All @@ -64,6 +65,16 @@ bzl_library(
deps = ["@com_github_datadog_rules_oci//oci:providers"],
)

bzl_library(
name = "oci_image_layout",
srcs = ["oci_image_layout.bzl"],
visibility = ["//visibility:public"],
deps = [
"@com_github_datadog_rules_oci//oci:debug_flag",
"@com_github_datadog_rules_oci//oci:providers",
],
)

bzl_library(
name = "push",
srcs = ["push.bzl"],
Expand Down
2 changes: 2 additions & 0 deletions oci/defs.bzl
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
load(":pull.bzl", _oci_pull = "oci_pull")
load(":push.bzl", _oci_push = "oci_push")
load(":image.bzl", _oci_image = "oci_image", _oci_image_index = "oci_image_index", _oci_image_layer = "oci_image_layer")
load(":oci_image_layout.bzl", _oci_image_layout = "oci_image_layout")

oci_pull = _oci_pull
oci_push = _oci_push

oci_image = _oci_image
oci_image_index = _oci_image_index
oci_image_layer = _oci_image_layer
oci_image_layout = _oci_image_layout
99 changes: 99 additions & 0 deletions oci/oci_image_layout.bzl
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
load("@com_github_datadog_rules_oci//oci:providers.bzl", "OCIDescriptor", "OCILayout")
load("@com_github_datadog_rules_oci//oci:debug_flag.bzl", "DebugInfo")

def _oci_image_layout_impl(ctx):
toolchain = ctx.toolchains["@com_github_datadog_rules_oci//oci:toolchain"]

layout = ctx.attr.manifest[OCILayout]
descriptor = ctx.attr.manifest[OCIDescriptor]

out_dir = ctx.actions.declare_directory(ctx.label.name)

ctx.actions.run(
executable = toolchain.sdk.ocitool,
arguments = [
"--layout={layout}".format(layout = layout.blob_index.path),
"--debug={debug}".format(debug = str(ctx.attr._debug[DebugInfo].debug)),
"create-oci-image-layout",
# We need to use the directory one level above bazel-out for the
# layout-relative directory. This is because the paths in
# oci_image_index's index.layout.json are of the form:
# "bazel-out/os_arch-fastbuild/bin/...". Unfortunately, bazel
# provides no direct way to access this directory, so here we traverse
# up 3 levels from the bin directory.
"--layout-relative={root}".format(root = ctx.bin_dir.path+"/../../../"),
"--desc={desc}".format(desc = descriptor.descriptor_file.path),
"--registry={registry}".format(registry = ctx.attr.registry),
"--repository={repository}".format(repository = ctx.attr.repository),
"--out-dir={out_dir}".format(out_dir = out_dir.path),
],
inputs = ctx.files.manifest,
outputs = [
out_dir,
],
use_default_shell_env = True,
)

return DefaultInfo(files = depset([out_dir]))

oci_image_layout = rule(
doc = """
Writes an OCI Image Index and related blobs to an OCI Image Format
directory. See https://github.com/opencontainers/image-spec/blob/main/image-layout.md
for the specification of the OCI Image Format directory. Local blobs are
used where available, and if a referenced blob is not present, it is
fetched from the provided OCI repository and placed in the output.
In order for this rule to work correctly in its current state, the
following flags must be provided to bazel:
--incompatible_strict_action_env=false
--spawn_strategy=local
The incompatible_strict_action_env flag is required because in order to
access the registry, a credential helper executable (named
docker-credential-<SOMETHING>) must be available so that ocitool can
execute it. The incompatible_strict_action_env flag makes the system
PATH available to bazel rules.
The spawn_strategy flag must be set to local because currently,
oci_image_index is only declaring the new JSON files it creates as
outputs; it's not declaring any manifests or layers from the images as
outputs. By default, Bazel only permits rules to access specifically
declared outputs of the rules direct dependencies. In order for this
rule to access the transitive set of outputs of all dependencies, we
must disable bazel's sandboxing by setting spawn_strategy=local.
""",
# TODO(kim.mason): Fix oci_image/oci_image_index so they explicitly declare
# outputs that include everything needed to build the image.
# TODO(kim.mason): Make it so that Docker credential helpers are available
# to oci_image_layout without making the system PATH available.
implementation = _oci_image_layout_impl,
attrs = {
"manifest": attr.label(
doc = """
An OCILayout index to be written to the OCI Image Format directory.
""",
providers = [OCILayout],
),
"registry": attr.string(
doc = """
A registry host that contains images referenced by the OCILayout index,
if not present consult the toolchain.
""",
),
"repository": attr.string(
doc = """
A repository that contains images referenced by the OCILayout index,
if not present consult the toolchain.
""",
),
"_debug": attr.label(
default = "//oci:debug",
providers = [DebugInfo],
),
},
provides = [
DefaultInfo,
],
toolchains = ["@com_github_datadog_rules_oci//oci:toolchain"],
)
2 changes: 1 addition & 1 deletion oci/providers.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ OCIImageManifest = provider(
OCIImageIndexManifest = provider(
doc = "",
fields = {
"manifests": "List of desciptors",
"manifests": "List of descriptors",
"annotations": "String map of arbitrary metadata",
},
)
Expand Down

0 comments on commit 0f02cd2

Please sign in to comment.