From ff2cbf09ae1f0a9c7ebdfc1fa337044158a7f57b Mon Sep 17 00:00:00 2001 From: Nicolas Lopez Date: Wed, 21 Nov 2018 15:46:58 -0500 Subject: [PATCH] Enable building kubectl hermetically as part of toolchain setup (#229) * adding option to build kubectl from src * trying to build kubectl * remove kwargs from http_file call * using a newer version of kubernetes * use src version of kubectl in rules * run buildifier * fixing issue with e2e tests not finding tool * moving validation of toolchain attrs to toolchain rule * missin period * more missing periods * fixing resolution of kubectl path * fixning last issue with kubectl binary resolution --- k8s/k8s.bzl | 10 ++- k8s/object.bzl | 6 +- toolchains/kubectl/BUILD | 6 +- .../kubectl/{BUILD.tpl => BUILD.path.tpl} | 0 toolchains/kubectl/BUILD.target.tpl | 25 +++++++ toolchains/kubectl/kubectl_configure.bzl | 75 +++++++++++++++++-- toolchains/kubectl/kubectl_toolchain.bzl | 13 +++- 7 files changed, 120 insertions(+), 15 deletions(-) rename toolchains/kubectl/{BUILD.tpl => BUILD.path.tpl} (100%) create mode 100644 toolchains/kubectl/BUILD.target.tpl diff --git a/k8s/k8s.bzl b/k8s/k8s.bzl index 54b44e10..8e2e2221 100644 --- a/k8s/k8s.bzl +++ b/k8s/k8s.bzl @@ -35,13 +35,15 @@ py_library( strip_prefix = "PyYAML-3.12/lib/yaml", ) - # Register the default kubectl toolchain that expects the 'kubectl' - # executable to be in the PATH + # Register the default kubectl toolchain targets for supported platforms + # note these work with the autoconfigured toolchain native.register_toolchains( "@io_bazel_rules_k8s//toolchains/kubectl:kubectl_linux_toolchain", "@io_bazel_rules_k8s//toolchains/kubectl:kubectl_osx_toolchain", "@io_bazel_rules_k8s//toolchains/kubectl:kubectl_windows_toolchain", ) - # WORKSPACE target to configure the kubectl tool - kubectl_configure(name = "local_k8s_config") + excludes = native.existing_rules().keys() + if "k8s_config" not in excludes: + # WORKSPACE target to configure the kubectl tool + kubectl_configure(name = "k8s_config", build_srcs = True) diff --git a/k8s/object.bzl b/k8s/object.bzl index bd01e1bd..a0491dd2 100644 --- a/k8s/object.bzl +++ b/k8s/object.bzl @@ -173,9 +173,13 @@ def _common_impl(ctx): namespace_arg = "--namespace=\"" + namespace_arg + "\"" kubectl_tool_info = ctx.toolchains["@io_bazel_rules_k8s//toolchains/kubectl:toolchain_type"].kubectlinfo + kubectl_tool = kubectl_tool_info.tool_path + if not kubectl_tool_info.tool_path: + kubectl_tool = _runfiles(ctx, kubectl_tool_info.tool_target.files.to_list()[0]) + files += kubectl_tool_info.tool_target.files.to_list() substitutions = { - "%{kubectl_tool}": kubectl_tool_info.tool_path, + "%{kubectl_tool}": kubectl_tool, "%{cluster}": cluster_arg, "%{context}": context_arg, "%{user}": user_arg, diff --git a/toolchains/kubectl/BUILD b/toolchains/kubectl/BUILD index bb8606f8..d1052854 100644 --- a/toolchains/kubectl/BUILD +++ b/toolchains/kubectl/BUILD @@ -32,7 +32,7 @@ toolchain( "@bazel_tools//platforms:linux", "@bazel_tools//platforms:x86_64", ], - toolchain = "@local_k8s_config//:toolchain", + toolchain = "@k8s_config//:toolchain", toolchain_type = ":toolchain_type", ) @@ -42,7 +42,7 @@ toolchain( "@bazel_tools//platforms:osx", "@bazel_tools//platforms:x86_64", ], - toolchain = "@local_k8s_config//:toolchain", + toolchain = "@k8s_config//:toolchain", toolchain_type = ":toolchain_type", ) @@ -52,6 +52,6 @@ toolchain( "@bazel_tools//platforms:windows", "@bazel_tools//platforms:x86_64", ], - toolchain = "@local_k8s_config//:toolchain", + toolchain = "@k8s_config//:toolchain", toolchain_type = ":toolchain_type", ) diff --git a/toolchains/kubectl/BUILD.tpl b/toolchains/kubectl/BUILD.path.tpl similarity index 100% rename from toolchains/kubectl/BUILD.tpl rename to toolchains/kubectl/BUILD.path.tpl diff --git a/toolchains/kubectl/BUILD.target.tpl b/toolchains/kubectl/BUILD.target.tpl new file mode 100644 index 00000000..4d504181 --- /dev/null +++ b/toolchains/kubectl/BUILD.target.tpl @@ -0,0 +1,25 @@ +# Copyright 2018 The Bazel Authors. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +""" +This BUILD file is auto-generated from toolchains/kubectl/BUILD.tpl +""" + +package(default_visibility = ["//visibility:public"]) + +load("@io_bazel_rules_k8s//toolchains/kubectl:kubectl_toolchain.bzl", "kubectl_toolchain") + +kubectl_toolchain( + name = "toolchain", + tool_target = "%{KUBECTL_TARGET}", +) diff --git a/toolchains/kubectl/kubectl_configure.bzl b/toolchains/kubectl/kubectl_configure.bzl index 081251fb..7b5146c1 100644 --- a/toolchains/kubectl/kubectl_configure.bzl +++ b/toolchains/kubectl/kubectl_configure.bzl @@ -16,16 +16,79 @@ Defines a repository rule for configuring the kubectl tool. """ def _impl(repository_ctx): - - kubectl_tool_path = repository_ctx.which("kubectl") + substitutions = None + label = None + if repository_ctx.attr.build_srcs: + kubectl_target = "@io_kubernetes//cmd/kubectl:kubectl" + substitutions = {"%{KUBECTL_TARGET}": "%s" % kubectl_target} + template = Label("@io_bazel_rules_k8s//toolchains/kubectl:BUILD.target.tpl") + else: + kubectl_tool_path = repository_ctx.which("kubectl") + substitutions = {"%{KUBECTL_TOOL}": "%s" % kubectl_tool_path} + template = Label("@io_bazel_rules_k8s//toolchains/kubectl:BUILD.path.tpl") repository_ctx.template( "BUILD", - Label("@io_bazel_rules_k8s//toolchains/kubectl:BUILD.tpl"), - {"%{KUBECTL_TOOL}": "%s" % kubectl_tool_path}, - False + template, + substitutions, + False, ) -kubectl_configure = repository_rule( +_kubectl_configure = repository_rule( implementation = _impl, + attrs = { + "build_srcs": attr.bool( + doc = "Optional. Set to true to build kubectl from sources.", + default = False, + mandatory = False, + ), + }, ) + +load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") + +def kubectl_configure(name, **kwargs): + """ + Creates an external repository with a kubectl_toolchain target + properly configured. + + Args: + **kwargs: + Required Args + name: A unique name for this rule. + Default Args: + build_srcs: Optional. Set to true to build kubectl from sources. Default: False + k8s_commit: Otional. Commit / release tag at which to build kubectl + from. Default "v1.13.0-beta.1" + k8s_sha256: Otional. sha256 of commit at which to build kubectl from. + Default . + k8s_prefix: Otional. Prefix to strip from commit / release archive. + Typically the same as the commit, or Kubernetes-. + Default . + Note: Not all versions/commits of kubernetes project can be used to compile + kubectl from an external repo. Notably, we have only tested with v1.13.0-beta.1 + or above. Note this rule has a hardcoded pointer to io_kubernetes_build repo + if your commit (above v1.13.0-beta.1) does not work due to problems, + related to @io_kubernetes_build repo, please send a PR to update these values. + """ + build_srcs = False + if "build_srcs" in kwargs and kwargs["build_srcs"]: + build_srcs = True + + # We keep these defaults here as they are only used by in this macro and not by the repo rule. + k8s_commit = kwargs["k8s_commit"] if "k8s_commit" in kwargs else "v1.13.0-beta.1" + k8s_sha256 = kwargs["k8s_sha256"] if "k8s_sha256" in kwargs else "dfb39ce36284c1ce228954ca12bf016c09be61e40a875e8af4fff84e116bd3a7" + k8s_prefix = kwargs["k8s_prefix"] if "k8s_prefix" in kwargs else "kubernetes-1.13.0-beta.1" + http_archive( + name = "io_kubernetes", + sha256 = k8s_sha256, + strip_prefix = k8s_prefix, + urls = [("https://github.com/kubernetes/kubernetes/archive/%s.tar.gz" % k8s_commit)], + ) + http_archive( + name = "io_kubernetes_build", + sha256 = "21160531ea8a9a4001610223ad815622bf60671d308988c7057168a495a7e2e8", + strip_prefix = "repo-infra-b4bc4f1552c7fc1d4654753ca9b0e5e13883429f", + urls = ["https://github.com/kubernetes/repo-infra/archive/b4bc4f1552c7fc1d4654753ca9b0e5e13883429f.tar.gz"], + ) + _kubectl_configure(name = name, build_srcs = build_srcs) diff --git a/toolchains/kubectl/kubectl_toolchain.bzl b/toolchains/kubectl/kubectl_toolchain.bzl index 5b1adeab..012c5342 100644 --- a/toolchains/kubectl/kubectl_toolchain.bzl +++ b/toolchains/kubectl/kubectl_toolchain.bzl @@ -19,13 +19,17 @@ KubectlInfo = provider( doc = "Information about how to invoke the kubectl tool.", fields = { "tool_path": "Path to the kubectl executable", + "tool_target": "Target to build kubectl executable", }, ) def _kubectl_toolchain_impl(ctx): + if not ctx.attr.tool_path and not ctx.attr.tool_target: + fail("Invalid kubectl_toolchain. kubectl_toolchain must have either tool_path or tool_target.") toolchain_info = platform_common.ToolchainInfo( kubectlinfo = KubectlInfo( tool_path = ctx.attr.tool_path, + tool_target = ctx.attr.tool_target, ), ) return [toolchain_info] @@ -33,6 +37,13 @@ def _kubectl_toolchain_impl(ctx): kubectl_toolchain = rule( implementation = _kubectl_toolchain_impl, attrs = { - "tool_path": attr.string(), + "tool_path": attr.string( + doc = "Absolute path to a pre-installed kubectl binary.", + mandatory = False, + ), + "tool_target": attr.label( + doc = "Target to build kubectl from source.", + mandatory = False, + ), }, )