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 Aug 23, 2024
1 parent 0e0d74e commit 706f35f
Show file tree
Hide file tree
Showing 5 changed files with 125 additions and 2 deletions.
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
19 changes: 18 additions & 1 deletion oci/image.bzl
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
load("@com_github_datadog_rules_oci//oci:providers.bzl", "OCIDescriptor", "OCILayout")
load("@com_github_datadog_rules_oci//oci:providers.bzl", "OCIDescriptor", "OCIImageLayoutInfo", "OCILayout")

def get_descriptor_file(ctx, desc):
if hasattr(desc, "descriptor_file"):
Expand Down Expand Up @@ -45,6 +45,7 @@ def _oci_image_layer_impl(ctx):
return [
OCIDescriptor(
descriptor_file = descriptor_file,
file = ctx.outputs.layer,
),
]

Expand Down Expand Up @@ -107,6 +108,8 @@ def _oci_image_index_impl(ctx):
outputs = outputs,
)

oci_layouts = [m[OCIImageLayoutInfo].oci_image_layout_dirs for m in ctx.attr.manifests]

return [
OCIDescriptor(
descriptor_file = index_desc_file,
Expand All @@ -115,6 +118,10 @@ def _oci_image_index_impl(ctx):
blob_index = layout_file,
files = depset(direct = [index_file, layout_file], transitive = [layout_files]),
),
# Pass through any OCIImageLayoutInfo data from the manifests.
OCIImageLayoutInfo(
oci_image_layout_dirs = depset(transitive = oci_layouts)
),
DefaultInfo(
files = depset(outputs),
),
Expand Down Expand Up @@ -213,6 +220,9 @@ def _oci_image_impl(ctx):
blob_index = layout_file,
files = depset(ctx.files.layers + [manifest_file, config_file, layout_file]),
),
OCIImageLayoutInfo(
oci_image_layout_dirs = depset(ctx.files.pulled_base) if ctx.attr.pulled_base != None else [],
),
DefaultInfo(
files = depset([
entrypoint_config_file,
Expand All @@ -238,6 +248,13 @@ oci_image = rule(
OCILayout,
],
),
"pulled_base": attr.label(
doc = """A directory that contains the base image in OCI Image Layout format.
See https://github.com/opencontainers/image-spec/blob/main/image-layout.md for a description
of the OCI Image Layout format. This is optional, and if present, is passed through as an output of oci_image,
by the OCIImageLayoutInfo provider.""",
allow_single_file = True,
),
"entrypoint": attr.string_list(
doc = """A list of entrypoints for the image; these will be inserted into the generated
OCI image config""",
Expand Down
85 changes: 85 additions & 0 deletions oci/oci_image_layout.bzl
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
load("@com_github_datadog_rules_oci//oci:providers.bzl", "OCIDescriptor", "OCIImageLayoutInfo", "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]
base_layouts = ctx.attr.manifest[OCIImageLayoutInfo]
base_layout_dirs = ""
if base_layouts != None:
base_layouts = base_layouts.oci_image_layout_dirs.to_list()
base_layout_dirs = ",".join([p.path for p in base_layouts])


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),
"--base-image-layouts={base_layouts}".format(base_layouts = base_layout_dirs),
"--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:
--spawn_strategy=local
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 rule's 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, OCIImageLayoutInfo],
),
"_debug": attr.label(
default = "//oci:debug",
providers = [DebugInfo],
),
},
provides = [
DefaultInfo,
],
toolchains = ["@com_github_datadog_rules_oci//oci:toolchain"],
)
10 changes: 9 additions & 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 All @@ -56,3 +56,11 @@ OCIPlatform = provider(
"variant": "Variant is an optional field specifying a variant of the CPU",
},
)

OCIImageLayoutInfo = provider(
doc = "This provider represents a list of directories that each contain an OCI Image Layout." +
"See https://github.com/opencontainers/image-spec/blob/main/image-layout.md for a description of the format.",
fields = {
"oci_image_layout_dirs": "A list of directories, each containing an OCI Image Layout."
},
)

0 comments on commit 706f35f

Please sign in to comment.