Skip to content
This repository was archived by the owner on Jan 12, 2025. It is now read-only.

Commit 4d15b67

Browse files
authored
Update kubectx-kubens to install Go versions (fixes #459) (#499)
* Update kubectx-kubens to install Go versions (fixes #459) * Fix typo
1 parent 3f9164f commit 4d15b67

File tree

4 files changed

+203
-63
lines changed

4 files changed

+203
-63
lines changed

src/kubectx-kubens/devcontainer-feature.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "Kubectx and Kubens (via Github Releases)",
33
"id": "kubectx-kubens",
4-
"version": "1.0.2",
4+
"version": "1.0.3",
55
"description": "kubectx is a tool to switch between contexts (clusters) on kubectl faster. kubens is a tool to switch between Kubernetes namespaces (and configure them for kubectl) easily.",
66
"documentationURL": "https://github.com/devcontainers-contrib/features/tree/main/src/kubectx-kubens",
77
"installsAfter": [

src/kubectx-kubens/install.sh

Lines changed: 20 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -1,72 +1,33 @@
11
#!/usr/bin/env bash
22

3-
KUBCTX_KUBENS_VERSION="${VERSION:-"latest"}"
3+
KUBECTX_KUBENS_VERSION="${VERSION:-"latest"}"
44

55
set -e
66

7-
# Clean up
8-
rm -rf /var/lib/apt/lists/*
7+
source ./library_scripts.sh
8+
9+
# nanolayer is a cli utility which keeps container layers as small as possible
10+
# source code: https://github.com/devcontainers-contrib/nanolayer
11+
# `ensure_nanolayer` is a bash function that will find any existing nanolayer installations,
12+
# and if missing - will download a temporary copy that automatically get deleted at the end
13+
# of the script
14+
ensure_nanolayer nanolayer_location "v0.4.45"
915

1016
if [ "$(id -u)" -ne 0 ]; then
1117
echo -e 'Script must be run as root. Use sudo, su, or add "USER root" to your Dockerfile before running this script.'
1218
exit 1
1319
fi
1420

15-
# Checks if packages are installed and installs them if not
16-
check_packages() {
17-
if ! dpkg -s "$@" >/dev/null 2>&1; then
18-
if [ "$(find /var/lib/apt/lists/* | wc -l)" = "0" ]; then
19-
echo "Running apt-get update..."
20-
apt-get update -y
21-
fi
22-
apt-get -y install --no-install-recommends "$@"
23-
fi
24-
}
25-
26-
# Figure out correct version of a three part version number is not passed
27-
find_version_from_git_tags() {
28-
local variable_name=$1
29-
local requested_version=${!variable_name}
30-
if [ "${requested_version}" = "none" ]; then return; fi
31-
local repository=$2
32-
local prefix=${3:-"tags/v"}
33-
local separator=${4:-"."}
34-
local last_part_optional=${5:-"false"}
35-
if [ "$(echo "${requested_version}" | grep -o "." | wc -l)" != "2" ]; then
36-
local escaped_separator=${separator//./\\.}
37-
local last_part
38-
if [ "${last_part_optional}" = "true" ]; then
39-
last_part="(${escaped_separator}[0-9]+)?"
40-
else
41-
last_part="${escaped_separator}[0-9]+"
42-
fi
43-
local regex="${prefix}\\K[0-9]+${escaped_separator}[0-9]+${last_part}$"
44-
local version_list="$(git ls-remote --tags ${repository} | grep -oP "${regex}" | tr -d ' ' | tr "${separator}" "." | sort -rV)"
45-
if [ "${requested_version}" = "latest" ] || [ "${requested_version}" = "current" ] || [ "${requested_version}" = "lts" ]; then
46-
declare -g ${variable_name}="$(echo "${version_list}" | head -n 1)"
47-
else
48-
set +e
49-
declare -g ${variable_name}="$(echo "${version_list}" | grep -E -m 1 "^${requested_version//./\\.}([\\.\\s]|$)")"
50-
set -e
51-
fi
52-
fi
53-
if [ -z "${!variable_name}" ] || ! echo "${version_list}" | grep "^${!variable_name//./\\.}$" >/dev/null 2>&1; then
54-
echo -e "Invalid ${variable_name} value: ${requested_version}\nValid values:\n${version_list}" >&2
55-
exit 1
56-
fi
57-
echo "${variable_name}=${!variable_name}"
58-
}
59-
60-
find_version_from_git_tags KUBCTX_KUBENS_VERSION 'https://github.com/ahmetb/kubectx'
61-
62-
check_packages ca-certificates curl
63-
64-
curl -L -o /usr/local/bin/kubectx https://raw.githubusercontent.com/ahmetb/kubectx/v${KUBCTX_KUBENS_VERSION}/kubectx &&
65-
curl -L -o /usr/local/bin/kubens https://raw.githubusercontent.com/ahmetb/kubectx/v${KUBCTX_KUBENS_VERSION}/kubens &&
66-
chmod +x /usr/local/bin/kubectx &&
67-
chmod +x /usr/local/bin/kubens
68-
69-
# Clean up
70-
rm -rf /var/lib/apt/lists/*
21+
$nanolayer_location \
22+
install \
23+
devcontainer-feature \
24+
"ghcr.io/devcontainers-contrib/features/gh-release:1" \
25+
--option repo='ahmetb/kubectx' --option binaryNames='kubectx' --option version="$KUBECTX_KUBENS_VERSION" --option assetRegex="kubectx.*"
26+
27+
$nanolayer_location \
28+
install \
29+
devcontainer-feature \
30+
"ghcr.io/devcontainers-contrib/features/gh-release:1" \
31+
--option repo='ahmetb/kubectx' --option binaryNames='kubens' --option version="$KUBECTX_KUBENS_VERSION" --option assetRegex="kubens.*"
7132

7233
echo "Done!"

src/kubectx-kubens/library_scripts.sh

Lines changed: 179 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,179 @@
1+
#!/bin/bash -i
2+
3+
4+
clean_download() {
5+
# The purpose of this function is to download a file with minimal impact on contaier layer size
6+
# this means if no valid downloader is found (curl or wget) then we install a downloader (currently wget) in a
7+
# temporary manner, and making sure to
8+
# 1. uninstall the downloader at the return of the function
9+
# 2. revert back any changes to the package installer database/cache (for example apt-get lists)
10+
# The above steps will minimize the leftovers being created while installing the downloader
11+
# Supported distros:
12+
# debian/ubuntu/alpine
13+
14+
url=$1
15+
output_location=$2
16+
tempdir=$(mktemp -d)
17+
downloader_installed=""
18+
19+
function _apt_get_install() {
20+
tempdir=$1
21+
22+
# copy current state of apt list - in order to revert back later (minimize contianer layer size)
23+
cp -p -R /var/lib/apt/lists $tempdir
24+
apt-get update -y
25+
apt-get -y install --no-install-recommends wget ca-certificates
26+
}
27+
28+
function _apt_get_cleanup() {
29+
tempdir=$1
30+
31+
echo "removing wget"
32+
apt-get -y purge wget --auto-remove
33+
34+
echo "revert back apt lists"
35+
rm -rf /var/lib/apt/lists/*
36+
rm -r /var/lib/apt/lists && mv $tempdir/lists /var/lib/apt/lists
37+
}
38+
39+
function _apk_install() {
40+
tempdir=$1
41+
# copy current state of apk cache - in order to revert back later (minimize contianer layer size)
42+
cp -p -R /var/cache/apk $tempdir
43+
44+
apk add --no-cache wget
45+
}
46+
47+
function _apk_cleanup() {
48+
tempdir=$1
49+
50+
echo "removing wget"
51+
apk del wget
52+
}
53+
# try to use either wget or curl if one of them already installer
54+
if type curl >/dev/null 2>&1; then
55+
downloader=curl
56+
elif type wget >/dev/null 2>&1; then
57+
downloader=wget
58+
else
59+
downloader=""
60+
fi
61+
62+
# in case none of them is installed, install wget temporarly
63+
if [ -z $downloader ] ; then
64+
if [ -x "/usr/bin/apt-get" ] ; then
65+
_apt_get_install $tempdir
66+
elif [ -x "/sbin/apk" ] ; then
67+
_apk_install $tempdir
68+
else
69+
echo "distro not supported"
70+
exit 1
71+
fi
72+
downloader="wget"
73+
downloader_installed="true"
74+
fi
75+
76+
if [ $downloader = "wget" ] ; then
77+
wget -q $url -O $output_location
78+
else
79+
curl -sfL $url -o $output_location
80+
fi
81+
82+
# NOTE: the cleanup procedure was not implemented using `trap X RETURN` only because
83+
# alpine lack bash, and RETURN is not a valid signal under sh shell
84+
if ! [ -z $downloader_installed ] ; then
85+
if [ -x "/usr/bin/apt-get" ] ; then
86+
_apt_get_cleanup $tempdir
87+
elif [ -x "/sbin/apk" ] ; then
88+
_apk_cleanup $tempdir
89+
else
90+
echo "distro not supported"
91+
exit 1
92+
fi
93+
fi
94+
95+
}
96+
97+
98+
ensure_nanolayer() {
99+
# Ensure existance of the nanolayer cli program
100+
local variable_name=$1
101+
102+
local required_version=$2
103+
# normalize version
104+
if ! [[ $required_version == v* ]]; then
105+
required_version=v$required_version
106+
fi
107+
108+
local nanolayer_location=""
109+
110+
# If possible - try to use an already installed nanolayer
111+
if [[ -z "${NANOLAYER_FORCE_CLI_INSTALLATION}" ]]; then
112+
if [[ -z "${NANOLAYER_CLI_LOCATION}" ]]; then
113+
if type nanolayer >/dev/null 2>&1; then
114+
echo "Found a pre-existing nanolayer in PATH"
115+
nanolayer_location=nanolayer
116+
fi
117+
elif [ -f "${NANOLAYER_CLI_LOCATION}" ] && [ -x "${NANOLAYER_CLI_LOCATION}" ] ; then
118+
nanolayer_location=${NANOLAYER_CLI_LOCATION}
119+
echo "Found a pre-existing nanolayer which were given in env variable: $nanolayer_location"
120+
fi
121+
122+
# make sure its of the required version
123+
if ! [[ -z "${nanolayer_location}" ]]; then
124+
local current_version
125+
current_version=$($nanolayer_location --version)
126+
if ! [[ $current_version == v* ]]; then
127+
current_version=v$current_version
128+
fi
129+
130+
if ! [ $current_version == $required_version ]; then
131+
echo "skipping usage of pre-existing nanolayer. (required version $required_version does not match existing version $current_version)"
132+
nanolayer_location=""
133+
fi
134+
fi
135+
136+
fi
137+
138+
# If not previuse installation found, download it temporarly and delete at the end of the script
139+
if [[ -z "${nanolayer_location}" ]]; then
140+
141+
if [ "$(uname -sm)" == "Linux x86_64" ] || [ "$(uname -sm)" == "Linux aarch64" ]; then
142+
tmp_dir=$(mktemp -d -t nanolayer-XXXXXXXXXX)
143+
144+
clean_up () {
145+
ARG=$?
146+
rm -rf $tmp_dir
147+
exit $ARG
148+
}
149+
trap clean_up EXIT
150+
151+
152+
if [ -x "/sbin/apk" ] ; then
153+
clib_type=musl
154+
else
155+
clib_type=gnu
156+
fi
157+
158+
tar_filename=nanolayer-"$(uname -m)"-unknown-linux-$clib_type.tgz
159+
160+
# clean download will minimize leftover in case a downloaderlike wget or curl need to be installed
161+
clean_download https://github.com/devcontainers-contrib/cli/releases/download/$required_version/$tar_filename $tmp_dir/$tar_filename
162+
163+
tar xfzv $tmp_dir/$tar_filename -C "$tmp_dir"
164+
chmod a+x $tmp_dir/nanolayer
165+
nanolayer_location=$tmp_dir/nanolayer
166+
167+
168+
else
169+
echo "No binaries compiled for non-x86-linux architectures yet: $(uname -m)"
170+
exit 1
171+
fi
172+
fi
173+
174+
# Expose outside the resolved location
175+
declare -g ${variable_name}=$nanolayer_location
176+
177+
}
178+
179+

test/kubectx-kubens/test.sh

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,9 @@ set -e
44

55
source dev-container-features-test-lib
66

7-
# we are simply checking existance for now.
7+
# we are simply checking version for now.
88
# full operability depends on the existance of kubectl.
9-
check "kubectx existance" which kubectx
10-
check "kubens existance" which kubens
9+
check "kubectx version" kubectx --version
10+
check "kubens version" kubens --version
1111

1212
reportResults

0 commit comments

Comments
 (0)