Skip to content

Commit 386a89f

Browse files
committed
Make transitions optional
Transitions, introduced in bazelbuild#1963 can now be disabled by calling bazel with `--@io_bazel_rules_docker//transitions:enable=no`. Added tests to verify the behaviour.
1 parent 6ea707b commit 386a89f

8 files changed

Lines changed: 230 additions & 6 deletions

File tree

README.md

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -208,6 +208,12 @@ like:
208208
Unable to load package for //:WORKSPACE: BUILD file not found in any of the following directories.
209209
```
210210

211+
* rules_docker uses transitions to build your containers using toolchains the correct
212+
architecture and operating system. If you run into issues with toolchain resolutions,
213+
you can disable this behaviour, by adding this to your .bazelrc:
214+
```
215+
build --@io_bazel_rules_docker//transitions:enable=false
216+
```
211217
## Using with Docker locally.
212218

213219
Suppose you have a `container_image` target `//my/image:helloworld`:
@@ -635,7 +641,7 @@ nodejs_image(
635641
name = "nodejs_image",
636642
entry_point = "@your_workspace//path/to:file.js",
637643
# npm deps will be put into their own layer
638-
data = [":file.js", "@npm//some-npm-dep"],
644+
data = [":file.js", "@npm//some-npm-dep"],
639645
...
640646
)
641647
```
@@ -1150,7 +1156,7 @@ load("@io_bazel_rules_docker//toolchains/docker:toolchain.bzl",
11501156

11511157
docker_toolchain_configure(
11521158
name = "docker_config",
1153-
# Replace this with a Bazel label to the config.json file. Note absolute or relative
1159+
# Replace this with a Bazel label to the config.json file. Note absolute or relative
11541160
# paths are not supported. Docker allows you to specify custom authentication credentials
11551161
# in the client configuration JSON file.
11561162
# See https://docs.docker.com/engine/reference/commandline/cli/#configuration-files

container/image.bzl

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -770,7 +770,15 @@ _outputs["config_digest"] = "%{name}.json.sha256"
770770
_outputs["build_script"] = "%{name}.executable"
771771

772772
def _image_transition_impl(settings, attr):
773-
return dicts.add(settings, {
773+
if not settings["@io_bazel_rules_docker//transitions:enable"]:
774+
# Once bazel < 5.0 is not supported we can return an empty dict here
775+
return {
776+
"//command_line_option:platforms": settings["//command_line_option:platforms"],
777+
"@io_bazel_rules_docker//platforms:image_transition_cpu": "//plaftorms:image_transition_cpu_unset",
778+
"@io_bazel_rules_docker//platforms:image_transition_os": "//plaftorms:image_transition_os_unset",
779+
}
780+
781+
return {
774782
"//command_line_option:platforms": "@io_bazel_rules_docker//platforms:image_transition",
775783
"@io_bazel_rules_docker//platforms:image_transition_cpu": "@platforms//cpu:" + {
776784
# Architecture aliases.
@@ -779,11 +787,14 @@ def _image_transition_impl(settings, attr):
779787
"ppc64le": "ppc",
780788
}.get(attr.architecture, attr.architecture),
781789
"@io_bazel_rules_docker//platforms:image_transition_os": "@platforms//os:" + attr.operating_system,
782-
})
790+
}
783791

784792
_image_transition = transition(
785793
implementation = _image_transition_impl,
786-
inputs = [],
794+
inputs = [
795+
"@io_bazel_rules_docker//transitions:enable",
796+
"//command_line_option:platforms",
797+
],
787798
outputs = [
788799
"//command_line_option:platforms",
789800
"@io_bazel_rules_docker//platforms:image_transition_cpu",

tests/container/BUILD

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ load("//contrib:test.bzl", "container_test")
3030
load(":apple.bzl", "create_banana_directory")
3131
load(":empty_layers.bzl", "empty_layers")
3232
load(":pull_info_validation_test.bzl", "pull_info_validation_test")
33+
load(":transitions.bzl", "templated_file", "transition_test")
3334

3435
package(default_visibility = ["//visibility:public"])
3536

@@ -999,3 +1000,80 @@ container_bundle(
9991000
"localhost:5000/image4:latest": "//testdata:with_double_label",
10001001
},
10011002
)
1003+
1004+
genrule(
1005+
name = "got_os",
1006+
outs = ["got_os.txt"],
1007+
cmd = select({
1008+
"@platforms//os:windows": "echo windows > \"$@\"",
1009+
"@platforms//os:linux": "echo linux > \"$@\"",
1010+
"@platforms//os:macos": "echo macos > \"$@\"",
1011+
}),
1012+
)
1013+
1014+
genrule(
1015+
name = "got_arch",
1016+
outs = ["got_arch.txt"],
1017+
cmd = select({
1018+
"@platforms//cpu:arm64": "echo arm64 > \"$@\"",
1019+
"@platforms//cpu:aarch64": "echo arm64 > \"$@\"",
1020+
"@platforms//cpu:x86_64": "echo x86_64 > \"$@\"",
1021+
"@platforms//cpu:arm": "echo arm > \"$@\"",
1022+
}),
1023+
)
1024+
1025+
container_image(
1026+
name = "transitioned_image",
1027+
architecture = "arm64",
1028+
files = [
1029+
":got_arch",
1030+
":got_os",
1031+
],
1032+
operating_system = "windows",
1033+
)
1034+
1035+
templated_file(
1036+
name = "transitions_off",
1037+
out = "transitions_off.yaml",
1038+
substitutions =
1039+
select({
1040+
"@platforms//os:linux": ["%WANT_OS%=linux"],
1041+
"@platforms//os:macos": ["%WANT_OS%=macos"],
1042+
}) + select({
1043+
"@platforms//cpu:arm64": ["%WANT_ARCH%=arm64"],
1044+
"@platforms//cpu:aarch64": ["%WANT_ARCH%=arm64"],
1045+
"@platforms//cpu:x86_64": ["%WANT_ARCH%=x86_64"],
1046+
}),
1047+
template = "//tests/container/configs:transitions_off.yaml.tpl",
1048+
)
1049+
1050+
container_test(
1051+
name = "_transitions_on_test_base",
1052+
configs = ["//tests/container/configs:transitions_on.yaml"],
1053+
driver = "tar",
1054+
image = ":transitioned_image",
1055+
# marked manual, because it will only pass if transitions are enabled
1056+
# enabled or disabled
1057+
tags = ["manual"],
1058+
)
1059+
1060+
transition_test(
1061+
name = "transitions_on_test",
1062+
actual = ":_transitions_on_test_base",
1063+
transitions_enabled = True,
1064+
)
1065+
1066+
container_test(
1067+
name = "_transitions_off_test_base",
1068+
configs = ["transitions_off"],
1069+
driver = "tar",
1070+
image = ":transitioned_image",
1071+
# marked manual, because it will only pass if transitions are disabled
1072+
tags = ["manual"],
1073+
)
1074+
1075+
transition_test(
1076+
name = "transitions_off_test",
1077+
actual = ":_transitions_off_test_base",
1078+
transitions_enabled = False,
1079+
)

tests/container/configs/BUILD

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,4 +12,4 @@
1212
# See the License for the specific language governing permissions and
1313
# limitations under the License.
1414

15-
exports_files(glob(["*.yaml"]))
15+
exports_files(glob(["*.yaml"]) + glob(["*.yaml.tpl"]))
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
schemaVersion: 2.0.0
2+
3+
fileContentTests:
4+
- name: "validate architecture"
5+
path: "/Files/got_arch.txt"
6+
expectedContents: ["%WANT_ARCH%"]
7+
- name: "validate os"
8+
path: "/Files/got_os.txt"
9+
expectedContents: ["%WANT_OS%"]
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
schemaVersion: 2.0.0
2+
3+
fileContentTests:
4+
- name: "validate architecture"
5+
path: "/Files/got_arch.txt"
6+
expectedContents: ["arm64"]
7+
- name: "validate os"
8+
path: "/Files/got_os.txt"
9+
expectedContents: ["windows"]

tests/container/transitions.bzl

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
"""
2+
Rules for running tests with a specific value of the //transitions:enabled flag
3+
"""
4+
5+
def _templated_file_impl(ctx):
6+
out = ctx.outputs.out
7+
ctx.actions.expand_template(
8+
template = ctx.file.template,
9+
output = out,
10+
substitutions = dict([s.split("=", 1) for s in ctx.attr.substitutions]),
11+
)
12+
return DefaultInfo(
13+
files = depset([out]),
14+
)
15+
16+
# Replaces substitutions split on `=` in the template. Substitution is a list
17+
# so that is usable with multiple selects,
18+
templated_file = rule(
19+
attrs = {
20+
"template": attr.label(
21+
mandatory = True,
22+
allow_single_file = True,
23+
),
24+
"substitutions": attr.string_list(),
25+
"out": attr.output(),
26+
},
27+
implementation = _templated_file_impl,
28+
)
29+
30+
def _enable_transition_impl(settings, attr):
31+
_ = settings
32+
return {"@io_bazel_rules_docker//transitions:enable": attr.transitions_enabled}
33+
34+
_enable_transition = transition(
35+
implementation = _enable_transition_impl,
36+
inputs = [],
37+
outputs = [
38+
"@io_bazel_rules_docker//transitions:enable",
39+
],
40+
)
41+
42+
def _transitioned_test(ctx):
43+
source_info = ctx.attr.actual[DefaultInfo]
44+
45+
# Bazel wants the executable to be generated by this rule, let's oblige by
46+
# just copying the actual runner.
47+
executable = None
48+
if source_info.files_to_run and source_info.files_to_run.executable:
49+
executable = ctx.actions.declare_file("{}_{}".format(ctx.file.actual.basename, "on" if ctx.attr.transitions_enabled else "off"))
50+
ctx.actions.run_shell(
51+
command = "cp {} {}".format(source_info.files_to_run.executable.path, executable.path),
52+
inputs = [source_info.files_to_run.executable],
53+
outputs = [executable],
54+
)
55+
return [DefaultInfo(
56+
files = depset(ctx.files.actual),
57+
runfiles = source_info.default_runfiles.merge(source_info.data_runfiles),
58+
executable = executable,
59+
)]
60+
61+
# Defines a test that runs with a specific value of the
62+
# @io_bazel_rules_docker//transitions:enable flag.
63+
transition_test = rule(
64+
attrs = {
65+
"actual": attr.label(
66+
mandatory = True,
67+
allow_single_file = True,
68+
),
69+
"transitions_enabled": attr.bool(),
70+
"_allowlist_function_transition": attr.label(
71+
default = "@bazel_tools//tools/allowlists/function_transition_allowlist",
72+
),
73+
},
74+
cfg = _enable_transition,
75+
test = True,
76+
implementation = _transitioned_test,
77+
)

transitions/BUILD

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
# Copyright 2022 The Bazel Authors. All rights reserved.
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
load("@bazel_skylib//rules:common_settings.bzl", "bool_flag")
16+
17+
package(
18+
default_visibility = ["//visibility:public"],
19+
)
20+
21+
bool_flag(
22+
name = "enable",
23+
build_setting_default = True,
24+
)
25+
26+
config_setting(
27+
name = "enabled",
28+
flag_values = {"@io_bazel_rules_docker//transitions:enable": "true"},
29+
)
30+
31+
config_setting(
32+
name = "disabled",
33+
flag_values = {"@io_bazel_rules_docker//transitions:enable": "false"},
34+
)

0 commit comments

Comments
 (0)