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
67 changes: 35 additions & 32 deletions docs/docs.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,38 +2,6 @@

public API

<a id="oci_image"></a>

## oci_image

<pre>
load("@rules_oci//oci:defs.bzl", "oci_image")

oci_image(<a href="#oci_image-name">name</a>, <a href="#oci_image-annotations">annotations</a>, <a href="#oci_image-arch">arch</a>, <a href="#oci_image-base">base</a>, <a href="#oci_image-entrypoint">entrypoint</a>, <a href="#oci_image-env">env</a>, <a href="#oci_image-labels">labels</a>, <a href="#oci_image-layers">layers</a>, <a href="#oci_image-os">os</a>, <a href="#oci_image-stamp">stamp</a>, <a href="#oci_image-tars">tars</a>)
</pre>

Creates a new image manifest and config by appending the `layers` to an existing image
manifest and config defined by `base`. If `base` is an image index, then `os` and `arch` will
be used to extract the image manifest.

**ATTRIBUTES**


| Name | Description | Type | Mandatory | Default |
| :------------- | :------------- | :------------- | :------------- | :------------- |
| <a id="oci_image-name"></a>name | A unique name for this target. | <a href="https://bazel.build/concepts/labels#target-names">Name</a> | required | |
| <a id="oci_image-annotations"></a>annotations | [OCI Annotations](https://github.com/opencontainers/image-spec/blob/main/annotations.md) to add to the manifest. | <a href="https://bazel.build/rules/lib/dict">Dictionary: String -> String</a> | optional | `{}` |
| <a id="oci_image-arch"></a>arch | Used to extract a manifest from base if base is an index | String | optional | `""` |
| <a id="oci_image-base"></a>base | A base image, as defined by oci_pull or oci_image | <a href="https://bazel.build/concepts/labels">Label</a> | required | |
| <a id="oci_image-entrypoint"></a>entrypoint | A list of entrypoints for the image; these will be inserted into the generated OCI image config | List of strings | optional | `[]` |
| <a id="oci_image-env"></a>env | Entries are in the format of `VARNAME=VARVALUE`. These values act as defaults and are merged with any specified when creating a container. | List of strings | optional | `[]` |
| <a id="oci_image-labels"></a>labels | labels that will be applied to the image configuration, as defined in [the OCI config](https://github.com/opencontainers/image-spec/blob/main/config.md#properties). These behave the same way as [docker LABEL](https://docs.docker.com/engine/reference/builder/#label); in particular, labels from the base image are inherited. An empty value for a label will cause that label to be deleted. For backwards compatibility, if this is not set, then the value of annotations will be used instead. | <a href="https://bazel.build/rules/lib/dict">Dictionary: String -> String</a> | optional | `{}` |
| <a id="oci_image-layers"></a>layers | A list of layers defined by oci_image_layer | <a href="https://bazel.build/concepts/labels">List of labels</a> | optional | `[]` |
| <a id="oci_image-os"></a>os | Used to extract a manifest from base if base is an index | String | optional | `""` |
| <a id="oci_image-stamp"></a>stamp | Whether to encode build information into the output. Possible values:<br><br>- `stamp = 1`: Always stamp the build information into the output, even in [--nostamp](https://docs.bazel.build/versions/main/user-manual.html#flag--stamp) builds. This setting should be avoided, since it is non-deterministic. It potentially causes remote cache misses for the target and any downstream actions that depend on the result. - `stamp = 0`: Never stamp, instead replace build information by constant values. This gives good build result caching. - `stamp = -1`: Embedding of build information is controlled by the [--[no]stamp](https://docs.bazel.build/versions/main/user-manual.html#flag--stamp) flag. Stamped targets are not rebuilt unless their dependencies change. | Integer | optional | `-1` |
| <a id="oci_image-tars"></a>tars | A list of tars to add as layers | <a href="https://bazel.build/concepts/labels">List of labels</a> | optional | `[]` |


<a id="oci_image_config"></a>

## oci_image_config
Expand Down Expand Up @@ -167,6 +135,41 @@ not be an issue when using the `oci_image` rule).
The config file named after the rule, os, and arch


<a id="oci_image"></a>

## oci_image

<pre>
load("@rules_oci//oci:defs.bzl", "oci_image")

oci_image(<a href="#oci_image-name">name</a>, <a href="#oci_image-base">base</a>, <a href="#oci_image-annotations">annotations</a>, <a href="#oci_image-arch">arch</a>, <a href="#oci_image-entrypoint">entrypoint</a>, <a href="#oci_image-env">env</a>, <a href="#oci_image-labels">labels</a>, <a href="#oci_image-layers">layers</a>, <a href="#oci_image-os">os</a>, <a href="#oci_image-tars">tars</a>, <a href="#oci_image-kwargs">kwargs</a>)
</pre>

oci_image

Creates a new image manifest and config by appending the `layers` to an
existing image manifest and config defined by `base`. If `base` is an image
index, then `os` and `arch` will be used to extract the image manifest.


**PARAMETERS**


| Name | Description | Default Value |
| :------------- | :------------- | :------------- |
| <a id="oci_image-name"></a>name | The name of the rule. | none |
| <a id="oci_image-base"></a>base | A base image, as defined by oci_pull or oci_image. | none |
| <a id="oci_image-annotations"></a>annotations | OCI Annotations to add to the manifest. | `None` |
| <a id="oci_image-arch"></a>arch | Used to extract a manifest from base if base is an index. | `None` |
| <a id="oci_image-entrypoint"></a>entrypoint | A list of entrypoints for the image; these will be inserted into the generated container configuration. | `None` |
| <a id="oci_image-env"></a>env | Entries are in the format of `VARNAME=VARVALUE`. These values act as defaults and are merged with any specified when creating a container. | `None` |
| <a id="oci_image-labels"></a>labels | Labels that will be applied to the image configuration, as defined in the OCI config. These behave the same way as docker LABEL. In particular, labels from the base image are inherited. An empty value for a label will cause that label to be deleted. For backwards compatibility, if this is not set, then the value of annotations will be used instead. | `None` |
| <a id="oci_image-layers"></a>layers | A list of layers defined by oci_image_layer. | `None` |
| <a id="oci_image-os"></a>os | Used to extract a manifest from base if base is an index. | `None` |
| <a id="oci_image-tars"></a>tars | A list of tars to add as layers. | `None` |
| <a id="oci_image-kwargs"></a>kwargs | Additional keyword arguments, e.g. tags or visibility | none |


<a id="oci_image_layer"></a>

## oci_image_layer
Expand Down
10 changes: 4 additions & 6 deletions go/cmd/ocitool/appendlayer_cmd.go
Original file line number Diff line number Diff line change
Expand Up @@ -207,18 +207,16 @@ func AppendLayersCmd(c *cli.Context) error {
layerDescs = append(layerDescs, tarDesc)
}

var entrypoint []string
if entrypoint_file := c.String("entrypoint"); entrypoint_file != "" {
var entrypoint *[]string
if entrypointPath := c.String("entrypoint"); entrypointPath != "" {
var entrypointStruct struct {
Entrypoint []string `json:"entrypoint"`
}

err := jsonutil.DecodeFromFile(entrypoint_file, &entrypointStruct)
err := jsonutil.DecodeFromFile(entrypointPath, &entrypointStruct)
if err != nil {
return fmt.Errorf("failed to read entrypoint config file: %w", err)
}

entrypoint = entrypointStruct.Entrypoint
entrypoint = &entrypointStruct.Entrypoint
}

outIngestor := layer.NewAppendIngester(c.String("out-manifest"), c.String("out-config"))
Expand Down
6 changes: 4 additions & 2 deletions go/pkg/layer/append.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ func AppendLayers(
labels map[string]string,
env []string,
created time.Time,
entrypoint []string,
entrypoint *[]string,
platform ocispec.Platform,
) (ocispec.Descriptor, ocispec.Descriptor, error) {
if annotations == nil {
Expand Down Expand Up @@ -136,7 +136,9 @@ func AppendLayers(
imageConfig.History = append(imageConfig.History, history...)

imageConfig.Author = "rules_oci"
imageConfig.Config.Entrypoint = entrypoint
if entrypoint != nil {
imageConfig.Config.Entrypoint = *entrypoint
}
imageConfig.Config.Env = append(imageConfig.Config.Env, env...)

newConfig, err := ociutil.IngestorJSONEncode(
Expand Down
217 changes: 130 additions & 87 deletions oci/image.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,65 @@
load("@aspect_bazel_lib//lib:stamping.bzl", "STAMP_ATTRS", "maybe_stamp")
load("@com_github_datadog_rules_oci//oci:providers.bzl", "OCIDescriptor", "OCILayout")

def oci_image(
name,
base,
annotations = None,
arch = None,
entrypoint = None,
env = None,
labels = None,
layers = None,
os = None,
tars = None,
**kwargs):
""" oci_image

Creates a new image manifest and config by appending the `layers` to an
existing image manifest and config defined by `base`. If `base` is an image
index, then `os` and `arch` will be used to extract the image manifest.

Args:
name: The name of the rule.
base: A base image, as defined by oci_pull or oci_image.
annotations: OCI Annotations to add to the manifest.
arch: Used to extract a manifest from base if base is an index.
entrypoint: A list of entrypoints for the image; these will be inserted
into the generated container configuration.
env: Entries are in the format of `VARNAME=VARVALUE`. These values act
as defaults and are merged with any specified when creating a
container.
labels: Labels that will be applied to the image configuration, as
defined in the OCI config. These behave the same way as docker
LABEL. In particular, labels from the base image are inherited. An
empty value for a label will cause that label to be deleted. For
backwards compatibility, if this is not set, then the value of
annotations will be used instead.
layers: A list of layers defined by oci_image_layer.
os: Used to extract a manifest from base if base is an index.
tars: A list of tars to add as layers.
**kwargs: Additional keyword arguments, e.g. tags or visibility
"""
if entrypoint == None:
entrypoint_override = False
else:
entrypoint_override = True

_oci_image(
name = name,
base = base,
annotations = annotations,
arch = arch,
entrypoint = entrypoint,
entrypoint_override = entrypoint_override,
env = env,
labels = labels,
layers = layers,
os = os,
tars = tars,
**kwargs
)

# buildifier: disable=function-docstring
def get_descriptor_file(ctx, desc):
if hasattr(desc, "descriptor_file"):
Expand Down Expand Up @@ -98,16 +157,6 @@ def _oci_image_impl(ctx):
config_file = ctx.actions.declare_file("{}.config.json".format(ctx.label.name))
layout_file = ctx.actions.declare_file("{}.layout.json".format(ctx.label.name))

entrypoint_config_file = ctx.actions.declare_file("{}.entrypoint.config.json".format(ctx.label.name))
entrypoint_config = struct(
entrypoint = ctx.attr.entrypoint,
)

ctx.actions.write(
output = entrypoint_config_file,
content = json.encode(entrypoint_config),
)

annotations = ctx.attr.annotations

# Backwards compatibility: code that doesn't use the labels attr will expect annotations to be
Expand All @@ -132,44 +181,69 @@ def _oci_image_impl(ctx):
if maybe_stamp(ctx):
stamp_args.append("--bazel-version-file={}".format(ctx.version_file.path))

arguments = [
"--layout={}".format(base_layout.blob_index.path),
"append-layers",
"--base={}".format(base_desc.path),
"--os={}".format(ctx.attr.os),
"--arch={}".format(ctx.attr.arch),
"--out-manifest={}".format(manifest_file.path),
"--out-config={}".format(config_file.path),
"--out-layout={}".format(layout_file.path),
"--outd={}".format(manifest_desc_file.path),
] + [
"--layer={}={}".format(layer, descriptor)
for layer, descriptor in layer_and_descriptor_paths
] + [
"--tar={}".format(tar.path)
for tar in tars
] + [
"--annotations={}={}".format(k, v)
for k, v in annotations.items()
] + [
"--labels={}={}".format(k, v)
for k, v in labels.items()
] + [
"--env={}".format(env)
for env in ctx.attr.env
] + stamp_args

default_info_files = [
config_file,
layout_file,
manifest_desc_file,
manifest_file,
]

inputs = [
ctx.version_file,
base_desc,
base_layout.blob_index,
] + ctx.files.layers + layer_descriptor_files + base_layout.files.to_list() + tars

if ctx.attr.entrypoint_override:
entrypoint_config_file = ctx.actions.declare_file("{}.entrypoint.config.json".format(ctx.label.name))
entrypoint_config = struct(
entrypoint = ctx.attr.entrypoint,
)
ctx.actions.write(
output = entrypoint_config_file,
content = json.encode(entrypoint_config),
)
arguments.append("--entrypoint={}".format(entrypoint_config_file.path))
default_info_files.append(entrypoint_config_file)
inputs.append(entrypoint_config_file)

ctx.actions.run(
executable = toolchain.sdk.ocitool,
arguments = [
"--layout={}".format(base_layout.blob_index.path),
"append-layers",
"--base={}".format(base_desc.path),
"--os={}".format(ctx.attr.os),
"--arch={}".format(ctx.attr.arch),
"--out-manifest={}".format(manifest_file.path),
"--out-config={}".format(config_file.path),
"--out-layout={}".format(layout_file.path),
"--outd={}".format(manifest_desc_file.path),
"--entrypoint={}".format(entrypoint_config_file.path),
] +
[
"--layer={}={}".format(layer, descriptor)
for layer, descriptor in layer_and_descriptor_paths
] +
["--tar={}".format(tar.path) for tar in tars] +
["--annotations={}={}".format(k, v) for k, v in annotations.items()] +
["--labels={}={}".format(k, v) for k, v in labels.items()] +
["--env={}".format(env) for env in ctx.attr.env] +
stamp_args,
inputs = [
ctx.version_file,
base_desc,
base_layout.blob_index,
entrypoint_config_file,
] + ctx.files.layers +
layer_descriptor_files +
base_layout.files.to_list() +
tars,
arguments = arguments,
inputs = inputs,
mnemonic = "OCIImageAppendLayers",
outputs = [
manifest_file,
config_file,
layout_file,
manifest_desc_file,
manifest_file,
],
)

Expand All @@ -180,72 +254,41 @@ def _oci_image_impl(ctx):
OCILayout(
blob_index = layout_file,
files = depset(
ctx.files.layers + ctx.files.tars + [manifest_file, config_file, layout_file],
ctx.files.layers + ctx.files.tars + [
manifest_file,
config_file,
layout_file,
],
transitive = [base_layout.files],
),
),
DefaultInfo(
files = depset([
entrypoint_config_file,
manifest_file,
config_file,
layout_file,
manifest_desc_file,
]),
files = depset(default_info_files),
),
]

oci_image = rule(
_oci_image = rule(
implementation = _oci_image_impl,
doc = """Creates a new image manifest and config by appending the `layers` to an existing image
manifest and config defined by `base`. If `base` is an image index, then `os` and `arch` will
be used to extract the image manifest.""",
attrs = dict({
"annotations": attr.string_dict(),
"arch": attr.string(),
"base": attr.label(
doc = """A base image, as defined by oci_pull or oci_image""",
mandatory = True,
providers = [
OCIDescriptor,
OCILayout,
],
),
"entrypoint": attr.string_list(
doc = """A list of entrypoints for the image; these will be inserted into the generated
OCI image config""",
),
"os": attr.string(
doc = "Used to extract a manifest from base if base is an index",
),
"arch": attr.string(
doc = "Used to extract a manifest from base if base is an index",
),
"env": attr.string_list(
doc = """Entries are in the format of `VARNAME=VARVALUE`. These values act as defaults and
are merged with any specified when creating a container.""",
providers = [OCIDescriptor, OCILayout],
),
"entrypoint": attr.string_list(),
"entrypoint_override": attr.bool(),
"env": attr.string_list(),
"labels": attr.string_dict(),
"layers": attr.label_list(
doc = "A list of layers defined by oci_image_layer",
providers = [
OCIDescriptor,
],
),
"os": attr.string(),
"tars": attr.label_list(
doc = "A list of tars to add as layers",
allow_files = [".tar", ".tar.gz", ".tgz", ".tar.zst"],
),
"annotations": attr.string_dict(
doc = """[OCI Annotations](https://github.com/opencontainers/image-spec/blob/main/annotations.md)
to add to the manifest.""",
),
"labels": attr.string_dict(
doc = """labels that will be applied to the image configuration, as defined in
[the OCI config](https://github.com/opencontainers/image-spec/blob/main/config.md#properties).
These behave the same way as
[docker LABEL](https://docs.docker.com/engine/reference/builder/#label);
in particular, labels from the base image are inherited. An empty value for a label
will cause that label to be deleted. For backwards compatibility, if this is not set,
then the value of annotations will be used instead.""",
),
}, **STAMP_ATTRS),
toolchains = ["@com_github_datadog_rules_oci//oci:toolchain"],
provides = [OCIDescriptor, OCILayout],
Expand Down
Loading