Support using container tag in rbe_autoconfig(). (#298) * Support using container tag in rbe_autoconfig(). * Add a rbe_autoconfig target for RBE Ubuntu1604 container testing.
diff --git a/WORKSPACE b/WORKSPACE index 225f6e9..513f28e 100644 --- a/WORKSPACE +++ b/WORKSPACE
@@ -101,7 +101,7 @@ sha256 = "5feceb66ffc86f38d952786c6d696c79c2dbc239dd4e91b46729d73a27fb57e9", ) -load("//rules:rbe_repo.bzl", "rbe_autoconfig") +load("@bazel_toolchains//rules:rbe_repo.bzl", "rbe_autoconfig") rbe_autoconfig(name = "rbe_default") @@ -130,3 +130,12 @@ ), output_base = "configs/ubuntu16_04_clang/1.1", ) + +# Use in the RBE Ubuntu1604 container release. +rbe_autoconfig( + name = "rbe_ubuntu1604_test", + env = clang_env(), + registry = "gcr.io", + repository = "asci-toolchain/test-rbe-ubuntu16_04", + tag = "latest", +)
diff --git a/configs/ubuntu16_04_clang/versions.bzl b/configs/ubuntu16_04_clang/versions.bzl index 0dbf8b8..2307032 100644 --- a/configs/ubuntu16_04_clang/versions.bzl +++ b/configs/ubuntu16_04_clang/versions.bzl
@@ -12,9 +12,18 @@ # See the License for the specific language governing permissions and # limitations under the License -# Returns a dict with major container versions mapped to supported bazel versions. -def config_to_bazel_versions(): +# Returns a dict with suppported Bazel versions mapped to the config version to use. +def bazel_to_config_versions(): return { - "1.0": ["0.13.0", "0.14.1", "0.15.0", "0.16.1"], - "1.1": ["0.16.1", "0.17.1", "0.18.0", "0.19.0", "0.19.2", "0.20.0", "0.21.0"], + "0.13.0": "1.0", + "0.14.1": "1.0", + "0.15.0": "1.0", + "0.16.1": "1.1", + "0.17.1": "1.1", + "0.18.0": "1.1", + "0.19.0": "1.1", + "0.19.2": "1.1", + "0.20.0": "1.1", + "0.21.0": "1.1", + "0.22.0": "1.1", }
diff --git a/rules/get_java_home.sh.tpl b/rules/get_java_home.sh.tpl index 7cd2593..5f4857c 100644 --- a/rules/get_java_home.sh.tpl +++ b/rules/get_java_home.sh.tpl
@@ -20,4 +20,3 @@ # var in a docker image. echo $(docker inspect -f '{{range $i, $v := .Config.Env}}{{println $v}}{{end}}' %{image_name} | grep JAVA_HOME | cut -d'=' -f2) -
diff --git a/rules/rbe_repo.bzl b/rules/rbe_repo.bzl index 2ea33f2..71caa74 100644 --- a/rules/rbe_repo.bzl +++ b/rules/rbe_repo.bzl
@@ -78,7 +78,7 @@ name = "rbe_my_custom_container", registry = "gcr.io", repository = "my-project/my-base", - # tag is not supported, always use a digest + # Digest is recommended for any use case other than testing. digest = "sha256:deadbeef", ) @@ -144,8 +144,8 @@ The {bazel_version} above corresponds to the version of bazel installed locally. Note you can override this version and pass an optional rc # if desired. Running this rule with a non release version (e.g., built from source) will result in -picking as bazel version <bazel_version_fallback> defined in the attrs of this rule. -Note the bazel_version / bazel_rc must be published in https://releases.bazel.build/... +picking as bazel version _BAZEL_VERSION_FALLBACK. Note the bazel_version / bazel_rc_version +must be published in https://releases.bazel.build/... Note this is a very not hermetic repository rule that can actually change the contents of your project sources. While this is generally not recommended by @@ -168,7 +168,7 @@ load( "//configs/ubuntu16_04_clang:versions.bzl", - "config_to_bazel_versions", + "bazel_to_config_versions", ) load("//rules:environments.bzl", "clang_env") load( @@ -183,6 +183,9 @@ "parse_rc", ) +# Version to fallback to if not provided explicitly and local is non-release version. +_BAZEL_VERSION_FALLBACK = "0.22.0" + # External folder is set to be deprecated, lets keep it here for easy # refactoring # https://github.com/bazelbuild/bazel/issues/1262 @@ -214,23 +217,11 @@ def _impl(ctx): """Core implementation of _rbe_autoconfig repository rule.""" - # Resolve the Bazel version to use - bazel_version = None - bazel_rc_version = None - if ctx.attr.bazel_version == "local": - bazel_version = str(extract_version_number(ctx.attr.bazel_version_fallback)) - rc = parse_rc(native.bazel_version) - bazel_rc_version = rc if rc != -1 else None - if ctx.attr.bazel_version != "local": - bazel_version = ctx.attr.bazel_version - bazel_rc_version = ctx.attr.bazel_rc_version - # Deal with the simple case first: if user picks rbe-ubuntu 16_04 container and # a config exists for the current version of Bazel, just create aliases - if ctx.attr.use_checked_in_confs: - if _use_standard_config(ctx, bazel_version, bazel_rc_version, ctx.attr.revision): - # If a standard config was found we are done and can just return. - return + if ctx.attr.config_version: + _use_standard_config(ctx, ctx.attr.bazel_version, ctx.attr.config_version) + return # Perform some safety checks _validate_host(ctx) @@ -256,9 +247,22 @@ outputs_tar = ctx.attr.name + "_out.tar" # Pull the image using 'docker pull' - image_name = ctx.attr.registry + "/" + ctx.attr.repository + "@" + ctx.attr.digest + image_name = None + if ctx.attr.digest: + image_name = ctx.attr.registry + "/" + ctx.attr.repository + "@" + ctx.attr.digest + else: + image_name = ctx.attr.registry + "/" + ctx.attr.repository + ":" + ctx.attr.tag _pull_image(ctx, image_name) + # If tag is specified instead of digest, resolve it to digest in the + # image_name as it will be used later on in the platform targets. + if ctx.attr.tag: + result = ctx.execute(["docker", "inspect", "--format={{index .RepoDigests 0}}", image_name]) + _print_exec_results("Resolve image digest", result, fail_on_error = True) + image_name = result.stdout.splitlines()[0] + print("Image with given tag `%s` is resolved to %s" % + (ctx.attr.tag, image_name)) + # Get the value of JAVA_HOME to set in the produced # java_runtime java_home = _get_java_home(ctx, image_name) @@ -266,8 +270,8 @@ # run the container and extract the autoconf directory _run_and_extract( ctx, - bazel_version = bazel_version, - bazel_rc_version = bazel_rc_version, + bazel_version = ctx.attr.bazel_version, + bazel_rc_version = ctx.attr.bazel_rc_version, image_name = image_name, outputs_tar = outputs_tar, project_root = project_root, @@ -278,7 +282,7 @@ # will work with RBE with the produced toolchain _create_platform( ctx, - bazel_version = bazel_version, + bazel_version = ctx.attr.bazel_version, image_name = image_name, java_home = java_home, name = name, @@ -287,7 +291,7 @@ # Expand outputs to project dir if user requested it _expand_outputs( ctx, - bazel_version = bazel_version, + bazel_version = ctx.attr.bazel_version, project_root = project_root, ) @@ -315,26 +319,11 @@ if not ctx.which("tar"): fail("Cannot run rbe_autoconfig as 'tar' was not found on the path.") -# Checks if a standard published config can be used for the given revision -# of the rbe ubuntu 16_04 container. If so, produces BUILD files with aliases -# for all the required toolchain / platform targets. Otherwise returns false. -def _use_standard_config(ctx, bazel_version, bazel_rc_version, revision): - # If rc version is required, simply return - if bazel_rc_version: - return False +# Produces BUILD files with aliases for all the required toolchain / platform targets. +def _use_standard_config(ctx, bazel_version, config_version): + print("Using checked-in configs.") - # Verify a toolchain config exists for the given version of Bazel and the - # given revision of the container - config_version = public_rbe_ubuntu16_04_config_version().get(revision, None) - config_found = False - for b_v in config_to_bazel_versions().get(config_version): - if b_v == bazel_version: - config_found = True - break - if not config_found: - return False - - # If a config is found, create the BUILD files with the aliases + # Create the BUILD files with the aliases template = ctx.path(Label("@bazel_toolchains//rules:BUILD.std_container.tpl")) jdk = "@bazel_toolchains//configs/ubuntu16_04_clang/%s:jdk8" % config_version cc_toolchain = "@bazel_toolchains//configs/ubuntu16_04_clang/%s/bazel_%s/cpp:cc-toolchain-clang-x86_64-default" % (config_version, bazel_version) @@ -360,11 +349,10 @@ }, False, ) - return True # Pulls an image using 'docker pull'. def _pull_image(ctx, image_name): - print("Pulling image.") + print("Pulling image %s." % image_name) result = ctx.execute(["docker", "pull", image_name]) _print_exec_results("pull image", result, fail_on_error = True) print("Image pulled.") @@ -504,7 +492,10 @@ # If we use the default project, we need to modify the WORKSPACE # and BUILD files, so don't mount read-only mount_read_only_flag = "" - target = project_root + ":" + _REPO_DIR + mount_read_only_flag + + # If the rule is invoked from bazel-toolchains itself, then project_root + # is a symlink, which can cause mounting issues on GCB. + target = "$(realpath " + project_root + "):" + _REPO_DIR + mount_read_only_flag docker_run_flags += ["-v", target] docker_run_flags += ["-v", str(ctx.path("container")) + ":/container"] @@ -603,29 +594,29 @@ _rbe_autoconfig = repository_rule( attrs = { "bazel_rc_version": attr.string( - doc = ("Optional. An rc version to use. Note an installer for the rc " + - "must be available in https://releases.bazel.build."), + doc = ("Optional. An rc version to use. Note an installer for " + + "the rc must be available in https://releases.bazel.build."), ), "bazel_version": attr.string( default = "local", doc = ("The version of Bazel to use to generate toolchain configs." + "Use only (major, minor, patch), e.g., '0.20.0'."), ), - "bazel_version_fallback": attr.string( - default = "0.22.0", - doc = ("Version to fallback to if not provided explicitly and local " + - "is non-release version."), - ), "config_dir": attr.string( - doc = ("Optional. Use only if output_base is defined. If you want to " + - "create multiple toolchain configs (for the same version of Bazel) " + - "you can use this attr to indicate a type of config (e.g., default, " + - "msan). The configs will be generated in a sub-directory when this attr " + - "is used."), + doc = ("Optional. Use only if output_base is defined. If you " + + "want to create multiple toolchain configs (for the same " + + "version of Bazel) you can use this attr to indicate a " + + "type of config (e.g., default, msan). The configs will " + + "be generated in a sub-directory when this attr is used."), + ), + "config_version": attr.string( + doc = ("The config version found for the given container and " + + "Bazel version. " + + "Used internally when use_checked_in_confs is true."), ), "digest": attr.string( - mandatory = True, - doc = ("The digest (sha256 sum) of the image to pull. For example, " + + doc = ("Optional. The digest (sha256 sum) of the image to pull. " + + "For example, " + "sha256:f1330b2f02714d3a3e98c5b1f6524fbb9c15154e44a31fb3caecb7a6ad4e8445" + ", note the digest includes 'sha256:'"), ), @@ -636,7 +627,7 @@ ), "exec_compatible_with": attr.string_list( default = _RBE_UBUNTU_EXEC_COMPAT_WITH, - doc = ("The list of constraints that will be added to the " + + doc = ("Optional. The list of constraints that will be added to the " + "toolchain in its exec_compatible_with attribute (and to " + "the platform in its constraint_values attr). For " + "example, [\"@bazel_tools//platforms:linux\"]. Default " + @@ -655,25 +646,25 @@ ), "registry": attr.string( default = _RBE_UBUNTU_REGISTRY, - doc = ("The registry to pull the container from. For example, " + + doc = ("Optional. The registry to pull the container from. For example, " + "l.gcr.io or marketplace.gcr.io. The default is the " + "value for rbe-ubuntu16-04 image."), ), "repository": attr.string( default = _RBE_UBUNTU_REPO, - doc = ("The repository to pull the container from. For example," + + doc = ("Optional. The repository to pull the container from. For example," + " google/ubuntu. The default is the " + " value for the rbe-ubuntu16-04 image."), ), - "revision": attr.string( - doc = ("The revision of the rbe-ubuntu16-04 container."), - ), "setup_cmd": attr.string( default = "cd .", doc = ("Optional. Pass an additional command that will be executed " + "(inside the container) before running bazel to generate the " + "toolchain configs"), ), + "tag": attr.string( + doc = ("Optional. The tag of the image to pull, e.g. latest."), + ), "target_compatible_with": attr.string_list( default = _RBE_UBUNTU_TARGET_COMPAT_WITH, doc = ("The list of constraints that will be added to the " + @@ -681,11 +672,6 @@ "example, [\"@bazel_tools//platforms:linux\"]. Default " + " is set to values for rbe-ubuntu16-04 container."), ), - "use_checked_in_confs": attr.bool( - default = True, - doc = ("If set to False the checked-in configs in bazel-toolchains" + - "repo are ignored and a container is allways pulled."), - ), }, environ = [ _RBE_AUTOCONF_ROOT, @@ -696,14 +682,14 @@ def rbe_autoconfig( name, bazel_version = None, - bazel_rc = None, + bazel_rc_version = None, config_dir = None, digest = None, env = None, exec_compatible_with = None, java_home = None, output_base = None, - revision = None, + tag = None, registry = None, repository = None, target_compatible_with = None, @@ -718,33 +704,39 @@ `Use only (major, minor, patch), e.g., '0.20.0'. Default is "local" which means the same version of Bazel that is currently running will be used. If local is a non release version, rbe_autoconfig will fallback - to using the latest release version (see default for bazel_version_fallback - in attrs of _rbe_autoconfig for current latest). - bazel_rc: The rc (for the given version of Bazel) to use. Must be published - in https://releases.bazel.build + to using the latest release version (see _BAZEL_VERSION_FALLBACK). + bazel_rc_version: The rc (for the given version of Bazel) to use. + Must be published in https://releases.bazel.build. E.g. 2. + config_dir: Optional. Subdirectory where configs will be copied to. + Use only if output_base is defined. + digest: Optional. The digest of the image to pull. + Should not be set if tag is used. + Must be set together with registry and repository. exec_compatible_with: Optional. List of constraints to add to the produced toolchain/platform targets (e.g., ["@bazel_tools//platforms:linux"] in the exec_compatible_with/constraint_values attrs, respectively. - digest: Optional. The digest of the image to pull. Should only be set if - a custom container is required. - Must be set together with registry and repository. + env: dict. Optional. Additional env variables that will be set when + running the Bazel command to generate the toolchain configs. + Set to values for gcr.io/cloud-marketplace/google/rbe-ubuntu16-04 container. + Does not need to be set if your custom container extends + the rbe-ubuntu16-04 container. + Should be overriden if a custom container does not extend the + rbe-ubuntu16-04 container. java_home: Optional. The location of java_home in the container. For example , '/usr/lib/jvm/java-8-openjdk-amd64'. If not set, the rule will attempt to read the JAVA_HOME env var from the container. If that is not set the rule will fail. output_base: Optional. The directory (under the project root) where the produced toolchain configs will be copied to. - config_dir: Optional. Subdirectory where configs will be copied to. - Use only if output_base is defined. + tag: Optional. The tag of the container to use. + Should not be set if digest is used. + Must be set together with registry and repository. registry: Optional. The registry from which to pull the base image. Should only be set if a custom container is required. Must be set together with digest and repository. repository: Optional. he `repository` of images to pull from. Should only be set if a custom container is required. Must be set together with registry and digest. - revision: Optional. A revision of an rbe-ubuntu16-04 container to use. - Should not be set if repository, registry and digest are used. - See gcr.io/cloud-marketplace/google/rbe-ubuntu16-04 target_compatible_with: List of constraints to add to the produced toolchain target (e.g., ["@bazel_tools//platforms:linux"]) in the target_compatible_with attr. @@ -752,49 +744,58 @@ before generating them. If set to false the rule will allways attempt to generate the configs by pulling a toolchain container and running Bazel inside. - env: dict. Optional. Additional env variables that will be set when - running the Bazel command to generate the toolchain configs. - Set to values for rbe-ubuntu16-04 container. - Does not need to be set if your custom container extends - an rbe-ubuntu16-04 container. - Should be overriden if a custom container does not extend - rbe-ubuntu16-04. """ if not output_base and config_dir: fail("config_dir can only be used when output_base is set.") - if revision and (digest or repository or registry): - fail("'revision' cannot be set if 'digest', 'repository' or " + - "'registry' are set.") - if not ((not digest and not repository and not registry) or - (digest and repository and registry)): - fail("All of 'digest', 'repository' and 'registry' or none of them " + - "must be set.") - if bazel_rc and not bazel_version: - fail("bazel_rc can only be used with bazel_version.") - if not digest: - if not revision or revision == "latest": - revision = RBE_UBUNTU16_04_LATEST - digest = public_rbe_ubuntu16_04_sha256s().get(revision, None) - if not env: - env = clang_env() - if not digest: - fail(("Could not find a valid digest for revision %s, " + - "please make sure it is declared in " + - "@bazel_toolchains//rules:toolchain_containers.bzl" % revision)) - # If the user has set a custom env, custom java_home, - # registry or repository, don't use - # checked in configs - if ((env and env != clang_env()) or - (java_home) or - (registry and registry != _RBE_UBUNTU_REGISTRY) or - (repository and repository != _RBE_UBUNTU_REPO)): - use_checked_in_confs = False + if bazel_rc_version and not bazel_version: + fail("bazel_rc_version can only be used with bazel_version.") + + # Resolve the Bazel version to use. + if not bazel_version or bazel_version == "local": + bazel_version = str(extract_version_number(_BAZEL_VERSION_FALLBACK)) + rc = parse_rc(native.bazel_version) + bazel_rc_version = rc if rc != -1 else None + + if tag and digest: + fail("'tag' and 'digest' cannot be set at the same time.") + + if not ((not digest and not tag and not repository and not registry) or + (digest and repository and registry) or + (tag and repository and registry)): + fail("All of 'digest', 'repository' and 'registry' or " + + "all of 'tag', 'repository' and 'registry' or " + + "none of them must be set.") + + # Set to defaults only if all are unset. + if not repository and not registry and not tag and not digest: + repository = _RBE_UBUNTU_REPO + registry = _RBE_UBUNTU_REGISTRY + tag = RBE_UBUNTU16_04_LATEST + + if ((registry and registry == _RBE_UBUNTU_REGISTRY) and + (repository and repository == _RBE_UBUNTU_REPO) and + (not env)): + env = clang_env() + + config_version = validateUseOfCheckedInConfigs( + registry = registry, + repository = repository, + tag = tag, + digest = digest, + use_checked_in_confs = use_checked_in_confs, + env = env, + java_home = java_home, + bazel_version = bazel_version, + bazel_rc_version = bazel_rc_version, + ) + _rbe_autoconfig( name = name, bazel_version = bazel_version, - bazel_rc = bazel_rc, + bazel_rc_version = bazel_rc_version, config_dir = config_dir, + config_version = config_version, digest = digest, env = env, exec_compatible_with = exec_compatible_with, @@ -802,7 +803,55 @@ output_base = output_base, registry = registry, repository = repository, - revision = revision, + tag = tag, target_compatible_with = target_compatible_with, - use_checked_in_confs = use_checked_in_confs, ) + +# Check if checked-in configs are available and should be used. If so, return +# the config version. Otherwise return None. +def validateUseOfCheckedInConfigs( + registry, + repository, + tag, + digest, + use_checked_in_confs, + env, + java_home, + bazel_version, + bazel_rc_version): + if not use_checked_in_confs: + return None + if registry and registry != _RBE_UBUNTU_REGISTRY: + return None + if repository and repository != _RBE_UBUNTU_REPO: + return None + if env and env != clang_env(): + return None + if java_home: + return None + if bazel_rc_version: + return None + + if tag: # Implies `digest` is not specified. + if tag == "latest": + tag = RBE_UBUNTU16_04_LATEST + digest = public_rbe_ubuntu16_04_sha256s().get(tag, None) + if not digest: # We didn't find checked-in configs in this repo. + return None + else: # Implies tag is not specified + for pair in public_rbe_ubuntu16_04_sha256s().items(): + if pair[1] == digest: + tag = pair[0] + break + if not tag: + # The given RBE Ubuntu1604 container digest is not one of the + # released ones. + return None + + # Verify a toolchain config exists for the given version of Bazel and the + # given tag of the container + config_version = public_rbe_ubuntu16_04_config_version().get(tag, None) + if not config_version or config_version != bazel_to_config_versions().get(bazel_version): + return None + + return config_version