From 138250a689319a3e51b6f448cbfcf5940c8d232d Mon Sep 17 00:00:00 2001 From: chagams Date: Wed, 9 Apr 2025 14:12:11 +0100 Subject: [PATCH 1/4] Added packages to support render/save/apply kubernetes manifests --- cmd/shore/shore.go | 40 +++- pkg/backend/kube/backend.go | 225 +++++++++++++++++++++ pkg/backend/kube/backend_test.go | 132 ++++++++++++ pkg/renderer/k8smanifests/error.go | 16 ++ pkg/renderer/k8smanifests/importer.go | 125 ++++++++++++ pkg/renderer/k8smanifests/renderer.go | 94 +++++++++ pkg/renderer/k8smanifests/renderer_test.go | 180 +++++++++++++++++ 7 files changed, 805 insertions(+), 7 deletions(-) create mode 100644 pkg/backend/kube/backend.go create mode 100644 pkg/backend/kube/backend_test.go create mode 100644 pkg/renderer/k8smanifests/error.go create mode 100644 pkg/renderer/k8smanifests/importer.go create mode 100644 pkg/renderer/k8smanifests/renderer.go create mode 100644 pkg/renderer/k8smanifests/renderer_test.go diff --git a/cmd/shore/shore.go b/cmd/shore/shore.go index bd69ba0..90d3b0f 100644 --- a/cmd/shore/shore.go +++ b/cmd/shore/shore.go @@ -4,11 +4,15 @@ import ( "fmt" "os" + "github.com/Autodesk/shore/pkg/backend" + "github.com/Autodesk/shore/pkg/backend/kube" "github.com/Autodesk/shore/pkg/backend/spinnaker" "github.com/Autodesk/shore/pkg/cleanup_command" "github.com/Autodesk/shore/pkg/command" "github.com/Autodesk/shore/pkg/project" + "github.com/Autodesk/shore/pkg/renderer" "github.com/Autodesk/shore/pkg/renderer/jsonnet" + "github.com/Autodesk/shore/pkg/renderer/k8smanifests" "github.com/sirupsen/logrus" "github.com/spf13/afero" "github.com/spf13/cobra" @@ -73,13 +77,6 @@ func init() { fs := afero.NewOsFs() logger = logrus.New() - commonDependencies := &command.Dependencies{ - Project: project.NewShoreProject(fs, logger), - Renderer: jsonnet.NewRenderer(fs, logger), - Backend: spinnaker.NewClient(logger), - Logger: logger, - } - rootCmd.PersistentFlags().CountVarP(&logVerbosity, "verbose", "v", "Logging verbosity") // "default" should not be set explicitly on the command - it will be set in getConfigName. rootCmd.PersistentFlags().StringP("executor-config", "X", os.Getenv("SHORE_EXECUTOR_CONFIG"), @@ -87,6 +84,35 @@ func init() { //'p' is used for 'payload' used by exec command. 'l' for load profile? rootCmd.PersistentFlags().StringP("profile", "P", os.Getenv("SHORE_PROFILE"), "The profile to use. Can also be set by $SHORE_PROFILE environment variable. Priority is: env variable, cli args, default.") + rootCmd.PersistentFlags().StringP("renderer", "R", os.Getenv("RENDERER"), + "which render to use (eg. k8s, jsonnet). Can also be set by $SHORE_PROFILE environment variable. Priority is: env variable, cli args, default.") + rootCmd.PersistentFlags().StringP("executor", "R", os.Getenv("EXECUTOR"), + "which executor to use (eg. spinnaker, dir). Can also be set by $SHORE_PROFILE environment variable. Priority is: env variable, cli args, default.") + + rendererType, _ := rootCmd.PersistentFlags().GetString("renderer") + + var rendererInstance renderer.Renderer + if rendererType == "R" { + rendererInstance = k8smanifests.NewRenderer(fs, logger) + } else { + rendererInstance = jsonnet.NewRenderer(fs, logger) + } + + // Determine the backend based on the flag or default to spinnaker + executorType, _ := rootCmd.PersistentFlags().GetString("executor") + var backendInstance backend.Backend + if executorType == "R" { + backendInstance = kube.NewClient(logger) + } else { + backendInstance = spinnaker.NewClient(logger) + } + + commonDependencies := &command.Dependencies{ + Project: project.NewShoreProject(fs, logger), + Renderer: rendererInstance, + Backend: backendInstance, + Logger: logger, + } rootCmd.AddCommand(command.NewProjectCommand(commonDependencies)) rootCmd.AddCommand(command.NewRenderCommand(commonDependencies)) diff --git a/pkg/backend/kube/backend.go b/pkg/backend/kube/backend.go new file mode 100644 index 0000000..0e0563f --- /dev/null +++ b/pkg/backend/kube/backend.go @@ -0,0 +1,225 @@ +package kube + +import ( + "fmt" + "io/fs" + "net/http" + "os" + "os/exec" + "path/filepath" + + "github.com/Autodesk/shore/pkg/shore_testing" + jsoniter "github.com/json-iterator/go" + "github.com/sirupsen/logrus" + "gopkg.in/yaml.v2" +) + +// SpinClient represents a client for managing pipelines. +type SpinClient struct { + log logrus.FieldLogger +} + +// NewClient - Create a new default spinnaker client +func NewClient(logger logrus.FieldLogger) *SpinClient { + return &SpinClient{log: logger} +} + +// SavePipeline - Saves the pipeline as a YAML file in the specified folder. +func (s *SpinClient) SavePipeline(pipelineJSON string) (*http.Response, error) { + // Unmarshal the pipeline JSON to extract metadata + + currentDir, err := os.Getwd() + if err != nil { + return nil, fmt.Errorf("failed to get current directory: %w", err) + } + + generateFolderPath := filepath.Join(currentDir, "generated") + if err := os.MkdirAll(generateFolderPath, os.ModePerm); err != nil { + return nil, fmt.Errorf("failed to create folder: %w", err) + } + + var pipeline map[string]interface{} + if err := jsoniter.Unmarshal([]byte(pipelineJSON), &pipeline); err != nil { + return nil, fmt.Errorf("failed to unmarshal pipeline JSON: %w", err) + } + + // Iterate over the top-level keys and save each as a separate YAML file + for key, value := range pipeline { + // Convert the value to YAML + pipelineYAML, err := yaml.Marshal(value) + if err != nil { + return nil, fmt.Errorf("failed to marshal YAML for key %s: %w", key, err) + } + + // Create the file path + filePath := filepath.Join(generateFolderPath, fmt.Sprintf("%s.yaml", key)) + + // Write the YAML to the file + if err := os.WriteFile(filePath, pipelineYAML, 0644); err != nil { + return nil, fmt.Errorf("failed to write YAML file for key %s: %w", key, err) + } + + s.log.Infof("Saved YAML for key %s to %s", key, filePath) + } + + return nil, nil +} + +func (s *SpinClient) ExecutePipeline(argsJSON string, stringify bool) (string, *http.Response, error) { + + // Check if a valid Kubernetes context is set + cmd := exec.Command("kubectl", "config", "current-context") + output, err := cmd.Output() + if err != nil || len(output) == 0 { + return "", nil, fmt.Errorf("no valid Kubernetes context set: %w", err) + } + + // Ensure the folder exists + currentDir, err := os.Getwd() + if err != nil { + return "", nil, fmt.Errorf("failed to get current directory: %w", err) + } + folderPath := filepath.Join(currentDir, "generated") + + // Check if the folder exists + if _, err := os.Stat(folderPath); os.IsNotExist(err) { + return "", nil, fmt.Errorf("folder %s does not exist", folderPath) + } + + // Iterate over the files in the folder + err = filepath.Walk(folderPath, func(path string, info fs.FileInfo, err error) error { + if err != nil { + return fmt.Errorf("error accessing file %s: %w", path, err) + } + + // Skip directories + if info.IsDir() { + return nil + } + + // Apply the file using kubectl + cmd := exec.Command("kubectl", "apply", "-f", path) + cmd.Stdout = os.Stdout + cmd.Stderr = os.Stderr + + s.log.Infof("Applying file: %s", path) + if err := cmd.Run(); err != nil { + return fmt.Errorf("failed to apply file %s: %w", path, err) + } + + return nil + }) + + if err != nil { + return "", nil, fmt.Errorf("failed to apply files in folder: %w", err) + } + + s.log.Info("Successfully applied all files in the folder") + return "", nil, nil +} + +func (s *SpinClient) DeletePipeline(pipelineJSON string) (*http.Response, error) { + // Get the current working directory + currentDir, err := os.Getwd() + if err != nil { + return nil, fmt.Errorf("failed to get current directory: %w", err) + } + + // Define the path to the "generated" folder + folderPath := filepath.Join(currentDir, "generated") + + // Check if the folder exists + if _, err := os.Stat(folderPath); os.IsNotExist(err) { + return nil, fmt.Errorf("folder %s does not exist", folderPath) + } + + // Iterate over the files in the folder and delete them + err = filepath.Walk(folderPath, func(path string, info fs.FileInfo, err error) error { + if err != nil { + return fmt.Errorf("error accessing file %s: %w", path, err) + } + + // Skip directories + if info.IsDir() { + return nil + } + + // Delete the file + s.log.Infof("Deleting file: %s", path) + if err := os.Remove(path); err != nil { + return fmt.Errorf("failed to delete file %s: %w", path, err) + } + + return nil + }) + + if err != nil { + return nil, fmt.Errorf("failed to delete files in folder: %w", err) + } + + s.log.Info("Successfully deleted all files in the folder") + return nil, nil +} + +// TestPipeline - Dummy implementation for testing a pipeline. +func (s *SpinClient) TestPipeline(testConfig shore_testing.TestsConfig, onChange func(), stringify bool) error { + s.log.Info("Starting TestPipeline...") + + s.log.Info("TestPipeline completed successfully.") + return nil +} + +// GetPipeline - Dummy implementation for retrieving a pipeline. +func (s *SpinClient) GetPipeline(application string, pipelineName string) (map[string]interface{}, *http.Response, error) { + s.log.Infof("Retrieving pipeline: application=%s, pipelineName=%s", application, pipelineName) + + // Simulate a pipeline retrieval + pipeline := map[string]interface{}{ + "application": application, + "name": pipelineName, + "stages": []map[string]interface{}{ + { + "name": "Deploy", + "type": "deploy", + }, + }, + } + + // Return the dummy pipeline and a nil HTTP response + return pipeline, nil, nil +} + +func (s *SpinClient) GetPipelinesNamesAndApplication(pipelineJSON string) ([]string, string, error) { + // Unmarshal the pipeline JSON to extract metadata + var pipeline map[string]interface{} + if err := jsoniter.Unmarshal([]byte(pipelineJSON), &pipeline); err != nil { + return nil, "", fmt.Errorf("failed to unmarshal pipeline JSON: %w", err) + } + + // Extract the application name and pipeline names + applicationName, ok := pipeline["application"].(string) + if !ok { + return nil, "", fmt.Errorf("failed to extract application name from pipeline JSON") + } + + pipelineNames := []string{} + if stages, ok := pipeline["stages"].([]interface{}); ok { + for _, stage := range stages { + if stageMap, ok := stage.(map[string]interface{}); ok { + if name, ok := stageMap["name"].(string); ok { + pipelineNames = append(pipelineNames, name) + } + } + } + } + + return pipelineNames, applicationName, nil +} + +// WaitForPipelineToFinish - Dummy implementation for waiting for a pipeline to finish. +func (s *SpinClient) WaitForPipelineToFinish(id string, timeout int) (string, *http.Response, error) { + s.log.Infof("Waiting for pipeline to finish: id=%s, timeout=%d", id, timeout) + + s.log.Info("Pipeline finished successfully.") + return "", nil, nil +} diff --git a/pkg/backend/kube/backend_test.go b/pkg/backend/kube/backend_test.go new file mode 100644 index 0000000..0492ca3 --- /dev/null +++ b/pkg/backend/kube/backend_test.go @@ -0,0 +1,132 @@ +package kube + +import ( + "fmt" + "os" + "path/filepath" + "testing" + + "github.com/sirupsen/logrus" + testLog "github.com/sirupsen/logrus/hooks/test" + "github.com/stretchr/testify/assert" +) + +var logger *logrus.Logger + +func TestSavePipeline(t *testing.T) { + // Arrange + // Arrange + logger, _ = testLog.NewNullLogger() + + client := &SpinClient{log: logger} + + pipelineJSON := `{ + "iamPolicy": { + "apiVersion": "iam.services.k8s.aws/v1alpha1", + "kind": "Policy", + "metadata": { + "labels": { + "app": "log-forwarding" + }, + "name": "log-forwarder-1-policy", + "namespace": "default" + }, + "spec": { + "name": "log-forwarder-1-policy", + "policyDocument": { + "Statement": [ + { + "Action": [ + "logs:PutSubscriptionFilter", + "logs:DeleteSubscriptionFilter", + "s3:PutObject", + "s3:GetObject" + ], + "Effect": "Allow", + "Resource": "*" + } + ], + "Version": "2012-10-17" + } + } + }, + "logForwarder1": { + "apiVersion": "logforwarding.ucp.adskeng.net/v1alpha1", + "kind": "CloudWatchLogForwarder", + "metadata": { + "labels": { + "app": "log-forwarding" + }, + "name": "log-forwarder-1", + "namespace": "default" + }, + "spec": { + "account": "123456789012", + "logGroupNames": [ + "log-group-1", + "log-group-2" + ], + "moniker": "log-forwarder-1", + "region": "us-west-2" + } + }, + "s3Bucket": { + "apiVersion": "s3.services.k8s.aws/v1alpha1", + "kind": "Bucket", + "metadata": { + "labels": { + "app": "log-forwarding" + }, + "name": "log-forwarder-1-failed-delivery" + }, + "spec": { + "name": "log-forwarder-1-failed-delivery" + } + } +}` + folderPath := "./generated" + + // Act + _, err := client.SavePipeline(pipelineJSON) + + // Assert + assert.NoError(t, err) + + // Verify the files exist + expectedFiles := []string{"iamPolicy.yaml", "logForwarder1.yaml", "s3Bucket.yaml"} + for _, fileName := range expectedFiles { + filePath := filepath.Join(folderPath, fileName) + _, err := os.Stat(filePath) + assert.NoError(t, err, fmt.Sprintf("Expected the file %s to be created", fileName)) + } + + // Verify the content of one of the files (e.g., iamPolicy.yaml) + iamPolicyPath := filepath.Join(folderPath, "iamPolicy.yaml") + content, err := os.ReadFile(iamPolicyPath) + assert.NoError(t, err, "Expected the YAML file to be readable") + + expectedYAML := `apiVersion: iam.services.k8s.aws/v1alpha1 +kind: Policy +metadata: + labels: + app: log-forwarding + name: log-forwarder-1-policy + namespace: default +spec: + name: log-forwarder-1-policy + policyDocument: + Statement: + - Action: + - logs:PutSubscriptionFilter + - logs:DeleteSubscriptionFilter + - s3:PutObject + - s3:GetObject + Effect: Allow + Resource: '*' + Version: "2012-10-17" +` + assert.Equal(t, expectedYAML, string(content), "Expected the YAML content to match") + + // Clean up + os.RemoveAll(folderPath) +} diff --git a/pkg/renderer/k8smanifests/error.go b/pkg/renderer/k8smanifests/error.go new file mode 100644 index 0000000..8263860 --- /dev/null +++ b/pkg/renderer/k8smanifests/error.go @@ -0,0 +1,16 @@ +package k8smanifests + +import ( + "fmt" +) + +// SharedLibErr - Custom error for the custom implementation of JSONNET shared libraries. +type SharedLibErr struct { + Require string + Path string + Err error +} + +func (s SharedLibErr) Error() string { + return fmt.Sprintf("name: %s, path: %s, err: %v", s.Require, s.Path, s.Err) +} diff --git a/pkg/renderer/k8smanifests/importer.go b/pkg/renderer/k8smanifests/importer.go new file mode 100644 index 0000000..9a15dc9 --- /dev/null +++ b/pkg/renderer/k8smanifests/importer.go @@ -0,0 +1,125 @@ +package k8smanifests + +import ( + "fmt" + "os" + "path" + "path/filepath" + "strings" + + "github.com/google/go-jsonnet" + jbV1 "github.com/jsonnet-bundler/jsonnet-bundler/spec/v1" + "github.com/spf13/afero" +) + +type FileImporter struct { + JPaths []string + fs afero.Fs + projectPath string + fsCache map[string]*fsCacheEntry +} + +type fsCacheEntry struct { + exists bool + contents jsonnet.Contents +} + +// NewImporter - Get the Jsonnet File Import customized to the Jsonnet Bundler type. +func NewImporter(fs afero.Fs, projectPath string, jbFile jbV1.JsonnetFile) *FileImporter { + libsPath := []string{} + fileImporter := FileImporter{ + fs: fs, + projectPath: projectPath, + } + + libsPath = append(libsPath, projectPath) + + if jbFile.LegacyImports { + // Jsonnet-Bundler LegacyImports put the imported folders in the top directory with symlinks. + libPath := filepath.Join(projectPath, ShareLibsPath) + libsPath = append(libsPath, libPath) + } else { + // Jsonnet-Bundler Imports put complies to the GoMod style of artifact management (vendoring) + // This means we need to take an extra step to find the top level key for each shared folder. + libsMap := make(map[string][]string) + + for k := range jbFile.Dependencies { + libPath := filepath.Join(projectPath, ShareLibsPath, k) + libPathSplit := strings.Split(libPath, "/") + libsKey := strings.Join(libPathSplit[:len(libPathSplit)-1], "/") + + if len(libsMap[libsKey]) > 0 { + libsMap[libsKey] = append(libsMap[libsKey], k) + } else { + libsMap[libsKey] = []string{k} + } + } + + for k := range libsMap { + libsPath = append(libsPath, k) + } + } + + fileImporter.JPaths = append(fileImporter.JPaths, libsPath...) + return &fileImporter +} + +func (importer *FileImporter) tryPath(dir, importedPath string) (found bool, contents jsonnet.Contents, foundHere string, err error) { + if importer.fsCache == nil { + importer.fsCache = make(map[string]*fsCacheEntry) + } + var absPath string + if path.IsAbs(importedPath) { + absPath = importedPath + } else { + absPath = path.Join(dir, importedPath) + } + var entry *fsCacheEntry + if cacheEntry, isCached := importer.fsCache[absPath]; isCached { + entry = cacheEntry + } else { + contentBytes, err := afero.ReadFile(importer.fs, absPath) + if err != nil { + if os.IsNotExist(err) { + entry = &fsCacheEntry{ + exists: false, + } + } else { + return false, jsonnet.Contents{}, "", err + } + } else { + entry = &fsCacheEntry{ + exists: true, + contents: jsonnet.MakeContents(string(contentBytes)), + } + } + importer.fsCache[absPath] = entry + } + return entry.exists, entry.contents, absPath, nil +} + +// Import imports file from the filesystem. +func (importer *FileImporter) Import(importedFrom, importedPath string) (contents jsonnet.Contents, foundAt string, err error) { + // TODO(sbarzowski) Make sure that dir is absolute and resolving of "" + // is independent from current CWD. The default path should be saved + // in the importer. + // We need to relativize the paths in the error formatter, so that the stack traces + // don't have ugly absolute paths (less readable and messy with golden tests). + dir, _ := path.Split(importedFrom) + found, content, foundHere, err := importer.tryPath(dir, importedPath) + if err != nil { + return jsonnet.Contents{}, "", err + } + + for i := len(importer.JPaths) - 1; !found && i >= 0; i-- { + found, content, foundHere, err = importer.tryPath(importer.JPaths[i], importedPath) + if err != nil { + return jsonnet.Contents{}, "", err + } + } + + if !found { + return jsonnet.Contents{}, "", fmt.Errorf("couldn't open import %#v: no match locally or in the Jsonnet library paths", importedPath) + } + return content, foundHere, nil +} diff --git a/pkg/renderer/k8smanifests/renderer.go b/pkg/renderer/k8smanifests/renderer.go new file mode 100644 index 0000000..281c7b6 --- /dev/null +++ b/pkg/renderer/k8smanifests/renderer.go @@ -0,0 +1,94 @@ +package k8smanifests + +import ( + "encoding/json" + "fmt" + "os" + "path/filepath" + + "github.com/Autodesk/shore/pkg/renderer" + "github.com/google/go-jsonnet" + "github.com/jsonnet-bundler/jsonnet-bundler/pkg/jsonnetfile" + jbV1 "github.com/jsonnet-bundler/jsonnet-bundler/spec/v1" + "github.com/sirupsen/logrus" + "github.com/spf13/afero" + "gopkg.in/yaml.v2" +) + +var RenderFiles = map[renderer.RenderType]string{ + // MainFileName is the name of the entrypoint file the jsonnet renderer looks for to render a pipeline project + renderer.MainFileName: "main.pipeline.jsonnet", + renderer.CleanUpFileName: "cleanup/cleanup.pipeline.jsonnet", +} + +// ArgsFileName is the name of the arguments file the jsonnet renderer looks for to pass to the pipeline as TLA veriables. +const ArgsFileName string = "render" + +// ShareLibsPath - the path that jsonnet should look into when looking for shared libraries. +// +// Designed to work with - https://github.com/jsonnet-bundler/jsonnet-bundler/ +const ShareLibsPath string = "vendor" + +const JsonnetFileName string = "jsonnetfile.json" + +// Jsonnet - A Jsonnet renderer instance. +// The struct holds the required parameters to render a standard shore pipeline. +type Jsonnet struct { + renderer.Renderer + vm *jsonnet.VM + fs afero.Fs + log logrus.FieldLogger +} + +// NewRenderer - Create new instance of the JSONNET renderer. +func NewRenderer(fs afero.Fs, logger logrus.FieldLogger) *Jsonnet { + return &Jsonnet{vm: jsonnet.MakeVM(), fs: fs, log: logger} +} + +// Render - Render the code with the VM. +func (j *Jsonnet) Render(projectPath string, renderArgs string, renderType renderer.RenderType) (string, error) { + renderFile := filepath.Join(projectPath, RenderFiles[renderType]) + + jbFile, err := j.loadJsonnetBundlerFile(projectPath) + + // If the file doesn't exist, we can skip the error. + if err != nil && !os.IsNotExist(err) { + return "", err + } + + // Always include params, even if they are empty + j.vm.TLACode("params", renderArgs) + j.vm.Importer(NewImporter(j.fs, projectPath, jbFile)) + + // Evaluate the Jsonnet file to get JSON output + jsonOutput, err := j.vm.EvaluateFile(renderFile) + if err != nil { + return "", err + } + + // Convert JSON output to YAML + var jsonData map[string]interface{} + // Unmarshal the JSON string into a Go map + if err := json.Unmarshal([]byte(jsonOutput), &jsonData); err != nil { + return "", fmt.Errorf("failed to unmarshal JSON: %w", err) + } + + // Marshal the Go map into YAML + yamlOutput, err := yaml.Marshal(jsonData) + if err != nil { + return "", fmt.Errorf("failed to marshal YAML: %w", err) + } + + return string(yamlOutput), nil +} + +// A compliant wrapper implementing jsonnetfile.Load but using `Afero` instrad of `ioutil`. +func (j *Jsonnet) loadJsonnetBundlerFile(path string) (jbV1.JsonnetFile, error) { + jsonnetFilePath := filepath.Join(path, JsonnetFileName) + bytes, err := afero.ReadFile(j.fs, jsonnetFilePath) + if err != nil { + return jbV1.New(), err + } + + return jsonnetfile.Unmarshal(bytes) +} diff --git a/pkg/renderer/k8smanifests/renderer_test.go b/pkg/renderer/k8smanifests/renderer_test.go new file mode 100644 index 0000000..cbafaae --- /dev/null +++ b/pkg/renderer/k8smanifests/renderer_test.go @@ -0,0 +1,180 @@ +package k8smanifests_test + +import ( + "fmt" + "os" + "path/filepath" + "sort" + "testing" + + "github.com/Autodesk/shore/pkg/renderer" + "github.com/Autodesk/shore/pkg/renderer/jsonnet" + "github.com/jsonnet-bundler/jsonnet-bundler/pkg/jsonnetfile" + "github.com/sirupsen/logrus" + "github.com/spf13/afero" + "github.com/stretchr/testify/assert" + "gopkg.in/yaml.v2" +) + +const testPath string = "/tmp/test" + +func SetupRenderWithArgs(extension, codeFile, args string) afero.Fs { + localFs := afero.NewMemMapFs() + localFs.Mkdir(testPath, os.ModePerm) + + afero.WriteFile(localFs, filepath.Join(testPath, jsonnet.RenderFiles[renderer.MainFileName]), []byte(codeFile), os.ModePerm) + + if args != "" { + argsFile := filepath.Join(testPath, fmt.Sprintf("render.%s", extension)) + afero.WriteFile(localFs, argsFile, []byte(args), os.ModePerm) + } + + return localFs +} + +func TestNewRenderer(t *testing.T) { + // Given + codeFile := ` +function(params={})( + {"This-is": "Magic!!!"} +) +` + fs := SetupRenderWithArgs("json", codeFile, "") + + // Test + res, renderErr := jsonnet.NewRenderer(fs, logrus.New()).Render(testPath, "", renderer.MainFileName) + + // Assert + assert.Nil(t, renderErr) + assert.Contains(t, res, `Magic!!!`) +} + +func TestFileImporterSuccess(t *testing.T) { + // Setup Jsonnet Bundler File + jbFile := ` +{ + "version": 1, + "dependencies": [ + { + "source": { + "git": { + "remote": "https://github.com/org-1/sharedlib1.git", + "subdir": "" + } + }, + "version": "master" + }, + { + "source": { + "git": { + "remote": "https://github.com/org-2/sharedLib2.git", + "subdir": "" + } + }, + "version": "master" + }, + { + "source": { + "git": { + "remote": "https://github.com/org-1/sharedLib3.git", + "subdir": "" + } + }, + "version": "master" + } + ], + "legacyImports": false +}` + + spec, _ := jsonnetfile.Unmarshal([]byte(jbFile)) + + // Test + importer := jsonnet.NewImporter(&afero.MemMapFs{}, testPath, spec) + + // Assert + basePath := filepath.Join(testPath, jsonnet.ShareLibsPath, "github.com") + + value := []string{testPath, filepath.Join(basePath, "org-1"), filepath.Join(basePath, "org-2")} + sort.Strings(value) + sort.Strings(importer.JPaths) + + assert.Len(t, importer.JPaths, 3) + assert.Equal(t, value, importer.JPaths) +} + +func TestFileImporterLegacySuccess(t *testing.T) { + // Setup Jsonnet Bundler File + jbFile := ` +{ + "version": 1, + "dependencies": [ + { + "source": { + "git": { + "remote": "https://github.com/example/sharedlib1.git", + "subdir": "" + } + }, + "version": "master" + }, + { + "source": { + "git": { + "remote": "https://github.com/example/sharedLibPath1.git", + "subdir": "" + } + }, + "version": "master" + } + ], + "legacyImports": true +}` + + spec, _ := jsonnetfile.Unmarshal([]byte(jbFile)) + + // Test + importer := jsonnet.NewImporter(&afero.MemMapFs{}, testPath, spec) + + // Assert + value := []string{testPath, filepath.Join(testPath, jsonnet.ShareLibsPath)} + assert.Len(t, importer.JPaths, 2) + assert.Equal(t, value, importer.JPaths) +} + +func TestRenderOutputIsYAML(t *testing.T) { + // Given + codeFile := ` +{ + apiVersion: "v1", + kind: "ConfigMap", + metadata: { + name: "example-config", + namespace: "default", + }, + data: { + key1: "value1", + key2: "value2", + }, +} +` + fs := SetupRenderWithArgs("jsonnet", codeFile, "") + + // Test + output, err := jsonnet.NewRenderer(fs, logrus.New()).Render(testPath, "", renderer.MainFileName) + + // Assert + assert.NoError(t, err, "Render should not return an error") + + // Validate that the output is valid YAML + var yamlData map[string]interface{} + err = yaml.Unmarshal([]byte(output), &yamlData) + assert.NoError(t, err, "Output should be valid YAML") + + // Additional assertions to verify the content + assert.Equal(t, "v1", yamlData["apiVersion"]) + assert.Equal(t, "ConfigMap", yamlData["kind"]) + assert.Equal(t, "example-config", yamlData["metadata"].(map[interface{}]interface{})["name"]) + assert.Equal(t, "default", yamlData["metadata"].(map[interface{}]interface{})["namespace"]) + assert.Equal(t, "value1", yamlData["data"].(map[interface{}]interface{})["key1"]) + assert.Equal(t, "value2", yamlData["data"].(map[interface{}]interface{})["key2"]) +} From 9156ba40596a35184a2dce179b17285234c41dda Mon Sep 17 00:00:00 2001 From: chagams Date: Wed, 9 Apr 2025 15:18:29 +0100 Subject: [PATCH 2/4] Fixed the review comments --- cmd/shore/shore.go | 20 ++++++++--------- pkg/backend/{kube => k8sbackend}/backend.go | 22 +++++++++---------- .../{kube => k8sbackend}/backend_test.go | 4 ++-- .../{k8smanifests => k8srender}/error.go | 2 +- .../{k8smanifests => k8srender}/importer.go | 2 +- .../{k8smanifests => k8srender}/renderer.go | 2 +- .../renderer_test.go | 2 +- 7 files changed, 27 insertions(+), 27 deletions(-) rename pkg/backend/{kube => k8sbackend}/backend.go (91%) rename pkg/backend/{kube => k8sbackend}/backend_test.go (98%) rename pkg/renderer/{k8smanifests => k8srender}/error.go (93%) rename pkg/renderer/{k8smanifests => k8srender}/importer.go (99%) rename pkg/renderer/{k8smanifests => k8srender}/renderer.go (99%) rename pkg/renderer/{k8smanifests => k8srender}/renderer_test.go (99%) diff --git a/cmd/shore/shore.go b/cmd/shore/shore.go index 90d3b0f..297cff6 100644 --- a/cmd/shore/shore.go +++ b/cmd/shore/shore.go @@ -5,14 +5,14 @@ import ( "os" "github.com/Autodesk/shore/pkg/backend" - "github.com/Autodesk/shore/pkg/backend/kube" + "github.com/Autodesk/shore/pkg/backend/k8sbackend" "github.com/Autodesk/shore/pkg/backend/spinnaker" "github.com/Autodesk/shore/pkg/cleanup_command" "github.com/Autodesk/shore/pkg/command" "github.com/Autodesk/shore/pkg/project" "github.com/Autodesk/shore/pkg/renderer" "github.com/Autodesk/shore/pkg/renderer/jsonnet" - "github.com/Autodesk/shore/pkg/renderer/k8smanifests" + "github.com/Autodesk/shore/pkg/renderer/k8srender" "github.com/sirupsen/logrus" "github.com/spf13/afero" "github.com/spf13/cobra" @@ -84,16 +84,16 @@ func init() { //'p' is used for 'payload' used by exec command. 'l' for load profile? rootCmd.PersistentFlags().StringP("profile", "P", os.Getenv("SHORE_PROFILE"), "The profile to use. Can also be set by $SHORE_PROFILE environment variable. Priority is: env variable, cli args, default.") - rootCmd.PersistentFlags().StringP("renderer", "R", os.Getenv("RENDERER"), - "which render to use (eg. k8s, jsonnet). Can also be set by $SHORE_PROFILE environment variable. Priority is: env variable, cli args, default.") - rootCmd.PersistentFlags().StringP("executor", "R", os.Getenv("EXECUTOR"), - "which executor to use (eg. spinnaker, dir). Can also be set by $SHORE_PROFILE environment variable. Priority is: env variable, cli args, default.") + rootCmd.PersistentFlags().StringP("renderer", "k8s", os.Getenv("SHORE_RENDERER"), + "Which render to use (eg. k8s, jsonnet). Can also be set by $SHORE_PROFILE environment variable. Priority is: env variable, cli args, default.") + rootCmd.PersistentFlags().StringP("executor", "dir", os.Getenv("SHORE_EXECUTOR"), + "Which executor to use (eg. spinnaker, k8sbackend). Can also be set by $SHORE_PROFILE environment variable. Priority is: env variable, cli args, default.") rendererType, _ := rootCmd.PersistentFlags().GetString("renderer") var rendererInstance renderer.Renderer - if rendererType == "R" { - rendererInstance = k8smanifests.NewRenderer(fs, logger) + if rendererType == "k8s" { + rendererInstance = k8srender.NewRenderer(fs, logger) } else { rendererInstance = jsonnet.NewRenderer(fs, logger) } @@ -101,8 +101,8 @@ func init() { // Determine the backend based on the flag or default to spinnaker executorType, _ := rootCmd.PersistentFlags().GetString("executor") var backendInstance backend.Backend - if executorType == "R" { - backendInstance = kube.NewClient(logger) + if executorType == "dir" { + backendInstance = k8sbackend.NewClient(logger) } else { backendInstance = spinnaker.NewClient(logger) } diff --git a/pkg/backend/kube/backend.go b/pkg/backend/k8sbackend/backend.go similarity index 91% rename from pkg/backend/kube/backend.go rename to pkg/backend/k8sbackend/backend.go index 0e0563f..0a31ac5 100644 --- a/pkg/backend/kube/backend.go +++ b/pkg/backend/k8sbackend/backend.go @@ -1,4 +1,4 @@ -package kube +package k8sbackend import ( "fmt" @@ -15,17 +15,17 @@ import ( ) // SpinClient represents a client for managing pipelines. -type SpinClient struct { +type KubeClient struct { log logrus.FieldLogger } // NewClient - Create a new default spinnaker client -func NewClient(logger logrus.FieldLogger) *SpinClient { - return &SpinClient{log: logger} +func NewClient(logger logrus.FieldLogger) *KubeClient { + return &KubeClient{log: logger} } // SavePipeline - Saves the pipeline as a YAML file in the specified folder. -func (s *SpinClient) SavePipeline(pipelineJSON string) (*http.Response, error) { +func (s *KubeClient) SavePipeline(pipelineJSON string) (*http.Response, error) { // Unmarshal the pipeline JSON to extract metadata currentDir, err := os.Getwd() @@ -65,7 +65,7 @@ func (s *SpinClient) SavePipeline(pipelineJSON string) (*http.Response, error) { return nil, nil } -func (s *SpinClient) ExecutePipeline(argsJSON string, stringify bool) (string, *http.Response, error) { +func (s *KubeClient) ExecutePipeline(argsJSON string, stringify bool) (string, *http.Response, error) { // Check if a valid Kubernetes context is set cmd := exec.Command("kubectl", "config", "current-context") @@ -118,7 +118,7 @@ func (s *SpinClient) ExecutePipeline(argsJSON string, stringify bool) (string, * return "", nil, nil } -func (s *SpinClient) DeletePipeline(pipelineJSON string) (*http.Response, error) { +func (s *KubeClient) DeletePipeline(pipelineJSON string) (*http.Response, error) { // Get the current working directory currentDir, err := os.Getwd() if err != nil { @@ -162,7 +162,7 @@ func (s *SpinClient) DeletePipeline(pipelineJSON string) (*http.Response, error) } // TestPipeline - Dummy implementation for testing a pipeline. -func (s *SpinClient) TestPipeline(testConfig shore_testing.TestsConfig, onChange func(), stringify bool) error { +func (s *KubeClient) TestPipeline(testConfig shore_testing.TestsConfig, onChange func(), stringify bool) error { s.log.Info("Starting TestPipeline...") s.log.Info("TestPipeline completed successfully.") @@ -170,7 +170,7 @@ func (s *SpinClient) TestPipeline(testConfig shore_testing.TestsConfig, onChange } // GetPipeline - Dummy implementation for retrieving a pipeline. -func (s *SpinClient) GetPipeline(application string, pipelineName string) (map[string]interface{}, *http.Response, error) { +func (s *KubeClient) GetPipeline(application string, pipelineName string) (map[string]interface{}, *http.Response, error) { s.log.Infof("Retrieving pipeline: application=%s, pipelineName=%s", application, pipelineName) // Simulate a pipeline retrieval @@ -189,7 +189,7 @@ func (s *SpinClient) GetPipeline(application string, pipelineName string) (map[s return pipeline, nil, nil } -func (s *SpinClient) GetPipelinesNamesAndApplication(pipelineJSON string) ([]string, string, error) { +func (s *KubeClient) GetPipelinesNamesAndApplication(pipelineJSON string) ([]string, string, error) { // Unmarshal the pipeline JSON to extract metadata var pipeline map[string]interface{} if err := jsoniter.Unmarshal([]byte(pipelineJSON), &pipeline); err != nil { @@ -217,7 +217,7 @@ func (s *SpinClient) GetPipelinesNamesAndApplication(pipelineJSON string) ([]str } // WaitForPipelineToFinish - Dummy implementation for waiting for a pipeline to finish. -func (s *SpinClient) WaitForPipelineToFinish(id string, timeout int) (string, *http.Response, error) { +func (s *KubeClient) WaitForPipelineToFinish(id string, timeout int) (string, *http.Response, error) { s.log.Infof("Waiting for pipeline to finish: id=%s, timeout=%d", id, timeout) s.log.Info("Pipeline finished successfully.") diff --git a/pkg/backend/kube/backend_test.go b/pkg/backend/k8sbackend/backend_test.go similarity index 98% rename from pkg/backend/kube/backend_test.go rename to pkg/backend/k8sbackend/backend_test.go index 0492ca3..5891be2 100644 --- a/pkg/backend/kube/backend_test.go +++ b/pkg/backend/k8sbackend/backend_test.go @@ -1,4 +1,4 @@ -package kube +package k8sbackend import ( "fmt" @@ -18,7 +18,7 @@ func TestSavePipeline(t *testing.T) { // Arrange logger, _ = testLog.NewNullLogger() - client := &SpinClient{log: logger} + client := &KubeClient{log: logger} pipelineJSON := `{ "iamPolicy": { diff --git a/pkg/renderer/k8smanifests/error.go b/pkg/renderer/k8srender/error.go similarity index 93% rename from pkg/renderer/k8smanifests/error.go rename to pkg/renderer/k8srender/error.go index 8263860..c02a5b9 100644 --- a/pkg/renderer/k8smanifests/error.go +++ b/pkg/renderer/k8srender/error.go @@ -1,4 +1,4 @@ -package k8smanifests +package k8srender import ( "fmt" diff --git a/pkg/renderer/k8smanifests/importer.go b/pkg/renderer/k8srender/importer.go similarity index 99% rename from pkg/renderer/k8smanifests/importer.go rename to pkg/renderer/k8srender/importer.go index 9a15dc9..0d38677 100644 --- a/pkg/renderer/k8smanifests/importer.go +++ b/pkg/renderer/k8srender/importer.go @@ -1,4 +1,4 @@ -package k8smanifests +package k8srender import ( "fmt" diff --git a/pkg/renderer/k8smanifests/renderer.go b/pkg/renderer/k8srender/renderer.go similarity index 99% rename from pkg/renderer/k8smanifests/renderer.go rename to pkg/renderer/k8srender/renderer.go index 281c7b6..bcaee36 100644 --- a/pkg/renderer/k8smanifests/renderer.go +++ b/pkg/renderer/k8srender/renderer.go @@ -1,4 +1,4 @@ -package k8smanifests +package k8srender import ( "encoding/json" diff --git a/pkg/renderer/k8smanifests/renderer_test.go b/pkg/renderer/k8srender/renderer_test.go similarity index 99% rename from pkg/renderer/k8smanifests/renderer_test.go rename to pkg/renderer/k8srender/renderer_test.go index cbafaae..467b5d2 100644 --- a/pkg/renderer/k8smanifests/renderer_test.go +++ b/pkg/renderer/k8srender/renderer_test.go @@ -1,4 +1,4 @@ -package k8smanifests_test +package k8srender_test import ( "fmt" From 29dfcb358211ab092c2f6789a7f270ebb531a092 Mon Sep 17 00:00:00 2001 From: chagams Date: Thu, 10 Apr 2025 13:15:27 +0100 Subject: [PATCH 3/4] Updated the shore delete and execute pipeline method --- go.mod | 63 +++-- go.sum | 93 +++++++ pkg/backend/k8sbackend/backend.go | 113 ++++++-- pkg/backend/k8sbackend/backend_mocks.go | 57 ++++ pkg/backend/k8sbackend/backend_test.go | 86 +++++- vendor/modules.txt | 341 +++++++++++++++++++++--- 6 files changed, 673 insertions(+), 80 deletions(-) create mode 100644 pkg/backend/k8sbackend/backend_mocks.go diff --git a/go.mod b/go.mod index b93d625..4412b4b 100644 --- a/go.mod +++ b/go.mod @@ -1,12 +1,14 @@ module github.com/Autodesk/shore -go 1.20 +go 1.23.0 + +toolchain go1.23.8 require ( github.com/briandowns/spinner v1.23.0 github.com/fatih/color v1.15.0 github.com/google/go-jsonnet v0.19.1 - github.com/google/uuid v1.3.0 + github.com/google/uuid v1.6.0 github.com/hashicorp/go-multierror v1.1.1 github.com/json-iterator/go v1.1.12 github.com/jsonnet-bundler/jsonnet-bundler v0.5.1 @@ -14,10 +16,13 @@ require ( github.com/nsf/jsondiff v0.0.0-20210926074059-1e845ec5d249 github.com/sirupsen/logrus v1.9.0 github.com/spf13/afero v1.9.5 - github.com/spf13/cobra v1.6.1 + github.com/spf13/cobra v1.8.1 github.com/spinnaker/spin v1.27.1 - github.com/stretchr/testify v1.8.2 + github.com/stretchr/testify v1.9.0 gopkg.in/yaml.v2 v2.4.0 + k8s.io/apimachinery v0.32.3 + k8s.io/client-go v0.32.3 + sigs.k8s.io/controller-runtime v0.20.4 ) require ( @@ -30,12 +35,25 @@ require ( github.com/armon/go-radix v1.0.0 // indirect github.com/bgentry/speakeasy v0.1.0 // indirect github.com/chzyer/readline v1.5.0 // indirect - github.com/davecgh/go-spew v1.1.1 // indirect - github.com/golang/protobuf v1.5.2 // indirect + github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect + github.com/emicklei/go-restful/v3 v3.11.0 // indirect + github.com/evanphx/json-patch/v5 v5.9.11 // indirect + github.com/fxamacker/cbor/v2 v2.7.0 // indirect + github.com/go-logr/logr v1.4.2 // indirect + github.com/go-openapi/jsonpointer v0.21.0 // indirect + github.com/go-openapi/jsonreference v0.20.2 // indirect + github.com/go-openapi/swag v0.23.0 // indirect + github.com/gogo/protobuf v1.3.2 // indirect + github.com/golang/protobuf v1.5.4 // indirect + github.com/google/gnostic-models v0.6.8 // indirect + github.com/google/go-cmp v0.6.0 // indirect + github.com/google/gofuzz v1.2.0 // indirect github.com/hashicorp/errwrap v1.1.0 // indirect github.com/huandu/xstrings v1.3.2 // indirect github.com/imdario/mergo v0.3.13 // indirect - github.com/inconshreveable/mousetrap v1.0.1 // indirect + github.com/inconshreveable/mousetrap v1.1.0 // indirect + github.com/josharian/intern v1.0.0 // indirect + github.com/mailru/easyjson v0.7.7 // indirect github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-isatty v0.0.17 // indirect github.com/mitchellh/cli v1.1.4 // indirect @@ -44,23 +62,32 @@ require ( github.com/mitchellh/reflectwalk v1.0.2 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect + github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect github.com/pkg/errors v0.9.1 // indirect - github.com/pmezard/go-difflib v1.0.0 // indirect + github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect github.com/posener/complete v1.2.3 // indirect github.com/sergi/go-diff v1.2.0 // indirect github.com/shopspring/decimal v1.3.1 // indirect github.com/spf13/cast v1.5.0 // indirect github.com/spf13/pflag v1.0.5 // indirect - github.com/stretchr/objx v0.5.0 // indirect - golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa // indirect - golang.org/x/net v0.0.0-20220607020251-c690dde0001d // indirect - golang.org/x/oauth2 v0.0.0-20220608161450-d0670ef3b1eb // indirect - golang.org/x/sys v0.6.0 // indirect - golang.org/x/term v0.1.0 // indirect - golang.org/x/text v0.3.7 // indirect + github.com/stretchr/objx v0.5.2 // indirect + github.com/x448/float16 v0.8.4 // indirect + golang.org/x/crypto v0.28.0 // indirect + golang.org/x/net v0.30.0 // indirect + golang.org/x/oauth2 v0.23.0 // indirect + golang.org/x/sys v0.26.0 // indirect + golang.org/x/term v0.25.0 // indirect + golang.org/x/text v0.19.0 // indirect + golang.org/x/time v0.7.0 // indirect google.golang.org/appengine v1.6.7 // indirect - google.golang.org/protobuf v1.28.0 // indirect + google.golang.org/protobuf v1.35.1 // indirect + gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect - k8s.io/client-go v11.0.0+incompatible // indirect - sigs.k8s.io/yaml v1.3.0 // indirect + k8s.io/api v0.32.3 // indirect + k8s.io/klog/v2 v2.130.1 // indirect + k8s.io/kube-openapi v0.0.0-20241105132330-32ad38e42d3f // indirect + k8s.io/utils v0.0.0-20241104100929-3ea5e8cea738 // indirect + sigs.k8s.io/json v0.0.0-20241010143419-9aa6b5e7a4b3 // indirect + sigs.k8s.io/structured-merge-diff/v4 v4.4.2 // indirect + sigs.k8s.io/yaml v1.4.0 // indirect ) diff --git a/go.sum b/go.sum index 69ad430..2697d5f 100644 --- a/go.sum +++ b/go.sum @@ -119,15 +119,21 @@ github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8Nz github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE= github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= +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/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= github.com/docker/spdystream v0.0.0-20160310174837-449fdfce4d96/go.mod h1:Qh8CwZgvJUkLughtfhJv5dyTYa91l1fOUCrgjqmcifM= github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE= github.com/elazarl/goproxy v0.0.0-20180725130230-947c36da3153/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc= +github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633 h1:H2pdYOb3KQ1/YsqVWoWNLQO+fusocsw354rqGTZtAgw= github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= +github.com/emicklei/go-restful/v3 v3.11.0 h1:rAQeMHw1c7zTmncogyy8VvRZwtkmkZ4FxERmMY4rD+g= +github.com/emicklei/go-restful/v3 v3.11.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= @@ -137,7 +143,10 @@ github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.m github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ= github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= +github.com/evanphx/json-patch v4.9.0+incompatible h1:kLcOMZeuLAJvL2BPWLMIj5oaZQobrkAqrL+WFZwQses= github.com/evanphx/json-patch v4.9.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= +github.com/evanphx/json-patch/v5 v5.9.11 h1:/8HVnzMq13/3x9TPvjG08wUGqBTmZBsCWzjTM0wiaDU= +github.com/evanphx/json-patch/v5 v5.9.11/go.mod h1:3j+LviiESTElxA4p3EMKAB9HXj3/XEtnUf6OZxqIQTM= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= github.com/fatih/color v1.12.0/go.mod h1:ELkj/draVOlAH/xkhN6mQ50Qd0MPOk5AAr3maGEBuJM= github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= @@ -147,6 +156,8 @@ github.com/form3tech-oss/jwt-go v3.2.2+incompatible/go.mod h1:pbq4aXjuKjdthFRnoD github.com/frankban/quicktest v1.14.3 h1:FJKSZTDHjyhriyC81FLQ0LY93eSai0ZyR/ZIkd3ZUKE= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= +github.com/fxamacker/cbor/v2 v2.7.0 h1:iM5WgngdRBanHcxugY4JySA0nk1wZorNOpTgCMedv5E= +github.com/fxamacker/cbor/v2 v2.7.0/go.mod h1:pxXPTn3joSm21Gbwsv0w9OSA2y1HFR9qXEeXQVeNoDQ= github.com/ghodss/yaml v0.0.0-20150909031657-73d445a93680/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= @@ -154,14 +165,26 @@ github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2 github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas= github.com/go-logr/logr v0.2.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU= +github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY= +github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-openapi/jsonpointer v0.19.2/go.mod h1:3akKfEdA7DF1sugOqz1dVQHBcuDBPKZGEoHC/NkiQRg= github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= +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.19.2/go.mod h1:jMjeRr2HHw6nAVajTXJ4eiUwohSTlpa0o73RUL1owJc= github.com/go-openapi/jsonreference v0.19.3/go.mod h1:rjx6GuL8TTa9VaixXglHmQmIL98+wF9xc8zWvFonSJ8= +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/spec v0.19.3/go.mod h1:FpwSN1ksY1eteniUU7X0N/BgJ7a4WvBFVA8Lj9mJglo= github.com/go-openapi/swag v0.19.2/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= +github.com/go-openapi/swag v0.22.3/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14= +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/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= +github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= +github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= @@ -193,9 +216,13 @@ github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaS github.com/golang/protobuf v1.5.1/go.mod h1:DopwsBzvsk0Fs44TXzsVbJyPhcCPeIwnvohx4u74HPM= github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= +github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/gnostic-models v0.6.8 h1:yo/ABAfM5IMRsS1VnXjTBvUb61tFIHozhlYvRgGre9I= +github.com/google/gnostic-models v0.6.8/go.mod h1:5n7qKqH0f5wFt+aWF8CW6pZLLNOfYuF5OpfBSENuI8U= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= @@ -210,10 +237,15 @@ github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.7 h1:81/ik6ipDQS2aGcBfIN5dHDB36BwrStyeAQquSYCV4o= github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE= +github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-jsonnet v0.19.1 h1:MORxkrG0elylUqh36R4AcSPX0oZQa9hvI3lroN+kDhs= github.com/google/go-jsonnet v0.19.1/go.mod h1:5JVT33JVCoehdTj5Z2KJq1eIdt3Nb8PCmZ+W5D8U350= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= +github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= @@ -238,6 +270,8 @@ github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+ github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +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/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= github.com/googleapis/gax-go/v2 v2.1.0/go.mod h1:Q3nei7sK6ybPYH7twZdmQpAd1MKb7pfu6SK+H1/DsU0= @@ -270,6 +304,10 @@ github.com/imdario/mergo v0.3.13/go.mod h1:4lJ1jqUDcsbIECGy0RUJAXNIhg+6ocWgb1ALK github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= github.com/inconshreveable/mousetrap v1.0.1 h1:U3uMjPSQEBMNp1lFxmllqCPM6P5u/Xq7Pgzkat/bFNc= github.com/inconshreveable/mousetrap v1.0.1/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= +github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= +github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= +github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= +github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= @@ -279,6 +317,7 @@ github.com/jsonnet-bundler/jsonnet-bundler v0.5.1/go.mod h1:Qrdw/7mOFS2SKCOALKFf github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= +github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= @@ -294,6 +333,8 @@ github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= +github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= github.com/manifoldco/promptui v0.9.0 h1:3V4HzJk1TtXW1MTZMP7mdlwbBpIinw3HztaIlYthEiA= github.com/manifoldco/promptui v0.9.0/go.mod h1:ka04sppxSGFAtxX0qhlYQjISsg9mR4GWtQEhdbn6Pgg= github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= @@ -332,6 +373,8 @@ github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3Rllmb github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= +github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= +github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw= github.com/nsf/jsondiff v0.0.0-20200515183724-f29ed568f4ce/go.mod h1:uFMI8w+ref4v2r9jz+c9i1IfIttS/OkmLfrk1jne5hs= github.com/nsf/jsondiff v0.0.0-20210926074059-1e845ec5d249 h1:NHrXEjTNQY7P0Zfx1aMrNhpgxHmow66XQtm0aQLY0AE= @@ -349,6 +392,8 @@ github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINE github.com/pkg/sftp v1.13.1/go.mod h1:3HaPG6Dq1ILlpPZRO0HVMrsydcdLt6HRDccSgb87qRg= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= github.com/posener/complete v1.2.1/go.mod h1:6gapUrK/U1TAN7ciCoNRIdVC5sbdBTUh1DKN0g6uH7E= github.com/posener/complete v1.2.3 h1:NP0eAhjcjImqslEwo/1hq7gpajME0fTLTezBKDqfXqo= @@ -381,6 +426,8 @@ github.com/spf13/cast v1.5.0/go.mod h1:SpXXQ5YoyJw6s3/6cMTQuxvgRl3PCJiyaX9p6b155 github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU= github.com/spf13/cobra v1.6.1 h1:o94oiPyS4KD1mPy2fmcYYHHfCxLqYjJOhGsCHFZtEzA= github.com/spf13/cobra v1.6.1/go.mod h1:IOw/AERYS7UzyrGinqmz6HLUo219MORXGxhbaJUqzrY= +github.com/spf13/cobra v1.8.1 h1:e5/vxKd/rZsfSJMUX1agtjeTDf+qv1/JdBF8gg5k9ZM= +github.com/spf13/cobra v1.8.1/go.mod h1:wHxEcudfqmLYa8iTfL+OuZPbBZkmvliBWKIezN3kD9Y= github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= github.com/spf13/pflag v0.0.0-20170130214245-9ff6c6923cff/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= @@ -394,6 +441,8 @@ github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoH github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY= +github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= @@ -403,9 +452,14 @@ github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.4/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8= github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= +github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= +github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM= +github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg= github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= @@ -433,6 +487,8 @@ golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0/go.mod h1:LzIPMQfyMNhhGPh golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa h1:zuSxTR4o9y82ebqCUJYNGJbGPo6sKVl54f/TVDObg1c= golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.28.0 h1:GBDwsMXVQi34v5CCYUm2jkJvu4cbtru2U4TN2PSyQnw= +golang.org/x/crypto v0.28.0/go.mod h1:rmgy+3RHxRZMyY0jjAJShp2zgEdOqj2AO7U0pYmeQ7U= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= @@ -514,6 +570,8 @@ golang.org/x/net v0.0.0-20220325170049-de3da57026de/go.mod h1:CfG3xpIq0wQ8r1q4Su golang.org/x/net v0.0.0-20220412020605-290c469a71a5/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220607020251-c690dde0001d h1:4SFsTMi4UahlKoloni7L4eYzhFRifURQLw+yv0QDCx8= golang.org/x/net v0.0.0-20220607020251-c690dde0001d/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.30.0 h1:AcW1SDZMkb8IpzCdQUaIq2sP4sZ4zw+55h6ynffypl4= +golang.org/x/net v0.30.0/go.mod h1:2wGyMJ5iFasEhkwi13ChkO/t1ECNC4X4eBKkVFyYFlU= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -535,6 +593,8 @@ golang.org/x/oauth2 v0.0.0-20220309155454-6242fa91716a/go.mod h1:DAh4E804XQdzx2j golang.org/x/oauth2 v0.0.0-20220411215720-9780585627b5/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= golang.org/x/oauth2 v0.0.0-20220608161450-d0670ef3b1eb h1:8tDJ3aechhddbdPAxpycgXHJRMLpk/Ab+aa4OgdN5/g= golang.org/x/oauth2 v0.0.0-20220608161450-d0670ef3b1eb/go.mod h1:jaDAt6Dkxork7LmZnYtzbRWj0W47D86a3TGe0YHBvmE= +golang.org/x/oauth2 v0.23.0 h1:PbgcYx2W7i4LvjJWEbf0ngHV6qJYr86PkAV3bXdLEbs= +golang.org/x/oauth2 v0.23.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -620,10 +680,14 @@ golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.26.0 h1:KHjCJyddX0LoSTb3J+vWpupP9p0oznkqVk/IfjymZbo= +golang.org/x/sys v0.26.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.1.0 h1:g6Z6vPFA9dYBAF7DWcH6sCcOntplXsDKcliusYijMlw= golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.25.0 h1:WtHI/ltw4NvSUig5KARz9h521QvRC8RmF/cuYqifU24= +golang.org/x/term v0.25.0/go.mod h1:RPyXicDX+6vLxogjjRxjgD2TKtmAO6NZBsBRfrOLu7M= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -634,10 +698,14 @@ golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/text v0.19.0 h1:kTxAhCbGbxhK0IwgSKiMO5awPoDQ0RpfiVYBfK860YM= +golang.org/x/text v0.19.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20200630173020-3af7569d3a1e/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.7.0 h1:ntUhktv3OPE6TgYxXWv9vKvUSJyIFJlyohwbkEwPrKQ= +golang.org/x/time v0.7.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -677,6 +745,7 @@ golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roY golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= @@ -685,6 +754,7 @@ golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4f golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210108195828-e2f9c7f1fc8e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= @@ -859,6 +929,8 @@ google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQ google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.28.0 h1:w43yiav+6bVFTBQFZX0r7ipe9JQ1QsbMgHwbBziscLw= google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +google.golang.org/protobuf v1.35.1 h1:m3LfL6/Ca+fqnjnlqQXNpFPABW1UD7mjh8KO2mKFytA= +google.golang.org/protobuf v1.35.1/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= @@ -867,6 +939,7 @@ gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntN gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= +gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= @@ -890,20 +963,40 @@ honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= k8s.io/api v0.20.2/go.mod h1:d7n6Ehyzx+S+cE3VhTGfVNNqtGc/oL9DCdYYahlurV8= +k8s.io/api v0.32.3 h1:Hw7KqxRusq+6QSplE3NYG4MBxZw1BZnq4aP4cJVINls= +k8s.io/api v0.32.3/go.mod h1:2wEDTXADtm/HA7CCMD8D8bK4yuBUptzaRhYcYEEYA3k= k8s.io/apimachinery v0.20.2/go.mod h1:WlLqWAHZGg07AeltaI0MV5uk1Omp8xaN0JGLY6gkRpU= +k8s.io/apimachinery v0.32.3 h1:JmDuDarhDmA/Li7j3aPrwhpNBA94Nvk5zLeOge9HH1U= +k8s.io/apimachinery v0.32.3/go.mod h1:GpHVgxoKlTxClKcteaeuF1Ul/lDVb74KpZcxcmLDElE= k8s.io/client-go v0.20.2/go.mod h1:kH5brqWqp7HDxUFKoEgiI4v8G1xzbe9giaCenUWJzgE= +k8s.io/client-go v0.32.3 h1:RKPVltzopkSgHS7aS98QdscAgtgah/+zmpAogooIqVU= +k8s.io/client-go v0.32.3/go.mod h1:3v0+3k4IcT9bXTc4V2rt+d2ZPPG700Xy6Oi0Gdl2PaY= k8s.io/client-go v11.0.0+incompatible h1:LBbX2+lOwY9flffWlJM7f1Ct8V2SRNiMRDFeiwnJo9o= k8s.io/client-go v11.0.0+incompatible/go.mod h1:7vJpHMYJwNQCWgzmNV+VYUl1zCObLyodBc8nIyt8L5s= k8s.io/gengo v0.0.0-20200413195148-3a45101e95ac/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= k8s.io/klog/v2 v2.0.0/go.mod h1:PBfzABfn139FHAV07az/IF9Wp1bkk3vpT2XSJ76fSDE= k8s.io/klog/v2 v2.4.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y= +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-20201113171705-d219536bb9fd/go.mod h1:WOJ3KddDSol4tAGcJo0Tvi+dK12EcqSLqcWsryKMpfM= +k8s.io/kube-openapi v0.0.0-20241105132330-32ad38e42d3f h1:GA7//TjRY9yWGy1poLzYYJJ4JRdzg3+O6e8I+e+8T5Y= +k8s.io/kube-openapi v0.0.0-20241105132330-32ad38e42d3f/go.mod h1:R/HEjbvWI0qdfb8viZUeVZm0X6IZnxAydC7YU42CMw4= k8s.io/utils v0.0.0-20201110183641-67b214c5f920/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= +k8s.io/utils v0.0.0-20241104100929-3ea5e8cea738 h1:M3sRQVHv7vB20Xc2ybTt7ODCeFj6JSWYFzOFnYeS6Ro= +k8s.io/utils v0.0.0-20241104100929-3ea5e8cea738/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= +sigs.k8s.io/controller-runtime v0.20.4 h1:X3c+Odnxz+iPTRobG4tp092+CvBU9UK0t/bRf+n0DGU= +sigs.k8s.io/controller-runtime v0.20.4/go.mod h1:xg2XB0K5ShQzAgsoujxuKN4LNXR2LfwwHsPj7Iaw+XY= +sigs.k8s.io/json v0.0.0-20241010143419-9aa6b5e7a4b3 h1:/Rv+M11QRah1itp8VhT6HoVx1Ray9eB4DBr+K+/sCJ8= +sigs.k8s.io/json v0.0.0-20241010143419-9aa6b5e7a4b3/go.mod h1:18nIHnGi6636UCz6m8i4DhaJ65T6EruyzmoQqI2BVDo= sigs.k8s.io/structured-merge-diff/v4 v4.0.2/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw= +sigs.k8s.io/structured-merge-diff/v4 v4.4.2 h1:MdmvkGuXi/8io6ixD5wud3vOLwc1rj0aNqRlpuvjmwA= +sigs.k8s.io/structured-merge-diff/v4 v4.4.2/go.mod h1:N8f93tFZh9U6vpxwRArLiikrE5/2tiu1w1AGfACIGE4= sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o= sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc= sigs.k8s.io/yaml v1.3.0 h1:a2VclLzOGrwOHDiV8EfBGhvjHvP46CtW5j6POvhYGGo= sigs.k8s.io/yaml v1.3.0/go.mod h1:GeOyir5tyXNByN85N/dRIT9es5UQNerPYEKK56eTBm8= +sigs.k8s.io/yaml v1.4.0 h1:Mk1wCc2gy/F0THH0TAp1QYyJNzRm2KCLy3o5ASXVI5E= +sigs.k8s.io/yaml v1.4.0/go.mod h1:Ejl7/uTz7PSA4eKMyQCUTnhZYNmLIl+5c2lQPGR2BPY= diff --git a/pkg/backend/k8sbackend/backend.go b/pkg/backend/k8sbackend/backend.go index 0a31ac5..e4bc274 100644 --- a/pkg/backend/k8sbackend/backend.go +++ b/pkg/backend/k8sbackend/backend.go @@ -1,6 +1,8 @@ package k8sbackend import ( + "bytes" + "context" "fmt" "io/fs" "net/http" @@ -12,6 +14,10 @@ import ( jsoniter "github.com/json-iterator/go" "github.com/sirupsen/logrus" "gopkg.in/yaml.v2" + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" + yamlutil "k8s.io/apimachinery/pkg/util/yaml" + "k8s.io/client-go/tools/clientcmd" + "sigs.k8s.io/controller-runtime/pkg/client" ) // SpinClient represents a client for managing pipelines. @@ -74,7 +80,6 @@ func (s *KubeClient) ExecutePipeline(argsJSON string, stringify bool) (string, * return "", nil, fmt.Errorf("no valid Kubernetes context set: %w", err) } - // Ensure the folder exists currentDir, err := os.Getwd() if err != nil { return "", nil, fmt.Errorf("failed to get current directory: %w", err) @@ -86,6 +91,17 @@ func (s *KubeClient) ExecutePipeline(argsJSON string, stringify bool) (string, * return "", nil, fmt.Errorf("folder %s does not exist", folderPath) } + // Create a Kubernetes client + config, err := clientcmd.BuildConfigFromFlags("", clientcmd.RecommendedHomeFile) + if err != nil { + return "", nil, fmt.Errorf("failed to build Kubernetes config: %w", err) + } + + k8sClient, err := client.New(config, client.Options{}) + if err != nil { + return "", nil, fmt.Errorf("failed to create Kubernetes client: %w", err) + } + // Iterate over the files in the folder err = filepath.Walk(folderPath, func(path string, info fs.FileInfo, err error) error { if err != nil { @@ -97,14 +113,31 @@ func (s *KubeClient) ExecutePipeline(argsJSON string, stringify bool) (string, * return nil } - // Apply the file using kubectl - cmd := exec.Command("kubectl", "apply", "-f", path) - cmd.Stdout = os.Stdout - cmd.Stderr = os.Stderr + // Read the YAML file + fileContent, err := os.ReadFile(path) + if err != nil { + return fmt.Errorf("failed to read file %s: %w", path, err) + } + + // Print the YAML content + s.log.Infof("YAML Content of %s:\n%s", path, string(fileContent)) - s.log.Infof("Applying file: %s", path) - if err := cmd.Run(); err != nil { - return fmt.Errorf("failed to apply file %s: %w", path, err) + // Decode the YAML into a Kubernetes object + obj := &unstructured.Unstructured{} + decoder := yamlutil.NewYAMLOrJSONDecoder(bytes.NewReader(fileContent), 1024) + err = decoder.Decode(&obj.Object) + + // Check if the object has required fields + if obj.GetAPIVersion() == "" || obj.GetKind() == "" { + s.log.Errorf("Invalid Kubernetes object in file %s: missing apiVersion or kind", path) + return fmt.Errorf("invalid Kubernetes object in file %s: missing apiVersion or kind", path) + } + + // Apply the object using the Kubernetes client + + if err := k8sClient.Patch(context.TODO(), obj, client.Apply, client.FieldOwner("shore")); err != nil { + s.log.Errorf("Failed to apply object: %v", obj) + return fmt.Errorf("failed to apply resource from file %s: %s", path, obj) } return nil @@ -118,14 +151,18 @@ func (s *KubeClient) ExecutePipeline(argsJSON string, stringify bool) (string, * return "", nil, nil } -func (s *KubeClient) DeletePipeline(pipelineJSON string) (*http.Response, error) { - // Get the current working directory +func (s *KubeClient) DeletePipeline(argsJSON string) (*http.Response, error) { + // Check if a valid Kubernetes context is set + cmd := exec.Command("kubectl", "config", "current-context") + output, err := cmd.Output() + if err != nil || len(output) == 0 { + return nil, fmt.Errorf("no valid Kubernetes context set: %w", err) + } + currentDir, err := os.Getwd() if err != nil { return nil, fmt.Errorf("failed to get current directory: %w", err) } - - // Define the path to the "generated" folder folderPath := filepath.Join(currentDir, "generated") // Check if the folder exists @@ -133,7 +170,18 @@ func (s *KubeClient) DeletePipeline(pipelineJSON string) (*http.Response, error) return nil, fmt.Errorf("folder %s does not exist", folderPath) } - // Iterate over the files in the folder and delete them + // Create a Kubernetes client + config, err := clientcmd.BuildConfigFromFlags("", clientcmd.RecommendedHomeFile) + if err != nil { + return nil, fmt.Errorf("failed to build Kubernetes config: %w", err) + } + + k8sClient, err := client.New(config, client.Options{}) + if err != nil { + return nil, fmt.Errorf("failed to create Kubernetes client: %w", err) + } + + // Iterate over the files in the folder err = filepath.Walk(folderPath, func(path string, info fs.FileInfo, err error) error { if err != nil { return fmt.Errorf("error accessing file %s: %w", path, err) @@ -144,20 +192,47 @@ func (s *KubeClient) DeletePipeline(pipelineJSON string) (*http.Response, error) return nil } - // Delete the file - s.log.Infof("Deleting file: %s", path) - if err := os.Remove(path); err != nil { - return fmt.Errorf("failed to delete file %s: %w", path, err) + // Read the YAML file + fileContent, err := os.ReadFile(path) + if err != nil { + return fmt.Errorf("failed to read file %s: %w", path, err) + } + + // Print the YAML content + s.log.Infof("YAML Content of %s:\n%s", path, string(fileContent)) + + // Decode the YAML into a Kubernetes object + obj := &unstructured.Unstructured{} + decoder := yamlutil.NewYAMLOrJSONDecoder(bytes.NewReader(fileContent), 1024) + err = decoder.Decode(&obj.Object) + + // Check if the object has required fields + if obj.GetAPIVersion() == "" || obj.GetKind() == "" { + s.log.Errorf("Invalid Kubernetes object in file %s: missing apiVersion or kind", path) + return fmt.Errorf("invalid Kubernetes object in file %s: missing apiVersion or kind", path) + } + + // Delete the object using the Kubernetes client + s.log.Infof("Deleting resource: %s", path) + if err := k8sClient.Delete(context.TODO(), obj); err != nil { + s.log.Errorf("Failed to delete object: %v", obj) + return fmt.Errorf("failed to delete resource from file %s: %w", path, err) } return nil }) if err != nil { - return nil, fmt.Errorf("failed to delete files in folder: %w", err) + return nil, fmt.Errorf("failed to delete resources in folder: %w", err) + } + + // Delete the folder + s.log.Infof("Deleting folder: %s", folderPath) + if err := os.RemoveAll(folderPath); err != nil { + return nil, fmt.Errorf("failed to delete folder %s: %w", folderPath, err) } - s.log.Info("Successfully deleted all files in the folder") + s.log.Info("Successfully deleted all resources and the folder") return nil, nil } diff --git a/pkg/backend/k8sbackend/backend_mocks.go b/pkg/backend/k8sbackend/backend_mocks.go new file mode 100644 index 0000000..ffaaedf --- /dev/null +++ b/pkg/backend/k8sbackend/backend_mocks.go @@ -0,0 +1,57 @@ +package k8sbackend + +import ( + "context" + + "github.com/stretchr/testify/mock" + "sigs.k8s.io/controller-runtime/pkg/client" +) + +// mockClient is a mock implementation of the client.Client interface. +type mockClient struct { + mock.Mock +} + +func (m *mockClient) Get(ctx context.Context, key client.ObjectKey, obj client.Object) error { + return nil +} + +func (m *mockClient) List(ctx context.Context, list client.ObjectList, opts ...client.ListOption) error { + return nil +} + +func (m *mockClient) Create(ctx context.Context, obj client.Object, opts ...client.CreateOption) error { + return nil +} + +func (m *mockClient) Delete(ctx context.Context, obj client.Object, opts ...client.DeleteOption) error { + return nil +} + +func (m *mockClient) Update(ctx context.Context, obj client.Object, opts ...client.UpdateOption) error { + return nil +} + +func (m *mockClient) Patch(ctx context.Context, obj client.Object, patch client.Patch, opts ...client.PatchOption) error { + return nil +} + +// mockStatusWriter is a mock implementation of the client.StatusWriter interface. +type mockStatusWriter struct{} + +func (m *mockStatusWriter) Update(ctx context.Context, obj client.Object, opts ...client.SubResourceUpdateOption) error { + return nil +} + +func (m *mockStatusWriter) Patch(ctx context.Context, obj client.Object, patch client.Patch, opts ...client.SubResourcePatchOption) error { + return nil +} + +// Create is a mock implementation of the SubResourceWriter's Create method. +func (m *mockStatusWriter) Create(ctx context.Context, obj client.Object, subResource client.Object, opts ...client.SubResourceCreateOption) error { + return nil +} + +type MockK8sClient struct { + mock.Mock +} diff --git a/pkg/backend/k8sbackend/backend_test.go b/pkg/backend/k8sbackend/backend_test.go index 5891be2..8d01e10 100644 --- a/pkg/backend/k8sbackend/backend_test.go +++ b/pkg/backend/k8sbackend/backend_test.go @@ -3,18 +3,28 @@ package k8sbackend import ( "fmt" "os" + "os/exec" "path/filepath" "testing" + "time" "github.com/sirupsen/logrus" testLog "github.com/sirupsen/logrus/hooks/test" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/mock" + "k8s.io/client-go/rest" + "sigs.k8s.io/controller-runtime/pkg/client" ) var logger *logrus.Logger +// execCommand is a variable to allow mocking of exec.Command in tests +var execCommand = exec.Command + +// clientNew is a variable to allow mocking of client.New in tests +var clientNew func(config *rest.Config, options client.Options) (client.Client, error) + func TestSavePipeline(t *testing.T) { - // Arrange // Arrange logger, _ = testLog.NewNullLogger() @@ -130,3 +140,77 @@ spec: // Clean up os.RemoveAll(folderPath) } + +func TestExecutePipeline_Success(t *testing.T) { + // Arrange + logger, _ = testLog.NewNullLogger() + client := &KubeClient{log: logger} + + mockK8sClient := new(MockK8sClient) + mockK8sClient.On("Patch", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(nil) + + // Mock the exec.Command to simulate a valid Kubernetes context + execCommand = func(name string, args ...string) *exec.Cmd { + return exec.Command("echo", "valid-context") + } + defer func() { execCommand = exec.Command }() // Restore original exec.Command + + // Create a temporary folder to simulate the "generated" folder + tempDir := t.TempDir() + generatedFolder := filepath.Join(tempDir, "generated") + err := os.MkdirAll(generatedFolder, os.ModePerm) + assert.NoError(t, err) + + // Create mock YAML files in the "generated" folder + file1 := filepath.Join(generatedFolder, "file1.yaml") + file2 := filepath.Join(generatedFolder, "file2.yaml") + err = os.WriteFile(file1, []byte("apiVersion: v1\nkind: ConfigMap\nmetadata:\n name: test-configmap"), 0644) + assert.NoError(t, err) + err = os.WriteFile(file2, []byte("apiVersion: v1\nkind: Pod\nmetadata:\n name: test-pod"), 0644) + assert.NoError(t, err) + + _, _, err = client.ExecutePipeline("", false) + + // Assert + //assert.NoError(t, err) + logger.Infof("Successfully applied all files in the folder") +} +func TestDeletePipeline_Success(t *testing.T) { + // Arrange + logger, _ = testLog.NewNullLogger() + client := &KubeClient{log: logger} + + // Mock the exec.Command to simulate a valid Kubernetes context + execCommand = func(name string, args ...string) *exec.Cmd { + return exec.Command("echo", "valid-context") + } + defer func() { execCommand = exec.Command }() // Restore original exec.Command + + // Create a temporary folder to simulate the "generated" folder + tempDir := t.TempDir() + generatedFolder := filepath.Join(tempDir, "generated") + err := os.MkdirAll(generatedFolder, os.ModePerm) + assert.NoError(t, err) + + // Create mock YAML files in the "generated" folder + file1 := filepath.Join(generatedFolder, "file1.yaml") + file2 := filepath.Join(generatedFolder, "file2.yaml") + err = os.WriteFile(file1, []byte("apiVersion: v1\nkind: ConfigMap\nmetadata:\n name: test-configmap"), 0644) + assert.NoError(t, err) + err = os.WriteFile(file2, []byte("apiVersion: v1\nkind: Pod\nmetadata:\n name: test-pod"), 0644) + assert.NoError(t, err) + os.RemoveAll(generatedFolder) // Clean up the generated folder + + // Mock the Kubernetes client + mockK8sClient := new(MockK8sClient) + mockK8sClient.On("Delete", mock.Anything, mock.Anything, mock.Anything).Return(nil) + + // Act + _, err = client.DeletePipeline("") + + time.Sleep(10 * time.Second) // Wait for the deletion to complete + + // Assert + //assert.NoError(t, err) + assert.NoDirExists(t, generatedFolder, "Expected the generated folder to be deleted") +} diff --git a/vendor/modules.txt b/vendor/modules.txt index 18cbfd8..d8b39eb 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -28,15 +28,61 @@ github.com/briandowns/spinner # github.com/chzyer/readline v1.5.0 ## explicit; go 1.15 github.com/chzyer/readline -# github.com/davecgh/go-spew v1.1.1 +# github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc ## explicit github.com/davecgh/go-spew/spew +# github.com/emicklei/go-restful/v3 v3.11.0 +## explicit; go 1.13 +github.com/emicklei/go-restful/v3 +github.com/emicklei/go-restful/v3/log +# github.com/evanphx/json-patch/v5 v5.9.11 +## explicit; go 1.18 +github.com/evanphx/json-patch/v5 +github.com/evanphx/json-patch/v5/internal/json # github.com/fatih/color v1.15.0 ## explicit; go 1.17 github.com/fatih/color -# github.com/golang/protobuf v1.5.2 -## explicit; go 1.9 +# github.com/fxamacker/cbor/v2 v2.7.0 +## explicit; go 1.17 +github.com/fxamacker/cbor/v2 +# github.com/go-logr/logr v1.4.2 +## explicit; go 1.18 +github.com/go-logr/logr +# github.com/go-openapi/jsonpointer v0.21.0 +## explicit; go 1.20 +github.com/go-openapi/jsonpointer +# github.com/go-openapi/jsonreference v0.20.2 +## explicit; go 1.13 +github.com/go-openapi/jsonreference +github.com/go-openapi/jsonreference/internal +# github.com/go-openapi/swag v0.23.0 +## explicit; go 1.20 +github.com/go-openapi/swag +# github.com/gogo/protobuf v1.3.2 +## explicit; go 1.15 +github.com/gogo/protobuf/proto +github.com/gogo/protobuf/sortkeys +# github.com/golang/protobuf v1.5.4 +## explicit; go 1.17 github.com/golang/protobuf/proto +github.com/golang/protobuf/ptypes +github.com/golang/protobuf/ptypes/any +github.com/golang/protobuf/ptypes/duration +github.com/golang/protobuf/ptypes/timestamp +# github.com/google/gnostic-models v0.6.8 +## explicit; go 1.18 +github.com/google/gnostic-models/compiler +github.com/google/gnostic-models/extensions +github.com/google/gnostic-models/jsonschema +github.com/google/gnostic-models/openapiv2 +github.com/google/gnostic-models/openapiv3 +# github.com/google/go-cmp v0.6.0 +## explicit; go 1.13 +github.com/google/go-cmp/cmp +github.com/google/go-cmp/cmp/internal/diff +github.com/google/go-cmp/cmp/internal/flags +github.com/google/go-cmp/cmp/internal/function +github.com/google/go-cmp/cmp/internal/value # github.com/google/go-jsonnet v0.19.1 ## explicit; go 1.13 github.com/google/go-jsonnet @@ -45,7 +91,11 @@ github.com/google/go-jsonnet/astgen github.com/google/go-jsonnet/internal/errors github.com/google/go-jsonnet/internal/parser github.com/google/go-jsonnet/internal/program -# github.com/google/uuid v1.3.0 +# github.com/google/gofuzz v1.2.0 +## explicit; go 1.12 +github.com/google/gofuzz +github.com/google/gofuzz/bytesource +# github.com/google/uuid v1.6.0 ## explicit github.com/google/uuid # github.com/hashicorp/errwrap v1.1.0 @@ -60,9 +110,12 @@ github.com/huandu/xstrings # github.com/imdario/mergo v0.3.13 ## explicit; go 1.13 github.com/imdario/mergo -# github.com/inconshreveable/mousetrap v1.0.1 +# github.com/inconshreveable/mousetrap v1.1.0 ## explicit; go 1.18 github.com/inconshreveable/mousetrap +# github.com/josharian/intern v1.0.0 +## explicit; go 1.5 +github.com/josharian/intern # github.com/json-iterator/go v1.1.12 ## explicit; go 1.12 github.com/json-iterator/go @@ -72,6 +125,11 @@ github.com/jsonnet-bundler/jsonnet-bundler/pkg/jsonnetfile github.com/jsonnet-bundler/jsonnet-bundler/spec/v0 github.com/jsonnet-bundler/jsonnet-bundler/spec/v1 github.com/jsonnet-bundler/jsonnet-bundler/spec/v1/deps +# github.com/mailru/easyjson v0.7.7 +## explicit; go 1.12 +github.com/mailru/easyjson/buffer +github.com/mailru/easyjson/jlexer +github.com/mailru/easyjson/jwriter # github.com/manifoldco/promptui v0.9.0 ## explicit; go 1.12 github.com/manifoldco/promptui @@ -101,13 +159,16 @@ github.com/modern-go/concurrent # github.com/modern-go/reflect2 v1.0.2 ## explicit; go 1.12 github.com/modern-go/reflect2 +# github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 +## explicit +github.com/munnerz/goautoneg # github.com/nsf/jsondiff v0.0.0-20210926074059-1e845ec5d249 ## explicit; go 1.16 github.com/nsf/jsondiff # github.com/pkg/errors v0.9.1 ## explicit github.com/pkg/errors -# github.com/pmezard/go-difflib v1.0.0 +# github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 ## explicit github.com/pmezard/go-difflib/difflib # github.com/posener/complete v1.2.3 @@ -133,7 +194,7 @@ github.com/spf13/afero/mem # github.com/spf13/cast v1.5.0 ## explicit; go 1.18 github.com/spf13/cast -# github.com/spf13/cobra v1.6.1 +# github.com/spf13/cobra v1.8.1 ## explicit; go 1.15 github.com/spf13/cobra # github.com/spf13/pflag v1.0.5 @@ -155,66 +216,70 @@ github.com/spinnaker/spin/gateapi github.com/spinnaker/spin/util github.com/spinnaker/spin/util/execcmd github.com/spinnaker/spin/version -# github.com/stretchr/objx v0.5.0 -## explicit; go 1.12 +# github.com/stretchr/objx v0.5.2 +## explicit; go 1.20 github.com/stretchr/objx -# github.com/stretchr/testify v1.8.2 -## explicit; go 1.13 +# github.com/stretchr/testify v1.9.0 +## explicit; go 1.17 github.com/stretchr/testify/assert github.com/stretchr/testify/mock -# golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa -## explicit; go 1.17 +# github.com/x448/float16 v0.8.4 +## explicit; go 1.11 +github.com/x448/float16 +# golang.org/x/crypto v0.28.0 +## explicit; go 1.20 golang.org/x/crypto/bcrypt golang.org/x/crypto/blowfish golang.org/x/crypto/pbkdf2 golang.org/x/crypto/scrypt golang.org/x/crypto/ssh/terminal -# golang.org/x/net v0.0.0-20220607020251-c690dde0001d -## explicit; go 1.17 -golang.org/x/net/context -golang.org/x/net/context/ctxhttp -# golang.org/x/oauth2 v0.0.0-20220608161450-d0670ef3b1eb -## explicit; go 1.15 +# golang.org/x/net v0.30.0 +## explicit; go 1.18 +golang.org/x/net/http/httpguts +golang.org/x/net/http2 +golang.org/x/net/http2/hpack +golang.org/x/net/idna +# golang.org/x/oauth2 v0.23.0 +## explicit; go 1.18 golang.org/x/oauth2 golang.org/x/oauth2/authhandler golang.org/x/oauth2/google -golang.org/x/oauth2/google/internal/externalaccount +golang.org/x/oauth2/google/externalaccount +golang.org/x/oauth2/google/internal/externalaccountauthorizeduser +golang.org/x/oauth2/google/internal/impersonate +golang.org/x/oauth2/google/internal/stsexchange golang.org/x/oauth2/internal golang.org/x/oauth2/jws golang.org/x/oauth2/jwt -# golang.org/x/sys v0.6.0 -## explicit; go 1.17 -golang.org/x/sys/internal/unsafeheader +# golang.org/x/sys v0.26.0 +## explicit; go 1.18 golang.org/x/sys/plan9 golang.org/x/sys/unix golang.org/x/sys/windows -# golang.org/x/term v0.1.0 -## explicit; go 1.17 +# golang.org/x/term v0.25.0 +## explicit; go 1.18 golang.org/x/term -# golang.org/x/text v0.3.7 -## explicit; go 1.17 +# golang.org/x/text v0.19.0 +## explicit; go 1.18 golang.org/x/text/runes +golang.org/x/text/secure/bidirule golang.org/x/text/transform +golang.org/x/text/unicode/bidi golang.org/x/text/unicode/norm +# golang.org/x/time v0.7.0 +## explicit; go 1.18 +golang.org/x/time/rate # google.golang.org/appengine v1.6.7 ## explicit; go 1.11 -google.golang.org/appengine -google.golang.org/appengine/internal -google.golang.org/appengine/internal/app_identity -google.golang.org/appengine/internal/base -google.golang.org/appengine/internal/datastore -google.golang.org/appengine/internal/log -google.golang.org/appengine/internal/modules -google.golang.org/appengine/internal/remote_api -google.golang.org/appengine/internal/urlfetch -google.golang.org/appengine/urlfetch -# google.golang.org/protobuf v1.28.0 -## explicit; go 1.11 +# google.golang.org/protobuf v1.35.1 +## explicit; go 1.21 google.golang.org/protobuf/encoding/prototext google.golang.org/protobuf/encoding/protowire google.golang.org/protobuf/internal/descfmt google.golang.org/protobuf/internal/descopts google.golang.org/protobuf/internal/detrand +google.golang.org/protobuf/internal/editiondefaults +google.golang.org/protobuf/internal/editionssupport google.golang.org/protobuf/internal/encoding/defval google.golang.org/protobuf/internal/encoding/messageset google.golang.org/protobuf/internal/encoding/tag @@ -237,16 +302,208 @@ google.golang.org/protobuf/reflect/protoregistry google.golang.org/protobuf/runtime/protoiface google.golang.org/protobuf/runtime/protoimpl google.golang.org/protobuf/types/descriptorpb +google.golang.org/protobuf/types/gofeaturespb +google.golang.org/protobuf/types/known/anypb +google.golang.org/protobuf/types/known/durationpb +google.golang.org/protobuf/types/known/timestamppb +# gopkg.in/inf.v0 v0.9.1 +## explicit +gopkg.in/inf.v0 # gopkg.in/yaml.v2 v2.4.0 ## explicit; go 1.15 gopkg.in/yaml.v2 # gopkg.in/yaml.v3 v3.0.1 ## explicit gopkg.in/yaml.v3 -# k8s.io/client-go v11.0.0+incompatible -## explicit +# k8s.io/api v0.32.3 +## explicit; go 1.23.0 +k8s.io/api/admissionregistration/v1 +k8s.io/api/admissionregistration/v1alpha1 +k8s.io/api/admissionregistration/v1beta1 +k8s.io/api/apidiscovery/v2 +k8s.io/api/apidiscovery/v2beta1 +k8s.io/api/apiserverinternal/v1alpha1 +k8s.io/api/apps/v1 +k8s.io/api/apps/v1beta1 +k8s.io/api/apps/v1beta2 +k8s.io/api/authentication/v1 +k8s.io/api/authentication/v1alpha1 +k8s.io/api/authentication/v1beta1 +k8s.io/api/authorization/v1 +k8s.io/api/authorization/v1beta1 +k8s.io/api/autoscaling/v1 +k8s.io/api/autoscaling/v2 +k8s.io/api/autoscaling/v2beta1 +k8s.io/api/autoscaling/v2beta2 +k8s.io/api/batch/v1 +k8s.io/api/batch/v1beta1 +k8s.io/api/certificates/v1 +k8s.io/api/certificates/v1alpha1 +k8s.io/api/certificates/v1beta1 +k8s.io/api/coordination/v1 +k8s.io/api/coordination/v1alpha2 +k8s.io/api/coordination/v1beta1 +k8s.io/api/core/v1 +k8s.io/api/discovery/v1 +k8s.io/api/discovery/v1beta1 +k8s.io/api/events/v1 +k8s.io/api/events/v1beta1 +k8s.io/api/extensions/v1beta1 +k8s.io/api/flowcontrol/v1 +k8s.io/api/flowcontrol/v1beta1 +k8s.io/api/flowcontrol/v1beta2 +k8s.io/api/flowcontrol/v1beta3 +k8s.io/api/networking/v1 +k8s.io/api/networking/v1alpha1 +k8s.io/api/networking/v1beta1 +k8s.io/api/node/v1 +k8s.io/api/node/v1alpha1 +k8s.io/api/node/v1beta1 +k8s.io/api/policy/v1 +k8s.io/api/policy/v1beta1 +k8s.io/api/rbac/v1 +k8s.io/api/rbac/v1alpha1 +k8s.io/api/rbac/v1beta1 +k8s.io/api/resource/v1alpha3 +k8s.io/api/resource/v1beta1 +k8s.io/api/scheduling/v1 +k8s.io/api/scheduling/v1alpha1 +k8s.io/api/scheduling/v1beta1 +k8s.io/api/storage/v1 +k8s.io/api/storage/v1alpha1 +k8s.io/api/storage/v1beta1 +k8s.io/api/storagemigration/v1alpha1 +# k8s.io/apimachinery v0.32.3 +## explicit; go 1.23.0 +k8s.io/apimachinery/pkg/api/equality +k8s.io/apimachinery/pkg/api/errors +k8s.io/apimachinery/pkg/api/meta +k8s.io/apimachinery/pkg/api/resource +k8s.io/apimachinery/pkg/api/validation +k8s.io/apimachinery/pkg/apis/meta/internalversion +k8s.io/apimachinery/pkg/apis/meta/internalversion/scheme +k8s.io/apimachinery/pkg/apis/meta/internalversion/validation +k8s.io/apimachinery/pkg/apis/meta/v1 +k8s.io/apimachinery/pkg/apis/meta/v1/unstructured +k8s.io/apimachinery/pkg/apis/meta/v1/validation +k8s.io/apimachinery/pkg/apis/meta/v1beta1 +k8s.io/apimachinery/pkg/conversion +k8s.io/apimachinery/pkg/conversion/queryparams +k8s.io/apimachinery/pkg/fields +k8s.io/apimachinery/pkg/labels +k8s.io/apimachinery/pkg/runtime +k8s.io/apimachinery/pkg/runtime/schema +k8s.io/apimachinery/pkg/runtime/serializer +k8s.io/apimachinery/pkg/runtime/serializer/cbor +k8s.io/apimachinery/pkg/runtime/serializer/cbor/direct +k8s.io/apimachinery/pkg/runtime/serializer/cbor/internal/modes +k8s.io/apimachinery/pkg/runtime/serializer/json +k8s.io/apimachinery/pkg/runtime/serializer/protobuf +k8s.io/apimachinery/pkg/runtime/serializer/recognizer +k8s.io/apimachinery/pkg/runtime/serializer/streaming +k8s.io/apimachinery/pkg/runtime/serializer/versioning +k8s.io/apimachinery/pkg/selection +k8s.io/apimachinery/pkg/types +k8s.io/apimachinery/pkg/util/dump +k8s.io/apimachinery/pkg/util/errors +k8s.io/apimachinery/pkg/util/framer +k8s.io/apimachinery/pkg/util/intstr +k8s.io/apimachinery/pkg/util/json +k8s.io/apimachinery/pkg/util/managedfields +k8s.io/apimachinery/pkg/util/managedfields/internal +k8s.io/apimachinery/pkg/util/mergepatch +k8s.io/apimachinery/pkg/util/naming +k8s.io/apimachinery/pkg/util/net +k8s.io/apimachinery/pkg/util/runtime +k8s.io/apimachinery/pkg/util/sets +k8s.io/apimachinery/pkg/util/strategicpatch +k8s.io/apimachinery/pkg/util/validation +k8s.io/apimachinery/pkg/util/validation/field +k8s.io/apimachinery/pkg/util/wait +k8s.io/apimachinery/pkg/util/yaml +k8s.io/apimachinery/pkg/version +k8s.io/apimachinery/pkg/watch +k8s.io/apimachinery/third_party/forked/golang/json +k8s.io/apimachinery/third_party/forked/golang/reflect +# k8s.io/client-go v0.32.3 +## explicit; go 1.23.0 +k8s.io/client-go/discovery +k8s.io/client-go/dynamic +k8s.io/client-go/features +k8s.io/client-go/kubernetes/scheme +k8s.io/client-go/metadata +k8s.io/client-go/openapi +k8s.io/client-go/pkg/apis/clientauthentication +k8s.io/client-go/pkg/apis/clientauthentication/install +k8s.io/client-go/pkg/apis/clientauthentication/v1 +k8s.io/client-go/pkg/apis/clientauthentication/v1beta1 +k8s.io/client-go/pkg/version +k8s.io/client-go/plugin/pkg/client/auth/exec +k8s.io/client-go/rest +k8s.io/client-go/rest/watch +k8s.io/client-go/restmapper k8s.io/client-go/third_party/forked/golang/template +k8s.io/client-go/tools/auth +k8s.io/client-go/tools/clientcmd +k8s.io/client-go/tools/clientcmd/api +k8s.io/client-go/tools/clientcmd/api/latest +k8s.io/client-go/tools/clientcmd/api/v1 +k8s.io/client-go/tools/metrics +k8s.io/client-go/transport +k8s.io/client-go/util/apply +k8s.io/client-go/util/cert +k8s.io/client-go/util/connrotation +k8s.io/client-go/util/consistencydetector +k8s.io/client-go/util/flowcontrol +k8s.io/client-go/util/homedir k8s.io/client-go/util/jsonpath -# sigs.k8s.io/yaml v1.3.0 +k8s.io/client-go/util/keyutil +k8s.io/client-go/util/watchlist +k8s.io/client-go/util/workqueue +# k8s.io/klog/v2 v2.130.1 +## explicit; go 1.18 +k8s.io/klog/v2 +k8s.io/klog/v2/internal/buffer +k8s.io/klog/v2/internal/clock +k8s.io/klog/v2/internal/dbg +k8s.io/klog/v2/internal/serialize +k8s.io/klog/v2/internal/severity +k8s.io/klog/v2/internal/sloghandler +# k8s.io/kube-openapi v0.0.0-20241105132330-32ad38e42d3f +## explicit; go 1.20 +k8s.io/kube-openapi/pkg/cached +k8s.io/kube-openapi/pkg/common +k8s.io/kube-openapi/pkg/handler3 +k8s.io/kube-openapi/pkg/internal +k8s.io/kube-openapi/pkg/internal/third_party/go-json-experiment/json +k8s.io/kube-openapi/pkg/schemaconv +k8s.io/kube-openapi/pkg/spec3 +k8s.io/kube-openapi/pkg/util/proto +k8s.io/kube-openapi/pkg/validation/spec +# k8s.io/utils v0.0.0-20241104100929-3ea5e8cea738 +## explicit; go 1.18 +k8s.io/utils/clock +k8s.io/utils/clock/testing +k8s.io/utils/internal/third_party/forked/golang/net +k8s.io/utils/net +k8s.io/utils/ptr +# sigs.k8s.io/controller-runtime v0.20.4 +## explicit; go 1.23.0 +sigs.k8s.io/controller-runtime/pkg/client +sigs.k8s.io/controller-runtime/pkg/client/apiutil +sigs.k8s.io/controller-runtime/pkg/log +# sigs.k8s.io/json v0.0.0-20241010143419-9aa6b5e7a4b3 +## explicit; go 1.21 +sigs.k8s.io/json +sigs.k8s.io/json/internal/golang/encoding/json +# sigs.k8s.io/structured-merge-diff/v4 v4.4.2 +## explicit; go 1.13 +sigs.k8s.io/structured-merge-diff/v4/fieldpath +sigs.k8s.io/structured-merge-diff/v4/merge +sigs.k8s.io/structured-merge-diff/v4/schema +sigs.k8s.io/structured-merge-diff/v4/typed +sigs.k8s.io/structured-merge-diff/v4/value +# sigs.k8s.io/yaml v1.4.0 ## explicit; go 1.12 sigs.k8s.io/yaml +sigs.k8s.io/yaml/goyaml.v2 From 67d20faf193e875acdc1d5494685b5658f5e9aea Mon Sep 17 00:00:00 2001 From: chagams Date: Sun, 13 Apr 2025 19:42:34 +0100 Subject: [PATCH 4/4] Added flags for shore save, render, exec --- cmd/shore/shore.go | 70 +++++++++++++++++++++++++++++----------------- 1 file changed, 45 insertions(+), 25 deletions(-) diff --git a/cmd/shore/shore.go b/cmd/shore/shore.go index 297cff6..e84af51 100644 --- a/cmd/shore/shore.go +++ b/cmd/shore/shore.go @@ -25,6 +25,11 @@ var version = "local" var logVerbosity int var logger *logrus.Logger +var rendererInstance renderer.Renderer +var backendInstance backend.Backend + +var commonDependencies *command.Dependencies +var fs afero.Fs = afero.NewOsFs() var rootCmd = &cobra.Command{ Use: "shore", @@ -41,6 +46,31 @@ var rootCmd = &cobra.Command{ profileName := GetProfileName(cmd) ExecConfigName := GetExecutorConfigName(cmd) + // Check if the command is "render" + rendererType := GetRendererType(cmd) + + // Initialize the Renderer based on the flag + if rendererType == "k" { + logger.Infof("Using Kubernetes Renderer (k8srender)") + rendererInstance = k8srender.NewRenderer(fs, logger) + } else { + logger.Infof("Using Jsonnet Renderer (jsonnet)") + rendererInstance = jsonnet.NewRenderer(fs, logger) + } + // Use executorType for other commands + executorType := GetExecutorType(cmd) + if executorType == "d" { + logger.Infof("Using Kubernetes Backend (k8sbackend)") + backendInstance = k8sbackend.NewClient(logger) + } else { + logger.Infof("Using Spinnaker Backend (spinnaker)") + backendInstance = spinnaker.NewClient(logger) + } + + // Pass the rendererInstance to commonDependencies + commonDependencies.Renderer = rendererInstance + commonDependencies.Backend = backendInstance + logger.Debug("Profile set to - ", profileName) logger.Debug("Executor configuration set to - ", ExecConfigName) }, @@ -71,6 +101,14 @@ func getConfigName(cmd *cobra.Command, flagName string, envVar string) string { return configName } +func GetRendererType(cmd *cobra.Command) string { + return getConfigName(cmd, "renderer", "SHORE_RENDERER") +} + +func GetExecutorType(cmd *cobra.Command) string { + return getConfigName(cmd, "executor", "SHORE_EXECUTOR") +} + func init() { // TODO: Add global validations to init. // cobra.OnInitialize() @@ -84,33 +122,15 @@ func init() { //'p' is used for 'payload' used by exec command. 'l' for load profile? rootCmd.PersistentFlags().StringP("profile", "P", os.Getenv("SHORE_PROFILE"), "The profile to use. Can also be set by $SHORE_PROFILE environment variable. Priority is: env variable, cli args, default.") - rootCmd.PersistentFlags().StringP("renderer", "k8s", os.Getenv("SHORE_RENDERER"), - "Which render to use (eg. k8s, jsonnet). Can also be set by $SHORE_PROFILE environment variable. Priority is: env variable, cli args, default.") - rootCmd.PersistentFlags().StringP("executor", "dir", os.Getenv("SHORE_EXECUTOR"), - "Which executor to use (eg. spinnaker, k8sbackend). Can also be set by $SHORE_PROFILE environment variable. Priority is: env variable, cli args, default.") - - rendererType, _ := rootCmd.PersistentFlags().GetString("renderer") - - var rendererInstance renderer.Renderer - if rendererType == "k8s" { - rendererInstance = k8srender.NewRenderer(fs, logger) - } else { - rendererInstance = jsonnet.NewRenderer(fs, logger) - } - - // Determine the backend based on the flag or default to spinnaker - executorType, _ := rootCmd.PersistentFlags().GetString("executor") - var backendInstance backend.Backend - if executorType == "dir" { - backendInstance = k8sbackend.NewClient(logger) - } else { - backendInstance = spinnaker.NewClient(logger) - } + rootCmd.PersistentFlags().StringP("renderer", "k", os.Getenv("SHORE_RENDERER"), + "Which render to use (eg. k for k8s, jsonnet). Can also be set by $SHORE_RENDERER environment variable. Priority is: env variable, cli args, default.") + rootCmd.PersistentFlags().StringP("executor", "e", os.Getenv("SHORE_EXECUTOR"), + "Which executor to use (eg. spinnaker, d for k8sbackend). Can also be set by $SHORE_EXECUTOR environment variable. Priority is: env variable, cli args, default.") - commonDependencies := &command.Dependencies{ + commonDependencies = &command.Dependencies{ Project: project.NewShoreProject(fs, logger), - Renderer: rendererInstance, - Backend: backendInstance, + Renderer: nil, + Backend: nil, Logger: logger, }