diff --git a/README.md b/README.md index 131f164..fa50982 100644 --- a/README.md +++ b/README.md @@ -16,26 +16,22 @@ With this provider you can manage Argo CD instances and clusters on [Akuity Plat - [Terraform](https://www.terraform.io/downloads.html) >= 1.0 ## Typical use case - Add a new cluster `test-cluster` to the existing Argo CD instance `manualy-created` and then install [the agent](https://docs.akuity.io/akuity-platform/agent) to the configured cluster. + Add a new cluster `test-cluster` to the existing Argo CD instance `manualy-created` and install [the agent](https://docs.akuity.io/akuity-platform/agent) to the configured cluster. 1. Create an API key for your organization * Use `Admin` role for the key -1. Configure Environment variables +2. Configure Environment variables ```shell export AKUITY_API_KEY_ID= export AKUITY_API_KEY_SECRET= ``` -1. Use this or similar configuration: +3. Use this or similar configuration: ```hcl terraform { required_providers { akp = { source = "akuity/akp" - version = "~> 0.1" - } - kubectl = { - source = "gavinbunney/kubectl" - version = "~> 1.14" + version = "~> 0.2" } } } @@ -44,55 +40,21 @@ With this provider you can manage Argo CD instances and clusters on [Akuity Plat org_name = "" } - provider "kubectl" { - # Configure the kubectl provider - # to connect to the existing kubernetes cluster - } - - # Read Existing Argo CD Instance + # Read the existing Argo CD Instance data "akp_instance" "existing" { name = "manualy-created" } - # Add cluster to the existing instance + # Add cluster to the existing instance and install the agent resource "akp_cluster" "test" { name = "test-cluster" description = "Test Cluster 1" namespace = "akuity" instance_id = data.akp_instance.existing.id + kube_config = { + # Configuration similar to `kubernetes` provider + } } - # Split and install agent manifests - data "kubectl_file_documents" "agent" { - content = akp_cluster.test.manifests - } - - # Create namespace first - resource "kubectl_manifest" "agent_namespace" { - yaml_body = lookup(data.kubectl_file_documents.agent.manifests, "/api/v1/namespaces/${akp_cluster.test.namespace}/namespaces/${akp_cluster.test.namespace}") - wait = true - } - - # Create everything else - resource "kubectl_manifest" "agent" { - for_each = data.kubectl_file_documents.agent.manifests - yaml_body = each.value - # Important! - wait_for_rollout = false - depends_on = [ - kubectl_manifest.agent_namespace - ] - } - - ``` -1. First create the cluster using `-target` - ```shell - terraform apply -target akp_cluster.test - ``` - This has to be done first, because terraform is unable to apply an unknown number of manifests in `for_each` loop, and the manifests only available *after* the cluster is created - -1. Then you can apply the manifests - ```shell - terraform apply ``` diff --git a/akp/data_source_akp_cluster.go b/akp/data_source_akp_cluster.go index c708a95..5b08c87 100644 --- a/akp/data_source_akp_cluster.go +++ b/akp/data_source_akp_cluster.go @@ -89,6 +89,77 @@ func (d *AkpClusterDataSource) Schema(ctx context.Context, req datasource.Schema MarkdownDescription: "Cluster Annotations", Computed: true, }, + "agent_version": schema.StringAttribute{ + MarkdownDescription: "Installed agent version", + Computed: true, + }, + "kube_config": schema.SingleNestedAttribute{ + MarkdownDescription: "Kubernetes connection setings. If configured, terraform will try to connect to the cluster and install the agent", + Optional: true, + Attributes: map[string]schema.Attribute{ + "host": schema.StringAttribute{ + Optional: true, + Description: "The hostname (in form of URI) of Kubernetes master.", + + }, + "username": schema.StringAttribute{ + Optional: true, + Description: "The username to use for HTTP basic authentication when accessing the Kubernetes master endpoint.", + }, + "password": schema.StringAttribute{ + Optional: true, + Sensitive: true, + Description: "The password to use for HTTP basic authentication when accessing the Kubernetes master endpoint.", + }, + "insecure": schema.BoolAttribute{ + Optional: true, + Description: "Whether server should be accessed without verifying the TLS certificate.", + }, + "client_certificate": schema.StringAttribute{ + Optional: true, + Description: "PEM-encoded client certificate for TLS authentication.", + }, + "client_key": schema.StringAttribute{ + Optional: true, + Sensitive: true, + Description: "PEM-encoded client certificate key for TLS authentication.", + }, + "cluster_ca_certificate": schema.StringAttribute{ + Optional: true, + Description: "PEM-encoded root certificates bundle for TLS authentication.", + }, + "config_paths": schema.ListAttribute{ + ElementType: types.StringType, + Optional: true, + Description: "A list of paths to kube config files. Can be set with KUBE_CONFIG_PATHS environment variable.", + }, + "config_path": schema.StringAttribute{ + Optional: true, + Description: "Path to the kube config file.", + }, + "config_context": schema.StringAttribute{ + Optional: true, + Description: "Context name to load from the kube config file.", + }, + "config_context_auth_info": schema.StringAttribute{ + Optional: true, + Description: "", + }, + "config_context_cluster": schema.StringAttribute{ + Optional: true, + Description: "", + }, + "token": schema.StringAttribute{ + Optional: true, + Sensitive: true, + Description: "Token to authenticate an service account", + }, + "proxy_url": schema.StringAttribute{ + Optional: true, + Description: "URL to the proxy to be used for all API requests", + }, + }, + }, }, } } diff --git a/akp/data_source_akp_clusters.go b/akp/data_source_akp_clusters.go index 995be8d..220eb0c 100644 --- a/akp/data_source_akp_clusters.go +++ b/akp/data_source_akp_clusters.go @@ -106,6 +106,77 @@ func (d *AkpClustersDataSource) Schema(ctx context.Context, req datasource.Schem MarkdownDescription: "Cluster Annotations", Computed: true, }, + "agent_version": schema.StringAttribute{ + MarkdownDescription: "Installed agent version", + Computed: true, + }, + "kube_config": schema.SingleNestedAttribute{ + MarkdownDescription: "Kubernetes connection setings. If configured, terraform will try to connect to the cluster and install the agent", + Optional: true, + Attributes: map[string]schema.Attribute{ + "host": schema.StringAttribute{ + Optional: true, + Description: "The hostname (in form of URI) of Kubernetes master.", + + }, + "username": schema.StringAttribute{ + Optional: true, + Description: "The username to use for HTTP basic authentication when accessing the Kubernetes master endpoint.", + }, + "password": schema.StringAttribute{ + Optional: true, + Sensitive: true, + Description: "The password to use for HTTP basic authentication when accessing the Kubernetes master endpoint.", + }, + "insecure": schema.BoolAttribute{ + Optional: true, + Description: "Whether server should be accessed without verifying the TLS certificate.", + }, + "client_certificate": schema.StringAttribute{ + Optional: true, + Description: "PEM-encoded client certificate for TLS authentication.", + }, + "client_key": schema.StringAttribute{ + Optional: true, + Sensitive: true, + Description: "PEM-encoded client certificate key for TLS authentication.", + }, + "cluster_ca_certificate": schema.StringAttribute{ + Optional: true, + Description: "PEM-encoded root certificates bundle for TLS authentication.", + }, + "config_paths": schema.ListAttribute{ + ElementType: types.StringType, + Optional: true, + Description: "A list of paths to kube config files. Can be set with KUBE_CONFIG_PATHS environment variable.", + }, + "config_path": schema.StringAttribute{ + Optional: true, + Description: "Path to the kube config file.", + }, + "config_context": schema.StringAttribute{ + Optional: true, + Description: "Context name to load from the kube config file.", + }, + "config_context_auth_info": schema.StringAttribute{ + Optional: true, + Description: "", + }, + "config_context_cluster": schema.StringAttribute{ + Optional: true, + Description: "", + }, + "token": schema.StringAttribute{ + Optional: true, + Sensitive: true, + Description: "Token to authenticate an service account", + }, + "proxy_url": schema.StringAttribute{ + Optional: true, + Description: "URL to the proxy to be used for all API requests", + }, + }, + }, }, }, }, diff --git a/akp/kube/apply.go b/akp/kube/apply.go new file mode 100644 index 0000000..00e680b --- /dev/null +++ b/akp/kube/apply.go @@ -0,0 +1,120 @@ +package kube + +import ( + "bytes" + "context" + "encoding/json" + "strings" + + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" + "k8s.io/apimachinery/pkg/util/sets" + "k8s.io/cli-runtime/pkg/genericclioptions" + "k8s.io/cli-runtime/pkg/printers" + "k8s.io/cli-runtime/pkg/resource" + "k8s.io/client-go/dynamic" + "k8s.io/kubectl/pkg/cmd/apply" + "k8s.io/kubectl/pkg/cmd/delete" + cmdutil "k8s.io/kubectl/pkg/cmd/util" + +) + +type ApplyOpts struct { + DryRunStrategy cmdutil.DryRunStrategy + Force bool + Validate bool +} + +// ApplyResource performs an apply of a unstructured resource +func (k *Kubectl) ApplyResource(ctx context.Context, obj *unstructured.Unstructured, applyOpts ApplyOpts) (string, error) { + objBytes, err := json.Marshal(obj) + if err != nil { + return "", err + } + ioStreams := genericclioptions.IOStreams{ + In: &bytes.Buffer{}, + Out: &bytes.Buffer{}, + ErrOut: &bytes.Buffer{}, + } + path, err := writeFile(objBytes) + if err != nil { + return "", err + } + defer deleteFile(path) + kubeApplyOpts, err := k.newApplyOptions(ioStreams, obj, path, applyOpts) + if err != nil { + return "", err + } + applyErr := kubeApplyOpts.Run() + var out []string + if buf := strings.TrimSpace(ioStreams.Out.(*bytes.Buffer).String()); len(buf) > 0 { + out = append(out, buf) + } + if buf := strings.TrimSpace(ioStreams.ErrOut.(*bytes.Buffer).String()); len(buf) > 0 { + out = append(out, buf) + } + return strings.Join(out, ". "), applyErr +} + +func (k *Kubectl) newApplyOptions(ioStreams genericclioptions.IOStreams, obj *unstructured.Unstructured, path string, applyOpts ApplyOpts) (*apply.ApplyOptions, error) { + flags := apply.NewApplyFlags(k.fact, ioStreams) + o := &apply.ApplyOptions{ + IOStreams: ioStreams, + VisitedUids: sets.NewString(), + VisitedNamespaces: sets.NewString(), + Recorder: genericclioptions.NoopRecorder{}, + PrintFlags: flags.PrintFlags, + Overwrite: true, + OpenAPIPatch: true, + } + dynamicClient, err := dynamic.NewForConfig(k.config) + if err != nil { + return nil, err + } + o.DynamicClient = dynamicClient + o.DeleteOptions, err = delete.NewDeleteFlags("").ToOptions(dynamicClient, ioStreams) + if err != nil { + return nil, err + } + o.OpenAPISchema, err = k.OpenAPISchema() + if err != nil { + return nil, err + } + o.DryRunVerifier = resource.NewQueryParamVerifier(dynamicClient, k.fact.OpenAPIGetter(), resource.QueryParamFieldValidation) + validateDirective := metav1.FieldValidationIgnore + if applyOpts.Validate { + validateDirective = metav1.FieldValidationStrict + } + o.Validator, err = k.fact.Validator(validateDirective, o.DryRunVerifier) + if err != nil { + return nil, err + } + o.Builder = k.fact.NewBuilder() + o.Mapper, err = k.fact.ToRESTMapper() + if err != nil { + return nil, err + } + + o.ToPrinter = func(operation string) (printers.ResourcePrinter, error) { + o.PrintFlags.NamePrintFlags.Operation = operation + switch o.DryRunStrategy { + case cmdutil.DryRunClient: + err = o.PrintFlags.Complete("%s (dry run)") + if err != nil { + return nil, err + } + case cmdutil.DryRunServer: + err = o.PrintFlags.Complete("%s (server dry run)") + if err != nil { + return nil, err + } + } + return o.PrintFlags.ToPrinter() + } + o.DeleteOptions.FilenameOptions.Filenames = []string{path} + o.Namespace = obj.GetNamespace() + o.DeleteOptions.ForceDeletion = applyOpts.Force + o.DryRunStrategy = applyOpts.DryRunStrategy + return o, nil +} + diff --git a/akp/kube/config.go b/akp/kube/config.go new file mode 100644 index 0000000..fa2acdf --- /dev/null +++ b/akp/kube/config.go @@ -0,0 +1,176 @@ +package kube + +import ( + "fmt" + + "github.com/hashicorp/terraform-plugin-framework/types" + "github.com/mitchellh/go-homedir" + "k8s.io/client-go/rest" + "k8s.io/client-go/tools/clientcmd" + "k8s.io/client-go/discovery" + "k8s.io/kubectl/pkg/util/openapi" + "k8s.io/cli-runtime/pkg/genericclioptions" + cmdutil "k8s.io/kubectl/pkg/cmd/util" + apimachineryschema "k8s.io/apimachinery/pkg/runtime/schema" + clientcmdapi "k8s.io/client-go/tools/clientcmd/api" +) + +type KubeConfig struct{ + Host types.String `tfsdk:"host"` + Username types.String `tfsdk:"username"` + Password types.String `tfsdk:"password"` + Insecure types.Bool `tfsdk:"insecure"` + ClientCertificate types.String `tfsdk:"client_certificate"` + ClientKey types.String `tfsdk:"client_key"` + ClusterCaCertificate types.String `tfsdk:"cluster_ca_certificate"` + ConfigPath types.String `tfsdk:"config_path"` + ConfigPaths types.List `tfsdk:"config_paths"` + ConfigContext types.String `tfsdk:"config_context"` + ConfigContextAuthInfo types.String `tfsdk:"config_context_auth_info"` + ConfigContextCluster types.String `tfsdk:"config_context_cluster"` + Token types.String `tfsdk:"token"` + ProxyUrl types.String `tfsdk:"proxy_url"` +} + +type Kubectl struct { + config *rest.Config + fact cmdutil.Factory + openAPISchema openapi.Resources +} + +// NewKubectl returns a kubectl instance from a rest config +func NewKubectl(config *rest.Config) (*Kubectl, error) { + kubeConfigFlags := genericclioptions.NewConfigFlags(true) + kubeConfigFlags.WithWrapConfigFn(func(_ *rest.Config) *rest.Config { + return config + }) + matchVersionKubeConfigFlags := cmdutil.NewMatchVersionFlags(kubeConfigFlags) + fact := cmdutil.NewFactory(matchVersionKubeConfigFlags) + return &Kubectl{ + config: config, + fact: fact, + }, nil +} + +// Adapted github.com/gavinbunney/terraform-provider-kubectl/kubernetes/provider.go functions + +func InitializeConfiguration(k *KubeConfig) (*rest.Config, error) { + overrides := &clientcmd.ConfigOverrides{} + loader := &clientcmd.ClientConfigLoadingRules{} + configPaths := []string{} + if v := k.ConfigPath.ValueString(); v != "" { + configPaths = []string{v} + } else if v := k.ConfigPaths.Elements(); len(v) > 0 { + for _, p := range v { + configPaths = append(configPaths, p.String()) + } + } + if len(configPaths) > 0 { + expandedPaths := []string{} + for _, p := range configPaths { + path, err := homedir.Expand(p) + if err != nil { + return nil, err + } + expandedPaths = append(expandedPaths, path) + } + + if len(expandedPaths) == 1 { + loader.ExplicitPath = expandedPaths[0] + } else { + loader.Precedence = expandedPaths + } + + ctxSuffix := "; default context" + + kubectx := k.ConfigContext.ValueString() + authInfo := k.ConfigContextAuthInfo.ValueString() + cluster := k.ConfigContextCluster.ValueString() + if kubectx != "" || authInfo != "" || cluster != "" { + ctxSuffix = "; overriden context" + if kubectx != "" { + overrides.CurrentContext = kubectx + ctxSuffix += fmt.Sprintf("; config ctx: %s", overrides.CurrentContext) + } + + overrides.Context = clientcmdapi.Context{} + if authInfo != "" { + overrides.Context.AuthInfo = authInfo + ctxSuffix += fmt.Sprintf("; auth_info: %s", overrides.Context.AuthInfo) + } + if cluster != "" { + overrides.Context.Cluster = cluster + ctxSuffix += fmt.Sprintf("; cluster: %s", overrides.Context.Cluster) + } + } + } + // Overriding with static configuration + if !k.Insecure.IsNull() { + overrides.ClusterInfo.InsecureSkipTLSVerify = k.Insecure.ValueBool() + } + if v := k.ClusterCaCertificate.ValueString(); v != "" { + overrides.ClusterInfo.CertificateAuthorityData = []byte(v) + } + if v := k.ClientCertificate.ValueString(); v != "" { + overrides.AuthInfo.ClientCertificateData = []byte(v) + } + if v := k.Host.ValueString(); v != "" { + // Server has to be the complete address of the kubernetes cluster (scheme://hostname:port), not just the hostname, + // because `overrides` are processed too late to be taken into account by `defaultServerUrlFor()`. + // This basically replicates what defaultServerUrlFor() does with config but for overrides, + // see https://github.com/kubernetes/client-go/blob/v12.0.0/rest/url_utils.go#L85-L87 + hasCA := len(overrides.ClusterInfo.CertificateAuthorityData) != 0 + hasCert := len(overrides.AuthInfo.ClientCertificateData) != 0 + defaultTLS := hasCA || hasCert || overrides.ClusterInfo.InsecureSkipTLSVerify + host, _, err := rest.DefaultServerURL(v, "", apimachineryschema.GroupVersion{}, defaultTLS) + if err != nil { + return nil, fmt.Errorf("Failed to parse host: %s", err) + } + + overrides.ClusterInfo.Server = host.String() + } + if v := k.Username.ValueString(); v != "" { + overrides.AuthInfo.Username = v + } + if v := k.Password.ValueString(); v != "" { + overrides.AuthInfo.Password = v + } + if v := k.ClientKey.ValueString(); v != "" { + overrides.AuthInfo.ClientKeyData = []byte(v) + } + if v := k.Token.ValueString(); v != "" { + overrides.AuthInfo.Token = v + } + if v := k.ProxyUrl.ValueString(); v != "" { + overrides.ClusterDefaults.ProxyURL = v + } + + cc := clientcmd.NewNonInteractiveDeferredLoadingClientConfig(loader, overrides) + cfg, err := cc.ClientConfig() + if err != nil { + return nil, fmt.Errorf("Invalid provider configuration: %s", err) + } + cfg.QPS = 100.0 + cfg.Burst = 100 + + // Overriding with static configuration + terraformVersion := "unknown" + cfg.UserAgent = fmt.Sprintf("HashiCorp/1.0 Terraform/%s", terraformVersion) + return cfg, nil +} + +func (k *Kubectl) OpenAPISchema() (openapi.Resources, error) { + if k.openAPISchema != nil { + return k.openAPISchema, nil + } + disco, err := discovery.NewDiscoveryClientForConfig(k.config) + if err != nil { + return nil, err + } + openAPISchema, err := openapi.NewOpenAPIParser(openapi.NewOpenAPIGetter(disco)).Parse() + if err != nil { + return nil, err + } + k.openAPISchema = openAPISchema + return k.openAPISchema, nil +} diff --git a/akp/kube/delete.go b/akp/kube/delete.go new file mode 100644 index 0000000..69d0293 --- /dev/null +++ b/akp/kube/delete.go @@ -0,0 +1,74 @@ +package kube + +import ( + "bytes" + "context" + "encoding/json" + + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" + "k8s.io/cli-runtime/pkg/genericclioptions" + "k8s.io/cli-runtime/pkg/resource" + "k8s.io/client-go/dynamic" + "k8s.io/kubectl/pkg/cmd/delete" + "k8s.io/kubectl/pkg/cmd/util" +) + +type DeleteOpts struct { + Force bool + WaitForDeletion bool + IgnoreNotFound bool + GracePeriod int +} + +func (k *Kubectl) DeleteResource(ctx context.Context, obj *unstructured.Unstructured, deleteOpts DeleteOpts) (string, error) { + objBytes, err := json.Marshal(obj) + if err != nil { + return "", err + } + ioStreams := genericclioptions.IOStreams{ + In: &bytes.Buffer{}, + Out: &bytes.Buffer{}, + ErrOut: &bytes.Buffer{}, + } + path, err := writeFile(objBytes) + if err != nil { + return "", err + } + defer deleteFile(path) + dcmd := delete.NewCmdDelete(k.fact, ioStreams) + kubeDeleteOpts, err := k.newDeleteOptions(ioStreams, obj, path, deleteOpts) + if err != nil { + return "", err + } + err = kubeDeleteOpts.Complete(k.fact,[]string{}, dcmd) + if err != nil { + return "", err + } + err = kubeDeleteOpts.RunDelete(k.fact) + if err != nil { + return "", err + } + return "", nil +} + +func (k *Kubectl) newDeleteOptions(ioStreams genericclioptions.IOStreams, obj *unstructured.Unstructured, path string, deleteOpts DeleteOpts) (*delete.DeleteOptions, error){ + o := &delete.DeleteOptions{ + FilenameOptions: resource.FilenameOptions{ + Filenames: []string{path}, + }, + IgnoreNotFound: deleteOpts.IgnoreNotFound, + WaitForDeletion: deleteOpts.WaitForDeletion, + GracePeriod: deleteOpts.GracePeriod, + Output: "name", + IOStreams: ioStreams, + CascadingStrategy: metav1.DeletePropagationBackground, + } + dynamicClient, err := dynamic.NewForConfig(k.config) + if err != nil { + return nil, err + } + o.DynamicClient = dynamicClient + o.DryRunStrategy = util.DryRunNone + return o,nil +} diff --git a/akp/kube/io.go b/akp/kube/io.go new file mode 100644 index 0000000..5fe90d6 --- /dev/null +++ b/akp/kube/io.go @@ -0,0 +1,27 @@ +package kube + +import ( + "fmt" + "os" +) + +func writeFile(bytes []byte) (string, error) { + f, err := os.CreateTemp("", "") + if err != nil { + return "", fmt.Errorf("Failed to generate temp file for manifest: %v", err) + } + if _, err = f.Write(bytes); err != nil { + return "", fmt.Errorf("Failed to write manifest: %v", err) + } + if err = f.Close(); err != nil { + return "", fmt.Errorf("Failed to close manifest: %v", err) + } + return f.Name(), nil +} + +func deleteFile(path string) { + if _, err := os.Stat(path); os.IsNotExist(err) { + return + } + _ = os.Remove(path) +} diff --git a/akp/kube/yaml.go b/akp/kube/yaml.go new file mode 100644 index 0000000..a2c4a2f --- /dev/null +++ b/akp/kube/yaml.go @@ -0,0 +1,35 @@ +package kube + +import ( + "bytes" + "fmt" + "io" + + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/util/yaml" +) + +func SplitYAML(yamlData []byte) ([]unstructured.Unstructured, error) { + d := yaml.NewYAMLOrJSONDecoder(bytes.NewReader(yamlData), 4096) + var objs []unstructured.Unstructured + for { + ext := runtime.RawExtension{} + if err := d.Decode(&ext); err != nil { + if err == io.EOF { + break + } + return objs, fmt.Errorf("failed to unmarshal manifest: %v", err) + } + ext.Raw = bytes.TrimSpace(ext.Raw) + if len(ext.Raw) == 0 || bytes.Equal(ext.Raw, []byte("null")) { + continue + } + u := unstructured.Unstructured{} + if err := yaml.Unmarshal(ext.Raw, &u); err != nil { + return objs, fmt.Errorf("failed to unmarshal manifest: %v", err) + } + objs = append(objs, u) + } + return objs, nil +} diff --git a/akp/resource_akp_cluster.go b/akp/resource_akp_cluster.go index bbf3f7e..1ff0ef4 100644 --- a/akp/resource_akp_cluster.go +++ b/akp/resource_akp_cluster.go @@ -7,16 +7,23 @@ import ( argocdv1 "github.com/akuity/api-client-go/pkg/api/gen/argocd/v1" idv1 "github.com/akuity/api-client-go/pkg/api/gen/types/id/v1" + healthv1 "github.com/akuity/api-client-go/pkg/api/gen/types/status/health/v1" reconv1 "github.com/akuity/api-client-go/pkg/api/gen/types/status/reconciliation/v1" ctxutil "github.com/akuity/api-client-go/pkg/utils/context" + "k8s.io/client-go/rest" + + "github.com/akuity/terraform-provider-akp/akp/kube" akptypes "github.com/akuity/terraform-provider-akp/akp/types" - status "google.golang.org/grpc/status" - codes "google.golang.org/grpc/codes" + "github.com/hashicorp/terraform-plugin-framework/diag" "github.com/hashicorp/terraform-plugin-framework/path" "github.com/hashicorp/terraform-plugin-framework/resource" "github.com/hashicorp/terraform-plugin-framework/types" + + "github.com/hashicorp/terraform-plugin-framework/types/basetypes" "github.com/hashicorp/terraform-plugin-log/tflog" "golang.org/x/exp/slices" + codes "google.golang.org/grpc/codes" + status "google.golang.org/grpc/status" ) // Ensure provider defined types fully satisfy framework interfaces @@ -30,6 +37,7 @@ func NewAkpClusterResource() resource.Resource { // AkpClusterResource defines the resource implementation. type AkpClusterResource struct { akpCli *AkpCli + kcfg *rest.Config } func (r *AkpClusterResource) Metadata(ctx context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) { @@ -54,7 +62,31 @@ func (r *AkpClusterResource) Configure(ctx context.Context, req resource.Configu r.akpCli = akpCli } -func (r *AkpClusterResource) GetManifests(ctx context.Context, instanceId string, clusterId string) (manifests string, err error) { +func (r *AkpClusterResource) getKcfg(ctx context.Context, kubeConf types.Object) (*rest.Config, diag.Diagnostics) { + var kubeConfig kube.KubeConfig + var diag diag.Diagnostics + if kubeConf.IsNull() || kubeConf.IsUnknown() { + diag.AddWarning("Kubectl not configured", "Cannot update agent because kubectl configuration is missing") + return nil, diag + } + tflog.Debug(ctx, fmt.Sprintf("Kube config: %s", kubeConf)) + diag = kubeConf.As(ctx, &kubeConfig, basetypes.ObjectAsOptions{ + UnhandledNullAsEmpty: true, + UnhandledUnknownAsEmpty: true, + }) + if diag.HasError() { + return nil, diag + } + kcfg, err := kube.InitializeConfiguration(&kubeConfig) + tflog.Debug(ctx, fmt.Sprintf("Kcfg: %s", kcfg)) + if err != nil { + diag.AddError("Kubectl error", fmt.Sprintf("Cannot insitialize Kubectl. Check kubernetes configuration. Error: %s", err)) + return nil, diag + } + return kcfg, diag +} + +func (r *AkpClusterResource) getManifests(ctx context.Context, instanceId string, clusterId string) (string, error) { tflog.Info(ctx, "Retrieving manifests...") @@ -68,10 +100,108 @@ func (r *AkpClusterResource) GetManifests(ctx context.Context, instanceId string if err != nil { return "", err } + tflog.Debug(ctx, fmt.Sprintf("apiResp: %s", apiResp)) return string(apiResp.GetData()), nil } +func (r *AkpClusterResource) applyManifests(ctx context.Context, manifests string, cfg *rest.Config) diag.Diagnostics { + diag := diag.Diagnostics{} + kubectl, err := kube.NewKubectl(cfg) + if err != nil { + diag.AddError("Kubernetes error", fmt.Sprintf("failed to create kubectl, error=%s", err)) + } + resources, err := kube.SplitYAML([]byte(manifests)) + tflog.Info(ctx, fmt.Sprintf("%d resources to create", len(resources))) + if err != nil { + diag.AddError("YAML error", fmt.Sprintf("failed to parse manifest, error=%s", err)) + } + + for _, un := range resources { + msg, err := kubectl.ApplyResource(ctx, &un, kube.ApplyOpts{}) + if err != nil { + diag.AddError("Kubernetes error", fmt.Sprintf("failed to apply manifest %s, error=%s", un, err)) + return diag + } + tflog.Debug(ctx, msg) + } + return diag +} + +func (r *AkpClusterResource) deleteManifests(ctx context.Context, manifests string, cfg *rest.Config) diag.Diagnostics { + diag := diag.Diagnostics{} + kubectl, err := kube.NewKubectl(cfg) + if err != nil { + diag.AddError("Kubernetes error", fmt.Sprintf("failed to create kubectl, error=%s", err)) + } + resources, err := kube.SplitYAML([]byte(manifests)) + tflog.Info(ctx, fmt.Sprintf("%d resources to delete", len(resources))) + if err != nil { + diag.AddError("YAML error", fmt.Sprintf("failed to parse manifest, error=%s", err)) + } + + // Delete the resources in reverse order + for i := len(resources) - 1; i >= 0; i-- { + msg, err := kubectl.DeleteResource(ctx, &resources[i], kube.DeleteOpts{ + IgnoreNotFound: true, + WaitForDeletion: true, + Force: false, + }) + if err != nil { + diag.AddError("Kubernetes error", fmt.Sprintf("failed to delete manifest %s, error=%s", &resources[i], err)) + return diag + } + tflog.Debug(ctx, msg) + } + return diag +} + +func (r *AkpClusterResource) waitClusterReconStatus(ctx context.Context, cluster *argocdv1.Cluster, instanceId string) (*argocdv1.Cluster, error) { + + reconStatus := cluster.GetReconciliationStatus() + breakStatusesRecon := []reconv1.StatusCode{reconv1.StatusCode_STATUS_CODE_SUCCESSFUL, reconv1.StatusCode_STATUS_CODE_FAILED} + + for !slices.Contains(breakStatusesRecon, reconStatus.GetCode()) { + time.Sleep(1 * time.Second) + apiResp, err := r.akpCli.Cli.GetInstanceCluster(ctx, &argocdv1.GetInstanceClusterRequest{ + OrganizationId: r.akpCli.OrgId, + InstanceId: instanceId, + Id: cluster.GetId(), + IdType: idv1.Type_ID, + }) + if err != nil { + return nil, err + } + cluster = apiResp.GetCluster() + reconStatus = cluster.GetReconciliationStatus() + tflog.Debug(ctx, fmt.Sprintf("Cluster recon status: %s", reconStatus.String())) + } + return cluster, nil +} + +func (r *AkpClusterResource) waitClusterHealthStatus(ctx context.Context, cluster *argocdv1.Cluster, instanceId string) (*argocdv1.Cluster, error) { + + healthStatus := cluster.GetHealthStatus() + breakStatusesHealth := []healthv1.StatusCode{healthv1.StatusCode_STATUS_CODE_HEALTHY, healthv1.StatusCode_STATUS_CODE_DEGRADED} + + for !slices.Contains(breakStatusesHealth, healthStatus.GetCode()) { + time.Sleep(1 * time.Second) + apiResp, err := r.akpCli.Cli.GetInstanceCluster(ctx, &argocdv1.GetInstanceClusterRequest{ + OrganizationId: r.akpCli.OrgId, + InstanceId: instanceId, + Id: cluster.GetId(), + IdType: idv1.Type_ID, + }) + if err != nil { + return nil, err + } + cluster = apiResp.GetCluster() + healthStatus = cluster.GetHealthStatus() + tflog.Debug(ctx, fmt.Sprintf("Cluster health status: %s", healthStatus.String())) + } + return cluster, nil +} + func (r *AkpClusterResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) { var plan *akptypes.AkpCluster @@ -81,6 +211,7 @@ func (r *AkpClusterResource) Create(ctx context.Context, req resource.CreateRequ if resp.Diagnostics.HasError() { return } + ctx = ctxutil.SetClientCredential(ctx, r.akpCli.Cred) customArgoproj := plan.CustomImageRegistryArgoproj.ValueString() customAkuity := plan.CustomImageRegistryAkuity.ValueString() @@ -97,7 +228,7 @@ func (r *AkpClusterResource) Create(ctx context.Context, req resource.CreateRequ Namespace: plan.Namespace.ValueString(), NamespaceScoped: plan.NamespaceScoped.ValueBool(), Data: &argocdv1.ClusterData{ - Size: akptypes.StringClusterSize[plan.Size.ValueString()], + Size: akptypes.StringClusterSize[plan.Size.ValueString()], CustomImageRegistryArgoproj: &customArgoproj, CustomImageRegistryAkuity: &customAkuity, AutoUpgradeDisabled: &autoupgrade, @@ -115,24 +246,10 @@ func (r *AkpClusterResource) Create(ctx context.Context, req resource.CreateRequ return } - cluster := apiResp.GetCluster() - reconStatus := cluster.GetReconciliationStatus() - breakStatusesRecon := []reconv1.StatusCode{reconv1.StatusCode_STATUS_CODE_SUCCESSFUL, reconv1.StatusCode_STATUS_CODE_FAILED} - for !slices.Contains(breakStatusesRecon, reconStatus.GetCode()) { - time.Sleep(1 * time.Second) - apiResp2, err := r.akpCli.Cli.GetInstanceCluster(ctx, &argocdv1.GetInstanceClusterRequest{ - OrganizationId: r.akpCli.OrgId, - InstanceId: plan.InstanceId.ValueString(), - Id: cluster.GetId(), - IdType: idv1.Type_ID, - }) - if err != nil { - resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Unable to check health of cluster. %s", err)) - return - } - cluster = apiResp2.GetCluster() - reconStatus = cluster.GetReconciliationStatus() - tflog.Debug(ctx, fmt.Sprintf("Cluster instance status: %s", reconStatus.String())) + cluster, err := r.waitClusterReconStatus(ctx, apiResp.GetCluster(), plan.InstanceId.ValueString()) + if err != nil { + resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Unable to check cluster reconciliation status. %s", err)) + return } tflog.Info(ctx, "Cluster created") @@ -141,13 +258,24 @@ func (r *AkpClusterResource) Create(ctx context.Context, req resource.CreateRequ if diag.HasError() { resp.Diagnostics.Append(diag...) } - manifests, err := r.GetManifests(ctx, plan.InstanceId.ValueString(), cluster.GetId()) + + manifests, err := r.getManifests(ctx, plan.InstanceId.ValueString(), cluster.GetId()) if err != nil { resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Unable to get cluster manifests. %s", err)) return } - state.Manifests = types.StringValue(manifests) + state.KubeConfig = plan.KubeConfig + + kcfg, diag := r.getKcfg(ctx, plan.KubeConfig) + resp.Diagnostics.Append(diag...) + // Apply the manifests + if kcfg != nil { + tflog.Info(ctx, "Applying the manifests...") + resp.Diagnostics.Append(r.applyManifests(ctx, manifests, kcfg)...) + cluster, err = r.waitClusterHealthStatus(ctx, cluster, plan.InstanceId.ValueString()) + state.AgentVersion = types.StringValue(cluster.AgentState.GetVersion()) + } // Save data into Terraform state resp.Diagnostics.Append(resp.State.Set(ctx, &state)...) } @@ -185,7 +313,7 @@ func (r *AkpClusterResource) Read(ctx context.Context, req resource.ReadRequest, resp.Diagnostics.Append(state.UpdateFromProto(apiResp.GetCluster())...) if state.Manifests.IsNull() || state.Manifests.IsUnknown() { - manifests, _ := r.GetManifests(ctx, state.InstanceId.ValueString(), state.Id.ValueString()) + manifests, _ := r.getManifests(ctx, state.InstanceId.ValueString(), state.Id.ValueString()) state.Manifests = types.StringValue(manifests) } @@ -210,13 +338,13 @@ func (r *AkpClusterResource) Update(ctx context.Context, req resource.UpdateRequ var annotations map[string]string resp.Diagnostics.Append(plan.Labels.ElementsAs(ctx, &labels, true)...) resp.Diagnostics.Append(plan.Annotations.ElementsAs(ctx, &annotations, true)...) - apiReq :=&argocdv1.UpdateInstanceClusterRequest{ + apiReq := &argocdv1.UpdateInstanceClusterRequest{ OrganizationId: r.akpCli.OrgId, InstanceId: plan.InstanceId.ValueString(), Id: plan.Id.ValueString(), Description: plan.Description.ValueString(), Data: &argocdv1.ClusterData{ - Size: akptypes.StringClusterSize[plan.Size.ValueString()], + Size: akptypes.StringClusterSize[plan.Size.ValueString()], CustomImageRegistryArgoproj: &customArgoproj, CustomImageRegistryAkuity: &customAkuity, AutoUpgradeDisabled: &autoupgrade, @@ -239,7 +367,7 @@ func (r *AkpClusterResource) Update(ctx context.Context, req resource.UpdateRequ if diag.HasError() { resp.Diagnostics.Append(diag...) } - manifests, err := r.GetManifests(ctx, plan.InstanceId.ValueString(), cluster.GetId()) + manifests, err := r.getManifests(ctx, plan.InstanceId.ValueString(), cluster.GetId()) if err != nil { resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Unable to get cluster manifests. %s", err)) return @@ -247,6 +375,18 @@ func (r *AkpClusterResource) Update(ctx context.Context, req resource.UpdateRequ state.Manifests = types.StringValue(manifests) + kcfg, diag := r.getKcfg(ctx, plan.KubeConfig) + resp.Diagnostics.Append(diag...) + // Update k8s resources with terraform only if autoupgarde is disabled for the cluster + if state.AutoUpgradeDisabled.ValueBool() && kcfg != nil { + tflog.Info(ctx, "Applying the manifests...") + resp.Diagnostics.Append(r.applyManifests(ctx, manifests, kcfg)...) + cluster, err = r.waitClusterHealthStatus(ctx, cluster, plan.InstanceId.ValueString()) + state.AgentVersion = types.StringValue(cluster.AgentState.GetVersion()) + } + + state.KubeConfig = plan.KubeConfig + // Save updated data into Terraform state resp.Diagnostics.Append(resp.State.Set(ctx, &state)...) } @@ -260,9 +400,19 @@ func (r *AkpClusterResource) Delete(ctx context.Context, req resource.DeleteRequ if resp.Diagnostics.HasError() { return } - + kcfg, diag := r.getKcfg(ctx, state.KubeConfig) + resp.Diagnostics.Append(diag...) + // Delete the kubernetes resources + if kcfg != nil { + tflog.Info(ctx, "Deleting the resources...") + diag = r.deleteManifests(ctx, state.Manifests.ValueString(), kcfg) + } + if diag.HasError() { + resp.Diagnostics.Append(diag...) + return + } ctx = ctxutil.SetClientCredential(ctx, r.akpCli.Cred) - apiReq :=&argocdv1.DeleteInstanceClusterRequest{ + apiReq := &argocdv1.DeleteInstanceClusterRequest{ OrganizationId: r.akpCli.OrgId, InstanceId: state.InstanceId.ValueString(), Id: state.Id.ValueString(), diff --git a/akp/resource_akp_cluster_schema.go b/akp/resource_akp_cluster_schema.go index 2ecff0c..fb21f17 100644 --- a/akp/resource_akp_cluster_schema.go +++ b/akp/resource_akp_cluster_schema.go @@ -5,10 +5,11 @@ import ( "github.com/hashicorp/terraform-plugin-framework/resource" "github.com/hashicorp/terraform-plugin-framework/resource/schema" - "github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier" - "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier" "github.com/hashicorp/terraform-plugin-framework/resource/schema/boolplanmodifier" + "github.com/hashicorp/terraform-plugin-framework/resource/schema/listplanmodifier" "github.com/hashicorp/terraform-plugin-framework/resource/schema/mapplanmodifier" + "github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier" + "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier" "github.com/hashicorp/terraform-plugin-framework/types" ) @@ -114,6 +115,118 @@ func (r *AkpClusterResource) Schema(ctx context.Context, req resource.SchemaRequ mapplanmodifier.UseStateForUnknown(), }, }, + "agent_version": schema.StringAttribute{ + MarkdownDescription: "Installed agent version", + Computed: true, + }, + "kube_config": schema.SingleNestedAttribute{ + MarkdownDescription: "Kubernetes connection setings. If configured, terraform will try to connect to the cluster and install the agent", + Optional: true, + Attributes: map[string]schema.Attribute{ + "host": schema.StringAttribute{ + Optional: true, + Description: "The hostname (in form of URI) of Kubernetes master.", + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), + }, + }, + "username": schema.StringAttribute{ + Optional: true, + Description: "The username to use for HTTP basic authentication when accessing the Kubernetes master endpoint.", + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), + }, + }, + "password": schema.StringAttribute{ + Optional: true, + Sensitive: true, + Description: "The password to use for HTTP basic authentication when accessing the Kubernetes master endpoint.", + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), + }, + }, + "insecure": schema.BoolAttribute{ + Optional: true, + Description: "Whether server should be accessed without verifying the TLS certificate.", + PlanModifiers: []planmodifier.Bool{ + boolplanmodifier.UseStateForUnknown(), + }, + }, + "client_certificate": schema.StringAttribute{ + Optional: true, + Description: "PEM-encoded client certificate for TLS authentication.", + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), + }, + }, + "client_key": schema.StringAttribute{ + Optional: true, + Sensitive: true, + Description: "PEM-encoded client certificate key for TLS authentication.", + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), + }, + }, + "cluster_ca_certificate": schema.StringAttribute{ + Optional: true, + Description: "PEM-encoded root certificates bundle for TLS authentication.", + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), + }, + }, + "config_paths": schema.ListAttribute{ + ElementType: types.StringType, + Optional: true, + Description: "A list of paths to kube config files. Can be set with KUBE_CONFIG_PATHS environment variable.", + PlanModifiers: []planmodifier.List{ + listplanmodifier.UseStateForUnknown(), + }, + }, + "config_path": schema.StringAttribute{ + Optional: true, + Description: "Path to the kube config file.", + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), + }, + }, + "config_context": schema.StringAttribute{ + Optional: true, + Description: "Context name to load from the kube config file.", + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), + }, + }, + "config_context_auth_info": schema.StringAttribute{ + Optional: true, + Description: "", + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), + }, + }, + "config_context_cluster": schema.StringAttribute{ + Optional: true, + Description: "", + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), + }, + }, + "token": schema.StringAttribute{ + Optional: true, + Sensitive: true, + Description: "Token to authenticate an service account", + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), + }, + }, + "proxy_url": schema.StringAttribute{ + Optional: true, + Description: "URL to the proxy to be used for all API requests", + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), + }, + }, + }, + }, }, } } diff --git a/akp/types/cluster.go b/akp/types/cluster.go index 3a9dd76..15dfd64 100644 --- a/akp/types/cluster.go +++ b/akp/types/cluster.go @@ -3,9 +3,10 @@ package types import ( "context" + "github.com/hashicorp/terraform-plugin-framework/attr" argocdv1 "github.com/akuity/api-client-go/pkg/api/gen/argocd/v1" - "github.com/hashicorp/terraform-plugin-framework/types" "github.com/hashicorp/terraform-plugin-framework/diag" + "github.com/hashicorp/terraform-plugin-framework/types" ) type ProtoCluster struct { @@ -14,17 +15,35 @@ type ProtoCluster struct { var ( StringClusterSize = map[string]argocdv1.ClusterSize{ - "small": argocdv1.ClusterSize_CLUSTER_SIZE_SMALL, - "medium": argocdv1.ClusterSize_CLUSTER_SIZE_MEDIUM, - "large": argocdv1.ClusterSize_CLUSTER_SIZE_LARGE, + "small": argocdv1.ClusterSize_CLUSTER_SIZE_SMALL, + "medium": argocdv1.ClusterSize_CLUSTER_SIZE_MEDIUM, + "large": argocdv1.ClusterSize_CLUSTER_SIZE_LARGE, "unspecified": argocdv1.ClusterSize_CLUSTER_SIZE_UNSPECIFIED, } ClusterSizeString = map[argocdv1.ClusterSize]string{ - argocdv1.ClusterSize_CLUSTER_SIZE_SMALL: "small", - argocdv1.ClusterSize_CLUSTER_SIZE_MEDIUM: "medium", - argocdv1.ClusterSize_CLUSTER_SIZE_LARGE: "large", + argocdv1.ClusterSize_CLUSTER_SIZE_SMALL: "small", + argocdv1.ClusterSize_CLUSTER_SIZE_MEDIUM: "medium", + argocdv1.ClusterSize_CLUSTER_SIZE_LARGE: "large", argocdv1.ClusterSize_CLUSTER_SIZE_UNSPECIFIED: "unspecified", } + KubeConfigAttr=map[string]attr.Type{ + "host": types.StringType, + "username": types.StringType, + "password": types.StringType, + "insecure": types.BoolType, + "client_certificate": types.StringType, + "client_key": types.StringType, + "cluster_ca_certificate": types.StringType, + "config_path": types.StringType, + "config_paths": types.ListType{ + ElemType: types.StringType, + }, + "config_context": types.StringType, + "config_context_auth_info": types.StringType, + "config_context_cluster": types.StringType, + "token": types.StringType, + "proxy_url": types.StringType, + } ) type AkpCluster struct { @@ -41,6 +60,8 @@ type AkpCluster struct { Manifests types.String `tfsdk:"manifests"` Labels types.Map `tfsdk:"labels"` Annotations types.Map `tfsdk:"annotations"` + KubeConfig types.Object `tfsdk:"kube_config"` + AgentVersion types.String `tfsdk:"agent_version"` } func (x *ProtoCluster) FromProto(instanceId string) (*AkpCluster, diag.Diagnostics) { @@ -70,6 +91,12 @@ func (x *ProtoCluster) FromProto(instanceId string) (*AkpCluster, diag.Diagnosti Labels: labels, Annotations: annotations, } + if x.AgentState != nil { + res.AgentVersion = types.StringValue(x.AgentState.Version) + } else { + res.AgentVersion = types.StringNull() + } + res.KubeConfig = types.ObjectNull(KubeConfigAttr) return res, diags } @@ -99,5 +126,10 @@ func (x *AkpCluster) UpdateFromProto(protoCluster *argocdv1.Cluster) diag.Diagno x.CustomImageRegistryAkuity = types.StringValue(*protoCluster.Data.CustomImageRegistryAkuity) x.Annotations = annotations x.Labels = labels + if protoCluster.AgentState != nil { + x.AgentVersion = types.StringValue(protoCluster.AgentState.Version) + } else { + x.AgentVersion = types.StringNull() + } return diags } diff --git a/docs/data-sources/cluster.md b/docs/data-sources/cluster.md index eaeda91..c37ec4e 100644 --- a/docs/data-sources/cluster.md +++ b/docs/data-sources/cluster.md @@ -31,8 +31,13 @@ data "akp_cluster" "example" { - `instance_id` (String) Argo CD Instance ID - `name` (String) Cluster Name +### Optional + +- `kube_config` (Attributes) Kubernetes connection setings. If configured, terraform will try to connect to the cluster and install the agent (see [below for nested schema](#nestedatt--kube_config)) + ### Read-Only +- `agent_version` (String) Installed agent version - `annotations` (Map of String) Cluster Annotations - `auto_upgrade_disabled` (Boolean) Disable Agents Auto Upgrade - `custom_image_registry_akuity` (String) Custom Registry for Akuity Images @@ -45,4 +50,24 @@ data "akp_cluster" "example" { - `namespace_scoped` (Boolean) Agent Namespace Scoped - `size` (String) Cluster Size. One of `small`, `medium` or `large` + +### Nested Schema for `kube_config` + +Optional: + +- `client_certificate` (String) PEM-encoded client certificate for TLS authentication. +- `client_key` (String, Sensitive) PEM-encoded client certificate key for TLS authentication. +- `cluster_ca_certificate` (String) PEM-encoded root certificates bundle for TLS authentication. +- `config_context` (String) Context name to load from the kube config file. +- `config_context_auth_info` (String) +- `config_context_cluster` (String) +- `config_path` (String) Path to the kube config file. +- `config_paths` (List of String) A list of paths to kube config files. Can be set with KUBE_CONFIG_PATHS environment variable. +- `host` (String) The hostname (in form of URI) of Kubernetes master. +- `insecure` (Boolean) Whether server should be accessed without verifying the TLS certificate. +- `password` (String, Sensitive) The password to use for HTTP basic authentication when accessing the Kubernetes master endpoint. +- `proxy_url` (String) URL to the proxy to be used for all API requests +- `token` (String, Sensitive) Token to authenticate an service account +- `username` (String) The username to use for HTTP basic authentication when accessing the Kubernetes master endpoint. + diff --git a/docs/data-sources/clusters.md b/docs/data-sources/clusters.md index 810d4d5..cd461b6 100644 --- a/docs/data-sources/clusters.md +++ b/docs/data-sources/clusters.md @@ -37,8 +37,13 @@ data "akp_clusters" "example" { ### Nested Schema for `clusters` +Optional: + +- `kube_config` (Attributes) Kubernetes connection setings. If configured, terraform will try to connect to the cluster and install the agent (see [below for nested schema](#nestedatt--clusters--kube_config)) + Read-Only: +- `agent_version` (String) Installed agent version - `annotations` (Map of String) Cluster Annotations - `auto_upgrade_disabled` (Boolean) Disable Agents Auto Upgrade - `custom_image_registry_akuity` (String) Custom Registry for Akuity Images @@ -53,4 +58,24 @@ Read-Only: - `namespace_scoped` (Boolean) Agent Namespace Scoped - `size` (String) Cluster Size. One of `small`, `medium` or `large` + +### Nested Schema for `clusters.kube_config` + +Optional: + +- `client_certificate` (String) PEM-encoded client certificate for TLS authentication. +- `client_key` (String, Sensitive) PEM-encoded client certificate key for TLS authentication. +- `cluster_ca_certificate` (String) PEM-encoded root certificates bundle for TLS authentication. +- `config_context` (String) Context name to load from the kube config file. +- `config_context_auth_info` (String) +- `config_context_cluster` (String) +- `config_path` (String) Path to the kube config file. +- `config_paths` (List of String) A list of paths to kube config files. Can be set with KUBE_CONFIG_PATHS environment variable. +- `host` (String) The hostname (in form of URI) of Kubernetes master. +- `insecure` (Boolean) Whether server should be accessed without verifying the TLS certificate. +- `password` (String, Sensitive) The password to use for HTTP basic authentication when accessing the Kubernetes master endpoint. +- `proxy_url` (String) URL to the proxy to be used for all API requests +- `token` (String, Sensitive) Token to authenticate an service account +- `username` (String) The username to use for HTTP basic authentication when accessing the Kubernetes master endpoint. + diff --git a/docs/resources/cluster.md b/docs/resources/cluster.md index 83f8442..b142962 100644 --- a/docs/resources/cluster.md +++ b/docs/resources/cluster.md @@ -48,12 +48,34 @@ resource "akp_cluster" "example" { - `custom_image_registry_akuity` (String) Custom Registry for Akuity Images - `custom_image_registry_argoproj` (String) Custom Registry for Argoproj Images - `description` (String) Cluster Description +- `kube_config` (Attributes) Kubernetes connection setings. If configured, terraform will try to connect to the cluster and install the agent (see [below for nested schema](#nestedatt--kube_config)) - `labels` (Map of String) Cluster Labels - `namespace_scoped` (Boolean) Agent Namespace Scoped ### Read-Only +- `agent_version` (String) Installed agent version - `id` (String) Cluster ID - `manifests` (String, Sensitive) Agent Installation Manifests + +### Nested Schema for `kube_config` + +Optional: + +- `client_certificate` (String) PEM-encoded client certificate for TLS authentication. +- `client_key` (String, Sensitive) PEM-encoded client certificate key for TLS authentication. +- `cluster_ca_certificate` (String) PEM-encoded root certificates bundle for TLS authentication. +- `config_context` (String) Context name to load from the kube config file. +- `config_context_auth_info` (String) +- `config_context_cluster` (String) +- `config_path` (String) Path to the kube config file. +- `config_paths` (List of String) A list of paths to kube config files. Can be set with KUBE_CONFIG_PATHS environment variable. +- `host` (String) The hostname (in form of URI) of Kubernetes master. +- `insecure` (Boolean) Whether server should be accessed without verifying the TLS certificate. +- `password` (String, Sensitive) The password to use for HTTP basic authentication when accessing the Kubernetes master endpoint. +- `proxy_url` (String) URL to the proxy to be used for all API requests +- `token` (String, Sensitive) Token to authenticate an service account +- `username` (String) The username to use for HTTP basic authentication when accessing the Kubernetes master endpoint. + diff --git a/go.mod b/go.mod index c6a2b91..e956244 100644 --- a/go.mod +++ b/go.mod @@ -9,6 +9,63 @@ require ( github.com/hashicorp/terraform-plugin-go v0.14.3 github.com/hashicorp/terraform-plugin-log v0.7.0 github.com/hashicorp/terraform-plugin-sdk/v2 v2.24.1 + k8s.io/apimachinery v0.26.1 + k8s.io/cli-runtime v0.26.1 + k8s.io/client-go v0.26.1 + k8s.io/kubectl v0.26.1 +) + +require ( + github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 // indirect + github.com/MakeNowJust/heredoc v1.0.0 // indirect + github.com/chai2010/gettext-go v1.0.2 // indirect + github.com/emicklei/go-restful/v3 v3.9.0 // indirect + github.com/evanphx/json-patch v4.12.0+incompatible // indirect + github.com/exponent-io/jsonpath v0.0.0-20151013193312-d6023ce2651d // indirect + github.com/fatih/camelcase v1.0.0 // indirect + github.com/fvbommel/sortorder v1.0.1 // indirect + github.com/go-errors/errors v1.0.1 // indirect + github.com/go-logr/logr v1.2.3 // indirect + github.com/go-openapi/jsonpointer v0.19.5 // indirect + github.com/go-openapi/jsonreference v0.20.0 // indirect + github.com/go-openapi/swag v0.19.14 // indirect + github.com/gogo/protobuf v1.3.2 // indirect + github.com/google/btree v1.0.1 // indirect + github.com/google/gnostic v0.5.7-v3refs // indirect + github.com/google/gofuzz v1.1.0 // indirect + github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect + github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7 // indirect + github.com/inconshreveable/mousetrap v1.0.1 // indirect + github.com/jonboulle/clockwork v0.2.2 // indirect + github.com/josharian/intern v1.0.0 // indirect + github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de // indirect + github.com/mailru/easyjson v0.7.6 // indirect + github.com/moby/spdystream v0.2.0 // indirect + github.com/moby/term v0.0.0-20220808134915-39b0c02b01ae // indirect + github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00 // indirect + github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect + github.com/peterbourgon/diskv v2.0.1+incompatible // indirect + github.com/pkg/errors v0.9.1 // indirect + github.com/russross/blackfriday/v2 v2.1.0 // indirect + github.com/spf13/cobra v1.6.0 // indirect + github.com/spf13/pflag v1.0.5 // indirect + github.com/xlab/treeprint v1.1.0 // indirect + go.starlark.net v0.0.0-20200306205701-8dd3e2ee1dd5 // indirect + golang.org/x/oauth2 v0.0.0-20220722155238-128564f6959c // indirect + golang.org/x/term v0.3.0 // indirect + golang.org/x/time v0.0.0-20220210224613-90d013bbcef8 // indirect + gopkg.in/inf.v0 v0.9.1 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect + k8s.io/api v0.26.1 // indirect + k8s.io/component-base v0.26.1 // indirect + k8s.io/klog/v2 v2.80.1 // indirect + k8s.io/kube-openapi v0.0.0-20221012153701-172d655c2280 // indirect + k8s.io/utils v0.0.0-20221107191617-1a15be271d1d // indirect + sigs.k8s.io/json v0.0.0-20220713155537-f223a00ba0e2 // indirect + sigs.k8s.io/kustomize/api v0.12.1 // indirect + sigs.k8s.io/kustomize/kyaml v0.13.9 // indirect + sigs.k8s.io/structured-merge-diff/v4 v4.2.3 // indirect + sigs.k8s.io/yaml v1.3.0 // indirect ) require ( @@ -58,6 +115,7 @@ require ( github.com/mattn/go-isatty v0.0.14 // indirect github.com/mitchellh/cli v1.1.4 // indirect github.com/mitchellh/copystructure v1.2.0 // indirect + github.com/mitchellh/go-homedir v1.1.0 github.com/mitchellh/go-testing-interface v1.14.1 // indirect github.com/mitchellh/go-wordwrap v1.0.0 // indirect github.com/mitchellh/mapstructure v1.5.0 // indirect diff --git a/go.sum b/go.sum index a813955..9e5788b 100644 --- a/go.sum +++ b/go.sum @@ -1,4 +1,10 @@ +cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 h1:UQHMgLO+TxOElx5B5HZ4hJQsoJ/PvUvKRhJHDQXO8P8= +github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= +github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/MakeNowJust/heredoc v1.0.0 h1:cXCdzVdstXyiTqTvfqk9SDHpKNjxuom+DOlyEeQ4pzQ= +github.com/MakeNowJust/heredoc v1.0.0/go.mod h1:mG5amYoWBHf8vpLOuehzbGGw0EHxpZZ6lCpQ4fNJ8LE= github.com/Masterminds/goutils v1.1.0/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU= github.com/Masterminds/goutils v1.1.1 h1:5nUrii3FMTL5diU80unEVvNevw1nH4+ZV4DSLVJLSYI= github.com/Masterminds/goutils v1.1.1/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU= @@ -29,25 +35,52 @@ github.com/apparentlymart/go-textseg/v13 v13.0.0/go.mod h1:ZK2fH7c4NqDTLtiYLvIkE github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= github.com/armon/go-radix v1.0.0 h1:F4z6KzEeeQIMeLFa97iZU6vupzoecKdU5TX24SNppXI= github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio= github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs= github.com/bgentry/speakeasy v0.1.0 h1:ByYyxL9InA1OWqxJqqp2A5pYHUrCiAL6K3J+LKSsQkY= github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= +github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/chai2010/gettext-go v1.0.2 h1:1Lwwip6Q2QGsAdl/ZKPCwTe9fe0CjlUbqj5bFNSjIRk= +github.com/chai2010/gettext-go v1.0.2/go.mod h1:y+wnP2cHYaVj19NZhYKAwEMH2CI1gNHeQQ+5AjwawxA= +github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= +github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= +github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= +github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= +github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= +github.com/creack/pty v1.1.11 h1:07n33Z8lZxZ2qwegKbObQohDhXDQxiMMz1NOUGYlesw= +github.com/creack/pty v1.1.11/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/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE= +github.com/elazarl/goproxy v0.0.0-20180725130230-947c36da3153 h1:yUdfgN0XgIJw7foRItutHYUIhlcKzcSf5vDpdhQAKTc= +github.com/emicklei/go-restful/v3 v3.9.0 h1:XwGDlfxEnQZzuopoqxwSEllNcCOM9DhhFyhFIIGKwxE= +github.com/emicklei/go-restful/v3 v3.9.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= github.com/emirpasic/gods v1.12.0 h1:QAUIPSaCu4G+POclxeqb3F+WPpdKqFGlw36+yOzGlrg= github.com/emirpasic/gods v1.12.0/go.mod h1:YfzfFFoVP/catgzJb4IKIqXjX78Ha8FMSDh3ymbK86o= +github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= +github.com/evanphx/json-patch v4.12.0+incompatible h1:4onqiflcdA9EOZ4RxV643DvftH5pOlLGNtQ5lPWQu84= +github.com/evanphx/json-patch v4.12.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= +github.com/exponent-io/jsonpath v0.0.0-20151013193312-d6023ce2651d h1:105gxyaGwCFad8crR9dcMQWvV9Hvulu6hwUh4tWPJnM= +github.com/exponent-io/jsonpath v0.0.0-20151013193312-d6023ce2651d/go.mod h1:ZZMPRZwes7CROmyNKgQzC3XPs6L/G2EJLHddWejkmf4= +github.com/fatih/camelcase v1.0.0 h1:hxNvNX/xYBp0ovncs8WyWZrOrpBNub/JfaMvbURyft8= +github.com/fatih/camelcase v1.0.0/go.mod h1:yN2Sb0lFhZJUdVvtELVWefmrXpuZESvPmqwoZc+/fpc= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w= github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc= github.com/frankban/quicktest v1.14.3 h1:FJKSZTDHjyhriyC81FLQ0LY93eSai0ZyR/ZIkd3ZUKE= +github.com/fvbommel/sortorder v1.0.1 h1:dSnXLt4mJYH25uDDGa3biZNQsozaUWDSWeKJ0qqFfzE= +github.com/fvbommel/sortorder v1.0.1/go.mod h1:uk88iVf1ovNn1iLfgUVU2F9o5eO30ui720w+kxuqRs0= github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= github.com/gin-gonic/gin v1.8.1 h1:4+fr/el88TOO3ewCmQr8cx/CtZ/umlIRIs5M4NTNjf8= github.com/gin-gonic/gin v1.8.1/go.mod h1:ji8BvRH1azfM+SYow9zQ6SZMvR8qOMZHmsCuWR9tTTk= github.com/gliderlabs/ssh v0.2.2/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0= +github.com/go-errors/errors v1.0.1 h1:LUHzmkK3GUKUrL/1gfBUxAHzcev3apQlezX/+O7ma6w= +github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q= github.com/go-git/gcfg v1.5.0 h1:Q5ViNfGF8zFgyJWPqYwA7qGFoMTEiBmdlkcfRmpIMa4= github.com/go-git/gcfg v1.5.0/go.mod h1:5m20vg6GwYabIxaOonVkTdrILxQMpEShl1xiMF4ua+E= github.com/go-git/go-billy/v5 v5.2.0/go.mod h1:pmpqyWchKfYfrkb/UVH4otLvyi/5gJlGI4Hb3ZqZ3W0= @@ -56,6 +89,17 @@ github.com/go-git/go-billy/v5 v5.3.1/go.mod h1:pmpqyWchKfYfrkb/UVH4otLvyi/5gJlGI github.com/go-git/go-git-fixtures/v4 v4.2.1/go.mod h1:K8zd3kDUAykwTdDCr+I0per6Y6vMiRR/nnVTBtavnB0= github.com/go-git/go-git/v5 v5.4.2 h1:BXyZu9t0VkbiHtqrsvdq39UDhGJTl1h55VW6CSC4aY4= github.com/go-git/go-git/v5 v5.4.2/go.mod h1:gQ1kArt6d+n+BGd+/B/I74HwRTLhth2+zti4ihgckDc= +github.com/go-logr/logr v1.2.0/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-logr/logr v1.2.3 h1:2DntVwHkVopvECVRSlL5PSo9eG+cAkDCuckLubN+rq0= +github.com/go-logr/logr v1.2.3/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= +github.com/go-openapi/jsonpointer v0.19.5 h1:gZr+CIYByUqjcgeLXnQu2gHYQC9o73G2XUeOFYEICuY= +github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= +github.com/go-openapi/jsonreference v0.20.0 h1:MYlu0sBgChmCfJxxUKZ8g1cPWFOB37YSZqewK7OKeyA= +github.com/go-openapi/jsonreference v0.20.0/go.mod h1:Ag74Ico3lPc+zR+qjn4XBUmXymS4zJbYVCZmcgkasdo= +github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= +github.com/go-openapi/swag v0.19.14 h1:gm3vOOXfiuw5i9p5N9xJvfjvuofpyvLA9Wr6QfK5Fng= +github.com/go-openapi/swag v0.19.14/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ= github.com/go-playground/assert/v2 v2.0.1 h1:MsBgLAaY856+nPRTKrp3/OZK38U/wa0CcBYNjji3q3A= github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= github.com/go-playground/locales v0.14.0 h1:u50s323jtVGugKlcYeyzC0etD1HifMjqmJqb8WugfUU= @@ -69,25 +113,49 @@ github.com/go-resty/resty/v2 v2.7.0/go.mod h1:9PWDzw47qPphMRFfhsyk0NnSgvluHcljSM github.com/go-test/deep v1.0.3 h1:ZrJSEWsXzPOxaZnFteGEfooLba+ju3FYIbOrS+rQd68= github.com/goccy/go-json v0.9.7 h1:IcB+Aqpx/iMHu5Yooh7jEzJk1JZ7Pjtmys2ukPr7EeM= github.com/goccy/go-json v0.9.7/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= +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/glog v1.0.0 h1:nfP3RFugxnNRyKgeWd4oI1nYvXpxrx8ck8ZrcizshdQ= +github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/protobuf v1.1.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= +github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= +github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= +github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= +github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= +github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= 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/google/btree v1.0.1 h1:gK4Kx5IaGY9CD5sPJ36FHiBJ6ZXl0kilRiiCj+jdYp4= +github.com/google/btree v1.0.1/go.mod h1:xXMiIv4Fb/0kKde4SpL7qlzvu5cMJDRkFDxJfI9uaxA= +github.com/google/gnostic v0.5.7-v3refs h1:FhTMOKj2VhjpouxvWJAV1TL304uMlb9zcDqkl6cEI54= +github.com/google/gnostic v0.5.7-v3refs/go.mod h1:73MKFl6jIHelAJNaBGFzt3SPtZULs9dYrGFt8OiIsHQ= +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= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/gofuzz v1.1.0 h1:Hsa8mG0dQ46ij8Sl2AYJDUv1oA9/d6Vk+3LG99Oe02g= +github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4= +github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ= github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= 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/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7 h1:pdN6V1QBWetyv/0+wjACpqVH+eVULgEjkurDLq3goeM= +github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= github.com/grpc-ecosystem/grpc-gateway/v2 v2.11.2 h1:BqHID5W5qnMkug0Z8UmL8tN0gAy4jQ+B4WFt8cCgluU= github.com/grpc-ecosystem/grpc-gateway/v2 v2.11.2/go.mod h1:ZbS3MZTZq/apAfAEHGoB5HbsQQstoqP92SjAqtQ9zeg= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= @@ -148,16 +216,25 @@ github.com/imdario/mergo v0.3.11/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= github.com/imdario/mergo v0.3.13 h1:lFzP57bqS/wsqKssCGmtLAb8A0wKjLGrve2q3PPVcBk= github.com/imdario/mergo v0.3.13/go.mod h1:4lJ1jqUDcsbIECGy0RUJAXNIhg+6ocWgb1ALK2O4oXg= +github.com/inconshreveable/mousetrap v1.0.1 h1:U3uMjPSQEBMNp1lFxmllqCPM6P5u/Xq7Pgzkat/bFNc= +github.com/inconshreveable/mousetrap v1.0.1/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A= github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo= github.com/jessevdk/go-flags v1.5.0/go.mod h1:Fw0T6WPc1dYxT4mKEZRfG5kJhaTDP9pj1c2EWnYs/m4= github.com/jhump/protoreflect v1.6.0 h1:h5jfMVslIg6l29nsMs0D8Wj17RDVdNYti0vDN/PZZoE= +github.com/jonboulle/clockwork v0.2.2 h1:UOGuzwb1PwsrDAObMuhUnj0p5ULPj8V/xJ7Kx9qUBdQ= +github.com/jonboulle/clockwork v0.2.2/go.mod h1:Pkfl5aHPm1nk2H9h0bjmnJD/BcgbGXUBGnn1kMkgxc8= +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.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= github.com/kevinburke/ssh_config v0.0.0-20201106050909-4977a11b4351 h1:DowS9hvgyYSX4TO5NpyC606/Z4SxnNYbT+WX27or6Ck= github.com/kevinburke/ssh_config v0.0.0-20201106050909-4977a11b4351/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM= +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/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= @@ -169,6 +246,12 @@ github.com/kylelemons/godebug v0.0.0-20170820004349-d65d576e9348/go.mod h1:B69LE github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= github.com/leodido/go-urn v1.2.1 h1:BqpAaACuzVSgi/VLzGZIobT2z4v53pjosyNd9Yv6n/w= github.com/leodido/go-urn v1.2.1/go.mod h1:zt4jvISO2HfUBqxjfIshjdMTYS56ZS/qv49ictyFfxY= +github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de h1:9TO3cAIGXtEhnIaL+V+BEER86oLrvS+kWobKpbJuye0= +github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de/go.mod h1:zAbeS9B/r2mtpb6U+EI2rYA5OAXxsYw6wTamcNW+zcE= +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.6 h1:8yTIVnZgCoiM1TgqoeTl+LfU5Jg6/xL3QhGQnimLYnA= +github.com/mailru/easyjson v0.7.6/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= github.com/matryer/is v1.2.0/go.mod h1:2fLPjFQM9rhQ15aVEtbuwhJinnOqrmgXPNdZsdwlWXA= github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= @@ -194,29 +277,45 @@ github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RR github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= +github.com/moby/spdystream v0.2.0 h1:cjW1zVyyoiM0T7b6UoySUFqzXMoqRckQtXwGPiBhOM8= +github.com/moby/spdystream v0.2.0/go.mod h1:f7i0iNDQJ059oMTcWxx8MA/zKFIuD/lY+0GqbN2Wy8c= +github.com/moby/term v0.0.0-20220808134915-39b0c02b01ae h1:O4SWKdcHVCvYqyDV+9CJA1fcDN2L11Bule0iFy3YlAI= +github.com/moby/term v0.0.0-20220808134915-39b0c02b01ae/go.mod h1:E2VnQOmVuvZB6UYnnDB0qG5Nq/1tD9acaOpo6xmt0Kw= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= 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/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00 h1:n6/2gBQ3RWajuToeY6ZtZTIKv2v7ThUy5KKusIT0yc0= +github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00/go.mod h1:Pm3mSP3c5uWn86xMLZ5Sa7JB9GsEZySvHYXCTK4E9q4= +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/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= github.com/oklog/run v1.0.0 h1:Ru7dDtJNOyC66gQ5dQmaCa0qIsAUFY3sFpK1Xk8igrw= github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA= +github.com/onsi/ginkgo/v2 v2.4.0 h1:+Ig9nvqgS5OBSACXNk15PLdp0U9XPYROt9CFzVdFGIs= +github.com/onsi/gomega v1.23.0 h1:/oxKu9c2HVap+F3PfKort2Hw5DEU+HGlW8n+tguWsys= github.com/pelletier/go-toml/v2 v2.0.1 h1:8e3L2cCQzLFi2CR4g7vGFuFxX7Jl1kKX8gW+iV0GUKU= github.com/pelletier/go-toml/v2 v2.0.1/go.mod h1:r9LEWfGN8R5k0VXJ+0BkIe7MYkRdwZOjgMj2KwnJFUo= +github.com/peterbourgon/diskv v2.0.1+incompatible h1:UBdAOUP5p4RWqPBg048CAvpKN+vxiaj6gdUUzhl4XmI= +github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU= github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= 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/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= github.com/posener/complete v1.2.3 h1:NP0eAhjcjImqslEwo/1hq7gpajME0fTLTezBKDqfXqo= github.com/posener/complete v1.2.3/go.mod h1:WZIdtGGp+qx0sLrYKtIRAruyNpv6hFCicSgv7Sy7s/s= +github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= github.com/rogpeppe/go-internal v1.8.0 h1:FCbCCtXNOY3UtUuHUYaghJg4y7Fd14rXifAYUAtL9R8= github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE= github.com/russross/blackfriday v1.6.0 h1:KqfZb0pUVN2lYqZUYRddxF4OR8ZMURnJIG5Y3VRLtww= github.com/russross/blackfriday v1.6.0/go.mod h1:ti0ldHuxg49ri4ksnFxlkCfN+hvslNlmVHqNRXXJNAY= +github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= +github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/sebdah/goldie v1.0.0/go.mod h1:jXP4hmWywNEwZzhMuv2ccnqTSFpuq8iyQhtQdkkZBH4= github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= github.com/sergi/go-diff v1.2.0 h1:XU+rvMAioB0UC3q1MFrIQy4Vo5/4VsRDQQXHsEya6xQ= @@ -227,8 +326,15 @@ github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMB github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= github.com/spf13/cast v1.5.0 h1:rj3WzYc11XZaIZMPKmwP96zkFEnnAmV8s6XbB2aY32w= github.com/spf13/cast v1.5.0/go.mod h1:SpXXQ5YoyJw6s3/6cMTQuxvgRl3PCJiyaX9p6b155UU= +github.com/spf13/cobra v1.6.0 h1:42a0n6jwCot1pUmomAp4T7DeMD+20LFv4Q54pxLf2LI= +github.com/spf13/cobra v1.6.0/go.mod h1:IOw/AERYS7UzyrGinqmz6HLUo219MORXGxhbaJUqzrY= +github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= +github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/stoewer/go-strcase v1.2.0/go.mod h1:IBiWB2sKIp3wVVQ3Y035++gc+knqhUQag1KpM8ahLw8= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.2.0 h1:Hbg2NidpLE8veEBkEZTL3CvlkUIVzuU9jDplZO54c48= 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= @@ -250,15 +356,23 @@ github.com/vmihailenco/tagparser v0.1.1 h1:quXMXlA39OCbd2wAdTsGDlK9RkOk6Wuw+x37w github.com/vmihailenco/tagparser v0.1.1/go.mod h1:OeAg3pn3UbLjkWt+rN9oFYB6u/cQgqMEUPoW2WPyhdI= github.com/xanzy/ssh-agent v0.3.0 h1:wUMzuKtKilRgBAD1sUb8gOwwRr2FGoBVumcjoOACClI= github.com/xanzy/ssh-agent v0.3.0/go.mod h1:3s9xbODqPuuhK9JV1R321M/FlMZSBvE5aY6eAcqrDh0= +github.com/xlab/treeprint v1.1.0 h1:G/1DjNkPpfZCFt9CSh6b5/nY4VimlbHF3Rh4obvtzDk= +github.com/xlab/treeprint v1.1.0/go.mod h1:gj5Gd3gPdKtR1ikdDK6fnFLdmIS0X30kTTuNd/WEJu0= +github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/zclconf/go-cty v1.1.0/go.mod h1:xnAOWiHeOqg2nWS62VtQ7pbOu17FtxJNW8RLEih+O3s= github.com/zclconf/go-cty v1.2.0/go.mod h1:hOPWgoHbaTUnI5k4D2ld+GRpFJSCe6bCM7m1q/N4PQ8= github.com/zclconf/go-cty v1.10.0/go.mod h1:vVKLxnk3puL4qRAv72AO+W99LUD4da90g3uUAzyuvAk= github.com/zclconf/go-cty v1.12.1 h1:PcupnljUm9EIvbgSHQnHhUr3fO6oFmkOrvs2BAFNXXY= github.com/zclconf/go-cty v1.12.1/go.mod h1:s9IfD1LK5ccNMSWCVFCE2rJfHiZgi7JijgeWIMfhLvA= github.com/zclconf/go-cty-debug v0.0.0-20191215020915-b22d67c1ba0b/go.mod h1:ZRKQfBXbGkpdV6QMzT3rU1kSTAnfu1dO8dPKjYprgj8= +go.starlark.net v0.0.0-20200306205701-8dd3e2ee1dd5 h1:+FNtrFTmVw0YZGpBGX56XDee331t6JAXeK2bcyhLOOc= +go.starlark.net v0.0.0-20200306205701-8dd3e2ee1dd5/go.mod h1:nmDLcffg48OtT/PSW0Hg7FvpRQsQh5OSqIylirxKC7o= golang.org/x/crypto v0.0.0-20190219172222-a4c6cb3142f2/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200414173820-0848c9571904/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= @@ -266,15 +380,27 @@ golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e/go.mod h1:GvvjBRRGRdwPK5y golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d h1:sK3txAijHtOK88l68nt020reeT1ZdKLIYetKl95FzVY= golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20221204150635-6dcec336b2bb h1:QIsP/NmClBICkqnJ4rSIhnrGiGR7Yv9ZORGGnmmLTPk= golang.org/x/exp v0.0.0-20221204150635-6dcec336b2bb/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc= +golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= +golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180811021610-c39426892332/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20191009170851-d66e71096ffb/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210326060303-6b1517762897/go.mod h1:uSPa2vr4CLtc/ILN5odXGNXS6mhrKVzTaCXzk9m6W3k= @@ -282,23 +408,34 @@ golang.org/x/net v0.0.0-20211029224645-99673261e6eb/go.mod h1:9nx3DQGgdP8bBQD5qx golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.3.1-0.20221206200815-1e63c2f08a10 h1:Frnccbp+ok2GkUS2tC84yAq/U9Vg+0sIO7aRL3T4Xnc= golang.org/x/net v0.3.1-0.20221206200815-1e63c2f08a10/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE= +golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20220722155238-128564f6959c h1:q3gFqPqH7NVofKo3c3yETAP//pPI+G5mvB7qqj1Y5kY= +golang.org/x/oauth2 v0.0.0-20220722155238-128564f6959c/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg= 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= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191002063906-3421d5a6bb1c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210324051608-47abb6519492/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210502180810-71e4cd670f79/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -306,6 +443,8 @@ golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.3.0 h1:w8ZOecv6NaNa/zC8944JTU3vz4u6Lagfk4RPQxv92NQ= golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.3.0 h1:qoo4akIqOcDME5bhc/NgxUdovd6BSS2uMsVjB56q1xI= +golang.org/x/term v0.3.0/go.mod h1:q750SLmJuPmVoN1blW3UFBPREJfb1KmY3vwxfr+nFDA= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= @@ -314,17 +453,45 @@ golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.5.0 h1:OLmvp0KP+FVG99Ct/qFiL/Fhk4zp4QQnZ7b2U+5piUM= golang.org/x/text v0.5.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/time v0.0.0-20220210224613-90d013bbcef8 h1:vVKdlvoWBphwdxWKrFZEuM0kGgGLxUOYcY4U/2Vjg44= +golang.org/x/time v0.0.0-20220210224613-90d013bbcef8/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= +golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190624222133-a101b041ded4/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c= google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= +google.golang.org/genproto v0.0.0-20201019141844-1ed22bb0c154/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20220805133916-01dd62135a58 h1:sRT5xdTkj1Kbk30qbYC7VyMj73N5pZYsw6v+Nrzdhno= google.golang.org/genproto v0.0.0-20220805133916-01dd62135a58/go.mod h1:iHe1svFLAZg9VWz891+QbRMwUv9O/1Ww+/mngYeThbc= +google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= +google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.51.0 h1:E1eGv1FTqoLIdnBCZufiSHgKjlqG6fKFf6pPWtMTh8U= google.golang.org/grpc v1.51.0/go.mod h1:wgNDFcnuBGmxLKI/qn4T+m5BtEBYXJPvibbUPsAIPww= +google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= +google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= +google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= +google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= +google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= +google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w= @@ -336,15 +503,51 @@ gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8 gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= 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/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= +gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= gopkg.in/warnings.v0 v0.1.2 h1:wFXVbFY8DY5/xOe1ECiWdKCzZlxgshcYVNkBHstARME= gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gotest.tools/v3 v3.0.2/go.mod h1:3SzNCllyD9/Y+b5r9JIKQ474KzkZyqLqEfYqMsX94Bk= +gotest.tools/v3 v3.0.3 h1:4AuOwCGf4lLR9u3YOe2awrHygurzhO/HeQ6laiA6Sx0= +honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +k8s.io/api v0.26.1 h1:f+SWYiPd/GsiWwVRz+NbFyCgvv75Pk9NK6dlkZgpCRQ= +k8s.io/api v0.26.1/go.mod h1:xd/GBNgR0f707+ATNyPmQ1oyKSgndzXij81FzWGsejg= +k8s.io/apimachinery v0.26.1 h1:8EZ/eGJL+hY/MYCNwhmDzVqq2lPl3N3Bo8rvweJwXUQ= +k8s.io/apimachinery v0.26.1/go.mod h1:tnPmbONNJ7ByJNz9+n9kMjNP8ON+1qoAIIC70lztu74= +k8s.io/cli-runtime v0.26.1 h1:f9+bRQ1V3elQsx37KmZy5fRAh56mVLbE9A7EMdlqVdI= +k8s.io/cli-runtime v0.26.1/go.mod h1:+e5Ym/ARySKscUhZ8K3hZ+ZBo/wYPIcg+7b5sFYi6Gg= +k8s.io/client-go v0.26.1 h1:87CXzYJnAMGaa/IDDfRdhTzxk/wzGZ+/HUQpqgVSZXU= +k8s.io/client-go v0.26.1/go.mod h1:IWNSglg+rQ3OcvDkhY6+QLeasV4OYHDjdqeWkDQZwGE= +k8s.io/component-base v0.26.1 h1:4ahudpeQXHZL5kko+iDHqLj/FSGAEUnSVO0EBbgDd+4= +k8s.io/component-base v0.26.1/go.mod h1:VHrLR0b58oC035w6YQiBSbtsf0ThuSwXP+p5dD/kAWU= +k8s.io/klog/v2 v2.80.1 h1:atnLQ121W371wYYFawwYx1aEY2eUfs4l3J72wtgAwV4= +k8s.io/klog/v2 v2.80.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0= +k8s.io/kube-openapi v0.0.0-20221012153701-172d655c2280 h1:+70TFaan3hfJzs+7VK2o+OGxg8HsuBr/5f6tVAjDu6E= +k8s.io/kube-openapi v0.0.0-20221012153701-172d655c2280/go.mod h1:+Axhij7bCpeqhklhUTe3xmOn6bWxolyZEeyaFpjGtl4= +k8s.io/kubectl v0.26.1 h1:K8A0Jjlwg8GqrxOXxAbjY5xtmXYeYjLU96cHp2WMQ7s= +k8s.io/kubectl v0.26.1/go.mod h1:miYFVzldVbdIiXMrHZYmL/EDWwJKM+F0sSsdxsATFPo= +k8s.io/utils v0.0.0-20221107191617-1a15be271d1d h1:0Smp/HP1OH4Rvhe+4B8nWGERtlqAGSftbSbbmm45oFs= +k8s.io/utils v0.0.0-20221107191617-1a15be271d1d/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= +sigs.k8s.io/json v0.0.0-20220713155537-f223a00ba0e2 h1:iXTIw73aPyC+oRdyqqvVJuloN1p0AC/kzH07hu3NE+k= +sigs.k8s.io/json v0.0.0-20220713155537-f223a00ba0e2/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0= +sigs.k8s.io/kustomize/api v0.12.1 h1:7YM7gW3kYBwtKvoY216ZzY+8hM+lV53LUayghNRJ0vM= +sigs.k8s.io/kustomize/api v0.12.1/go.mod h1:y3JUhimkZkR6sbLNwfJHxvo1TCLwuwm14sCYnkH6S1s= +sigs.k8s.io/kustomize/kyaml v0.13.9 h1:Qz53EAaFFANyNgyOEJbT/yoIHygK40/ZcvU3rgry2Tk= +sigs.k8s.io/kustomize/kyaml v0.13.9/go.mod h1:QsRbD0/KcU+wdk0/L0fIp2KLnohkVzs6fQ85/nOXac4= +sigs.k8s.io/structured-merge-diff/v4 v4.2.3 h1:PRbqxJClWWYMNV1dhaG4NsibJbArud9kFxnAMREiWFE= +sigs.k8s.io/structured-merge-diff/v4 v4.2.3/go.mod h1:qjx8mGObPmV2aSZepjQjbmb2ihdVs8cGKBraizNC69E= +sigs.k8s.io/yaml v1.3.0 h1:a2VclLzOGrwOHDiV8EfBGhvjHvP46CtW5j6POvhYGGo= +sigs.k8s.io/yaml v1.3.0/go.mod h1:GeOyir5tyXNByN85N/dRIT9es5UQNerPYEKK56eTBm8=