Skip to main content

Features

feature.clone

Copies a subtree of an existing layer into the one under construction. To the extent possible, filesystem metadata are preserved.

Parameters

src_layer: str (selectable)

Buck target pointing to source image.layer.

This image must contain the contents to be cloned

path: Optional[str] (selectable) = None

src_path: Optional[str] (selectable) = None

Root path to clone from in src_layer

dst_path: Optional[str] (selectable) = None

Root path to clone into in the layer being built

user: Optional[str] = None

Set owning user on all files and directories

If not set, the same username is used between src_layer and the layer being built

group: Optional[str] = None

Set owning group on all files and directories

If not set, the same group name is used between src_layer and the layer being built

This copies from src_path in the src_layer to dst_path in this layer. If both paths are the same, you can just set path and it will serve as both the source and destination paths.

Trailing slashes on both paths are significant

The three supported cases are:

  • s/rc -> dest/ creates dest/rc
  • s/rc/ -> dest/ creates dest/(children of rc)
  • s/rc -> dest creates dest

More explicitly:

  • A trailing slash in src_path means "use the rsync convention":
    • Do not clone the source directory, but only its contents.
    • dest_path must be a pre-existing dir, and it must end in /
  • A trailing slash in dst_path means that it's a pre-existing directory (e.g. made by ensure_dirs_exist), and clone will only write to:
    • dst/(basename of src_path) if src_path lacks a trailing /
    • dst/(children of src_path) if src_path has a trailing /

Known deviations from perfect cloning

Most likely, SELinux attrs change.

UID/GID remapping

src_layer and the destination layer must have the same user/group names available, but those names do not need to map to the same ids. uid/gids will be remapped to the appropriate numeric id of that user/group in the destination layer.

When to use this?

Often, instead of using this, you should prefer layer_mount, which allows you to compose independent pieces of the filesystem at runtime, without incurring the cost of publishing images with a lot of duplicated content.

If you're trying to copy the output of a regular Buck target, instead use feature.install.

feature.dnf_module_enable

Enable this DNF module before resolving the DNF transaction

Parameters

name: str (selectable)

stream: str (selectable)

See this page for more details about modules https://docs.fedoraproject.org/en-US/modularity/using-modules/

Create a symlink to a directory.

Parameters

link: str (selectable)

target: str (selectable)

unsafe_dangling_symlink: bool = False

Trailing /s are not allowed, unlike ln where it is significant.

feature.ensure_dirs_exist

Equivalent to ensure_subdirs_exist("/", dirs, ...).

Parameters

dirs: str (selectable)

mode: int | str = 493

user: str = "root"

group: str = "root"

Create a symlink to a file.

Parameters

link: str (selectable)

target: str (selectable)

unsafe_dangling_symlink: bool = False

Trailing /s are not allowed, unlike ln where it is significant.

feature.ensure_subdirs_exist

Ensure directories exist in the image (analogous to mkdir -p).

Parameters

into_dir: str (selectable)

Parent directory (must already exist)

subdirs_to_create: str (selectable)

Subdirectories to create under into_dir

These subdirectories may already exist in the image. If so, they will be checked to ensure that the mode and user:group matches what is declared here.

mode: int | str (selectable) = 493

set file mode bits of the newly-created directories

user: str (selectable) = "root"

set owning user of the newly-created directories

group: str (selectable) = "root"

set owning group of the newly-created directories

feature.extract_buck_binary

Extract a buck-built binary and all of its runtime dependencies into the target layer.

Parameters

src: str (selectable)

binary target

dst: str (selectable)

path to install it to in the image

strip: bool (selectable) = True

strip debug info from the binary and discard it

This copies the binary and all of it's .so dependencies from the host filesystem. Any mismatched contents in these dependencies will cause an image build failure.

You almost definitely do NOT want this

This feature exists only for building extremely stripped down environments like initrds, where things like the fbcode runtime is unavailable.

In 99% of cases you actually want to just give your binary to feature.install

feature.extract_from_layer

Extract a binary and all of its runtime dependencies from layer into the target layer.

Parameters

layer: str (selectable)

antlir2 layer target to extract from

binaries: list[selector | str] (selectable)

list of file paths to extract

This copies the binary and all of it's .so dependencies from the host filesystem. Any mismatched contents in these dependencies will cause an image build failure.

You almost definitely do NOT want this

This feature exists only for building extremely stripped down environments like initrds, where things like the fbcode runtime is unavailable.

In 99% of cases you actually just want to use feature.install or feature.rpms_install

feature.feature_new

Create a target representing a collection of one or more image features.

Parameters

name: str

features: typing.Any

visibility: typing.Any = None

features is a list that can contain either:

  • inline (aka unnamed) features created with macros like install()
  • labels referring to other feature targets

feature.genrule

Parameters

cmd: Optional[list[selector | str]] (selectable) = None

bash: Optional[str] (selectable) = None

user: str (selectable) = "nobody"

bind_repo_ro: bool (selectable) = False

mount_platform: bool (selectable) = False

feature.group_add

Add a group entry to /etc/group

Parameters

groupname: str (selectable)

gid: Optional[int] (selectable) = None

uidmap: str = "default"

Group add semantics generally follow groupadd. If groupname or GID conflicts with existing entries, image build will fail.

Create a hardlink to a file.

Parameters

link: str (selectable)

target: str (selectable)

feature.host_mount

Parameters

source: str

is_directory: bool

mountpoint: Optional[str] = None

feature.install

Install a file or directory into the image.

Parameters

src: str (selectable)

source file or buck target

dst: str (selectable)

mode: Optional[int | str] (selectable) = None

mode to set on the installed file

In most cases this can be left unset and antlir2 will choose the most reasonable default based on the source. Buck-built binaries will automatically be marked as executable. These defaults can be manually overriden by default_permissions.

user: int | str (selectable) = "root"

owner of the installed contents

group: int | str (selectable) = "root"

owner of the installed contents

xattrs: dict[str, str] (selectable) = {}

extended attributes to set on the installed contents

never_use_dev_binary_symlink: bool = False

always install a binary as a regular file

In most cases this means that your binary will not be runnable in @mode/dev builds, but it guarantees that the binary will always be a regular file and never a symlink.

split_debuginfo: bool = True

strip debuginfo from the binary and place it into /usr/lib/debug

always_use_gnu_debuglink: bool = False

setcap: Optional[str] = None

add file capabilities to the installed file

Specified in the form described in cap_from_text(3).

default_permissions: default_permissions = record[default_permissions](binary=None, file=None, directory=None)

Default fallback permissions when mode is unset

feature.install_text

Parameters

text: str (selectable)

dst: str (selectable)

mode: Optional[int | str] (selectable) = None

user: int | str (selectable) = "root"

group: int | str (selectable) = "root"

xattrs: dict[str, str] (selectable) = {}

feature.layer_mount

Parameters

source: str (selectable)

mountpoint: Optional[str] = None

feature.remove

Recursively remove a file or directory

Parameters

path: str

must_exist: bool = True

must_be_empty: bool = False

These are allowed to remove paths inherited from the parent layer, or those installed in this layer.

By default, it is an error if the specified path is missing from the image, though this can be avoided by setting must_exist=False.

feature.requires

Add rule-level requirements on image layers.

Parameters

files: list[str] = []

groups: list[str] = []

users: list[str] = []

Currently this supports requiring users, groups and files to exist in the layer being built. This feature doesn't materialize anything in the built image, but it will cause a compiler error if any of the required features that are requested do not exist in either the parent_layer or the layer being built.

An example of a reasonable use-case of this functionality is defining a macro that generates systemd units that run as a specific user, where requires can be used for additional compile-time safety that the user, groups or files do indeed exist.

feature.rpms_install

Install RPMs by identifier or .rpm src

Parameters

rpms: list[str] = []

subjects: list[selector | str] (selectable) = []

deps: list[selector | str] (selectable) = []

subjects_src: Optional[str] (selectable) = None

Elements in rpms can be an rpm name like "systemd", a NEVR like "systemd-251.4-1.2.hs+fb.el8" (or anything that resolves as a DNF subject) or a buck target that produces a .rpm artifact.

If you want to select RPMs, you must explicitly use subjects (for DNF subjects) or deps (for buck targets).

feature.rpms_remove

Remove RPMs if they are installed, fail if they are not installed.

Parameters

rpms: list[selector | str] (selectable)

Elements in rpms can be any rpm specifier (name, NEVR, etc). If the rpm is not installed, this feature will fail.

note

Dependencies of these rpms may also be removed, but only if no explicitly-installed RPM depends on them (in this case, the goal cannot be solved and the image build will fail unless you remove those rpms as well).

feature.rpms_remove_if_exists

Remove RPMs if they are installed

Parameters

rpms: list[selector | str] (selectable)

Elements in rpms can be any rpm specifier (name, NEVR, etc). If the rpm is not installed, this feature is a no-op.

note

Dependencies of these rpms may also be removed, but only if no explicitly-installed RPM depends on them (in this case, the goal cannot be solved and the image build will fail unless you remove those rpms as well).

feature.rpms_upgrade

Force an upgrade (if possible, which includes respecting versionlock!) of these rpms.

Parameters

rpms: list[str] = []

subjects: list[selector | str] (selectable) = []

deps: list[selector | str] (selectable) = []

subjects_src: Optional[str] (selectable) = None

See feature.rpms_install for explanations of each argument.

feature.standard_user

A convenient function that wraps group_add, user_add, and home dir creation logic. The parent directory of home_dir must already exist.

Parameters

username: str

groupname: str

uid: Optional[int] = None

gid: Optional[int] = None

uidmap: str = "default"

home_dir: Optional[str] = None

shell: str = "/bin/bash"

supplementary_groups: list[str] = []

feature.tarball

Parameters

src: str

into_dir: str

force_root_ownership: bool = False

strip_components: int = 0

feature.user_add

Add a user entry to /etc/passwd.

Parameters

username: str (selectable)

primary_group: str (selectable)

home_dir: str (selectable)

uid: Optional[int] (selectable) = None

uidmap: str = "default"

shell: str (selectable) = "/sbin/nologin"

supplementary_groups: list[selector | str] (selectable) = []

comment: Optional[str] = None

Example usage:

feature.group_add(groupname = "myuser")
feature.user_add(
username = "myuser",
primary_group = "myuser",
home_dir = "/home/myuser",
)
feature.ensure_dirs_exist(
dirs = "/home/myuser",
mode = 0o755,
user = "myuser",
group = "myuser",
)

Unlike shadow-utils useradd, this item does not automatically create the new user's initial login group or home directory.

  • If username or uid conflicts with existing entries, image build will fail.
  • primary_group and supplementary_groups are specified as groupnames.
  • home_dir must exist

feature.usermod

Modify an existing entry in the /etc/passwd and /etc/group databases

Parameters

username: str (selectable)

add_supplementary_groups: list[selector | str] (selectable) = []