From 5a322516318e107ee474903066b4ccaba5dfe6b7 Mon Sep 17 00:00:00 2001 From: Atanas Todorov Date: Thu, 9 Jan 2025 15:26:29 +0200 Subject: [PATCH 1/4] TNZ-26666KCP provider skeleton + starlark example --- README.md | 1 + examples/kcp_provider.crsh | 20 ++++++++++++++++ starlark/kcp_provider.go | 48 ++++++++++++++++++++++++++++++++++++++ starlark/kube_config.go | 2 +- starlark/starlark_exec.go | 2 +- starlark/support.go | 2 ++ 6 files changed, 73 insertions(+), 2 deletions(-) create mode 100644 examples/kcp_provider.crsh create mode 100644 starlark/kcp_provider.go diff --git a/README.md b/README.md index 032a01dd..b97009cb 100644 --- a/README.md +++ b/README.md @@ -110,6 +110,7 @@ Crashd utilizes the concept of a provider to enumerate compute resources. Each i * *Kubernetes Nodes Provider* - extracts host information from a Kubernetes API node objects * *CAPV Provider* - uses Cluster-API to discover machines in vSphere cluster * *CAPA Provider* - uses Cluster-API to discover machines running on AWS +* *KCP Provider* - generates kubeconfig with all contexts for all KCP workspaces. * More providers coming! diff --git a/examples/kcp_provider.crsh b/examples/kcp_provider.crsh new file mode 100644 index 00000000..174fae4b --- /dev/null +++ b/examples/kcp_provider.crsh @@ -0,0 +1,20 @@ +## @copyright Copyright Broadcom. All Rights Reserved. +## The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. +## @license For licensing, see LICENSE.md. + +# object kinds to capture +kinds = [ +"SRS", +] + +def capture_kcp_objects(): + kcp_provider_result=kcp_provider(kcp_admin_secret_namespace="",kcp_admin_secret_name="") + contexts = kcp_provider_result.get("contexts") + # capture kubernetes objects in all kcp logical clusters + for context in contexts: + print("Capturing kcp objects for ", context) + config = kube_config(capi_provider=kcp_provider,cluster_context=context) + kube_capture(kube_config=config,what="objects", kinds=[kind], namespaces=namespace) + +def main(): + capture_kcp_objects() \ No newline at end of file diff --git a/starlark/kcp_provider.go b/starlark/kcp_provider.go new file mode 100644 index 00000000..42d4d6b8 --- /dev/null +++ b/starlark/kcp_provider.go @@ -0,0 +1,48 @@ +// Copyright (c) 2020 VMware, Inc. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +package starlark + +import ( + "context" + "fmt" + + "github.com/pkg/errors" + "go.starlark.net/starlark" + "go.starlark.net/starlarkstruct" +) + +// KcpProviderFn is a built-in starlark function that create a kubeconfig with all contexts for all KCP logical clusters +// Starlark format: kcp_provider(ucp_admin_secret_name= ucp_admin_secret_namespace=) +func KcpProviderFn(thread *starlark.Thread, _ *starlark.Builtin, args starlark.Tuple, kwargs []starlark.Tuple) (starlark.Value, error) { + + var ( + kcp_admin_secret_name, kcp_admin_secret_namespace string + ) + + err := starlark.UnpackArgs("kcp_provider", args, kwargs, + "kcp_admin_secret_namespace", &kcp_admin_secret_namespace, + "kcp_admin_secret_name", &kcp_admin_secret_name) + if err != nil { + return starlark.None, errors.Wrap(err, "failed to unpack input arguments") + } + + ctx, ok := thread.Local(identifiers.scriptCtx).(context.Context) + if !ok || ctx == nil { + return starlark.None, fmt.Errorf("script context not found") + } + + var kcpKubeConfigPath string + //TODO Generate a KCP admin kubeconfig + + // dictionary for capa provider struct + kcpProviderDict := starlark.StringDict{ + "kind": starlark.String(identifiers.capaProvider), + "kube_config": starlark.String(kcpKubeConfigPath), + } + + var contexts []starlark.Value + kcpProviderDict["contexts"] = starlark.NewList(contexts) + + return starlarkstruct.FromStringDict(starlark.String(identifiers.kcpProvider), kcpProviderDict), nil +} diff --git a/starlark/kube_config.go b/starlark/kube_config.go index 8b424b10..ee2719d6 100644 --- a/starlark/kube_config.go +++ b/starlark/kube_config.go @@ -37,7 +37,7 @@ func KubeConfigFn(_ *starlark.Thread, _ *starlark.Builtin, args starlark.Tuple, val := provider.Constructor() if constructor, ok := val.(starlark.String); ok { constStr := constructor.GoString() - if constStr != identifiers.capvProvider && constStr != identifiers.capaProvider { + if constStr != identifiers.capvProvider && constStr != identifiers.capaProvider && constStr != identifiers.kcpProvider { return starlark.None, errors.New("unknown capi provider") } } diff --git a/starlark/starlark_exec.go b/starlark/starlark_exec.go index 2120ce9b..450d20fa 100644 --- a/starlark/starlark_exec.go +++ b/starlark/starlark_exec.go @@ -137,7 +137,7 @@ func newPredeclareds() starlark.StringDict { identifiers.kubeGet: starlark.NewBuiltin(identifiers.kubeGet, KubeGetFn), identifiers.kubeNodesProvider: starlark.NewBuiltin(identifiers.kubeNodesProvider, KubeNodesProviderFn), identifiers.capvProvider: starlark.NewBuiltin(identifiers.capvProvider, CapvProviderFn), - identifiers.capaProvider: starlark.NewBuiltin(identifiers.capaProvider, CapaProviderFn), + identifiers.capaProvider: starlark.NewBuiltin(identifiers.capaProvider, KcpProviderFn), identifiers.setDefaults: starlark.NewBuiltin(identifiers.setDefaults, SetDefaultsFunc), identifiers.log: starlark.NewBuiltin(identifiers.log, logFunc), } diff --git a/starlark/support.go b/starlark/support.go index 6f3f3237..95991e3c 100644 --- a/starlark/support.go +++ b/starlark/support.go @@ -54,6 +54,7 @@ var ( kubeNodesProvider string capvProvider string capaProvider string + kcpProvider string sshAgent string }{ @@ -91,6 +92,7 @@ var ( kubeNodesProvider: "kube_nodes_provider", capvProvider: "capv_provider", capaProvider: "capa_provider", + kcpProvider: "kcp_provider", sshAgent: "crashd_ssh_agent", } From c6740d0c14c583fc9b20c22427934f9e147065c7 Mon Sep 17 00:00:00 2001 From: Atanas Todorov Date: Thu, 9 Jan 2025 17:45:03 +0200 Subject: [PATCH 2/4] some fixes --- examples/kcp_provider.crsh | 28 +++++++++++++++++++--------- starlark/kcp_provider.go | 5 +++-- starlark/starlark_exec.go | 3 ++- 3 files changed, 24 insertions(+), 12 deletions(-) diff --git a/examples/kcp_provider.crsh b/examples/kcp_provider.crsh index 174fae4b..3f1d4b75 100644 --- a/examples/kcp_provider.crsh +++ b/examples/kcp_provider.crsh @@ -4,17 +4,27 @@ # object kinds to capture kinds = [ -"SRS", +"space", ] def capture_kcp_objects(): - kcp_provider_result=kcp_provider(kcp_admin_secret_namespace="",kcp_admin_secret_name="") - contexts = kcp_provider_result.get("contexts") - # capture kubernetes objects in all kcp logical clusters - for context in contexts: - print("Capturing kcp objects for ", context) - config = kube_config(capi_provider=kcp_provider,cluster_context=context) - kube_capture(kube_config=config,what="objects", kinds=[kind], namespaces=namespace) + kcp_provider_result = kcp_provider( + kcp_admin_secret_namespace="", + kcp_admin_secret_name="" + ) + + # capture kubernetes objects from all kcp workspaces + for context in kcp_provider_result.contexts: + # TODO convert context to directory path and change workdir so that preserve directory structure + print("Capturing kcp objects for", context) + set_defaults(kube_config(capi_provider=kcp_provider_result, cluster_context=context)) + kube_capture(what="objects", kinds=kinds, namespaces=["default"]) + def main(): - capture_kcp_objects() \ No newline at end of file + work_dir = args.workdir if hasattr(args, "workdir") else fail("Error: workdir argument is required but not provided.") + conf = crashd_config(workdir=work_dir) + + capture_kcp_objects() + +main() diff --git a/starlark/kcp_provider.go b/starlark/kcp_provider.go index 42d4d6b8..1aae918e 100644 --- a/starlark/kcp_provider.go +++ b/starlark/kcp_provider.go @@ -32,16 +32,17 @@ func KcpProviderFn(thread *starlark.Thread, _ *starlark.Builtin, args starlark.T return starlark.None, fmt.Errorf("script context not found") } - var kcpKubeConfigPath string + var kcpKubeConfigPath = "/Users/tatanas/dev.kubeconfig" //TODO Generate a KCP admin kubeconfig // dictionary for capa provider struct kcpProviderDict := starlark.StringDict{ - "kind": starlark.String(identifiers.capaProvider), + "kind": starlark.String(identifiers.kcpProvider), "kube_config": starlark.String(kcpKubeConfigPath), } var contexts []starlark.Value + contexts = append(contexts, starlark.String("tanzu-cli-Falcons_GCP_New-staging-5a2f0150:project-ashindov")) kcpProviderDict["contexts"] = starlark.NewList(contexts) return starlarkstruct.FromStringDict(starlark.String(identifiers.kcpProvider), kcpProviderDict), nil diff --git a/starlark/starlark_exec.go b/starlark/starlark_exec.go index 450d20fa..f8668266 100644 --- a/starlark/starlark_exec.go +++ b/starlark/starlark_exec.go @@ -137,7 +137,8 @@ func newPredeclareds() starlark.StringDict { identifiers.kubeGet: starlark.NewBuiltin(identifiers.kubeGet, KubeGetFn), identifiers.kubeNodesProvider: starlark.NewBuiltin(identifiers.kubeNodesProvider, KubeNodesProviderFn), identifiers.capvProvider: starlark.NewBuiltin(identifiers.capvProvider, CapvProviderFn), - identifiers.capaProvider: starlark.NewBuiltin(identifiers.capaProvider, KcpProviderFn), + identifiers.capaProvider: starlark.NewBuiltin(identifiers.capaProvider, CapaProviderFn), + identifiers.kcpProvider: starlark.NewBuiltin(identifiers.kcpProvider, KcpProviderFn), identifiers.setDefaults: starlark.NewBuiltin(identifiers.setDefaults, SetDefaultsFunc), identifiers.log: starlark.NewBuiltin(identifiers.log, logFunc), } From d90451c6a19f440452034a7d852a8725ec5dfba2 Mon Sep 17 00:00:00 2001 From: Atanas Todorov Date: Thu, 9 Jan 2025 18:08:47 +0200 Subject: [PATCH 3/4] Add second context for better use-case description --- examples/kcp_provider.crsh | 1 + starlark/kcp_provider.go | 2 ++ 2 files changed, 3 insertions(+) diff --git a/examples/kcp_provider.crsh b/examples/kcp_provider.crsh index 3f1d4b75..aca3dac5 100644 --- a/examples/kcp_provider.crsh +++ b/examples/kcp_provider.crsh @@ -5,6 +5,7 @@ # object kinds to capture kinds = [ "space", +"configmap" ] def capture_kcp_objects(): diff --git a/starlark/kcp_provider.go b/starlark/kcp_provider.go index 1aae918e..da144cec 100644 --- a/starlark/kcp_provider.go +++ b/starlark/kcp_provider.go @@ -43,6 +43,8 @@ func KcpProviderFn(thread *starlark.Thread, _ *starlark.Builtin, args starlark.T var contexts []starlark.Value contexts = append(contexts, starlark.String("tanzu-cli-Falcons_GCP_New-staging-5a2f0150:project-ashindov")) + contexts = append(contexts, starlark.String("tanzu-cli-Falcons_GCP_New-staging-5a2f0150:project-ashindov:services-space")) + kcpProviderDict["contexts"] = starlark.NewList(contexts) return starlarkstruct.FromStringDict(starlark.String(identifiers.kcpProvider), kcpProviderDict), nil From 1cb5d5581ab958f655c2816f9d2cb792343cf175 Mon Sep 17 00:00:00 2001 From: Atanas Todorov Date: Fri, 10 Jan 2025 14:44:04 +0200 Subject: [PATCH 4/4] configure workdir to be relative to current context --- examples/kcp_provider.crsh | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/examples/kcp_provider.crsh b/examples/kcp_provider.crsh index aca3dac5..b0d79dad 100644 --- a/examples/kcp_provider.crsh +++ b/examples/kcp_provider.crsh @@ -8,6 +8,11 @@ kinds = [ "configmap" ] +def configure_work_dir(context): + work_dir = args.workdir if hasattr(args, "workdir") else fail("Error: workdir argument is required but not provided.") + context_dir = work_dir + "/" + context + conf = crashd_config(workdir=context_dir) + def capture_kcp_objects(): kcp_provider_result = kcp_provider( kcp_admin_secret_namespace="", @@ -16,16 +21,16 @@ def capture_kcp_objects(): # capture kubernetes objects from all kcp workspaces for context in kcp_provider_result.contexts: - # TODO convert context to directory path and change workdir so that preserve directory structure print("Capturing kcp objects for", context) + + # set kubeconfig path and context in threadlocal set_defaults(kube_config(capi_provider=kcp_provider_result, cluster_context=context)) - kube_capture(what="objects", kinds=kinds, namespaces=["default"]) + # configure work directory based on context name - context-name should use "/" + configure_work_dir(context) + kube_capture(what="objects", kinds=kinds, namespaces=["default"]) def main(): - work_dir = args.workdir if hasattr(args, "workdir") else fail("Error: workdir argument is required but not provided.") - conf = crashd_config(workdir=work_dir) - capture_kcp_objects() main()