Skip to content

Commit 048341b

Browse files
committed
kubeconfig_configure refactor
1 parent 107ead8 commit 048341b

File tree

6 files changed

+398
-236
lines changed

6 files changed

+398
-236
lines changed

README.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@ When you run `bazel run ///helloworld:mynamespace.apply`, it applies this file i
103103
| ***objects*** | `[]` | A list of other instances of `k8s_deploy` that this one depends on. See [Adding Dependencies](#adding-dependencies).
104104
| ***images*** | `{}` | A dict of labels of Docker images. See [Injecting Docker Images](#injecting-docker-images).
105105
| ***image_digest_tag*** | `False` | A flag for whether or not to tag the image with the container digest.
106-
| ***image_registry*** | `docker.io` | The registry to push images to.
106+
| ***image_registry*** | `docker.io` | The registry to push images to.
107107
| ***image_repository*** | `None` | The repository to push images to. By default, this is generated from the current package path.
108108
| ***image_repository_prefix*** | `None` | Add a prefix to the image_repository. Can be used to upload the images in
109109
| ***release_branch_prefix*** | `master` | A git branch name/prefix. Automatically run GitOps while building this branch. See [GitOps and Deployment](#gitops_and_deployment).
@@ -288,7 +288,7 @@ spec:
288288
- name: java_container
289289
image: registry.example.com/examples/image@sha256:c94d75d68f4c1b436f545729bbce82774fda07
290290
```
291-
Image substitutions for Custom Resource Definitions (CRD) resources could also use target references directly. Their digests are availabe through string substitution. For example,
291+
Image substitutions for Custom Resource Definitions (CRD) resources could also use target references directly. Their digests are availabe through string substitution. For example,
292292
```yaml
293293
apiVersion: v1
294294
kind: MyCrd
@@ -300,7 +300,7 @@ metadata:
300300
spec:
301301
image: "{{//example:my_image}}"
302302
```
303-
would become
303+
would become
304304
```yaml
305305
apiVersion: v1
306306
kind: MyCrd
@@ -381,7 +381,7 @@ The `k8s_test_setup` rule produces a shell script which creates a temporary name
381381

382382
The output of the `k8s_test_setup` rule (a shell script) is referenced in the `java_test` rule. It's listed under the `data` attribute, which declares the target as a dependency, and is included in the jvm flags in this clause: `$(location :service_it.setup)`. The "location" function is specific to Bazel: given a target, it returns the path to the file produced by that target. In this case, it returns the path to the shell script created by our `k8s_test_setup` rule.
383383

384-
The test code launches the script to perform the test setup. The tes code should also monitor the script console output to listen to the pod readiness events.
384+
The test code launches the script to perform the test setup. The test code should also monitor the script console output to listen to the pod readiness events.
385385

386386

387387
## Building & Testing

examples/WORKSPACE

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,9 +36,9 @@ go_image_repositories()
3636
#
3737
# Kubeconfig repository that will be used in k8s_test_setup
3838
#
39-
load("@com_adobe_rules_gitops//gitops:defs.bzl", "kubeconfig")
39+
load("@com_adobe_rules_gitops//gitops:defs.bzl", "kubeconfig_configure")
4040

41-
kubeconfig(
41+
kubeconfig_configure(
4242
name = "k8s_test",
4343
cluster = "kind-kind",
4444
user = "kind-kind", # kind cluster user name

gitops/defs.bzl

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,14 @@ load(
1616
"@com_adobe_rules_gitops//skylib:k8s.bzl",
1717
_k8s_deploy = "k8s_deploy",
1818
_k8s_test_setup = "k8s_test_setup",
19+
)
20+
load(
21+
"@com_adobe_rules_gitops//skylib:kubeconfig.bzl",
1922
_kubeconfig = "kubeconfig",
23+
_kubeconfig_configure = "kubeconfig_configure",
2024
)
2125

2226
k8s_deploy = _k8s_deploy
2327
k8s_test_setup = _k8s_test_setup
2428
kubeconfig = _kubeconfig
29+
kubeconfig_configure = _kubeconfig_configure

skylib/k8s.bzl

Lines changed: 1 addition & 213 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ load(
2020
"kustomize",
2121
kustomize_gitops = "gitops",
2222
)
23+
load("//skylib:kubeconfig.bzl", "KubeconfigInfo")
2324
load("//skylib:push.bzl", "k8s_container_push")
2425

2526
def _runfiles(ctx, f):
@@ -275,219 +276,6 @@ def k8s_deploy(
275276
visibility = visibility,
276277
)
277278

278-
KubeconfigInfo = provider(fields = [
279-
"server",
280-
"cluster",
281-
"user",
282-
])
283-
284-
def _kubeconfig_file_impl(ctx):
285-
kubeconfig_file = ctx.actions.declare_file(ctx.label.name)
286-
ctx.actions.symlink(output = kubeconfig_file, target_file = ctx.file.config)
287-
files = depset(direct = [kubeconfig_file])
288-
runfiles = ctx.runfiles(files = [kubeconfig_file])
289-
return [
290-
DefaultInfo(files = files, runfiles = runfiles),
291-
KubeconfigInfo(
292-
server = ctx.attr.server,
293-
cluster = ctx.attr.cluster,
294-
user = ctx.attr.user,
295-
),
296-
]
297-
298-
kubeconfig_file = rule(
299-
implementation = _kubeconfig_file_impl,
300-
attrs = {
301-
"config": attr.label(
302-
doc = "Config file.",
303-
allow_single_file = True,
304-
mandatory = True,
305-
),
306-
"server": attr.string(
307-
doc = "Optional Kubernetes server url.",
308-
mandatory = False,
309-
),
310-
"cluster": attr.string(
311-
doc = "Optional Kubernetes cluster name.",
312-
mandatory = False,
313-
),
314-
"user": attr.string(
315-
doc = "Optional Kubernetes user name.",
316-
mandatory = True,
317-
),
318-
},
319-
provides = [DefaultInfo, KubeconfigInfo],
320-
)
321-
322-
_KUBECONFIG_BUILD_TEMPLATE = """# Generated by kubeconfig repostiory rule
323-
324-
load("@com_adobe_rules_gitops//skylib:k8s.bzl", "kubeconfig_file")
325-
326-
exports_files(["kubectl"])
327-
328-
kubeconfig_file(
329-
name = "kubeconfig",
330-
config = ":config",
331-
server = "{server}",
332-
cluster = "{cluster}",
333-
user = "{user}",
334-
visibility = ["//visibility:public"],
335-
)
336-
"""
337-
338-
# kubectl template
339-
def _kubectl_config(repository_ctx, args):
340-
kubectl = repository_ctx.path("kubectl")
341-
kubeconfig_yaml = repository_ctx.path("config")
342-
exec_result = repository_ctx.execute(
343-
[kubectl, "--kubeconfig", kubeconfig_yaml, "config"] + args,
344-
environment = {
345-
# prevent kubectl config to stumble on shared .kube/config.lock file
346-
"HOME": str(repository_ctx.path(".")),
347-
},
348-
quiet = True,
349-
)
350-
if exec_result.return_code != 0:
351-
fail("Error executing kubectl config %s" % " ".join(args))
352-
353-
def _kubeconfig_impl(repository_ctx):
354-
"""Find local kubernetes certificates"""
355-
356-
# find and symlink kubectl
357-
kubectl = repository_ctx.which("kubectl")
358-
if not kubectl:
359-
fail("Unable to find kubectl executable. PATH=%s" % repository_ctx.path)
360-
repository_ctx.symlink(kubectl, "kubectl")
361-
362-
home = repository_ctx.path(repository_ctx.os.environ["HOME"])
363-
364-
# use provided user name or fall back to current os user name
365-
if repository_ctx.attr.user:
366-
user = repository_ctx.attr.user
367-
elif "USER" in repository_ctx.os.environ:
368-
user = repository_ctx.os.environ["USER"]
369-
else:
370-
exec_result = repository_ctx.execute(["whoami"])
371-
if exec_result.return_code != 0:
372-
fail("Error detecting current user")
373-
user = exec_result.stdout.rstrip()
374-
375-
token = None
376-
ca_crt = None
377-
kubecert_cert = None
378-
kubecert_key = None
379-
server = repository_ctx.attr.server
380-
config = None
381-
382-
# check service account first
383-
serviceaccount = repository_ctx.path("/var/run/secrets/kubernetes.io/serviceaccount")
384-
if serviceaccount.exists:
385-
ca_crt = "/var/run/secrets/kubernetes.io/serviceaccount/ca.crt"
386-
token_file = serviceaccount.get_child("token")
387-
if token_file.exists:
388-
exec_result = repository_ctx.execute(["cat", token_file.realpath])
389-
if exec_result.return_code != 0:
390-
fail("Error reading user token")
391-
token = exec_result.stdout.rstrip()
392-
393-
# use master url from the environemnt
394-
if "KUBERNETES_SERVICE_HOST" in repository_ctx.os.environ:
395-
server = "https://%s:%s" % (
396-
repository_ctx.os.environ["KUBERNETES_SERVICE_HOST"],
397-
repository_ctx.os.environ["KUBERNETES_SERVICE_PORT"],
398-
)
399-
else:
400-
# fall back to the default
401-
server = "https://kubernetes.default"
402-
else:
403-
# check kubectl config file
404-
config = home.get_child(".kube").get_child("config")
405-
406-
if config and config.exists:
407-
# symlink ~/.kube/config if this file exists
408-
repository_ctx.symlink(config, repository_ctx.path("config"))
409-
else:
410-
# generate new config file service account token or certificates
411-
certs = home.get_child(".kube").get_child("certs")
412-
ca_crt = certs.get_child("ca.crt").realpath
413-
kubecert_cert = certs.get_child("kubecert.cert")
414-
kubecert_key = certs.get_child("kubecert.key")
415-
416-
# config set-cluster {cluster} \
417-
# --certificate-authority=... \
418-
# --server=https://dev3.k8s.tubemogul.info:443 \
419-
# --embed-certs",
420-
_kubectl_config(repository_ctx, [
421-
"set-cluster",
422-
repository_ctx.attr.cluster,
423-
"--server",
424-
server,
425-
"--certificate-authority",
426-
ca_crt,
427-
])
428-
429-
# config set-credentials {user} --token=...",
430-
if token:
431-
_kubectl_config(repository_ctx, [
432-
"set-credentials",
433-
user,
434-
"--token",
435-
token,
436-
])
437-
438-
# config set-credentials {user} --client-certificate=...",
439-
if kubecert_cert and kubecert_cert.exists:
440-
_kubectl_config(repository_ctx, [
441-
"set-credentials",
442-
user,
443-
"--client-certificate",
444-
kubecert_cert.realpath,
445-
])
446-
447-
# config set-credentials {user} --client-key=...",
448-
if kubecert_key and kubecert_key.exists:
449-
_kubectl_config(repository_ctx, [
450-
"set-credentials",
451-
user,
452-
"--client-key",
453-
kubecert_key.realpath,
454-
])
455-
456-
# export repostory contents
457-
repository_ctx.file("BUILD", _KUBECONFIG_BUILD_TEMPLATE.format(
458-
cluster = repository_ctx.attr.cluster,
459-
server = repository_ctx.attr.server,
460-
user = user,
461-
), False)
462-
463-
return {
464-
"cluster": repository_ctx.attr.cluster,
465-
"server": repository_ctx.attr.server,
466-
"user": user,
467-
}
468-
469-
kubeconfig = repository_rule(
470-
attrs = {
471-
"cluster": attr.string(
472-
mandatory = True,
473-
),
474-
"server": attr.string(
475-
mandatory = False,
476-
),
477-
"user": attr.string(
478-
mandatory = False,
479-
),
480-
},
481-
environ = [
482-
"HOME",
483-
"USER",
484-
"KUBERNETES_SERVICE_HOST",
485-
"KUBERNETES_SERVICE_PORT",
486-
],
487-
local = True,
488-
implementation = _kubeconfig_impl,
489-
)
490-
491279
def _stamp(ctx, string, output):
492280
stamps = [ctx.file._info_file]
493281
stamp_args = [

skylib/k8s_test_namespace.sh.tpl

Lines changed: 26 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
# governing permissions and limitations under the License.
1111

1212
set -euo pipefail
13+
1314
[ -o xtrace ] && env
1415

1516
function guess_runfiles() {
@@ -39,8 +40,25 @@ echo "Cluster: ${CLUSTER}" >&2
3940
# use BUILD_USER by defalt
4041
USER=${USER:-$BUILD_USER}
4142

43+
# create miniified self-contained kubectl configuration with the default context set to use newly created namespace
44+
mkdir -p $(dirname $KUBECONFIG_FILE)
45+
46+
# create context partion of new kubeconfig file from scratch
47+
# use --kubeconfig parameter to prevent any merging
48+
# create
49+
rm -f $KUBECONFIG_FILE-context
50+
CONTEXT=$CLUSTER-$BUILD_USER
51+
kubectl --kubeconfig=$KUBECONFIG_FILE-context --cluster=$CLUSTER --server=$SERVER --user=$USER --namespace=$BUILD_USER config set-context $CONTEXT >&2
52+
kubectl --kubeconfig=$KUBECONFIG_FILE-context config use-context $CONTEXT >&2
53+
54+
# merge newly generated context with system kubeconfig, flatten and minify the result
55+
KUBECONFIG=$KUBECONFIG_FILE-context:$KUBECONFIG kubectl config view --merge=true --minify=true --flatten=true --raw >$KUBECONFIG_FILE
56+
57+
# set generated kubeconfig for all following kubectl commands
58+
export KUBECONFIG=$KUBECONFIG_FILE
59+
4260
# check if username from provided configuration exists
43-
KUBECONFIG_USER=$(${KUBECTL} --kubeconfig=${KUBECONFIG} config view -o jsonpath='{.users[?(@.name == '"\"${USER}\")].name}")
61+
KUBECONFIG_USER=$(${KUBECTL} config view -o jsonpath='{.users[?(@.name == '"\"${USER}\")].name}")
4462
if [ -z "${KUBECONFIG_USER}" ]; then
4563
echo "Unable to find user configuration ${USER} for cluster ${CLUSTER}" >&2
4664
exit 1
@@ -64,13 +82,18 @@ else
6482
COUNT="0"
6583
while true; do
6684
NAMESPACE=${BUILD_USER}-$(( (RANDOM) + 32767 ))
67-
${KUBECTL} --kubeconfig=${KUBECONFIG} --cluster=${CLUSTER} --server=${SERVER} --user=${USER} create namespace ${NAMESPACE} && break
85+
${KUBECTL} create namespace ${NAMESPACE} && break
6886
COUNT=$[$COUNT + 1]
6987
if [ $COUNT -ge 10 ]; then
7088
echo "Unable to create namespace in $COUNT attempts!" >&2
7189
exit 1
7290
fi
7391
done
92+
# update context with created test namespace
93+
kubectl --namespace=$NAMESPACE config set-context $CONTEXT >&2
94+
95+
# rename test context (Note: this is required for backward compatibiliy)
96+
kubectl config rename-context $CONTEXT $CLUSTER-$NAMESPACE >&2
7497
fi
7598
echo "Namespace: ${NAMESPACE}" >&2
7699
set -e
@@ -79,21 +102,7 @@ set -e
79102
mkdir -p $(dirname $NAMESPACE_NAME_FILE)
80103
echo $NAMESPACE > $NAMESPACE_NAME_FILE
81104

82-
# create miniified self-contained kubectl configuration with the default context set to use newly created namespace
83-
mkdir -p $(dirname $KUBECONFIG_FILE)
84-
85-
# create context partion of new kubeconfig file from scratch
86-
# use --kubeconfig parameter to prevent any merging
87-
rm -f $KUBECONFIG_FILE-context
88-
CONTEXT=$CLUSTER-$NAMESPACE
89-
kubectl --kubeconfig=$KUBECONFIG_FILE-context --cluster=$CLUSTER --server=${SERVER} --user=$USER --namespace=$NAMESPACE config set-context $CONTEXT >&2
90-
kubectl --kubeconfig=$KUBECONFIG_FILE-context config use-context $CONTEXT >&2
91-
92-
# merge newly generated context with system kubeconfig, flatten and minify the result
93-
KUBECONFIG=$KUBECONFIG_FILE-context:$KUBECONFIG kubectl config view --merge=true --minify=true --flatten=true --raw >$KUBECONFIG_FILE
94-
95-
# set generated kubeconfig for all following kubectl commands
96-
export KUBECONFIG=$KUBECONFIG_FILE
105+
[ -o xtrace ] && kubectl config view >&2
97106

98107
# set runfiles for STMTS
99108
export PYTHON_RUNFILES=${RUNFILES}

0 commit comments

Comments
 (0)