Skip to content

Commit

Permalink
[antlir2][buck] new configuration settings for flavor/os
Browse files Browse the repository at this point in the history
Summary:
Add some buck2 configuration constraints for OS version.

This diff by itself enables `select()` based on these constraints, but does not
yet plumb it through the rest of the stack to make it consistent with `flavor`.

See the next diff for that implementation, more Summary details and staticdocs.

Test Plan:
```
❯ buck2 test fbcode//antlir/antlir2/test_images/cfg/os:
Buck UI: https://www.internalfb.com/buck2/ce167cd0-920b-4406-9ed1-49b6a64132cc
Test UI: https://www.internalfb.com/intern/testinfra/testrun/8725724465341791
Network: Up: 0B  Down: 101MiB  (reSessionID-3ba4921a-dc3f-4354-82d8-12b813ff7e5a)
Jobs completed: 604596. Time elapsed: 39.6s.
Tests finished: Pass 18. Fail 0. Fatal 0. Skip 0. Build failure 0
```

Reviewed By: epilatow

Differential Revision: D49553996

fbshipit-source-id: c8d219a3e7897d8cecafc8b822ec7a001f28dff6
  • Loading branch information
vmagro authored and facebook-github-bot committed Oct 20, 2023
1 parent f011fb8 commit b93764a
Show file tree
Hide file tree
Showing 10 changed files with 370 additions and 12 deletions.
71 changes: 67 additions & 4 deletions antlir/antlir2/bzl/image/cfg.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,25 @@ Currently this supports reconfiguring the target cpu architecture.
"""

load("//antlir/antlir2/bzl/image/facebook:fb_cfg.bzl", "fbcode_platform_refs", "transition_fbcode_platform")
load("//antlir/antlir2/os:defs.bzl", "OsVersionInfo")
load("//antlir/bzl:build_defs.bzl", "is_facebook")

def cfg_attrs():
return {
"default_os": attrs.option(attrs.string(), default = None, doc = """
Reconfigure the layer when no antlir2 os has been set yet, so that
each intermediate layer can be passed to `buck build` and give a
reasonable default.
For more details, see:
https://www.internalfb.com/intern/staticdocs/antlir2/docs/recipes/multi-os-images/
"""),
"target_arch": attrs.option(
attrs.enum(["x86_64", "aarch64"]),
default = None,
doc = "Build this image for a specific target arch without using `buck -c`",
),
}

def _impl(platform: PlatformInfo, refs: struct, attrs: struct) -> PlatformInfo:
constraints = platform.configuration.constraints

Expand All @@ -23,6 +40,26 @@ def _impl(platform: PlatformInfo, refs: struct, attrs: struct) -> PlatformInfo:
if is_facebook:
constraints = transition_fbcode_platform(refs, attrs, constraints)

if attrs.default_os:
os = getattr(refs, "os." + attrs.default_os)[OsVersionInfo]
os_constraint = os.constraint[ConstraintValueInfo]
family = os.family[ConstraintValueInfo]

# The rule transition to set the default antlir2 OS only happens if the
# target has not been configured for a specific OS yet. This way the dep
# transition takes precedence - in other words, the default_os attribute of
# the leaf image being built is always respected and reconfigures all layers
# along the parent_layer chain
if os_constraint.setting.label not in constraints:
constraints[os_constraint.setting.label] = os_constraint
constraints[family.setting.label] = family

# If a build appliance is being built, we must remove the OS configuration
# constraint to avoid circular dependencies.
if attrs.antlir_internal_build_appliance:
constraints.pop(refs.os_constraint[ConstraintSettingInfo].label, None)
constraints.pop(refs.os_family_constraint[ConstraintSettingInfo].label, None)

label = platform.label

# if we made any changes, change the label
Expand All @@ -42,13 +79,39 @@ layer_cfg = transition(
refs = {
"arch.aarch64": "ovr_config//cpu/constraints:arm64",
"arch.x86_64": "ovr_config//cpu/constraints:x86_64",
"os.centos8": "//antlir/antlir2/os:centos8",
"os.centos9": "//antlir/antlir2/os:centos9",
"os.eln": "//antlir/antlir2/os:eln",
"os.none": "//antlir/antlir2/os:none",
"os_constraint": "//antlir/antlir2/os:os",
"os_family_constraint": "//antlir/antlir2/os/family:family",
} | (
# @oss-disable
# @oss-enable {}
),
attrs = [
# target_arch on image.layer is read to reconfigure for the target cpu
# arch without having to use -c fbcode.arch
"target_arch",
attrs = cfg_attrs().keys() + [
# Build appliances are very low level and cannot depend on a flavor, so
# they are just not transitioned to an os configuration
"antlir_internal_build_appliance",
],
)

def _remove_os_impl(platform: PlatformInfo, refs: struct) -> PlatformInfo:
constraints = platform.configuration.constraints
constraints.pop(refs.os_constraint[ConstraintSettingInfo].label, None)
constraints.pop(refs.os_family_constraint[ConstraintSettingInfo].label, None)
return PlatformInfo(
label = platform.label,
configuration = ConfigurationInfo(
constraints = constraints,
values = platform.configuration.values,
),
)

remove_os_constraint = transition(
impl = _remove_os_impl,
refs = {
"os_constraint": "//antlir/antlir2/os:os",
"os_family_constraint": "//antlir/antlir2/os/family:family",
},
)
21 changes: 14 additions & 7 deletions antlir/antlir2/bzl/image/layer.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,14 @@ load(
)
# @oss-disable
# @oss-disable
load("//antlir/antlir2/os:package.bzl", "get_default_os_for_package", "should_all_images_in_package_use_default_os")
load("//antlir/bzl:build_defs.bzl", "alias", "is_facebook")
load("//antlir/bzl:constants.bzl", "REPO_CFG")
load("//antlir/bzl:types.bzl", "types")
load("//antlir/rpm/dnf2buck:repo.bzl", "RepoInfo", "RepoSetInfo")
# @oss-disable
load("//antlir/bzl/build_defs.bzl", "config", "get_visibility")
load(":cfg.bzl", "layer_cfg")
load(":cfg.bzl", "cfg_attrs", "layer_cfg", "remove_os_constraint")
load(":depgraph.bzl", "build_depgraph")
load(":mounts.bzl", "all_mounts", "container_mount_args")

Expand Down Expand Up @@ -451,7 +452,7 @@ _layer_attrs = {
"antlir2": attrs.exec_dep(default = "//antlir/antlir2/antlir2:antlir2"),
"antlir_internal_build_appliance": attrs.bool(default = False, doc = "mark if this image is a build appliance and is allowed to not have a flavor"),
"build_appliance": attrs.option(
attrs.dep(providers = [LayerInfo]),
attrs.transition_dep(providers = [LayerInfo], cfg = remove_os_constraint),
default = None,
),
"default_mountpoint": attrs.option(attrs.string(), default = None),
Expand Down Expand Up @@ -497,11 +498,6 @@ _layer_attrs = {
attrs.dep(providers = [LayerInfo]),
default = None,
),
"target_arch": attrs.option(
attrs.enum(["x86_64", "aarch64"]),
default = None,
doc = "Build this image for a specific target arch",
),
"_implicit_image_test": attrs.option(
attrs.exec_dep(providers = [ExternalRunnerTestInfo]),
default = None,
Expand All @@ -515,6 +511,8 @@ _layer_attrs = {
)),
}

_layer_attrs.update(cfg_attrs())

_layer_attrs.update(
{
"_feature_" + key: val
Expand All @@ -537,6 +535,9 @@ def layer(
# by a type hint inside feature.bzl. Feature targets or
# InlineFeatureInfo providers are accepted, at any level of nesting
features = [],
default_os: str | None = None,
# TODO: remove this flag when all images are using this new mechanism
use_default_os_from_package: bool | None = None,
# We'll implicitly forward some users to antlir2, so any hacks for them
# should be confined behind this flag
implicit_antlir2: bool = False,
Expand All @@ -551,6 +552,11 @@ def layer(
flavor = kwargs.pop("flavor", None)
kwargs["flavor"] = compat.from_antlir1_flavor(flavor) if flavor else None

if use_default_os_from_package == None:
use_default_os_from_package = should_all_images_in_package_use_default_os()
if use_default_os_from_package:
default_os = default_os or get_default_os_for_package()

kwargs.update({"_feature_" + key: val for key, val in feature_attrs(features).items()})

if is_facebook:
Expand Down Expand Up @@ -579,6 +585,7 @@ def layer(

return layer_rule(
name = name,
default_os = default_os,
visibility = get_visibility(visibility),
_implicit_image_test = "//antlir/antlir2/testing/implicit_image_test:implicit_image_test",
**kwargs
Expand Down
27 changes: 27 additions & 0 deletions antlir/antlir2/os/BUCK
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
load("@prelude//:rules.bzl", "constraint_setting")
load(":defs.bzl", "os_version")

constraint_setting(
name = "os",
visibility = ["PUBLIC"],
)

os_version(
name = "none",
family = "//antlir/antlir2/os/family:none",
)

os_version(
name = "centos8",
family = "//antlir/antlir2/os/family:centos",
)

os_version(
name = "centos9",
family = "//antlir/antlir2/os/family:centos",
)

os_version(
name = "eln",
family = "//antlir/antlir2/os/family:fedora",
)
53 changes: 53 additions & 0 deletions antlir/antlir2/os/defs.bzl
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
# Copyright (c) Meta Platforms, Inc. and affiliates.
#
# This source code is licensed under the MIT license found in the
# LICENSE file in the root directory of this source tree.

load("@prelude//:rules.bzl", "config_setting", "constraint_value")

OsVersionInfo = provider(fields = [
"constraint",
"family",
])

def _os_version_rule_impl(ctx: AnalysisContext) -> list[Provider]:
return [
DefaultInfo(),
ctx.attrs.config_setting[ConfigurationInfo],
OsVersionInfo(
constraint = ctx.attrs.constraint,
family = ctx.attrs.family,
),
]

_os_version_rule = rule(
impl = _os_version_rule_impl,
attrs = {
"config_setting": attrs.dep(providers = [ConfigurationInfo]),
"constraint": attrs.dep(providers = [ConstraintValueInfo]),
"family": attrs.dep(providers = [ConstraintValueInfo]),
},
)

def os_version(
name: str,
family: str):
constraint_value(
name = name + ".constraint",
constraint_setting = "//antlir/antlir2/os:os",
visibility = [":" + name],
)
config_setting(
name = name + ".config",
constraint_values = [
":{}.constraint".format(name),
family,
],
visibility = ["PUBLIC"],
)
_os_version_rule(
name = name,
family = family,
constraint = ":{}.constraint".format(name),
config_setting = ":{}.config".format(name),
)
25 changes: 25 additions & 0 deletions antlir/antlir2/os/family/BUCK
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
load("@prelude//:rules.bzl", "constraint_setting", "constraint_value")

constraint_setting(
name = "family",
visibility = ["PUBLIC"],
)

constraint_value(
name = "none",
constraint_setting = ":family",
visibility = ["PUBLIC"],
)

# Any version of CentOS.
constraint_value(
name = "centos",
constraint_setting = ":family",
visibility = ["PUBLIC"],
)

constraint_value(
name = "fedora",
constraint_setting = ":family",
visibility = ["PUBLIC"],
)
26 changes: 26 additions & 0 deletions antlir/antlir2/os/package.bzl
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# Copyright (c) Meta Platforms, Inc. and affiliates.
#
# This source code is licensed under the MIT license found in the
# LICENSE file in the root directory of this source tree.

def set_default_os_for_package(*, default_os: str):
write_package_value(
"antlir2.default_os",
default_os,
overwrite = True,
)

def get_default_os_for_package() -> str:
return read_package_value("antlir2.default_os")

def all_images_in_package_use_default_os(yes: bool = True):
write_package_value(
"antlir2.all_images_in_package_use_default_os",
yes,
overwrite = True,
)

def should_all_images_in_package_use_default_os() -> bool:
return read_package_value(
"antlir2.all_images_in_package_use_default_os",
) or False
74 changes: 74 additions & 0 deletions antlir/antlir2/test_images/cfg/os/BUCK
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
load("//antlir/antlir2/bzl/feature:defs.bzl", "feature")
load("//antlir/antlir2/bzl/image:defs.bzl", "image")
load("//antlir/antlir2/testing:image_test.bzl", "image_rust_test")
load(":defs.bzl", "write_os")

oncall("twimage")

image.layer(
name = "root",
features = [
feature.rpms_install(rpms = [
"bash",
"coreutils",
# @oss-disable
]),
write_os("/root.os"),
],
flavor = "//antlir/antlir2/test_images:test-image-flavor",
)

image.layer(
name = "intermediate",
features = [
write_os("/intermediate.os"),
],
parent_layer = ":root",
)

image.layer(
name = "leaf.generic",
features = [
write_os("/leaf.os"),
],
parent_layer = ":intermediate",
)

[
[
image.layer(
name = "leaf." + os,
default_os = os,
features = [
write_os("/leaf.os"),
],
parent_layer = ":intermediate",
),
image_rust_test(
name = "test-leaf." + os,
srcs = ["test.rs"],
crate = "test_leaf_" + os,
crate_root = "test.rs",
env = {
"OS": os,
},
layer = ":leaf." + os,
),
image_rust_test(
name = "test-leaf.generic." + os,
srcs = ["test.rs"],
crate = "test_leaf_generic_" + os,
crate_root = "test.rs",
default_os = os,
env = {
"OS": os,
},
layer = ":leaf.generic",
),
]
for os in [
"centos8",
"centos9",
"eln",
]
]
16 changes: 16 additions & 0 deletions antlir/antlir2/test_images/cfg/os/defs.bzl
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# Copyright (c) Meta Platforms, Inc. and affiliates.
#
# This source code is licensed under the MIT license found in the
# LICENSE file in the root directory of this source tree.

load("//antlir/antlir2/bzl/feature:defs.bzl", "feature")

def write_os(path: str):
return feature.install_text(
dst = path,
text = select({
"//antlir/antlir2/os:centos8": "centos8",
"//antlir/antlir2/os:centos9": "centos9",
"//antlir/antlir2/os:eln": "eln",
}),
)
Loading

0 comments on commit b93764a

Please sign in to comment.