-
-
Notifications
You must be signed in to change notification settings - Fork 159
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: implement oci_image_index (#34)
- Loading branch information
Showing
11 changed files
with
272 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
<!-- Generated with Stardoc: http://skydoc.bazel.build --> | ||
|
||
Implementation details for oci_image_index rule | ||
|
||
<a id="#oci_image_index"></a> | ||
|
||
## oci_image_index | ||
|
||
<pre> | ||
oci_image_index(<a href="#oci_image_index-name">name</a>, <a href="#oci_image_index-images">images</a>) | ||
</pre> | ||
|
||
Build a multi-architecture OCI compatible container image. | ||
|
||
It takes number of `oci_image`s to create a fat multi-architecture image. | ||
|
||
Requires `wc` and `shasum` to be installed on the execution machine. | ||
|
||
```starlark | ||
oci_image( | ||
name = "app_linux_amd64" | ||
) | ||
|
||
oci_image( | ||
name = "app_linux_arm64" | ||
) | ||
|
||
oci_image_index( | ||
name = "app", | ||
images = [ | ||
":app_linux_amd64", | ||
":app_linux_arm64" | ||
] | ||
) | ||
``` | ||
|
||
|
||
**ATTRIBUTES** | ||
|
||
|
||
| Name | Description | Type | Mandatory | Default | | ||
| :------------- | :------------- | :------------- | :------------- | :------------- | | ||
| <a id="oci_image_index-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_index-images"></a>images | List of labels to oci_image targets. | <a href="https://bazel.build/docs/build-ref.html#labels">List of labels</a> | required | | | ||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
load("//oci:defs.bzl", "oci_image", "oci_image_index") | ||
load("@rules_pkg//:pkg.bzl", "pkg_tar") | ||
load(":transition.bzl", "multi_arch") | ||
|
||
pkg_tar( | ||
name = "app", | ||
srcs = ["test.bash"], | ||
) | ||
|
||
oci_image( | ||
name = "image", | ||
architecture = select({ | ||
"@platforms//cpu:arm64": "arm64", | ||
"@platforms//cpu:x86_64": "amd64", | ||
}), | ||
base = "//example:base", | ||
cmd = ["test.bash"], | ||
entrypoint = ["bash"], | ||
os = "linux", | ||
tars = ["app.tar"], | ||
) | ||
|
||
multi_arch( | ||
name = "images", | ||
image = ":image", | ||
platforms = [ | ||
"//example:linux_arm64", | ||
"//example:linux_amd64", | ||
], | ||
) | ||
|
||
oci_image_index( | ||
name = "index", | ||
images = [ | ||
":images", | ||
], | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
echo "This is rules_oci!" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
"a rule transitioning an oci_image to multiple platforms" | ||
|
||
def _multiarch_transition(settings, attr): | ||
return [ | ||
{"//command_line_option:platforms": str(platform)} | ||
for platform in attr.platforms | ||
] | ||
|
||
multiarch_transition = transition( | ||
implementation = _multiarch_transition, | ||
inputs = [], | ||
outputs = ["//command_line_option:platforms"], | ||
) | ||
|
||
def _impl(ctx): | ||
return DefaultInfo(files = depset(ctx.files.image)) | ||
|
||
multi_arch = rule( | ||
implementation = _impl, | ||
attrs = { | ||
"image": attr.label(cfg = multiarch_transition), | ||
"platforms": attr.label_list(), | ||
"_allowlist_function_transition": attr.label( | ||
default = "@bazel_tools//tools/allowlists/function_transition_allowlist", | ||
), | ||
}, | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,79 @@ | ||
"Implementation details for oci_image_index rule" | ||
|
||
_DOC = """Build a multi-architecture OCI compatible container image. | ||
It takes number of `oci_image`s to create a fat multi-architecture image. | ||
Requires `wc` and `shasum` to be installed on the execution machine. | ||
```starlark | ||
oci_image( | ||
name = "app_linux_amd64" | ||
) | ||
oci_image( | ||
name = "app_linux_arm64" | ||
) | ||
oci_image_index( | ||
name = "app", | ||
images = [ | ||
":app_linux_amd64", | ||
":app_linux_arm64" | ||
] | ||
) | ||
``` | ||
""" | ||
|
||
_attrs = { | ||
"images": attr.label_list(mandatory = True, doc = "List of labels to oci_image targets."), | ||
"_image_index_sh_tpl": attr.label(default = "image_index.sh.tpl", allow_single_file = True), | ||
} | ||
|
||
def _expand_image_to_args(image, expander): | ||
args = [ | ||
"--image={}".format(image.path), | ||
] | ||
for file in expander.expand(image): | ||
if file.path.find("blobs") != -1: | ||
args.append("--blob={}".format(file.tree_relative_path)) | ||
return args | ||
|
||
def _oci_image_index_impl(ctx): | ||
yq = ctx.toolchains["@aspect_bazel_lib//lib:yq_toolchain_type"] | ||
|
||
launcher = ctx.actions.declare_file("image_index_{}.sh".format(ctx.label.name)) | ||
ctx.actions.expand_template( | ||
template = ctx.file._image_index_sh_tpl, | ||
output = launcher, | ||
is_executable = True, | ||
substitutions = { | ||
"{{yq_path}}": yq.yqinfo.bin.path, | ||
}, | ||
) | ||
|
||
output = ctx.actions.declare_directory(ctx.label.name) | ||
|
||
args = ctx.actions.args() | ||
args.add(output.path, format = "--output=%s") | ||
args.add_all(ctx.files.images, map_each = _expand_image_to_args, expand_directories = False) | ||
|
||
ctx.actions.run( | ||
inputs = ctx.files.images, | ||
arguments = [args], | ||
outputs = [output], | ||
executable = launcher, | ||
tools = [yq.yqinfo.bin], | ||
progress_message = "OCI Index %{label}", | ||
) | ||
|
||
return DefaultInfo(files = depset([output])) | ||
|
||
oci_image_index = rule( | ||
implementation = _oci_image_index_impl, | ||
attrs = _attrs, | ||
doc = _DOC, | ||
toolchains = [ | ||
"@aspect_bazel_lib//lib:yq_toolchain_type", | ||
], | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
#!/usr/bin/env bash | ||
set -o pipefail -o errexit -o nounset | ||
|
||
readonly YQ="{{yq_path}}" | ||
|
||
|
||
function add_image() { | ||
local image_path="$1" | ||
local output_path="$2" | ||
|
||
local manifests=$("${YQ}" eval '.manifests[]' "${image_path}/index.json") | ||
|
||
for manifest in "${manifests}"; do | ||
local manifest_blob_path=$("${YQ}" '.digest | sub(":"; "/")' <<< ${manifest}) | ||
local config_blob_path=$("${YQ}" '.config.digest | sub(":"; "/")' "${image_path}/blobs/${manifest_blob_path}") | ||
|
||
local platform=$("${YQ}" --output-format=json '{"os": .os, "architecture": .architecture, "variant": .variant, "os.version": .["os.version"], "os.features": .["os.features"]} | with_entries(select( .value != null ))' "${image_path}/blobs/${config_blob_path}") | ||
|
||
platform="${platform}" \ | ||
manifest="${manifest}" \ | ||
"${YQ}" --inplace --output-format=json '.manifests += [env(manifest) + {"platform": env(platform)}]' "${output_path}/manifest_list.json" | ||
done | ||
} | ||
|
||
function copy_blob() { | ||
local image_path="$1" | ||
local output_path="$2" | ||
local blob_image_relative_path="$3" | ||
local dest_path="${output_path}/${blob_image_relative_path}" | ||
mkdir -p "$(dirname "${dest_path}")" | ||
cat "${image_path}/${blob_image_relative_path}" > "${dest_path}" | ||
} | ||
|
||
function create_oci_layout() { | ||
local path="$1" | ||
mkdir -p "${path}" | ||
|
||
echo '{"imageLayoutVersion": "1.0.0"}' > "${path}/oci-layout" | ||
echo '{"schemaVersion": 2, "manifests": []}' > "${path}/index.json" | ||
echo '{"schemaVersion": 2, "mediaType": "application/vnd.oci.image.index.v1+json", "manifests": []}' > "${path}/manifest_list.json" | ||
} | ||
|
||
CURRENT_IMAGE="" | ||
OUTPUT="" | ||
|
||
for ARG in "$@"; do | ||
case "$ARG" in | ||
(--output=*) OUTPUT="${ARG#--output=}"; create_oci_layout "$OUTPUT" ;; | ||
(--image=*) CURRENT_IMAGE="${ARG#--image=}"; add_image "$CURRENT_IMAGE" "$OUTPUT" ;; | ||
(--blob=*) copy_blob "${CURRENT_IMAGE}" "$OUTPUT" "${ARG#--blob=}" ;; | ||
(*) echo "Unknown argument ${ARG}"; exit 1;; | ||
esac | ||
done | ||
|
||
|
||
export checksum=$(shasum -a 256 "${OUTPUT}/manifest_list.json" | cut -f 1 -d " ") | ||
export size=$(wc -c < "${OUTPUT}/manifest_list.json") | ||
|
||
"${YQ}" --inplace --output-format=json '.manifests += [{"mediaType": "application/vnd.oci.image.index.v1+json", "size": env(size), "digest": "sha256:" + env(checksum)}]' "$OUTPUT/index.json" | ||
|
||
mv "${OUTPUT}/manifest_list.json" "$OUTPUT/blobs/sha256/${checksum}" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters