From 6c5100e308ecd568ed6f94e14950e97575815bd4 Mon Sep 17 00:00:00 2001 From: mgianluc Date: Mon, 13 Jan 2025 18:01:45 +0100 Subject: [PATCH] (feat) Lua Scripting for Dynamic Kubernetes Deployments Sveltos can execute Lua code stored in ConfigMap or Secret resources. To enable this functionality, these resources must be annotated with the `projectsveltos.io/lua` annotation. 1. Resource Referencing: Sveltos profiles can reference ConfigMap and Secret resources. 2. Lua Code Identification: Sveltos identifies resources with the `projectsveltos.io/lua` annotation. 3. Lua Code Execution: Sveltos executes the Lua code found within these resources. 4. Deployment based on Output: The output generated by the Lua code is used to deploy configurations to matching clusters. Sveltos provides helper functions to simplify working with resources: 1. getResource(resources, "resource identifier"): Retrieves a specific resource using its identifier from the provided resource list. resources represents all Kubernetes resources defined in the Spec.TemplateResourceRefs section of a Sveltos profile. identifier must match an identifier previously defined in the Spec.TemplateResourceRefs section of the profile. 2. getLabel(resource, "key"): Returns the value of a label with the specified key for a given resource. 3. getAnnotation(resource, "key"): Returns the value of an annotation with the specified key for a given resource. 4. base64Encode and base64Decode 5. json.encode and json.decode 6. strings functions like Compare, Contains, HasPrefix, HasSuffix, Join, Replace, Split, ToLower, ToUpper. We use https://github.com/chai2010/glua-strings so full list can be found there. To use those methods `strings.ToUpper("mystring")` for instance Sveltos allows users to extend its Lua scripting capabilities by defining custom helper functions. These functions are packaged as Lua code within a ConfigMap residing in the projectsveltos namespace. For Sveltos to load and utilize these custom functions, the `lua-methods` argument must be provided to the addon-controller deployment. Once loaded, these custom methods become available whenever Lua code is executed by Sveltos. This PR uses: 1. https://github.com/chai2010/glua-strings/ 2. https://github.com/layeh/gopher-json --- api/v1alpha1/zz_generated.deepcopy.go | 5 +- api/v1beta1/zz_generated.deepcopy.go | 5 +- cmd/main.go | 6 + controllers/handlers_utils.go | 30 ++++- controllers/handlers_utils_test.go | 4 +- controllers/lua_instantiation.go | 126 +++++++++++++++++++++ controllers/lua_utils.go | 149 ------------------------ controllers/management_cluster.go | 27 ++++- controllers/validate_health.go | 11 +- go.mod | 37 +++--- go.sum | 84 +++++++------- test/fv/fv_suite_test.go | 20 ++++ test/fv/lua_instantiation_test.go | 157 ++++++++++++++++++++++++++ 13 files changed, 438 insertions(+), 223 deletions(-) create mode 100644 controllers/lua_instantiation.go delete mode 100644 controllers/lua_utils.go create mode 100644 test/fv/lua_instantiation_test.go diff --git a/api/v1alpha1/zz_generated.deepcopy.go b/api/v1alpha1/zz_generated.deepcopy.go index d809be47..efa4ed5d 100644 --- a/api/v1alpha1/zz_generated.deepcopy.go +++ b/api/v1alpha1/zz_generated.deepcopy.go @@ -21,11 +21,12 @@ limitations under the License. package v1alpha1 import ( - apiv1alpha1 "github.com/projectsveltos/libsveltos/api/v1alpha1" corev1 "k8s.io/api/core/v1" - "k8s.io/apimachinery/pkg/apis/meta/v1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" runtime "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/util/intstr" + + apiv1alpha1 "github.com/projectsveltos/libsveltos/api/v1alpha1" ) // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. diff --git a/api/v1beta1/zz_generated.deepcopy.go b/api/v1beta1/zz_generated.deepcopy.go index 76d116d2..7611fe87 100644 --- a/api/v1beta1/zz_generated.deepcopy.go +++ b/api/v1beta1/zz_generated.deepcopy.go @@ -21,11 +21,12 @@ limitations under the License. package v1beta1 import ( - apiv1beta1 "github.com/projectsveltos/libsveltos/api/v1beta1" - "k8s.io/api/core/v1" + v1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" runtime "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/util/intstr" + + apiv1beta1 "github.com/projectsveltos/libsveltos/api/v1beta1" ) // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. diff --git a/cmd/main.go b/cmd/main.go index 97c1a0a1..76853d7a 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -85,6 +85,7 @@ var ( healthAddr string profilerAddress string driftDetectionConfigMap string + luaConfigMap string disableCaching bool disableTelemetry bool ) @@ -169,6 +170,7 @@ func main() { ctx := ctrl.SetupSignalHandler() controllers.SetManagementClusterAccess(mgr.GetClient(), mgr.GetConfig()) controllers.SetDriftdetectionConfigMap(driftDetectionConfigMap) + controllers.SetLuaConfigMap(luaConfigMap) logsettings.RegisterForLogSettings(ctx, libsveltosv1beta1.ComponentAddonManager, ctrl.Log.WithName("log-setter"), @@ -239,6 +241,10 @@ func initFlags(fs *pflag.FlagSet) { fs.StringVar(&driftDetectionConfigMap, "drift-detection-config", "", "The name of the ConfigMap in the projectsveltos namespace containing the drift-detection-manager configuration") + fs.StringVar(&luaConfigMap, "lua-methods", "", + "The name of the ConfigMap in the projectsveltos namespace containing lua utilities to be loaded."+ + "Changing the content of the ConfigMap does not cause Sveltos to redeploy.") + const defautlRestConfigQPS = 20 fs.Float32Var(&restConfigQPS, "kube-api-qps", defautlRestConfigQPS, fmt.Sprintf("Maximum queries per second from the controller client to the Kubernetes API server. Defaults to %d", diff --git a/controllers/handlers_utils.go b/controllers/handlers_utils.go index 45355a41..a14d7ca0 100644 --- a/controllers/handlers_utils.go +++ b/controllers/handlers_utils.go @@ -329,6 +329,19 @@ func instantiateTemplate(referencedObject client.Object, logger logr.Logger) boo return false } +func instantiateWithLua(referencedObject client.Object, logger logr.Logger) bool { + annotations := referencedObject.GetAnnotations() + if annotations != nil { + if _, ok := annotations[libsveltosv1beta1.PolicyLuaAnnotation]; ok { + logger.V(logs.LogInfo).Info(fmt.Sprintf("referencedObject %s %s/%s contains a lua script", + referencedObject.GetObjectKind().GroupVersionKind().Kind, referencedObject.GetNamespace(), referencedObject.GetName())) + return true + } + } + + return false +} + func getSubresources(referencedObject client.Object) []string { annotations := referencedObject.GetAnnotations() if annotations != nil { @@ -354,7 +367,8 @@ func deployContent(ctx context.Context, deployingToMgmtCluster bool, destConfig subresources := getSubresources(referencedObject) instantiateTemplate := instantiateTemplate(referencedObject, logger) - resources, err := collectContent(ctx, clusterSummary, mgmtResources, data, instantiateTemplate, logger) + instantiateLua := instantiateWithLua(referencedObject, logger) + resources, err := collectContent(ctx, clusterSummary, mgmtResources, data, instantiateTemplate, instantiateLua, logger) if err != nil { return nil, err } @@ -941,7 +955,7 @@ func customSplit(text string) ([]string, error) { // Returns an error if one occurred. Otherwise it returns a slice of *unstructured.Unstructured. func collectContent(ctx context.Context, clusterSummary *configv1beta1.ClusterSummary, mgmtResources map[string]*unstructured.Unstructured, data map[string]string, - instantiateTemplate bool, logger logr.Logger, + instantiateTemplate, instantiateLua bool, logger logr.Logger, ) ([]*unstructured.Unstructured, error) { policies := make([]*unstructured.Unstructured, 0, len(data)) @@ -958,6 +972,16 @@ func collectContent(ctx context.Context, clusterSummary *configv1beta1.ClusterSu return nil, err } + section = instance + } else if instantiateLua { + instance, err := instantiateWithLuaScript(ctx, getManagementClusterConfig(), getManagementClusterClient(), + clusterSummary.Spec.ClusterType, clusterSummary.Spec.ClusterNamespace, clusterSummary.Spec.ClusterName, + section, mgmtResources, logger) + if err != nil { + logger.Error(err, fmt.Sprintf("failed to instantiate policy from Data %.100s", section)) + return nil, err + } + logger.V(logs.LogInfo).Info(fmt.Sprintf("lua output %q", instance)) section = instance } @@ -1993,7 +2017,7 @@ func getClusterProfileSpecHash(ctx context.Context, clusterSummary *configv1beta // If drift-detectionmanager configuration is in a ConfigMap. fetch ConfigMap and use its Data // section in the hash evaluation. if driftDetectionConfigMap := getDriftDetectionConfigMap(); driftDetectionConfigMap != "" { - configMap, err := collectDriftDetectionConfigMap(ctx, driftDetectionConfigMap) + configMap, err := collectDriftDetectionConfigMap(ctx) if err != nil { return nil, err } diff --git a/controllers/handlers_utils_test.go b/controllers/handlers_utils_test.go index f69f8080..089005bc 100644 --- a/controllers/handlers_utils_test.go +++ b/controllers/handlers_utils_test.go @@ -1419,7 +1419,7 @@ subjects: ` data := map[string]string{"policy.yaml": content} u, err := controllers.CollectContent(context.TODO(), clusterSummary, nil, data, false, - textlogger.NewLogger(textlogger.NewConfig())) + false, textlogger.NewLogger(textlogger.NewConfig())) Expect(err).To(BeNil()) Expect(len(u)).To(Equal(1)) Expect(u[0].GetName()).To(Equal("contour-gateway-provisioner")) @@ -1480,7 +1480,7 @@ stringData: policies := []string{service, deployment, secret} configMap := createConfigMapWithPolicy(randomString(), randomString(), policies...) u, err := controllers.CollectContent(context.TODO(), clusterSummary, nil, configMap.Data, false, - textlogger.NewLogger(textlogger.NewConfig())) + false, textlogger.NewLogger(textlogger.NewConfig())) Expect(err).To(BeNil()) Expect(len(u)).To(Equal(3)) }) diff --git a/controllers/lua_instantiation.go b/controllers/lua_instantiation.go new file mode 100644 index 00000000..a74d6f06 --- /dev/null +++ b/controllers/lua_instantiation.go @@ -0,0 +1,126 @@ +/* +Copyright 2024. projectsveltos.io. 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. +*/ + +package controllers + +import ( + "context" + "encoding/json" + "fmt" + + "github.com/go-logr/logr" + lua "github.com/yuin/gopher-lua" + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" + "k8s.io/client-go/rest" + "sigs.k8s.io/controller-runtime/pkg/client" + + libsveltosv1beta1 "github.com/projectsveltos/libsveltos/api/v1beta1" + logs "github.com/projectsveltos/libsveltos/lib/logsettings" + sveltoslua "github.com/projectsveltos/libsveltos/lib/lua" +) + +type luaResult struct { + // Resources is a list of Kubernetes resources + Resources string `json:"resources"` +} + +func instantiateWithLuaScript(ctx context.Context, config *rest.Config, c client.Client, + clusterType libsveltosv1beta1.ClusterType, clusterNamespace, clusterName, script string, + mgmtResources map[string]*unstructured.Unstructured, logger logr.Logger) (string, error) { + + if script == "" { + return "", nil + } + + luaCode := "" + + if luaConfigMap := getLuaConfigMap(); luaConfigMap != "" { + configMap, err := collectLuaConfigMap(ctx) + if err != nil { + return "", err + } + + for k := range configMap.Data { + luaCode += configMap.Data[k] + luaCode += "\n" + } + } + + luaCode += script + + objects, err := fecthClusterObjects(ctx, config, c, clusterNamespace, clusterName, clusterType, logger) + if err != nil { + return "", err + } + + if mgmtResources != nil { + objects.MgmtResources = make(map[string]map[string]interface{}) + for k := range mgmtResources { + logger.V(logs.LogDebug).Info(fmt.Sprintf("using mgmt resource %s %s/%s with identifier %s", + mgmtResources[k].GetKind(), mgmtResources[k].GetNamespace(), mgmtResources[k].GetName(), k)) + objects.MgmtResources[k] = mgmtResources[k].UnstructuredContent() + } + } + + // Create a new Lua state + l := lua.NewState() + defer l.Close() + + sveltoslua.LoadModulesAndRegisterMethods(l) + + // Load the Lua code + if err := l.DoString(luaCode); err != nil { + logger.V(logs.LogInfo).Info(fmt.Sprintf("doString failed: %v", err)) + return "", err + } + + argTable := l.NewTable() + for key, resource := range objects.MgmtResources { + lValue := sveltoslua.MapToTable(resource) + argTable.RawSetString(key, lValue) + } + + l.SetGlobal("resources", argTable) + + if err := l.CallByParam(lua.P{ + Fn: l.GetGlobal("evaluate"), // name of Lua function + NRet: 1, // number of returned values + Protect: true, // return err or panic + }, argTable); err != nil { + logger.V(logs.LogInfo).Info(fmt.Sprintf("failed to call evaluate function: %s", err.Error())) + return "", err + } + + lv := l.Get(-1) + tbl, ok := lv.(*lua.LTable) + if !ok { + logger.V(logs.LogInfo).Info(sveltoslua.LuaTableError) + return "", fmt.Errorf("%s", sveltoslua.LuaTableError) + } + + goResult := sveltoslua.ToGoValue(tbl) + resultJson, err := json.Marshal(goResult) + if err != nil { + logger.V(logs.LogInfo).Info(fmt.Sprintf("failed to marshal result: %v", err)) + return "", err + } + + var result luaResult + err = json.Unmarshal(resultJson, &result) + if err != nil { + logger.V(logs.LogInfo).Info(fmt.Sprintf("failed to marshal result: %v", err)) + return "", err + } + + return result.Resources, nil +} diff --git a/controllers/lua_utils.go b/controllers/lua_utils.go deleted file mode 100644 index c2cd4a08..00000000 --- a/controllers/lua_utils.go +++ /dev/null @@ -1,149 +0,0 @@ -/* -Copyright 2022. projectsveltos.io. 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. -*/ - -package controllers - -import ( - "fmt" - "time" - - lua "github.com/yuin/gopher-lua" -) - -const ( - luaTableError = "lua script output is not a lua table" - luaBoolError = "lua script output is not a lua bool" -) - -// mapToTable converts a Go map to a lua table -// credit to: https://github.com/yuin/gopher-lua/issues/160#issuecomment-447608033 -func mapToTable(m map[string]interface{}) *lua.LTable { - // Main table pointer - resultTable := &lua.LTable{} - - // Loop map - for key, element := range m { - switch element := element.(type) { - case float64: - resultTable.RawSetString(key, lua.LNumber(element)) - case int64: - resultTable.RawSetString(key, lua.LNumber(element)) - case string: - resultTable.RawSetString(key, lua.LString(element)) - case bool: - resultTable.RawSetString(key, lua.LBool(element)) - case []byte: - resultTable.RawSetString(key, lua.LString(string(element))) - case map[string]interface{}: - - // Get table from map - tble := mapToTable(element) - - resultTable.RawSetString(key, tble) - - case time.Time: - resultTable.RawSetString(key, lua.LNumber(element.Unix())) - - case []map[string]interface{}: - - // Create slice table - sliceTable := &lua.LTable{} - - // Loop element - for _, s := range element { - // Get table from map - tble := mapToTable(s) - - sliceTable.Append(tble) - } - - // Set slice table - resultTable.RawSetString(key, sliceTable) - - case []interface{}: - - // Create slice table - sliceTable := &lua.LTable{} - - // Loop interface slice - for _, s := range element { - // Switch interface type - switch s := s.(type) { - case map[string]interface{}: - - // Convert map to table - t := mapToTable(s) - - // Append result - sliceTable.Append(t) - - case float64: - - // Append result as number - sliceTable.Append(lua.LNumber(s)) - - case string: - - // Append result as string - sliceTable.Append(lua.LString(s)) - - case bool: - - // Append result as bool - sliceTable.Append(lua.LBool(s)) - } - } - - // Append to main table - resultTable.RawSetString(key, sliceTable) - } - } - - return resultTable -} - -// toGoValue converts the given LValue to a Go object. -// Credit to: https://github.com/yuin/gluamapper/blob/master/gluamapper.go -func toGoValue(lv lua.LValue) interface{} { - switch v := lv.(type) { - case *lua.LNilType: - return nil - case lua.LBool: - return bool(v) - case lua.LString: - return string(v) - case lua.LNumber: - return float64(v) - case *lua.LTable: - maxn := v.MaxN() - if maxn == 0 { // table - ret := make(map[string]interface{}) - v.ForEach(func(key, value lua.LValue) { - keystr := fmt.Sprint(toGoValue(key)) - ret[keystr] = toGoValue(value) - }) - return ret - } else { // array - ret := make([]interface{}, 0, maxn) - for i := 1; i <= maxn; i++ { - ret = append(ret, toGoValue(v.RawGetInt(i))) - } - return ret - } - default: - return v - } -} diff --git a/controllers/management_cluster.go b/controllers/management_cluster.go index 8772e48b..53748958 100644 --- a/controllers/management_cluster.go +++ b/controllers/management_cluster.go @@ -29,6 +29,7 @@ var ( managementClusterClient client.Client managementClusterConfig *rest.Config driftdetectionConfigMap string + luaConfigMap string ) func SetManagementClusterAccess(c client.Client, config *rest.Config) { @@ -40,6 +41,10 @@ func SetDriftdetectionConfigMap(name string) { driftdetectionConfigMap = name } +func SetLuaConfigMap(name string) { + luaConfigMap = name +} + func getManagementClusterConfig() *rest.Config { return managementClusterConfig } @@ -52,11 +57,29 @@ func getDriftDetectionConfigMap() string { return driftdetectionConfigMap } -func collectDriftDetectionConfigMap(ctx context.Context, name string) (*corev1.ConfigMap, error) { +func getLuaConfigMap() string { + return luaConfigMap +} + +func collectDriftDetectionConfigMap(ctx context.Context) (*corev1.ConfigMap, error) { + c := getManagementClusterClient() + configMap := &corev1.ConfigMap{} + + err := c.Get(ctx, types.NamespacedName{Namespace: projectsveltos, Name: getDriftDetectionConfigMap()}, + configMap) + if err != nil { + return nil, err + } + + return configMap, nil +} + +func collectLuaConfigMap(ctx context.Context) (*corev1.ConfigMap, error) { c := getManagementClusterClient() configMap := &corev1.ConfigMap{} - err := c.Get(ctx, types.NamespacedName{Namespace: projectsveltos, Name: name}, configMap) + err := c.Get(ctx, types.NamespacedName{Namespace: projectsveltos, Name: getLuaConfigMap()}, + configMap) if err != nil { return nil, err } diff --git a/controllers/validate_health.go b/controllers/validate_health.go index a131cbd7..dc0645a1 100644 --- a/controllers/validate_health.go +++ b/controllers/validate_health.go @@ -35,6 +35,7 @@ import ( configv1beta1 "github.com/projectsveltos/addon-controller/api/v1beta1" libsveltosv1beta1 "github.com/projectsveltos/libsveltos/api/v1beta1" logs "github.com/projectsveltos/libsveltos/lib/logsettings" + sveltoslua "github.com/projectsveltos/libsveltos/lib/lua" ) type healthStatus struct { @@ -173,7 +174,9 @@ func isHealthy(resource *unstructured.Unstructured, script string, logger logr.L l := lua.NewState() defer l.Close() - obj := mapToTable(resource.UnstructuredContent()) + sveltoslua.LoadModulesAndRegisterMethods(l) + + obj := sveltoslua.MapToTable(resource.UnstructuredContent()) err = l.DoString(script) if err != nil { @@ -196,11 +199,11 @@ func isHealthy(resource *unstructured.Unstructured, script string, logger logr.L lv := l.Get(-1) tbl, ok := lv.(*lua.LTable) if !ok { - logger.V(logs.LogInfo).Info(luaTableError) - return false, "", fmt.Errorf("%s", luaTableError) + logger.V(logs.LogInfo).Info(sveltoslua.LuaTableError) + return false, "", fmt.Errorf("%s", sveltoslua.LuaTableError) } - goResult := toGoValue(tbl) + goResult := sveltoslua.ToGoValue(tbl) resultJson, err := json.Marshal(goResult) if err != nil { logger.V(logs.LogInfo).Info(fmt.Sprintf("failed to marshal result: %v", err)) diff --git a/go.mod b/go.mod index 1c050a70..e1add7b6 100644 --- a/go.mod +++ b/go.mod @@ -5,6 +5,7 @@ go 1.23.4 require ( github.com/Masterminds/semver/v3 v3.3.1 github.com/TwiN/go-color v1.4.1 + github.com/chai2010/glua-strings v0.0.0-20200705094630-a37fb1f4ddeb github.com/dariubs/percent v1.0.0 github.com/docker/cli v27.5.0+incompatible github.com/fluxcd/pkg/http/fetch v0.14.0 @@ -14,10 +15,11 @@ require ( github.com/go-logr/logr v1.4.2 github.com/google/gofuzz v1.2.0 github.com/hexops/gotextdiff v1.0.3 + github.com/layeh/gopher-json v0.0.0-20201124131017-552bb3c4c3bf github.com/onsi/ginkgo/v2 v2.22.2 github.com/onsi/gomega v1.36.2 github.com/pkg/errors v0.9.1 - github.com/projectsveltos/libsveltos v0.45.0 + github.com/projectsveltos/libsveltos v0.45.1-0.20250120082144-a4e0a95406a3 github.com/prometheus/client_golang v1.20.5 github.com/spf13/pflag v1.0.5 github.com/yuin/gopher-lua v1.1.1 @@ -42,7 +44,7 @@ require ( cel.dev/expr v0.19.1 // indirect dario.cat/mergo v1.0.1 // indirect github.com/AdaLogics/go-fuzz-headers v0.0.0-20240806141605-e8a1dd7889d6 // indirect - github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 // indirect + github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c // indirect github.com/BurntSushi/toml v1.4.0 // indirect github.com/MakeNowJust/heredoc v1.0.0 // indirect github.com/Masterminds/goutils v1.1.1 // indirect @@ -55,15 +57,16 @@ require ( github.com/cenkalti/backoff/v4 v4.3.0 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect github.com/chai2010/gettext-go v1.0.3 // indirect - github.com/containerd/containerd v1.7.24 // indirect + github.com/chai2010/glua-helper v0.0.0-20171228064744-0e9a290dbcdf // indirect + github.com/containerd/containerd v1.7.25 // indirect github.com/containerd/errdefs v1.0.0 // indirect github.com/containerd/log v0.1.0 // indirect github.com/containerd/platforms v0.2.1 // indirect - github.com/cyphar/filepath-securejoin v0.3.6 // indirect + github.com/cyphar/filepath-securejoin v0.4.0 // indirect github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect github.com/distribution/reference v0.6.0 // indirect github.com/docker/distribution v2.8.3+incompatible // indirect - github.com/docker/docker v25.0.6+incompatible // indirect + github.com/docker/docker v27.5.0+incompatible // indirect github.com/docker/docker-credential-helpers v0.8.2 // indirect github.com/docker/go-connections v0.5.0 // indirect github.com/docker/go-metrics v0.0.1 // indirect @@ -73,15 +76,15 @@ require ( github.com/exponent-io/jsonpath v0.0.0-20210407135951-1de76d718b3f // indirect github.com/fatih/color v1.18.0 // indirect github.com/felixge/httpsnoop v1.0.4 // indirect - github.com/fluxcd/pkg/apis/acl v0.3.0 // indirect - github.com/fluxcd/pkg/apis/meta v1.6.1 // indirect - github.com/fsnotify/fsnotify v1.7.0 // indirect + github.com/fluxcd/pkg/apis/acl v0.5.0 // indirect + github.com/fluxcd/pkg/apis/meta v1.9.0 // indirect + github.com/fsnotify/fsnotify v1.8.0 // indirect github.com/fxamacker/cbor/v2 v2.7.0 // indirect - github.com/go-errors/errors v1.4.2 // indirect + github.com/go-errors/errors v1.5.1 // indirect github.com/go-gorp/gorp/v3 v3.1.0 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/go-openapi/jsonpointer v0.21.0 // indirect - github.com/go-openapi/jsonreference v0.20.2 // indirect + github.com/go-openapi/jsonreference v0.21.0 // indirect github.com/go-openapi/swag v0.23.0 // indirect github.com/go-task/slim-sprig/v3 v3.0.0 // indirect github.com/gobuffalo/flect v1.0.3 // indirect @@ -89,17 +92,17 @@ require ( github.com/gogo/protobuf v1.3.2 // indirect github.com/golang/protobuf v1.5.4 // indirect github.com/google/btree v1.1.3 // indirect - github.com/google/cel-go v0.22.0 // indirect + github.com/google/cel-go v0.22.1 // indirect github.com/google/gnostic-models v0.6.9 // indirect github.com/google/go-cmp v0.6.0 // indirect github.com/google/pprof v0.0.0-20241210010833-40e02aabc2ad // indirect github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect github.com/google/uuid v1.6.0 // indirect - github.com/gorilla/mux v1.8.0 // indirect - github.com/gorilla/websocket v1.5.0 // indirect + github.com/gorilla/mux v1.8.1 // indirect + github.com/gorilla/websocket v1.5.3 // indirect github.com/gosuri/uitable v0.0.4 // indirect github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79 // indirect - github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0 // indirect + github.com/grpc-ecosystem/grpc-gateway/v2 v2.25.1 // indirect github.com/hashicorp/errwrap v1.1.0 // indirect github.com/hashicorp/go-cleanhttp v0.5.2 // indirect github.com/hashicorp/go-multierror v1.1.1 // indirect @@ -169,8 +172,8 @@ require ( golang.org/x/time v0.8.0 // indirect golang.org/x/tools v0.28.0 // indirect gomodules.xyz/jsonpatch/v2 v2.4.0 // indirect - google.golang.org/genproto/googleapis/api v0.0.0-20241216192217-9240e9c98484 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20241216192217-9240e9c98484 // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20241219192143-6b3ec007d9bb // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20241219192143-6b3ec007d9bb // indirect google.golang.org/grpc v1.69.2 // indirect google.golang.org/protobuf v1.36.1 // indirect gopkg.in/evanphx/json-patch.v4 v4.12.0 // indirect @@ -178,7 +181,7 @@ require ( k8s.io/apiserver v0.32.1 // indirect k8s.io/cluster-bootstrap v0.32.0 // indirect k8s.io/kube-openapi v0.0.0-20241212222426-2c72e554b1e7 // indirect - k8s.io/kubectl v0.32.0 // indirect + k8s.io/kubectl v0.32.1 // indirect oras.land/oras-go v1.2.5 // indirect sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.31.0 // indirect sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8 // indirect diff --git a/go.sum b/go.sum index d7e891d2..29e0853c 100644 --- a/go.sum +++ b/go.sum @@ -6,8 +6,8 @@ filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA= filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4= github.com/AdaLogics/go-fuzz-headers v0.0.0-20240806141605-e8a1dd7889d6 h1:He8afgbRMd7mFxO99hRNu+6tazq8nFF9lIwo9JFroBk= github.com/AdaLogics/go-fuzz-headers v0.0.0-20240806141605-e8a1dd7889d6/go.mod h1:8o94RPi1/7XTJvwPpRSzSUedZrtlirdB3r9Z20bi2f8= -github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 h1:L/gRVlceqvL25UVaW/CKtUDjefjrs0SPonmDGUVOYP0= -github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= +github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c h1:udKWzYgxTojEKWjV8V+WSxDXJ4NFATAsZjh8iIbsQIg= +github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= github.com/BurntSushi/toml v1.4.0 h1:kuoIxZQy2WRRk1pttg9asf+WVv6tWQuBNVmK8+nqPr0= github.com/BurntSushi/toml v1.4.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho= github.com/DATA-DOG/go-sqlmock v1.5.2 h1:OcvFkGmslmlZibjAjaHm3L//6LiuBgolP7OputlJIzU= @@ -58,12 +58,16 @@ github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UF github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/chai2010/gettext-go v1.0.3 h1:9liNh8t+u26xl5ddmWLmsOsdNLwkdRTg5AG+JnTiM80= github.com/chai2010/gettext-go v1.0.3/go.mod h1:y+wnP2cHYaVj19NZhYKAwEMH2CI1gNHeQQ+5AjwawxA= +github.com/chai2010/glua-helper v0.0.0-20171228064744-0e9a290dbcdf h1:83/SiZ9gCO63c1fSVuBlYsNMSwbzYw0nLT6BgU3IAbU= +github.com/chai2010/glua-helper v0.0.0-20171228064744-0e9a290dbcdf/go.mod h1:g4T7SP6g4zcVGZu2Xt2l9v+j8WRUKnrSFI13MYeQtD4= +github.com/chai2010/glua-strings v0.0.0-20200705094630-a37fb1f4ddeb h1:veL8m2ukpS0WornX1koriByiNIils7J+wB6urWgB18c= +github.com/chai2010/glua-strings v0.0.0-20200705094630-a37fb1f4ddeb/go.mod h1:Ujv8AWr5PquFfwTqGV6c8MP+tuG1q7SgYdkZ7umTUsQ= github.com/containerd/cgroups v1.1.0 h1:v8rEWFl6EoqHB+swVNjVoCJE8o3jX7e8nqBGPLaDFBM= github.com/containerd/cgroups v1.1.0/go.mod h1:6ppBcbh/NOOUU+dMKrykgaBnK9lCIBxHqJDGwsa1mIw= -github.com/containerd/containerd v1.7.24 h1:zxszGrGjrra1yYJW/6rhm9cJ1ZQ8rkKBR48brqsa7nA= -github.com/containerd/containerd v1.7.24/go.mod h1:7QUzfURqZWCZV7RLNEn1XjUCQLEf0bkaK4GjUaZehxw= -github.com/containerd/continuity v0.4.2 h1:v3y/4Yz5jwnvqPKJJ+7Wf93fyWoCB3F5EclWG023MDM= -github.com/containerd/continuity v0.4.2/go.mod h1:F6PTNCKepoxEaXLQp3wDAjygEnImnZ/7o4JzpodfroQ= +github.com/containerd/containerd v1.7.25 h1:khEQOAXOEJalRO228yzVsuASLH42vT7DIo9Ss+9SMFQ= +github.com/containerd/containerd v1.7.25/go.mod h1:tWfHzVI0azhw4CT2vaIjsb2CoV4LJ9PrMPaULAr21Ok= +github.com/containerd/continuity v0.4.4 h1:/fNVfTJ7wIl/YPMHjf+5H32uFhl63JucB34PlCpMKII= +github.com/containerd/continuity v0.4.4/go.mod h1:/lNJvtJKUQStBzpVQ1+rasXO1LAWtUQssk28EZvJ3nE= github.com/containerd/errdefs v1.0.0 h1:tg5yIfIlQIrxYtu9ajqY42W3lpS19XqdxRQeEwYG8PI= github.com/containerd/errdefs v1.0.0/go.mod h1:+YBYIdtsnF4Iw6nWZhJcqGSg/dwvV7tyJ/kCkyJ2k+M= github.com/containerd/log v0.1.0 h1:TCJt7ioM2cr/tfR8GPbGf9/VRAX8D2B4PjzCpfX540I= @@ -75,11 +79,10 @@ github.com/coredns/caddy v1.1.1/go.mod h1:A6ntJQlAWuQfFlsd9hvigKbo2WS0VUs2l1e2F+ github.com/coredns/corefile-migration v1.0.24 h1:NL/zRKijhJZLYlNnMr891DRv5jXgfd3Noons1M6oTpc= github.com/coredns/corefile-migration v1.0.24/go.mod h1:56DPqONc3njpVPsdilEnfijCwNGC3/kTJLl7i7SPavY= github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= -github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/creack/pty v1.1.18 h1:n56/Zwd5o6whRC5PMGretI4IdRLlmBXYNjScPaBgsbY= github.com/creack/pty v1.1.18/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4= -github.com/cyphar/filepath-securejoin v0.3.6 h1:4d9N5ykBnSp5Xn2JkhocYDkOpURL/18CYMpo6xB9uWM= -github.com/cyphar/filepath-securejoin v0.3.6/go.mod h1:Sdj7gXlvMcPZsbhwhQ33GguGLDGQL7h7bg04C/+u9jI= +github.com/cyphar/filepath-securejoin v0.4.0 h1:PioTG9TBRSApBpYGnDU8HC+miIsX8vitBH9LGNNMoLQ= +github.com/cyphar/filepath-securejoin v0.4.0/go.mod h1:Sdj7gXlvMcPZsbhwhQ33GguGLDGQL7h7bg04C/+u9jI= github.com/dariubs/percent v1.0.0 h1:fY8q40FRYaCiFZ0gTOa73Cmp21hS32w+tSSmqbGnUzc= github.com/dariubs/percent v1.0.0/go.mod h1:NDZpkezJ8QqyIW/510MywB5T2KdC8v/0oTlEoPcMsRM= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -94,8 +97,8 @@ github.com/docker/cli v27.5.0+incompatible h1:aMphQkcGtpHixwwhAXJT1rrK/detk2JIvD github.com/docker/cli v27.5.0+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= github.com/docker/distribution v2.8.3+incompatible h1:AtKxIZ36LoNK51+Z6RpzLpddBirtxJnzDrHLEKxTAYk= github.com/docker/distribution v2.8.3+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= -github.com/docker/docker v25.0.6+incompatible h1:5cPwbwriIcsua2REJe8HqQV+6WlWc1byg2QSXzBxBGg= -github.com/docker/docker v25.0.6+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/docker v27.5.0+incompatible h1:um++2NcQtGRTz5eEgO6aJimo6/JxrTXC941hd05JO6U= +github.com/docker/docker v27.5.0+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= github.com/docker/docker-credential-helpers v0.8.2 h1:bX3YxiGzFP5sOXWc3bTPEXdEaZSeVMrFgOr3T+zrFAo= github.com/docker/docker-credential-helpers v0.8.2/go.mod h1:P3ci7E3lwkZg6XiHdRKft1KckHiO9a2rNtyFbZ/ry9M= github.com/docker/go-connections v0.5.0 h1:USnMq7hx7gwdVZq1L49hLXaFtUdTADjXGp+uj1Br63c= @@ -118,10 +121,10 @@ github.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM= github.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU= github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= -github.com/fluxcd/pkg/apis/acl v0.3.0 h1:UOrKkBTOJK+OlZX7n8rWt2rdBmDCoTK+f5TY2LcZi8A= -github.com/fluxcd/pkg/apis/acl v0.3.0/go.mod h1:WVF9XjSMVBZuU+HTTiSebGAWMgM7IYexFLyVWbK9bNY= -github.com/fluxcd/pkg/apis/meta v1.6.1 h1:maLhcRJ3P/70ArLCY/LF/YovkxXbX+6sTWZwZQBeNq0= -github.com/fluxcd/pkg/apis/meta v1.6.1/go.mod h1:YndB/gxgGZmKfqpAfFxyCDNFJFP0ikpeJzs66jwq280= +github.com/fluxcd/pkg/apis/acl v0.5.0 h1:+ykKezgerKUlZwSYFUy03lPMOIAyWlqvMNNLIWWqOhk= +github.com/fluxcd/pkg/apis/acl v0.5.0/go.mod h1:IVDZx3MAoDWjlLrJHMF9Z27huFuXAEQlnbWw0M6EcTs= +github.com/fluxcd/pkg/apis/meta v1.9.0 h1:wPgm7bWNJZ/ImS5GqikOxt362IgLPFBG73dZ27uWRiQ= +github.com/fluxcd/pkg/apis/meta v1.9.0/go.mod h1:pMea8eEZcsFSI7ngRnTHFtDZk2CEZGgtrueNgI6Iu70= github.com/fluxcd/pkg/http/fetch v0.14.0 h1:65iI38Vrl21v0YxT8IFCj/63I9/l43b7dPLaXJHjOEc= github.com/fluxcd/pkg/http/fetch v0.14.0/go.mod h1:/Ir27MZbgG11yN/npQwF32+oIETeJ+QdceoaxvvkLzQ= github.com/fluxcd/pkg/tar v0.10.0 h1:QWT/wou50jTrNp2YIMsT1MY/wbkT2OULbfFxAB9Ieao= @@ -134,14 +137,14 @@ github.com/foxcpp/go-mockdns v1.1.0 h1:jI0rD8M0wuYAxL7r/ynTrCQQq0BVqfB99Vgk7Dlme github.com/foxcpp/go-mockdns v1.1.0/go.mod h1:IhLeSFGed3mJIAXPH2aiRQB+kqz7oqu8ld2qVbOu7Wk= github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8= github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= -github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA= -github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM= +github.com/fsnotify/fsnotify v1.8.0 h1:dAwr6QBTBZIkG8roQaJjGof0pp0EeF+tNV7YBP3F/8M= +github.com/fsnotify/fsnotify v1.8.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0= github.com/fxamacker/cbor/v2 v2.7.0 h1:iM5WgngdRBanHcxugY4JySA0nk1wZorNOpTgCMedv5E= github.com/fxamacker/cbor/v2 v2.7.0/go.mod h1:pxXPTn3joSm21Gbwsv0w9OSA2y1HFR9qXEeXQVeNoDQ= github.com/gdexlab/go-render v1.0.1 h1:rxqB3vo5s4n1kF0ySmoNeSPRYkEsyHgln4jFIQY7v0U= github.com/gdexlab/go-render v1.0.1/go.mod h1:wRi5nW2qfjiGj4mPukH4UV0IknS1cHD4VgFTmJX5JzM= -github.com/go-errors/errors v1.4.2 h1:J6MZopCL4uSllY1OfXM374weqZFFItUbrImctkmUxIA= -github.com/go-errors/errors v1.4.2/go.mod h1:sIVyrIiJhuEF+Pj9Ebtd6P/rEYROXFi3BopGUQ5a5Og= +github.com/go-errors/errors v1.5.1 h1:ZwEMSLRCapFLflTpT7NKaAc7ukJ8ZPEjzlxt8rPN8bk= +github.com/go-errors/errors v1.5.1/go.mod h1:sIVyrIiJhuEF+Pj9Ebtd6P/rEYROXFi3BopGUQ5a5Og= github.com/go-gorp/gorp/v3 v3.1.0 h1:ItKF/Vbuj31dmV4jxA1qblpSwkl9g1typ24xoe70IGs= github.com/go-gorp/gorp/v3 v3.1.0/go.mod h1:dLEjIyyRNiXvNZ8PSmzpt1GsWAUK8kjVhEpjH8TixEw= github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= @@ -154,12 +157,10 @@ github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/go-logr/zapr v1.3.0 h1:XGdV8XW8zdwFiwOA2Dryh1gj2KRQyOOoNmBy4EplIcQ= github.com/go-logr/zapr v1.3.0/go.mod h1:YKepepNBd1u/oyhd/yQmtjVXmm9uML4IXUgMOwR8/Gg= -github.com/go-openapi/jsonpointer v0.19.6/go.mod h1:osyAmYz/mB/C3I+WsTTSgw1ONzaLJoLCyoi6/zppojs= github.com/go-openapi/jsonpointer v0.21.0 h1:YgdVicSA9vH5RiHs9TZW5oyafXZFc6+2Vc1rr/O9oNQ= github.com/go-openapi/jsonpointer v0.21.0/go.mod h1:IUyH9l/+uyhIYQ/PXVA41Rexl+kOkAPDdXEYns6fzUY= -github.com/go-openapi/jsonreference v0.20.2 h1:3sVjiK66+uXK/6oQ8xgcRKcFgQ5KXa2KvnJRumpMGbE= -github.com/go-openapi/jsonreference v0.20.2/go.mod h1:Bl1zwGIM8/wsvqjsOQLJ/SH+En5Ap4rVB5KVcIDZG2k= -github.com/go-openapi/swag v0.22.3/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14= +github.com/go-openapi/jsonreference v0.21.0 h1:Rs+Y7hSXT83Jacb7kFyjn4ijOuVGSvOdF2+tg1TRrwQ= +github.com/go-openapi/jsonreference v0.21.0/go.mod h1:LmZmgsrTkVg9LG4EaHeY8cBDslNPMo06cago5JNLkm4= github.com/go-openapi/swag v0.23.0 h1:vsEVJDUo2hPJ2tu0/Xc+4noaxyEffXNIs3cOULZ+GrE= github.com/go-openapi/swag v0.23.0/go.mod h1:esZ8ITTYEsH1V2trKHjAN8Ai7xHb8RV+YSZ577vPjgQ= github.com/go-sql-driver/mysql v1.8.1 h1:LedoTUt/eveggdHS9qUFC1EFSa8bU2+1pZjSRpvNJ1Y= @@ -185,8 +186,8 @@ github.com/gomodule/redigo v1.8.2 h1:H5XSIre1MB5NbPYFp+i1NBbb5qN1W8Y8YAQoAYbkm8k github.com/gomodule/redigo v1.8.2/go.mod h1:P9dn9mFrCBvWhGE1wpxx6fgq7BAeLBk+UUUzlpkBYO0= github.com/google/btree v1.1.3 h1:CVpQJjYgC4VbzxeGVHfvZrv1ctoYCAI8vbl07Fcxlyg= github.com/google/btree v1.1.3/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4= -github.com/google/cel-go v0.22.0 h1:b3FJZxpiv1vTMo2/5RDUqAHPxkT8mmMfJIrq1llbf7g= -github.com/google/cel-go v0.22.0/go.mod h1:BuznPXXfQDpXKWQ9sPW3TzlAJN5zzFe+i9tIs0yC4s8= +github.com/google/cel-go v0.22.1 h1:AfVXx3chM2qwoSbM7Da8g8hX8OVSkBFwX+rz2+PcK40= +github.com/google/cel-go v0.22.1/go.mod h1:BuznPXXfQDpXKWQ9sPW3TzlAJN5zzFe+i9tIs0yC4s8= github.com/google/gnostic-models v0.6.9 h1:MU/8wDLif2qCXZmzncUQ/BOfxWfthHi63KqpoNbWqVw= github.com/google/gnostic-models v0.6.9/go.mod h1:CiWsm0s6BSQd1hRn8/QmxqB6BesYcbSZxsz9b0KuDBw= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= @@ -204,16 +205,16 @@ github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/gorilla/handlers v1.5.1 h1:9lRY6j8DEeeBT10CvO9hGW0gmky0BprnvDI5vfhUHH4= github.com/gorilla/handlers v1.5.1/go.mod h1:t8XrUpc4KVXb7HGyJ4/cEnwQiaxrX/hz1Zv/4g96P1Q= -github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI= -github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= -github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc= -github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY= +github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ= +github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg= +github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/gosuri/uitable v0.0.4 h1:IG2xLKRvErL3uhY6e1BylFzG+aJiwQviDDTfOKeKTpY= github.com/gosuri/uitable v0.0.4/go.mod h1:tKR86bXuXPZazfOTG1FIzvjIdXzd0mo4Vtn16vt0PJo= github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79 h1:+ngKgrYPPJrOjhax5N+uePQ0Fh1Z7PheYoUI/0nzkPA= github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0 h1:bkypFPDjIYGfCYD5mRBvpqxfYX1YCS1PXdKYWi8FsN0= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0/go.mod h1:P+Lt/0by1T8bfcF3z737NnSbmxQAppXMRziHUxPOC8k= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.25.1 h1:VNqngBF40hVlDloBruUehVYC3ArSgIyScOAyMRqBxRg= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.25.1/go.mod h1:RBRO7fro65R6tjKzYgLAFo0t1QEXY1Dp+i/bvpRiqiQ= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= @@ -250,11 +251,8 @@ github.com/klauspost/cpuid/v2 v2.2.9 h1:66ze0taIn2H33fBvCkXuv9BmCwDfafmiIVpKV9kK github.com/klauspost/cpuid/v2 v2.2.9/go.mod h1:rqkxqrZ1EhYM9G+hXH7YdowN5R5RGN6NK4QwQ3WMXF8= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= -github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= -github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= -github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= @@ -263,6 +261,8 @@ github.com/lann/builder v0.0.0-20180802200727-47ae307949d0 h1:SOEGU9fKiNWd/HOJuq github.com/lann/builder v0.0.0-20180802200727-47ae307949d0/go.mod h1:dXGbAdH5GtBTC4WfIxhKZfyBF/HBFgRZSWwZ9g/He9o= github.com/lann/ps v0.0.0-20150810152359-62de8c46ede0 h1:P6pPBnrTSX3DEVR4fDembhRWSsG5rVo6hYhAB/ADZrk= github.com/lann/ps v0.0.0-20150810152359-62de8c46ede0/go.mod h1:vmVJ0l/dxyfGW6FmdpVm2joNMFikkuWg0EoCKLGUMNw= +github.com/layeh/gopher-json v0.0.0-20201124131017-552bb3c4c3bf h1:bg6J/5S/AeTz7K9i/luJRj31BJ8f+LgYwKQBSOZxSEM= +github.com/layeh/gopher-json v0.0.0-20201124131017-552bb3c4c3bf/go.mod h1:E/q28EyUVBgBQnONAVPIdwvEsv4Ve0vaCA9JWim4+3I= github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw= github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de h1:9TO3cAIGXtEhnIaL+V+BEER86oLrvS+kWobKpbJuye0= @@ -333,8 +333,8 @@ github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRI github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/poy/onpar v1.1.2 h1:QaNrNiZx0+Nar5dLgTVp5mXkyoVFIbepjyEoGSnhbAY= github.com/poy/onpar v1.1.2/go.mod h1:6X8FLNoxyr9kkmnlqpK6LSoiOtrO6MICtWwEuWkLjzg= -github.com/projectsveltos/libsveltos v0.45.0 h1:4YJxmGmi6HsJ1uBqQk2Yt0ifuZbaZXiQAQJOmz5X8GU= -github.com/projectsveltos/libsveltos v0.45.0/go.mod h1:ncyIWW5KY89X36cJmcq389ZMJiYQ7WTo+EMB6WR5q+E= +github.com/projectsveltos/libsveltos v0.45.1-0.20250120082144-a4e0a95406a3 h1:aCVjUqZJ7HDePWjMWhw1nNf0es1biPaApKqRhP7EYCA= +github.com/projectsveltos/libsveltos v0.45.1-0.20250120082144-a4e0a95406a3/go.mod h1:jxwqxR+CJq1FbDf+wOqtZKBLi1dhSReCDvRBAS33TDU= github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= github.com/prometheus/client_golang v1.1.0/go.mod h1:I1FGZT9+L76gKKOs5djB6ezCbFQP1xR9D75/vuwEF3g= @@ -506,10 +506,10 @@ golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8T golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= gomodules.xyz/jsonpatch/v2 v2.4.0 h1:Ci3iUJyx9UeRx7CeFN8ARgGbkESwJK+KB9lLcWxY/Zw= gomodules.xyz/jsonpatch/v2 v2.4.0/go.mod h1:AH3dM2RI6uoBZxn3LVrfvJ3E0/9dG4cSrbuBJT4moAY= -google.golang.org/genproto/googleapis/api v0.0.0-20241216192217-9240e9c98484 h1:ChAdCYNQFDk5fYvFZMywKLIijG7TC2m1C2CMEu11G3o= -google.golang.org/genproto/googleapis/api v0.0.0-20241216192217-9240e9c98484/go.mod h1:KRUmxRI4JmbpAm8gcZM4Jsffi859fo5LQjILwuqj9z8= -google.golang.org/genproto/googleapis/rpc v0.0.0-20241216192217-9240e9c98484 h1:Z7FRVJPSMaHQxD0uXU8WdgFh8PseLM8Q8NzhnpMrBhQ= -google.golang.org/genproto/googleapis/rpc v0.0.0-20241216192217-9240e9c98484/go.mod h1:lcTa1sDdWEIHMWlITnIczmw5w60CF9ffkb8Z+DVmmjA= +google.golang.org/genproto/googleapis/api v0.0.0-20241219192143-6b3ec007d9bb h1:B7GIB7sr443wZ/EAEl7VZjmh1V6qzkt5V+RYcUYtS1U= +google.golang.org/genproto/googleapis/api v0.0.0-20241219192143-6b3ec007d9bb/go.mod h1:E5//3O5ZIG2l71Xnt+P/CYUY8Bxs8E7WMoZ9tlcMbAY= +google.golang.org/genproto/googleapis/rpc v0.0.0-20241219192143-6b3ec007d9bb h1:3oy2tynMOP1QbTC0MsNNAV+Se8M2Bd0A5+x1QHyw+pI= +google.golang.org/genproto/googleapis/rpc v0.0.0-20241219192143-6b3ec007d9bb/go.mod h1:lcTa1sDdWEIHMWlITnIczmw5w60CF9ffkb8Z+DVmmjA= google.golang.org/grpc v1.69.2 h1:U3S9QEtbXC0bYNvRtcoklF3xGtLViumSYxWykJS+7AU= google.golang.org/grpc v1.69.2/go.mod h1:vyjdE6jLBI76dgpDojsFGNaHlxdjXN9ghpnd2o7JGZ4= google.golang.org/protobuf v1.36.1 h1:yBPeRvTftaleIgM3PZ/WBIZ7XM/eEYAaEyCwvyjq/gk= @@ -552,8 +552,8 @@ k8s.io/klog/v2 v2.130.1 h1:n9Xl7H1Xvksem4KFG4PYbdQCQxqc/tTUyrgXaOhHSzk= k8s.io/klog/v2 v2.130.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE= k8s.io/kube-openapi v0.0.0-20241212222426-2c72e554b1e7 h1:hcha5B1kVACrLujCKLbr8XWMxCxzQx42DY8QKYJrDLg= k8s.io/kube-openapi v0.0.0-20241212222426-2c72e554b1e7/go.mod h1:GewRfANuJ70iYzvn+i4lezLDAFzvjxZYK1gn1lWcfas= -k8s.io/kubectl v0.32.0 h1:rpxl+ng9qeG79YA4Em9tLSfX0G8W0vfaiPVrc/WR7Xw= -k8s.io/kubectl v0.32.0/go.mod h1:qIjSX+QgPQUgdy8ps6eKsYNF+YmFOAO3WygfucIqFiE= +k8s.io/kubectl v0.32.1 h1:/btLtXLQUU1rWx8AEvX9jrb9LaI6yeezt3sFALhB8M8= +k8s.io/kubectl v0.32.1/go.mod h1:sezNuyWi1STk4ZNPVRIFfgjqMI6XMf+oCVLjZen/pFQ= k8s.io/utils v0.0.0-20241210054802-24370beab758 h1:sdbE21q2nlQtFh65saZY+rRM6x6aJJI8IUa1AmH/qa0= k8s.io/utils v0.0.0-20241210054802-24370beab758/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= oras.land/oras-go v1.2.5 h1:XpYuAwAb0DfQsunIyMfeET92emK8km3W4yEzZvUbsTo= diff --git a/test/fv/fv_suite_test.go b/test/fv/fv_suite_test.go index c3bc0bae..8af8670e 100644 --- a/test/fv/fv_suite_test.go +++ b/test/fv/fv_suite_test.go @@ -149,3 +149,23 @@ var _ = BeforeSuite(func() { }) Expect(err).To(BeNil()) }) + +func addTypeInformationToObject(scheme *runtime.Scheme, obj client.Object) error { + gvks, _, err := scheme.ObjectKinds(obj) + if err != nil { + return fmt.Errorf("missing apiVersion or kind and cannot assign it; %w", err) + } + + for _, gvk := range gvks { + if gvk.Kind == "" { + continue + } + if gvk.Version == "" || gvk.Version == runtime.APIVersionInternal { + continue + } + obj.GetObjectKind().SetGroupVersionKind(gvk) + break + } + + return nil +} diff --git a/test/fv/lua_instantiation_test.go b/test/fv/lua_instantiation_test.go new file mode 100644 index 00000000..78a0e1e1 --- /dev/null +++ b/test/fv/lua_instantiation_test.go @@ -0,0 +1,157 @@ +/* +Copyright 2024. projectsveltos.io. 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. +*/ + +package fv_test + +import ( + "context" + + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + + corev1 "k8s.io/api/core/v1" + apierrors "k8s.io/apimachinery/pkg/api/errors" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/types" + + configv1beta1 "github.com/projectsveltos/addon-controller/api/v1beta1" + "github.com/projectsveltos/addon-controller/controllers" + libsveltosv1beta1 "github.com/projectsveltos/libsveltos/api/v1beta1" +) + +const ( + luaCode = `function evaluate() + local namespace = getResource(resources, "Namespace") + local hs = {} + local result = [[ +apiVersion: v1 +kind: Namespace +metadata: + name: ]] .. namespace.metadata.name .. [[ + + labels: + env: ]] .. getLabel(namespace, "env") + hs.resources = result + return hs +end` +) + +var _ = Describe("ConfigMap with Lua", func() { + const ( + namePrefix = "lua-" + ) + + It("Instantiate Lua code and deploy it", Label("FV", "EXTENDED"), func() { + envKey := randomString() + ns := &corev1.Namespace{ + ObjectMeta: metav1.ObjectMeta{ + Name: namePrefix + randomString(), + Labels: map[string]string{ + "env": envKey, + }, + }, + } + Byf("Create namespace %s in the management cluster", ns.Name) + Expect(k8sClient.Create(context.TODO(), ns)).To(Succeed()) + + Expect(addTypeInformationToObject(scheme, ns)).To(Succeed()) + + Byf("Create a ClusterProfile matching Cluster %s/%s", kindWorkloadCluster.Namespace, kindWorkloadCluster.Name) + clusterProfile := getClusterProfile(namePrefix, map[string]string{key: value}) + clusterProfile.Spec.SyncMode = configv1beta1.SyncModeContinuous + Expect(k8sClient.Create(context.TODO(), clusterProfile)).To(Succeed()) + + verifyClusterProfileMatches(clusterProfile) + + verifyClusterSummary(controllers.ClusterProfileLabelName, + clusterProfile.Name, &clusterProfile.Spec, + kindWorkloadCluster.Namespace, kindWorkloadCluster.Name) + + Byf("Create a configMap with a Lua code (with annotation projectsveltos.io/lua)") + configMap := createConfigMapWithPolicy(ns.Name, namePrefix+randomString(), luaCode) + configMap.Annotations = map[string]string{ + libsveltosv1beta1.PolicyLuaAnnotation: "ok", + } + Expect(k8sClient.Create(context.TODO(), configMap)).To(Succeed()) + currentConfigMap := &corev1.ConfigMap{} + Expect(k8sClient.Get(context.TODO(), + types.NamespacedName{Namespace: configMap.Namespace, Name: configMap.Name}, currentConfigMap)).To(Succeed()) + + Byf("Update ClusterProfile %s to reference ConfigMap %s/%s", clusterProfile.Name, configMap.Namespace, configMap.Name) + Byf("Update ClusterProfile %s to fetch Namespace %s", clusterProfile.Name, ns.Name) + currentClusterProfile := &configv1beta1.ClusterProfile{} + Expect(k8sClient.Get(context.TODO(), types.NamespacedName{Name: clusterProfile.Name}, currentClusterProfile)).To(Succeed()) + currentClusterProfile.Spec.TemplateResourceRefs = []configv1beta1.TemplateResourceRef{ + { + Identifier: "Namespace", // this is used in luaCode. Must match + Resource: corev1.ObjectReference{ + Kind: ns.Kind, + Name: ns.Name, + APIVersion: "v1", + }, + }, + } + currentClusterProfile.Spec.PolicyRefs = []configv1beta1.PolicyRef{ + { + Kind: string(libsveltosv1beta1.ConfigMapReferencedResourceKind), + Namespace: configMap.Namespace, + Name: configMap.Name, + }, + } + Expect(k8sClient.Update(context.TODO(), currentClusterProfile)).To(Succeed()) + + clusterSummary := verifyClusterSummary(controllers.ClusterProfileLabelName, + currentClusterProfile.Name, ¤tClusterProfile.Spec, + kindWorkloadCluster.Namespace, kindWorkloadCluster.Name) + + Byf("Verifying ClusterSummary %s status is set to Deployed for Resources feature", clusterSummary.Name) + verifyFeatureStatusIsProvisioned(kindWorkloadCluster.Namespace, clusterSummary.Name, + configv1beta1.FeatureResources) + + Byf("Getting client to access the workload cluster") + workloadClient, err := getKindWorkloadClusterKubeconfig() + Expect(err).To(BeNil()) + Expect(workloadClient).ToNot(BeNil()) + + Byf("Verifying proper Namespace %s is created in the workload cluster", ns.Name) + Eventually(func() error { + currentNamespace := &corev1.Namespace{} + return workloadClient.Get(context.TODO(), types.NamespacedName{Name: ns.Name}, currentNamespace) + }, timeout, pollingInterval).Should(BeNil()) + + Byf("Verifying Namespace %s has label env: %s", ns.Name, envKey) + currentNamespace := &corev1.Namespace{} + Expect(workloadClient.Get(context.TODO(), types.NamespacedName{Name: ns.Name}, + currentNamespace)).To(Succeed()) + Expect(currentNamespace.Labels).ToNot(BeNil()) + v, ok := currentNamespace.Labels["env"] + Expect(ok).To(BeTrue()) + Expect(v).To(Equal(envKey)) + + deleteClusterProfile(clusterProfile) + + Byf("Verifying proper Namespace %s is removed from the workload cluster", ns.Name) + Eventually(func() bool { + currentNamespace := &corev1.Namespace{} + err = workloadClient.Get(context.TODO(), types.NamespacedName{Name: ns.Name}, currentNamespace) + return apierrors.IsNotFound(err) + }, timeout, pollingInterval).Should(BeTrue()) + + err = k8sClient.Get(context.TODO(), types.NamespacedName{Name: ns.Name}, currentNamespace) + Expect(err).To(BeNil()) + Expect(k8sClient.Delete(context.TODO(), currentNamespace)).To(Succeed()) + }) +})