Support prebuilt kubectl for multiple os types (linux, mac, windows)
Currently we can only configure downloading a prebuilt kubectl from a single source, meaning a single os type, in this example Linux. https://github.com/bazelbuild/rules_k8s/tree/master/toolchains/kubectl#download-a-custom-kubectl-binary
Looking at rules_nodejs they provide an api where you specify a set of urls to download the prebuilt binary from
https://github.com/bazelbuild/rules_nodejs#installation-with-a-manually-specified-version-of-nodejs-and-yarn
Then the rule will choose what one to download based on what os it's being run on.
https://github.com/bazelbuild/rules_nodejs/blob/master/internal/node/node_repositories.bzl#L124
I think a simlar approach should work perfectly here.
related: https://github.com/bazelbuild/rules_k8s/issues/231#issuecomment-476804105
hi @Toxicable , Thanks for opening this issue! This is indeed a use case that we had not considered before and which is not well supported atm. We will look at how nodejs is doing their setup to see how big is our current gap.
Here is a quick and dirty http_archive_by_os we use internally.
load("@bazel_tools//tools/build_defs/repo:utils.bzl", "patch", "workspace_and_buildfile")
def os_name(repository_ctx):
os_name = repository_ctx.os.name.lower()
if os_name.startswith("mac os"):
return "darwin"
elif os_name.find("windows") != -1:
return "windows"
elif os_name.startswith("linux"):
return "linux"
else:
fail("Unsupported operating system: " + os_name)
_http_archive_by_os_attrs = {
"url": attr.string_dict(),
"urls": attr.string_list_dict(),
"sha256": attr.string_dict(),
"strip_prefix": attr.string_dict(),
"type": attr.string(),
"build_file": attr.label(allow_single_file = True),
"build_file_content": attr.string(),
"patches": attr.label_list(default = []),
"patch_tool": attr.string(default = "patch"),
"patch_args": attr.string_list(default = ["-p0"]),
"patch_cmds": attr.string_list(default = []),
"workspace_file": attr.label(allow_single_file = True),
"workspace_file_content": attr.string(),
}
def _http_archive_by_os_impl(ctx):
"""Implementation of the http_archive rule."""
if not ctx.attr.url and not ctx.attr.urls:
fail("At least one of url and urls must be provided")
if ctx.attr.build_file and ctx.attr.build_file_content:
fail("Only one of build_file and build_file_content can be provided.")
host = os_name(ctx)
url = ctx.attr.url.get(host)
urls = ctx.attr.urls.get(host)
sha256 = ctx.attr.sha256.get(host) or ""
strip_prefix = ctx.attr.strip_prefix.get(host) or ""
all_urls = []
if url:
all_urls = url
if urls:
all_urls = [urls] + all_urls
ctx.download_and_extract(
all_urls,
"",
sha256,
ctx.attr.type,
strip_prefix,
)
patch(ctx)
workspace_and_buildfile(ctx)
http_archive_by_os = repository_rule(
implementation = _http_archive_by_os_impl,
attrs = _http_archive_by_os_attrs,
)
Use it like this (behind it works like any http_archive):
http_archive_by_os(
name = "my_repo",
url = {
"darwin": "https://xxxx",
"linux": "https://yyyy",
},
sha256 = {
"darwin": "xxxx",
"linux": "yyy",
},
)
This is actually a showstopper for a project now, so I had to roll up own rules. Issue #530 is one way to alleviate the problem since that would make it possible to use a multiplatform toolchain.
But Bazel could handle this natively! Here's my five cents.
In deps:
http_file(
name = "kubectl_v1.18.0_linux",
urls = ["https://dl.k8s.io/v1.18.0/kubernetes-client-linux-amd64.tar.gz"],
sha256 = "de31ef68385cbb4f7bb3673e529d6b47550797b986a3afec585d747207bf1eeb",
executable = True
)
In toolchain:
kubectl_toolchain(
name = "kubectl_linux",
tool = "@kubectl_v1.18.0_linux//file",
visibility = ["//visibility:public"]
)
kubectl_toolchain(
name = "kubectl_osx",
....
)
kubectl_toolchain(
name = "kubectl_windows",
....
)
toolchain(
name = "kubectl_linux_toolchain",
exec_compatible_with = [
"@platforms//os:linux",
"@platforms//cpu:x86_64",
],
target_compatible_with = [
"@platforms//os:linux",
"@platforms//cpu:x86_64",
],
toolchain = ":kubectl_linux",
toolchain_type = "@io_bazel_rules_k8s//toolchains/kubectl:toolchain_type",
)
toolchain(
name = "kubectl_osx_toolchain",
....
)
toolchain(
name = "kubectl_windows_toolchain",
....
)