diff --git a/.golangci.yaml b/.golangci.yaml index a3b8d71..28803a9 100644 --- a/.golangci.yaml +++ b/.golangci.yaml @@ -221,4 +221,5 @@ formatters: simplify: true golines: max-len: 128 - tab-len: 4 \ No newline at end of file + tab-len: 4 + reformat-tags: false \ No newline at end of file diff --git a/README.md b/README.md index ba6cde3..c567ece 100644 --- a/README.md +++ b/README.md @@ -58,14 +58,14 @@ Available Commands: update-owner-references Update owner references of an export against the current cluster Flags: - -a, --archive If enabled, an archive with the exports is created + -a, --archive Create a tar.gz archive --as string Username to impersonate for the operation. User could be a regular user or a service account in a namespace. --as-group stringArray Group to impersonate for the operation, this flag can be repeated to specify multiple groups. --as-uid string UID to impersonate for the operation. --as-user-extra stringArray User extras to impersonate for the operation, this flag can be repeated to specify multiple values for the same key. - --cache-dir string Default cache directory (default "/home/bakito/.kube/cache") + --cache-dir string Default cache directory (default "/home/user/.kube/cache") --certificate-authority string Path to a cert file for the certificate authority - -c, --clear-target If enabled, the target dir is deleted before running the new export + -c, --clear-target Clear the target directory before exporting --client-certificate string Path to a client certificate file for TLS --client-key string Path to a client key file for TLS --cluster string The name of the kubeconfig cluster to use @@ -74,29 +74,29 @@ Flags: --created-within duration The max allowed age duration for the resources --disable-compression If true, opt-out of response compression for all requests to the server -d, --exclude-defaults If enabled, default excludes will be applied. [apps.ControllerRevision, apps.ReplicaSet, batch.Job, Pod, ReplicationController, discovery.k8s.io.EndpointSlice, Endpoints, Event, events.k8s.io.Event, coordination.k8s.io.Lease, metrics.k8s.io.NodeMetrics, metrics.k8s.io.PodMetrics, ComponentStatus, Secret, LocalSubjectAccessReview, SelfSubjectAccessReview, SelfSubjectRulesReview, SubjectAccessReview, TokenReview, Binding] - -e, --exclude-kinds strings Do not export excluded kinds + -e, --exclude-kinds strings List all kinds to be excluded -h, --help help for kubexporter - --include-cluster-resources Also export cluster-scoped resources when a namespace filter is active - -i, --include-kinds strings Export only included kinds, if included kinds are defined, excluded will be ignored + --include-cluster-resources Export cluster-scoped resources too, when a namespace filter is active + -i, --include-kinds strings List all kinds to be included --insecure-skip-tls-verify If true, the server's certificate will not be checked for validity. This will make your HTTPS connections insecure --kubeconfig string Path to the kubeconfig file to use for CLI requests. - -l, --lists If enabled, all resources are exported as lists instead of individual files - -n, --namespace strings Export only these namespaces, comma-separated (e.g. --namespace ns1,ns2) or repeated (e.g. --namespace ns1 --namespace ns2) + -l, --lists Export as lists instead of individual files + -n, --namespace strings A single namespace (default all) -o, --output string Output format. One of: (json, yaml, kyaml). (default "yaml") -p, --progress string Progress mode bar|bubbles|simple|none (default "bar") - -q, --quiet If enabled, output is prevented + -q, --quiet Output is prevented --request-timeout string The length of time to wait before giving up on a single server request. Non-zero values should contain a corresponding time unit (e.g. 1s, 2m, 3h). A value of zero means don't timeout requests. (default "0") -s, --server string The address and port of the Kubernetes API server --show-managed-fields If true, keep the managedFields when printing objects in JSON or YAML format. - --size If enabled, a exported file sizes are printed + --size Print the size of the exported files --summary If enabled, a summary is printed - -t, --target string Set the target directory (default "exports") + -t, --target string The target directory (default "exports") --tls-server-name string Server name to use for server certificate validation. If it is not provided, the hostname used to contact the server is used --token string Bearer token for authentication to the API server --user string The name of the kubeconfig user to use - -v, --verbose If enabled, errors during export are listed in summary + -v, --verbose Errors during export are listed in summary --version version for kubexporter - -w, --worker int The number of worker to use for the export (default 1) + -w, --worker int The number of parallel worker (default 1) Use "kubexporter [command] --help" for more information about a command. ``` @@ -159,27 +159,27 @@ sortSlices: fileNameTemplate: # Custom resource list file name template (string) listFileNameTemplate: -# Export as lists per kind (bool) +# Export as lists instead of individual files (bool) asLists: # Kubernetes query page size (0 use default) (int) queryPageSize: -# The target directory (default "exports") (string) +# The target directory (string) target: # Clear the target directory before exporting (bool) clearTarget: # If enabled, a summary is printed (bool) summary: -# Progress mode bar|bubbles|simple|none (default bar) (string) +# Progress mode bar|bubbles|simple|none (string) progress: # A single namespace (default all) (string) namespace: # Multiple namespaces (joined with namespace, if both are set) ([]string) namespaces: -# Export cluster-scoped resources too when a namespace filter is active (bool) +# Export cluster-scoped resources too, when a namespace filter is active (bool) includeClusterResources: # The number of parallel worker (int) worker: -# create an archive (bool) +# Create a tar.gz archive (bool) archive: # Number of days to keep old archives (int) archiveRetentionDays: diff --git a/cmd/docs/main.go b/cmd/docs/main.go index 66c56dd..76206d5 100644 --- a/cmd/docs/main.go +++ b/cmd/docs/main.go @@ -3,18 +3,24 @@ package main import ( "github.com/bakito/docs-gen/docs" "github.com/bakito/docs-gen/pkg/cli" + "github.com/bakito/docs-gen/pkg/cobra" "github.com/bakito/docs-gen/pkg/yaml" "github.com/bakito/kubexporter/pkg/types" ) const ( - cliStartMarker = "" - cliEndMarker = "" - yamlStartMarker = "" - yamlEndMarker = "" + cliStartMarker = "" + cliEndMarker = "" + yamlStartMarker = "" + yamlEndMarker = "" + cobraStartMarker = "// cobra-doc-start" + cobraEndMarker = "// cobra-doc-end" ) func main() { + docs.UpdateDocumentation("cmd/zz_generated_docs.go", + cobra.UpdateDocumentation[types.Config](cobraStartMarker, cobraEndMarker), + ) docs.UpdateDocumentation("README.md", cli.UpdateDocumentation(cliStartMarker, cliEndMarker, ".", "go", "run", ".", "--help"), yaml.UpdateDocumentation[types.Config](yamlStartMarker, yamlEndMarker), diff --git a/cmd/root.go b/cmd/root.go index dd291e8..25f15ff 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -7,6 +7,7 @@ import ( "io" "os" "strings" + "time" "github.com/mattn/go-isatty" "github.com/spf13/cobra" @@ -147,30 +148,24 @@ func Execute() { func init() { rootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file") - rootCmd.Flags().StringP("target", "t", "exports", "Set the target directory") - rootCmd.Flags().IntP("worker", "w", 1, "The number of worker to use for the export") - rootCmd.Flags(). - BoolP("clear-target", "c", false, "If enabled, the target dir is deleted before running the new export") - rootCmd.Flags().BoolP("quiet", "q", false, "If enabled, output is prevented") - rootCmd.Flags().BoolP("verbose", "v", false, "If enabled, errors during export are listed in summary") - rootCmd.Flags().Bool("summary", false, "If enabled, a summary is printed") - rootCmd.Flags().Bool("size", false, "If enabled, a exported file sizes are printed") - rootCmd.Flags().BoolP("archive", "a", false, "If enabled, an archive with the exports is created") rootCmd.Flags(). BoolP("exclude-defaults", "d", false, "If enabled, default excludes will be applied. ["+strings.Join(types.DefaultExcludedKinds, ", ")+"]") - rootCmd.Flags(). - StringP("progress", "p", string(types.ProgressBar), "Progress mode bar|bubbles|simple|none") - rootCmd.Flags(). - BoolP("lists", "l", false, "If enabled, all resources are exported as lists instead of individual files") - rootCmd.Flags(). - StringSliceP("include-kinds", "i", []string{}, - "Export only included kinds, if included kinds are defined, excluded will be ignored") - rootCmd.Flags().StringSliceP("exclude-kinds", "e", []string{}, "Do not export excluded kinds") - rootCmd.Flags().Duration("created-within", 0, "The max allowed age duration for the resources") - rootCmd.Flags().StringSliceP("namespace", "n", []string{}, - "Export only these namespaces, comma-separated (e.g. --namespace ns1,ns2) or repeated (e.g. --namespace ns1 --namespace ns2)") - rootCmd.Flags().Bool("include-cluster-resources", false, - "Also export cluster-scoped resources when a namespace filter is active") + + rootCmd.Flags().StringP(cflagP("target", "t", "exports")) + rootCmd.Flags().IntP(cflagP("worker", "w", 1)) + rootCmd.Flags().BoolP(cflagP("clear-target", "c", false)) + rootCmd.Flags().BoolP(cflagP("quiet", "q", false)) + rootCmd.Flags().BoolP(cflagP("verbose", "v", false)) + rootCmd.Flags().Bool(cflag("summary", false)) + rootCmd.Flags().Bool(cflag("size", false)) + rootCmd.Flags().BoolP(cflagP("archive", "a", false)) + rootCmd.Flags().StringP(cflagP("progress", "p", string(types.ProgressBar))) + rootCmd.Flags().BoolP(cflagP("lists", "l", false)) + rootCmd.Flags().StringSliceP(cflagP("include-kinds", "i", []string{})) + rootCmd.Flags().StringSliceP(cflagP("exclude-kinds", "e", []string{})) + rootCmd.Flags().Duration(cflag[time.Duration]("created-within", 0)) + rootCmd.Flags().StringSliceP(cflagP("namespace", "n", []string{})) + rootCmd.Flags().Bool(cflag("include-cluster-resources", false)) configFlags = genericclioptions.NewConfigFlags(true) configFlags.Namespace = nil diff --git a/cmd/zz_generated_docs.go b/cmd/zz_generated_docs.go new file mode 100644 index 0000000..6e19082 --- /dev/null +++ b/cmd/zz_generated_docs.go @@ -0,0 +1,35 @@ +// Code generated by docs-gen. DO NOT EDIT. +package cmd + +// cobra-doc-start +var docsCobraMapping = map[string]string{ + `exclude-kinds`: `List all kinds to be excluded`, + `include-kinds`: `List all kinds to be included`, + `created-within`: `The max allowed age duration for the resources`, + `lists`: `Export as lists instead of individual files`, + `target`: `The target directory`, + `clear-target`: `Clear the target directory before exporting`, + `summary`: `If enabled, a summary is printed`, + `progress`: `Progress mode bar|bubbles|simple|none`, + `namespace`: `A single namespace (default all)`, + `include-cluster-resources`: `Export cluster-scoped resources too, when a namespace filter is active`, + `worker`: `The number of parallel worker`, + `archive`: `Create a tar.gz archive`, + `quiet`: `Output is prevented`, + `verbose`: `Errors during export are listed in summary`, + `size`: `Print the size of the exported files`, +} + +func cflagVar[T any](p *T, name string, value T) (pOut *T, nameOut string, valueOut T, reason string) { + return p, name, value, docsCobraMapping[name] +} + +func cflag[T any](name string, value T) (nameOut string, valueOut T, reason string) { + return name, value, docsCobraMapping[name] +} + +func cflagP[T any](name, shorthand string, value T) (nameOut, shorthandOut string, valueOut T, reason string) { + return name, shorthand, value, docsCobraMapping[name] +} + +// cobra-doc-end diff --git a/go.mod b/go.mod index 2674dfb..cd58f4b 100644 --- a/go.mod +++ b/go.mod @@ -8,7 +8,7 @@ require ( charm.land/lipgloss/v2 v2.0.4 cloud.google.com/go/storage v1.63.0 github.com/Masterminds/sprig v2.22.0+incompatible - github.com/bakito/docs-gen v0.0.2 + github.com/bakito/docs-gen v0.0.5 github.com/dustin/go-humanize v1.0.1 github.com/ghodss/yaml v1.0.0 github.com/google/uuid v1.6.0 diff --git a/go.sum b/go.sum index ff39e22..38fe670 100644 --- a/go.sum +++ b/go.sum @@ -52,8 +52,8 @@ github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d h1:licZJFw2RwpH github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d/go.mod h1:asat636LX7Bqt5lYEZ27JNDcqxfjdBQuJ/MM4CN/Lzo= github.com/aymanbagabas/go-udiff v0.4.1 h1:OEIrQ8maEeDBXQDoGCbbTTXYJMYRCRO1fnodZ12Gv5o= github.com/aymanbagabas/go-udiff v0.4.1/go.mod h1:0L9PGwj20lrtmEMeyw4WKJ/TMyDtvAoK9bf2u/mNo3w= -github.com/bakito/docs-gen v0.0.2 h1:ACJVMRZuJsmpD1admjepbP8TXJtF9mCQp1ZYh7kAMTQ= -github.com/bakito/docs-gen v0.0.2/go.mod h1:vIPGcnC2b8MkK3zRiJU4TsPoByKshHPBNBmdkIfl/5k= +github.com/bakito/docs-gen v0.0.5 h1:bKqRKcf7taVxWd+rCzBWx4TO8HnLNHRUXdjHQESFXVA= +github.com/bakito/docs-gen v0.0.5/go.mod h1:vIPGcnC2b8MkK3zRiJU4TsPoByKshHPBNBmdkIfl/5k= github.com/blang/semver/v4 v4.0.0 h1:1PFHFE6yCCTv8C1TeyNNarDzntLi7wMI5i/pzqYIsAM= github.com/blang/semver/v4 v4.0.0/go.mod h1:IbckMUScFkM3pff0VJDNKRiT6TG/YpiHIM2yvyW5YoQ= github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= diff --git a/pkg/types/config.go b/pkg/types/config.go index 66f97f3..0b19daa 100644 --- a/pkg/types/config.go +++ b/pkg/types/config.go @@ -145,33 +145,33 @@ func NewConfig(configFlags *genericclioptions.ConfigFlags, printFlags *genericcl // Config export config. type Config struct { - Excluded Excluded `docs:"Excluded resources" json:"excluded" yaml:"excluded"` - Included Included `docs:"Included resources" json:"included" yaml:"included"` - CreatedWithin time.Duration `docs:"The max allowed age duration for the resources" json:"createdWithin" yaml:"createdWithin"` - ConsiderOwnerReferences bool `docs:"Consider owner references for not excluded resources" json:"considerOwnerReferences" yaml:"considerOwnerReferences"` - Masked *Masked `docs:"Field masking config" json:"masked" yaml:"masked"` - Encrypted *Encrypted `docs:"Field encryption config" json:"encrypted" yaml:"encrypted"` - SortSlices KindFields `docs:"sort the slice field value before exporting" json:"sortSlices" yaml:"sortSlices"` - FileNameTemplate string `docs:"Custom resource file name template" json:"fileNameTemplate" yaml:"fileNameTemplate"` - ListFileNameTemplate string `docs:"Custom resource list file name template" json:"listFileNameTemplate" yaml:"listFileNameTemplate"` - AsLists bool `docs:"Export as lists per kind" json:"asLists" yaml:"asLists"` - QueryPageSize int `docs:"Kubernetes query page size (0 use default)" json:"queryPageSize" yaml:"queryPageSize"` - Target string `docs:"The target directory (default \"exports\")" json:"target" yaml:"target"` - ClearTarget bool `docs:"Clear the target directory before exporting" json:"clearTarget" yaml:"clearTarget"` - Summary bool `docs:"If enabled, a summary is printed" json:"summary" yaml:"summary"` - Progress Progress `docs:"Progress mode bar|bubbles|simple|none (default bar)" json:"progress" yaml:"progress"` - Namespace *string `docs:"A single namespace (default all)" json:"namespace,omitempty" yaml:"namespace,omitempty"` - Namespaces []string `docs:"Multiple namespaces (joined with namespace, if both are set)" json:"namespaces,omitempty" yaml:"namespaces,omitempty"` - IncludeClusterResources bool `docs:"Export cluster-scoped resources too when a namespace filter is active" json:"includeClusterResources" yaml:"includeClusterResources"` - Worker int `docs:"The number of parallel worker" json:"worker" yaml:"worker"` - Archive bool `docs:"create an archive" json:"archive" yaml:"archive"` - ArchiveRetentionDays int `docs:"Number of days to keep old archives" json:"archiveRetentionDays" yaml:"archiveRetentionDays"` - ArchiveTarget string `docs:"The target directory for the archive(default \"exports\")" json:"archiveTarget" yaml:"archiveTarget"` - S3Config *S3Config `docs:"S3 Configuration to upload the archive to an S3 compatible storage" json:"s3" yaml:"s3"` - GCSConfig *GCSConfig `docs:"Google storage bucket configuration" json:"gcs" yaml:"gcs"` - Quiet bool `docs:"Output is prevented" json:"quiet" yaml:"quiet"` - Verbose bool `docs:"Errors during export are listed in summary" json:"verbose" yaml:"verbose"` - PrintSize bool `docs:"Print the size of the exported files" json:"printSize" yaml:"printSize"` + Excluded Excluded `docs:"Excluded resources" json:"excluded" yaml:"excluded"` + Included Included `docs:"Included resources" json:"included" yaml:"included"` + CreatedWithin time.Duration `docs:"The max allowed age duration for the resources" docs-cli:"created-within" json:"createdWithin" yaml:"createdWithin"` + ConsiderOwnerReferences bool `docs:"Consider owner references for not excluded resources" json:"considerOwnerReferences" yaml:"considerOwnerReferences"` + Masked *Masked `docs:"Field masking config" json:"masked" yaml:"masked"` + Encrypted *Encrypted `docs:"Field encryption config" json:"encrypted" yaml:"encrypted"` + SortSlices KindFields `docs:"sort the slice field value before exporting" json:"sortSlices" yaml:"sortSlices"` + FileNameTemplate string `docs:"Custom resource file name template" json:"fileNameTemplate" yaml:"fileNameTemplate"` + ListFileNameTemplate string `docs:"Custom resource list file name template" json:"listFileNameTemplate" yaml:"listFileNameTemplate"` + AsLists bool `docs:"Export as lists instead of individual files" docs-cli:"lists" json:"asLists" yaml:"asLists"` + QueryPageSize int `docs:"Kubernetes query page size (0 use default)" json:"queryPageSize" yaml:"queryPageSize"` + Target string `docs:"The target directory" docs-cli:"target" json:"target" yaml:"target"` + ClearTarget bool `docs:"Clear the target directory before exporting" docs-cli:"clear-target" json:"clearTarget" yaml:"clearTarget"` + Summary bool `docs:"If enabled, a summary is printed" docs-cli:"summary" json:"summary" yaml:"summary"` + Progress Progress `docs:"Progress mode bar|bubbles|simple|none" docs-cli:"progress" json:"progress" yaml:"progress"` + Namespace *string `docs:"A single namespace (default all)" docs-cli:"namespace" json:"namespace,omitempty" yaml:"namespace,omitempty"` + Namespaces []string `docs:"Multiple namespaces (joined with namespace, if both are set)" json:"namespaces,omitempty" yaml:"namespaces,omitempty"` + IncludeClusterResources bool `docs:"Export cluster-scoped resources too, when a namespace filter is active" docs-cli:"include-cluster-resources" json:"includeClusterResources" yaml:"includeClusterResources"` + Worker int `docs:"The number of parallel worker" docs-cli:"worker" json:"worker" yaml:"worker"` + Archive bool `docs:"Create a tar.gz archive" docs-cli:"archive" json:"archive" yaml:"archive"` + ArchiveRetentionDays int `docs:"Number of days to keep old archives" json:"archiveRetentionDays" yaml:"archiveRetentionDays"` + ArchiveTarget string `docs:"The target directory for the archive(default \"exports\")" json:"archiveTarget" yaml:"archiveTarget"` + S3Config *S3Config `docs:"S3 Configuration to upload the archive to an S3 compatible storage" json:"s3" yaml:"s3"` + GCSConfig *GCSConfig `docs:"Google storage bucket configuration" json:"gcs" yaml:"gcs"` + Quiet bool `docs:"Output is prevented" docs-cli:"quiet" json:"quiet" yaml:"quiet"` + Verbose bool `docs:"Errors during export are listed in summary" docs-cli:"verbose" json:"verbose" yaml:"verbose"` + PrintSize bool `docs:"Print the size of the exported files" docs-cli:"size" json:"printSize" yaml:"printSize"` excludedSet set includedSet set @@ -229,11 +229,11 @@ type Progress string // Excluded exclusion params. type Excluded struct { - Kinds []string `docs:"List all kinds to be excluded" json:"kinds" yaml:"kinds"` - Fields [][]string `docs:"List fields that should be removed for all resources before exported; slices are also traversed" json:"fields" yaml:"fields"` - KindFields KindFields `docs:"Kind specific excluded fields" json:"kindFields" yaml:"kindFields"` - KindsByField map[string][]FieldValue `docs:"Allows to exclude single instances with certain field values" json:"kindByField" yaml:"kindByField"` - PreservedFields PreservedFields `docs:"List of fields to be preserved" json:"preservedFields" yaml:"preservedFields"` + Kinds []string `docs:"List all kinds to be excluded" docs-cli:"exclude-kinds" json:"kinds" yaml:"kinds"` + Fields [][]string `docs:"List fields that should be removed for all resources before exported; slices are also traversed" json:"fields" yaml:"fields"` + KindFields KindFields `docs:"Kind specific excluded fields" json:"kindFields" yaml:"kindFields"` + KindsByField map[string][]FieldValue `docs:"Allows to exclude single instances with certain field values" json:"kindByField" yaml:"kindByField"` + PreservedFields PreservedFields `docs:"List of fields to be preserved" json:"preservedFields" yaml:"preservedFields"` } // PreservedFields defines fields that should be preserved when their parent field is excluded. @@ -309,7 +309,7 @@ func diffFields(this, other [][]string) [][]string { // Included inclusion params. type Included struct { - Kinds []string `docs:"List all kinds to be included" json:"kinds" yaml:"kinds"` + Kinds []string `docs:"List all kinds to be included" docs-cli:"include-kinds" json:"kinds" yaml:"kinds"` } // FieldValue field with value.