From bf517bbe4e5988e295b2e76b56d3ee15a160235e Mon Sep 17 00:00:00 2001 From: zhzhuang-zju Date: Mon, 17 Mar 2025 20:23:17 +0800 Subject: [PATCH 01/15] add gen-resourcesdocs to generate API docs Signed-off-by: zhzhuang-zju --- .../cluster-propagation-policy-v1alpha1.md | 6 +- .../propagation-policy-v1alpha1.md | 6 +- infra/gen-resourcesdocs/.gitignore | 5 + infra/gen-resourcesdocs/Makefile | 26 + infra/gen-resourcesdocs/README.md | 48 ++ infra/gen-resourcesdocs/cmd/cli/cli.go | 62 ++ infra/gen-resourcesdocs/cmd/cli/gvkeysmap.go | 44 ++ infra/gen-resourcesdocs/cmd/cli/helpers.go | 41 ++ infra/gen-resourcesdocs/cmd/cli/kwebsite.go | 48 ++ .../cmd/cli/resourceslist.go | 46 ++ infra/gen-resourcesdocs/cmd/cli/showtoc.go | 31 + infra/gen-resourcesdocs/cmd/main.go | 9 + .../config/current/fields.yaml | 3 + .../gen-resourcesdocs/config/current/toc.yaml | 99 +++ infra/gen-resourcesdocs/go.mod | 53 ++ infra/gen-resourcesdocs/go.sum | 567 ++++++++++++++++++ infra/gen-resourcesdocs/hack/reference-api.sh | 49 ++ .../pkg/config/categories.go | 51 ++ infra/gen-resourcesdocs/pkg/config/chapter.go | 146 +++++ infra/gen-resourcesdocs/pkg/config/helpers.go | 8 + infra/gen-resourcesdocs/pkg/config/output.go | 366 +++++++++++ .../pkg/config/output_test.go | 76 +++ infra/gen-resourcesdocs/pkg/config/toc.go | 186 ++++++ .../gen-resourcesdocs/pkg/config/toc_test.go | 48 ++ .../pkg/kubernetes/actions.go | 226 +++++++ .../pkg/kubernetes/apigroup.go | 28 + .../pkg/kubernetes/apigroup_test.go | 25 + .../pkg/kubernetes/apikind.go | 8 + .../pkg/kubernetes/apiversion.go | 128 ++++ .../pkg/kubernetes/apiversion_test.go | 190 ++++++ .../pkg/kubernetes/extensions.go | 147 +++++ .../pkg/kubernetes/extensions_test.go | 39 ++ infra/gen-resourcesdocs/pkg/kubernetes/key.go | 31 + .../pkg/kubernetes/linkend.go | 19 + .../pkg/kubernetes/parameters.go | 94 +++ .../pkg/kubernetes/property.go | 142 +++++ .../pkg/kubernetes/property_test.go | 131 ++++ .../pkg/kubernetes/resource.go | 72 +++ .../pkg/kubernetes/resource_test.go | 235 ++++++++ .../gen-resourcesdocs/pkg/kubernetes/spec.go | 161 +++++ .../pkg/kubernetes/spec_test.go | 29 + .../gen-resourcesdocs/pkg/openapi/openapi.go | 15 + .../pkg/openapi/openapi_test.go | 17 + .../pkg/outputs/interface.go | 36 ++ .../pkg/outputs/kwebsite/chapter.go | 118 ++++ .../pkg/outputs/kwebsite/files.go | 55 ++ .../pkg/outputs/kwebsite/kwebsite.go | 53 ++ .../pkg/outputs/kwebsite/links.go | 26 + .../pkg/outputs/kwebsite/part.go | 41 ++ .../pkg/outputs/kwebsite/section.go | 247 ++++++++ .../templates/chapter-single-definition.tmpl | 78 +++ .../gen-resourcesdocs/templates/chapter.tmpl | 80 +++ .../templates/part-index.tmpl | 9 + .../cluster-propagation-policy-v1alpha1.md | 6 +- .../propagation-policy-v1alpha1.md | 6 +- 55 files changed, 4500 insertions(+), 16 deletions(-) create mode 100644 infra/gen-resourcesdocs/.gitignore create mode 100644 infra/gen-resourcesdocs/Makefile create mode 100644 infra/gen-resourcesdocs/README.md create mode 100644 infra/gen-resourcesdocs/cmd/cli/cli.go create mode 100644 infra/gen-resourcesdocs/cmd/cli/gvkeysmap.go create mode 100644 infra/gen-resourcesdocs/cmd/cli/helpers.go create mode 100644 infra/gen-resourcesdocs/cmd/cli/kwebsite.go create mode 100644 infra/gen-resourcesdocs/cmd/cli/resourceslist.go create mode 100644 infra/gen-resourcesdocs/cmd/cli/showtoc.go create mode 100644 infra/gen-resourcesdocs/cmd/main.go create mode 100644 infra/gen-resourcesdocs/config/current/fields.yaml create mode 100644 infra/gen-resourcesdocs/config/current/toc.yaml create mode 100644 infra/gen-resourcesdocs/go.mod create mode 100644 infra/gen-resourcesdocs/go.sum create mode 100755 infra/gen-resourcesdocs/hack/reference-api.sh create mode 100644 infra/gen-resourcesdocs/pkg/config/categories.go create mode 100644 infra/gen-resourcesdocs/pkg/config/chapter.go create mode 100644 infra/gen-resourcesdocs/pkg/config/helpers.go create mode 100644 infra/gen-resourcesdocs/pkg/config/output.go create mode 100644 infra/gen-resourcesdocs/pkg/config/output_test.go create mode 100644 infra/gen-resourcesdocs/pkg/config/toc.go create mode 100644 infra/gen-resourcesdocs/pkg/config/toc_test.go create mode 100644 infra/gen-resourcesdocs/pkg/kubernetes/actions.go create mode 100644 infra/gen-resourcesdocs/pkg/kubernetes/apigroup.go create mode 100644 infra/gen-resourcesdocs/pkg/kubernetes/apigroup_test.go create mode 100644 infra/gen-resourcesdocs/pkg/kubernetes/apikind.go create mode 100644 infra/gen-resourcesdocs/pkg/kubernetes/apiversion.go create mode 100644 infra/gen-resourcesdocs/pkg/kubernetes/apiversion_test.go create mode 100644 infra/gen-resourcesdocs/pkg/kubernetes/extensions.go create mode 100644 infra/gen-resourcesdocs/pkg/kubernetes/extensions_test.go create mode 100644 infra/gen-resourcesdocs/pkg/kubernetes/key.go create mode 100644 infra/gen-resourcesdocs/pkg/kubernetes/linkend.go create mode 100644 infra/gen-resourcesdocs/pkg/kubernetes/parameters.go create mode 100644 infra/gen-resourcesdocs/pkg/kubernetes/property.go create mode 100644 infra/gen-resourcesdocs/pkg/kubernetes/property_test.go create mode 100644 infra/gen-resourcesdocs/pkg/kubernetes/resource.go create mode 100644 infra/gen-resourcesdocs/pkg/kubernetes/resource_test.go create mode 100644 infra/gen-resourcesdocs/pkg/kubernetes/spec.go create mode 100644 infra/gen-resourcesdocs/pkg/kubernetes/spec_test.go create mode 100644 infra/gen-resourcesdocs/pkg/openapi/openapi.go create mode 100644 infra/gen-resourcesdocs/pkg/openapi/openapi_test.go create mode 100644 infra/gen-resourcesdocs/pkg/outputs/interface.go create mode 100644 infra/gen-resourcesdocs/pkg/outputs/kwebsite/chapter.go create mode 100644 infra/gen-resourcesdocs/pkg/outputs/kwebsite/files.go create mode 100644 infra/gen-resourcesdocs/pkg/outputs/kwebsite/kwebsite.go create mode 100644 infra/gen-resourcesdocs/pkg/outputs/kwebsite/links.go create mode 100644 infra/gen-resourcesdocs/pkg/outputs/kwebsite/part.go create mode 100644 infra/gen-resourcesdocs/pkg/outputs/kwebsite/section.go create mode 100644 infra/gen-resourcesdocs/templates/chapter-single-definition.tmpl create mode 100644 infra/gen-resourcesdocs/templates/chapter.tmpl create mode 100644 infra/gen-resourcesdocs/templates/part-index.tmpl diff --git a/docs/reference/karmada-api/policy-resources/cluster-propagation-policy-v1alpha1.md b/docs/reference/karmada-api/policy-resources/cluster-propagation-policy-v1alpha1.md index a9407b9b..24b5c762 100644 --- a/docs/reference/karmada-api/policy-resources/cluster-propagation-policy-v1alpha1.md +++ b/docs/reference/karmada-api/policy-resources/cluster-propagation-policy-v1alpha1.md @@ -438,11 +438,9 @@ ClusterPropagationPolicy represents the cluster-wide policy that propagates a gr Behavior of PriorityClassName: - For KubePriorityClass: - When specified: Uses the named Kubernetes PriorityClass. - When empty: Uses the cluster's default PriorityClass (i.e., the PriorityClass marked as the global default in the cluster). - If neither exists: Sets priority=0 and preemptionPolicy=Never. + For KubePriorityClass: - When specified: Uses the named Kubernetes PriorityClass. - For PodPriorityClass: - Uses PriorityClassName from the PodTemplate. - If the specified PriorityClass is not found, falls back to the cluster's default PriorityClass - (i.e., the PriorityClass marked as the global default in the cluster). - - If no valid PriorityClass is found: Sets priority=0 and preemptionPolicy=Never. - Not yet implemented. + For PodPriorityClass: - Uses PriorityClassName from the PodTemplate. - Not yet implemented. For FederatedPriorityClass: - Not yet implemented. diff --git a/docs/reference/karmada-api/policy-resources/propagation-policy-v1alpha1.md b/docs/reference/karmada-api/policy-resources/propagation-policy-v1alpha1.md index ec178c11..410fb152 100644 --- a/docs/reference/karmada-api/policy-resources/propagation-policy-v1alpha1.md +++ b/docs/reference/karmada-api/policy-resources/propagation-policy-v1alpha1.md @@ -438,11 +438,9 @@ PropagationPolicy represents the policy that propagates a group of resources to Behavior of PriorityClassName: - For KubePriorityClass: - When specified: Uses the named Kubernetes PriorityClass. - When empty: Uses the cluster's default PriorityClass (i.e., the PriorityClass marked as the global default in the cluster). - If neither exists: Sets priority=0 and preemptionPolicy=Never. + For KubePriorityClass: - When specified: Uses the named Kubernetes PriorityClass. - For PodPriorityClass: - Uses PriorityClassName from the PodTemplate. - If the specified PriorityClass is not found, falls back to the cluster's default PriorityClass - (i.e., the PriorityClass marked as the global default in the cluster). - - If no valid PriorityClass is found: Sets priority=0 and preemptionPolicy=Never. - Not yet implemented. + For PodPriorityClass: - Uses PriorityClassName from the PodTemplate. - Not yet implemented. For FederatedPriorityClass: - Not yet implemented. diff --git a/infra/gen-resourcesdocs/.gitignore b/infra/gen-resourcesdocs/.gitignore new file mode 100644 index 00000000..5cbfe326 --- /dev/null +++ b/infra/gen-resourcesdocs/.gitignore @@ -0,0 +1,5 @@ +*.iml +.idea/ +_generated_*.md +api/ +kwebsite/ diff --git a/infra/gen-resourcesdocs/Makefile b/infra/gen-resourcesdocs/Makefile new file mode 100644 index 00000000..55c1e3d8 --- /dev/null +++ b/infra/gen-resourcesdocs/Makefile @@ -0,0 +1,26 @@ +VERSION ?= current +SWAGGER_FILE = "api/$(VERSION)/swagger.json" + +all: kwebsite + +clean: + rm -rf kwebsite/content/en/docs/* kwebsite/public + +kwebsite: clean + mkdir -p kwebsite/content/en/docs + + sed -i 's|\\u003c|\<|g' $(SWAGGER_FILE) + sed -i 's|\\u003e|\>|g' $(SWAGGER_FILE) + + sed -i '/```.*```/{s|\<|<|g}' $(SWAGGER_FILE) + sed -i '/```.*```/{s|\>|>|g}' $(SWAGGER_FILE) + + sed -i '/: ".*"/{s|{|[|g}' $(SWAGGER_FILE) + sed -i '/: ".*"/{s|}|]|g}' $(SWAGGER_FILE) + + go run cmd/main.go kwebsite --config-dir config/$(VERSION)/ --file $(SWAGGER_FILE) --output-dir kwebsite/content/en/docs --templates ./templates + + find kwebsite -name "_index.md" -print -exec rm {} \; + + mv kwebsite/content/en/docs/common-parameters kwebsite/content/en/docs/common-parameter + sed -i 's/..\/common-parameters\/common-parameters/..\/common-parameter\/common-parameters/g' `find kwebsite -name "*.md"` diff --git a/infra/gen-resourcesdocs/README.md b/infra/gen-resourcesdocs/README.md new file mode 100644 index 00000000..5e8fa6d2 --- /dev/null +++ b/infra/gen-resourcesdocs/README.md @@ -0,0 +1,48 @@ +# Karmada API resources documentation generator + +This tool extracts information from the OpenAPI specification file of the [Karmada API](https://github.com/karmada-io/karmada/blob/master/api/openapi-spec/swagger.json) and creates documentation in Markdown format, suitable for the [Karmada website](https://karmada.io/docs/category/karmada-api). + +## Outline + +The documentation is split into *parts*. Each part can contain any number of *chapters*. A chapter describes: + +- a main Karmada resource, +- any resources and definitions associated with the main resource, +- any *Operations* operating on the resources documented in the chapter. + +The parts and chapters are defined in the `config/current/toc.yaml` file. + +```yaml +parts: + - name: App Resources + chapters: + - name: WorkloadRebalancer + group: "apps.karmada.io" + version: v1alpha1 + - name: AutoScaling Resources + chapters: + - name: FederatedHPA + group: "autoscaling.karmada.io" + version: v1alpha1 + - name: CronFederatedHPA + group: "autoscaling.karmada.io" + version: v1alpha1 +``` + +In this example, the first part contains ont chapters and the second part two chapter. + +The first chapter describes the main `WorkloadRebalancer` resource (from the `apps.karmada.io` group and the `v1alpha1` version) and its associated resources and definitions. By default, if no `otherDefinitions` are defined, the associated resources are the `List` resource and the `Spec` and `Status` definitions, if appropriate. In this case, `WorkloadRebalancer`, `WorkloadRebalancerList`, `WorkloadRebalancerSpec` and `WorkloadRebalancerStatus` are documented. + +## Definition Documentation + +For each definition (including resources, which are definitions attached to a Group/Version), the fields are listed, with their type and documentation. + +## How to use + +### Script + +1. update the `config/current/toc.yaml` file according to the latest Karmada API resources. +2. generate the Karmada latest API resources documentation by running the following script: +```shell +$ hack/reference-api.sh +``` diff --git a/infra/gen-resourcesdocs/cmd/cli/cli.go b/infra/gen-resourcesdocs/cmd/cli/cli.go new file mode 100644 index 00000000..37479ad3 --- /dev/null +++ b/infra/gen-resourcesdocs/cmd/cli/cli.go @@ -0,0 +1,62 @@ +package cli + +import ( + "fmt" + "os" + "strings" + + "github.com/spf13/cobra" + "github.com/spf13/viper" +) + +const ( + fileOption = "file" + configDirOption = "config-dir" + outputDirOption = "output-dir" + templatesDirOption = "templates" + showDefinitionsOption = "show-definitions" +) + +// RootCmd defines the root cli command +func RootCmd() *cobra.Command { + cmd := &cobra.Command{ + Use: "kubernetes-api-reference", + Short: "K8s API documentation tools", + Long: `Tool to build documentation from OpenAPI specification of the Kubernetes API`, + SilenceErrors: true, + SilenceUsage: true, + PreRun: func(cmd *cobra.Command, args []string) { + viper.BindPFlags(cmd.Flags()) + }, + RunE: func(cmd *cobra.Command, args []string) error { + return nil + }, + } + + cmd.PersistentFlags().StringP(fileOption, "f", "", "OpenAPI spec file") + cmd.MarkFlagRequired(fileOption) + + subcommands := []func() *cobra.Command{ + ResourceslistCmd, ShowTOCCmd, GVKeysMap, KWebsite, + } + for _, subcommand := range subcommands { + cmd.AddCommand(subcommand()) + } + + cobra.OnInitialize(initConfig) + + viper.SetEnvKeyReplacer(strings.NewReplacer("-", "_")) + return cmd +} + +// Run the cli +func Run() { + if err := RootCmd().Execute(); err != nil { + fmt.Println(err) + os.Exit(1) + } +} + +func initConfig() { + viper.AutomaticEnv() +} diff --git a/infra/gen-resourcesdocs/cmd/cli/gvkeysmap.go b/infra/gen-resourcesdocs/cmd/cli/gvkeysmap.go new file mode 100644 index 00000000..51d0edc4 --- /dev/null +++ b/infra/gen-resourcesdocs/cmd/cli/gvkeysmap.go @@ -0,0 +1,44 @@ +package cli + +import ( + "fmt" + "sort" + + "github.com/spf13/cobra" + + "github.com/karmada-io/website/infra/gen-resourcesdocs/pkg/kubernetes" +) + +// GVKeysMap defines the `gvkeysmap` subcommand +func GVKeysMap() *cobra.Command { + cmd := &cobra.Command{ + Use: "gvkeysmap", + Short: "show the map between group/version and definition keys", + Long: "show the map between group/version and definition keys", + SilenceErrors: true, + SilenceUsage: true, + RunE: func(cmd *cobra.Command, args []string) error { + file := cmd.Flag(fileOption).Value.String() + spec, err := kubernetes.NewSpec(file) + if err != nil { + return err + } + gvs := make([]string, len(spec.GVToKey)) + i := 0 + for gv := range spec.GVToKey { + gvs[i] = gv + i++ + } + sort.Strings(gvs) + for _, gv := range gvs { + keys := spec.GVToKey[gv] + fmt.Printf("%s\n", gv) + for _, key := range keys { + fmt.Printf("\t%s\n", key) + } + } + return nil + }, + } + return cmd +} diff --git a/infra/gen-resourcesdocs/cmd/cli/helpers.go b/infra/gen-resourcesdocs/cmd/cli/helpers.go new file mode 100644 index 00000000..4f821741 --- /dev/null +++ b/infra/gen-resourcesdocs/cmd/cli/helpers.go @@ -0,0 +1,41 @@ +package cli + +import ( + "path" + + "github.com/spf13/cobra" + + "github.com/karmada-io/website/infra/gen-resourcesdocs/pkg/config" + "github.com/karmada-io/website/infra/gen-resourcesdocs/pkg/kubernetes" +) + +// prepareTOC loads Spec and Toc config, and completes TOC +// by adding associates resources and not specified resources in TOC +func prepareTOC(cmd *cobra.Command) (*config.TOC, error) { + file := cmd.Flag(fileOption).Value.String() + spec, err := kubernetes.NewSpec(file) + if err != nil { + return nil, err + } + + configDir := cmd.Flag(configDirOption).Value.String() + toc, err := config.LoadTOC(path.Join(configDir, "toc.yaml")) + err = toc.PopulateAssociates(spec) + if err != nil { + return nil, err + } + + toc.AddOtherResources(spec) + toc.Definitions = &spec.Swagger.Definitions + toc.Actions = spec.Actions + toc.Actions.Sort() + + // TODO browse directory + categories, err := config.LoadCategories([]string{path.Join(configDir, "fields.yaml")}) + if err != nil { + return nil, err + } + toc.Categories = categories + + return toc, nil +} diff --git a/infra/gen-resourcesdocs/cmd/cli/kwebsite.go b/infra/gen-resourcesdocs/cmd/cli/kwebsite.go new file mode 100644 index 00000000..9b460866 --- /dev/null +++ b/infra/gen-resourcesdocs/cmd/cli/kwebsite.go @@ -0,0 +1,48 @@ +package cli + +import ( + "fmt" + + "github.com/spf13/cobra" +) + +// Hugo defines the `kwebsite` subcommand +func KWebsite() *cobra.Command { + cmd := &cobra.Command{ + Use: "kwebsite", + Short: "output specification for k/website", + Long: "output the specification in a format usable for the Kubernetes website", + SilenceErrors: true, + SilenceUsage: true, + RunE: func(cmd *cobra.Command, args []string) error { + toc, err := prepareTOC(cmd) + if err != nil { + return fmt.Errorf("Unable to load specs and/or toc config: %v", err) + } + + outputDir := cmd.Flag(outputDirOption).Value.String() + templatesDir := cmd.Flag(templatesDirOption).Value.String() + err = toc.ToKWebsite(outputDir, templatesDir) + if err != nil { + return err + } + + show, err := cmd.Flags().GetBool(showDefinitionsOption) + if err != nil { + return err + } + if show { + toc.OutputDocumentedDefinitions() + } + return nil + }, + } + cmd.Flags().StringP(configDirOption, "c", "", "Directory containing documentation configuration") + cmd.MarkFlagRequired(configDirOption) + cmd.Flags().StringP(outputDirOption, "o", "", "Directory to write markdown files") + cmd.MarkFlagRequired(outputDirOption) + cmd.Flags().StringP(templatesDirOption, "t", "", "Directory containing go templates for output") + cmd.MarkFlagRequired(templatesDirOption) + cmd.Flags().Bool(showDefinitionsOption, false, "Show where definitions are defined on output") + return cmd +} diff --git a/infra/gen-resourcesdocs/cmd/cli/resourceslist.go b/infra/gen-resourcesdocs/cmd/cli/resourceslist.go new file mode 100644 index 00000000..a3ef41fd --- /dev/null +++ b/infra/gen-resourcesdocs/cmd/cli/resourceslist.go @@ -0,0 +1,46 @@ +package cli + +import ( + "fmt" + "sort" + + "github.com/spf13/cobra" + + "github.com/karmada-io/website/infra/gen-resourcesdocs/pkg/kubernetes" +) + +// ResourceslistCmd defines the `resourceslist` subcommand +func ResourceslistCmd() *cobra.Command { + cmd := &cobra.Command{ + Use: "resourceslist", + Short: "list k8s resources", + Long: "list Kubernetes resources in the specification", + SilenceErrors: true, + SilenceUsage: true, + RunE: func(cmd *cobra.Command, args []string) error { + file := cmd.Flag(fileOption).Value.String() + spec, err := kubernetes.NewSpec(file) + if err != nil { + return err + } + + resources := spec.Resources + i := 0 + keys := make([]string, len(*resources)) + for k := range *resources { + keys[i] = k.String() + i++ + } + sort.Strings(keys) + for _, k := range keys { + rs := (*resources)[kubernetes.APIKind(k)] + fmt.Println(k) + for _, r := range rs { + fmt.Println("\t" + r.GetGV()) + } + } + return nil + }, + } + return cmd +} diff --git a/infra/gen-resourcesdocs/cmd/cli/showtoc.go b/infra/gen-resourcesdocs/cmd/cli/showtoc.go new file mode 100644 index 00000000..8656a81a --- /dev/null +++ b/infra/gen-resourcesdocs/cmd/cli/showtoc.go @@ -0,0 +1,31 @@ +package cli + +import ( + "fmt" + "os" + + "github.com/spf13/cobra" +) + +// ShowTOCCmd defines the `showtoc` subcommand +func ShowTOCCmd() *cobra.Command { + cmd := &cobra.Command{ + Use: "showtoc", + Short: "show the table of contents", + Long: "list the parts and chapter of the documentation", + SilenceErrors: true, + SilenceUsage: true, + RunE: func(cmd *cobra.Command, args []string) error { + toc, err := prepareTOC(cmd) + if err != nil { + return fmt.Errorf("Unable to load specs and/or toc config: %v", err) + } + toc.ToMarkdown(os.Stdout) + return nil + }, + } + cmd.Flags().StringP(configDirOption, "c", "", "Directory containing documentation configuration") + cmd.MarkFlagRequired(configDirOption) + + return cmd +} diff --git a/infra/gen-resourcesdocs/cmd/main.go b/infra/gen-resourcesdocs/cmd/main.go new file mode 100644 index 00000000..9cb5f1d8 --- /dev/null +++ b/infra/gen-resourcesdocs/cmd/main.go @@ -0,0 +1,9 @@ +package main + +import ( + "github.com/karmada-io/website/infra/gen-resourcesdocs/cmd/cli" +) + +func main() { + cli.Run() +} diff --git a/infra/gen-resourcesdocs/config/current/fields.yaml b/infra/gen-resourcesdocs/config/current/fields.yaml new file mode 100644 index 00000000..52b0e8e2 --- /dev/null +++ b/infra/gen-resourcesdocs/config/current/fields.yaml @@ -0,0 +1,3 @@ +# used to order the fields, by default, the fields of a Definition are rendered in alphabetic order. +# do not remove this file, otherwise the resource docs generation will fail. +# for details see https://github.com/kubernetes-sigs/reference-docs/tree/master/gen-resourcesdocs#ordering-and-categorization-of-fields diff --git a/infra/gen-resourcesdocs/config/current/toc.yaml b/infra/gen-resourcesdocs/config/current/toc.yaml new file mode 100644 index 00000000..77f8aa4f --- /dev/null +++ b/infra/gen-resourcesdocs/config/current/toc.yaml @@ -0,0 +1,99 @@ +parts: + - name: App Resources + chapters: + - name: WorkloadRebalancer + group: "apps.karmada.io" + version: v1alpha1 + - name: AutoScaling Resources + chapters: + - name: FederatedHPA + group: "autoscaling.karmada.io" + version: v1alpha1 + - name: CronFederatedHPA + group: "autoscaling.karmada.io" + version: v1alpha1 + - name: Cluster Resources + chapters: + - name: Cluster + group: "cluster.karmada.io" + version: v1alpha1 + - name: Config Resources + chapters: + - name: ResourceInterpreterCustomization + group: "config.karmada.io" + version: v1alpha1 + - name: ResourceInterpreterWebhookConfiguration + group: "config.karmada.io" + version: v1alpha1 + - name: Networking Resources + chapters: + - name: MultiClusterIngress + group: "networking.karmada.io" + version: v1alpha1 + - name: MultiClusterService + group: "networking.karmada.io" + version: v1alpha1 + - name: Policy Resources + chapters: + - name: FederatedResourceQuota + group: "policy.karmada.io" + version: v1alpha1 + - name: OverridePolicy + group: "policy.karmada.io" + version: v1alpha1 + - name: ClusterOverridePolicy + group: "policy.karmada.io" + version: v1alpha1 + - name: PropagationPolicy + group: "policy.karmada.io" + version: v1alpha1 + - name: ClusterPropagationPolicy + group: "policy.karmada.io" + version: v1alpha1 + - name: Remedy Resources + chapters: + - name: Remedy + group: "remedy.karmada.io" + version: v1alpha1 + - name: Search Resources + chapters: + - name: ResourceRegistry + group: "search.karmada.io" + version: v1alpha1 + - name: Work Resources + chapters: + - name: Work + group: "work.karmada.io" + version: v1alpha1 + - name: ResourceBinding + group: "work.karmada.io" + version: v1alpha2 + - name: ClusterResourceBinding + group: "work.karmada.io" + version: v1alpha2 + - name: Common Definitions + chapters: + - name: DeleteOptions + key: io.k8s.apimachinery.pkg.apis.meta.v1.DeleteOptions + - name: LabelSelector + key: io.k8s.apimachinery.pkg.apis.meta.v1.LabelSelector + - name: ListMeta + key: io.k8s.apimachinery.pkg.apis.meta.v1.ListMeta + - name: NodeSelectorRequirement + key: io.k8s.api.core.v1.NodeSelectorRequirement + - name: ObjectMeta + key: io.k8s.apimachinery.pkg.apis.meta.v1.ObjectMeta + - name: Patch + key: io.k8s.apimachinery.pkg.apis.meta.v1.Patch + - name: Quantity + key: io.k8s.apimachinery.pkg.api.resource.Quantity + - name: Status + key: io.k8s.apimachinery.pkg.apis.meta.v1.Status + - name: TypedLocalObjectReference + key: io.k8s.api.core.v1.TypedLocalObjectReference +skippedResources: + - APIGroup + - APIGroupList + - APIResourceList + - APIVersions + - Status diff --git a/infra/gen-resourcesdocs/go.mod b/infra/gen-resourcesdocs/go.mod new file mode 100644 index 00000000..cf1d7d7b --- /dev/null +++ b/infra/gen-resourcesdocs/go.mod @@ -0,0 +1,53 @@ +module github.com/karmada-io/website/infra/gen-resourcesdocs + +go 1.22.12 + +require ( + github.com/Masterminds/sprig v2.22.0+incompatible + github.com/go-openapi/jsonreference v0.19.5 + github.com/go-openapi/loads v0.20.0 + github.com/go-openapi/spec v0.20.0 + github.com/spf13/cobra v1.1.1 + github.com/spf13/viper v1.7.1 + github.com/stoewer/go-strcase v1.2.0 + gopkg.in/yaml.v2 v2.4.0 +) + +require ( + github.com/Masterminds/goutils v1.1.0 // indirect + github.com/Masterminds/semver v1.5.0 // indirect + github.com/PuerkitoBio/purell v1.1.1 // indirect + github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 // indirect + github.com/asaskevich/govalidator v0.0.0-20200907205600-7a23bdc65eef // indirect + github.com/fsnotify/fsnotify v1.4.9 // indirect + github.com/go-openapi/analysis v0.19.16 // indirect + github.com/go-openapi/errors v0.19.9 // indirect + github.com/go-openapi/jsonpointer v0.19.5 // indirect + github.com/go-openapi/strfmt v0.19.11 // indirect + github.com/go-openapi/swag v0.19.12 // indirect + github.com/go-stack/stack v1.8.0 // indirect + github.com/google/uuid v1.1.1 // indirect + github.com/hashicorp/hcl v1.0.0 // indirect + github.com/huandu/xstrings v1.3.2 // indirect + github.com/imdario/mergo v0.3.9 // indirect + github.com/inconshreveable/mousetrap v1.0.0 // indirect + github.com/josharian/intern v1.0.0 // indirect + github.com/magiconair/properties v1.8.1 // indirect + github.com/mailru/easyjson v0.7.6 // indirect + github.com/mitchellh/copystructure v1.0.0 // indirect + github.com/mitchellh/mapstructure v1.4.0 // indirect + github.com/mitchellh/reflectwalk v1.0.0 // indirect + github.com/pelletier/go-toml v1.8.0 // indirect + github.com/smartystreets/assertions v1.0.0 // indirect + github.com/spf13/afero v1.2.2 // indirect + github.com/spf13/cast v1.3.1 // indirect + github.com/spf13/jwalterweatherman v1.1.0 // indirect + github.com/spf13/pflag v1.0.5 // indirect + github.com/subosito/gotenv v1.2.0 // indirect + go.mongodb.org/mongo-driver v1.4.4 // indirect + golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a // indirect + golang.org/x/net v0.0.0-20201202161906-c7110b5ffcbb // indirect + golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f // indirect + golang.org/x/text v0.3.4 // indirect + gopkg.in/ini.v1 v1.56.0 // indirect +) diff --git a/infra/gen-resourcesdocs/go.sum b/infra/gen-resourcesdocs/go.sum new file mode 100644 index 00000000..8bd380a5 --- /dev/null +++ b/infra/gen-resourcesdocs/go.sum @@ -0,0 +1,567 @@ +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= +cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= +cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= +cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= +cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= +cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= +cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= +cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= +cloud.google.com/go/firestore v1.1.0/go.mod h1:ulACoGHTpvq5r8rxGJ4ddJZBZqakUQqClKRT5SZwBmk= +cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= +cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= +dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= +github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= +github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= +github.com/Masterminds/goutils v1.1.0 h1:zukEsf/1JZwCMgHiK3GZftabmxiCw4apj3a28RPBiVg= +github.com/Masterminds/goutils v1.1.0/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU= +github.com/Masterminds/semver v1.5.0 h1:H65muMkzWKEuNDnfl9d70GUjFniHKHRbFPGBuZ3QEww= +github.com/Masterminds/semver v1.5.0/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF078ddwwvV3Y= +github.com/Masterminds/sprig v2.22.0+incompatible h1:z4yfnGrZ7netVz+0EDJ0Wi+5VZCSYp4Z0m2dk6cEM60= +github.com/Masterminds/sprig v2.22.0+incompatible/go.mod h1:y6hNFY5UBTIWBxnzTeuNhlNS5hqE0NB0E6fgfo2Br3o= +github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= +github.com/PuerkitoBio/purell v1.1.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= +github.com/PuerkitoBio/purell v1.1.1 h1:WEQqlqaGbrPkxLJWfBwQmfEAE1Z7ONdDLqrN38tNFfI= +github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= +github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 h1:d+Bc7a5rLufV/sSk/8dngufqelfh6jnri85riMAaF/M= +github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= +github.com/agnivade/levenshtein v1.0.1/go.mod h1:CURSv5d9Uaml+FovSIICkLbAUZ9S4RqaHDIsdSBg7lM= +github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo29Kk6CurOXKm700vrz8f0KW0JNfpkRJY/8= +github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= +github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= +github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/asaskevich/govalidator v0.0.0-20180720115003-f9ffefc3facf/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY= +github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY= +github.com/asaskevich/govalidator v0.0.0-20200108200545-475eaeb16496/go.mod h1:oGkLhpf+kjZl6xBf758TQhh5XrAeiJv/7FRz/2spLIg= +github.com/asaskevich/govalidator v0.0.0-20200428143746-21a406dcc535/go.mod h1:oGkLhpf+kjZl6xBf758TQhh5XrAeiJv/7FRz/2spLIg= +github.com/asaskevich/govalidator v0.0.0-20200907205600-7a23bdc65eef h1:46PFijGLmAjMPwCCCo7Jf0W6f9slllCkkv7vyc1yOSg= +github.com/asaskevich/govalidator v0.0.0-20200907205600-7a23bdc65eef/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw= +github.com/aws/aws-sdk-go v1.34.28/go.mod h1:H7NKnBqNVzoTJpGfLrQkkD+ytBA93eiDYi/+8rV9s48= +github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= +github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= +github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= +github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJmJgSg28kpZDP6UIiPt0e0Oz0kqKNGyRaWEPv84= +github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= +github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= +github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= +github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= +github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= +github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= +github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= +github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= +github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= +github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= +github.com/docker/go-units v0.3.3/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= +github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= +github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= +github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= +github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4= +github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= +github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +github.com/globalsign/mgo v0.0.0-20180905125535-1ca0a4f7cbcb/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q= +github.com/globalsign/mgo v0.0.0-20181015135952-eeefdecb41b8/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q= +github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= +github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= +github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= +github.com/go-openapi/analysis v0.0.0-20180825180245-b006789cd277/go.mod h1:k70tL6pCuVxPJOHXQ+wIac1FUrvNkHolPie/cLEU6hI= +github.com/go-openapi/analysis v0.17.0/go.mod h1:IowGgpVeD0vNm45So8nr+IcQ3pxVtpRoBWb8PVZO0ik= +github.com/go-openapi/analysis v0.18.0/go.mod h1:IowGgpVeD0vNm45So8nr+IcQ3pxVtpRoBWb8PVZO0ik= +github.com/go-openapi/analysis v0.19.2/go.mod h1:3P1osvZa9jKjb8ed2TPng3f0i/UY9snX6gxi44djMjk= +github.com/go-openapi/analysis v0.19.4/go.mod h1:3P1osvZa9jKjb8ed2TPng3f0i/UY9snX6gxi44djMjk= +github.com/go-openapi/analysis v0.19.5/go.mod h1:hkEAkxagaIvIP7VTn8ygJNkd4kAYON2rCu0v0ObL0AU= +github.com/go-openapi/analysis v0.19.10/go.mod h1:qmhS3VNFxBlquFJ0RGoDtylO9y4pgTAUNE9AEEMdlJQ= +github.com/go-openapi/analysis v0.19.16 h1:Ub9e++M8sDwtHD+S587TYi+6ANBG1NRYGZDihqk0SaY= +github.com/go-openapi/analysis v0.19.16/go.mod h1:GLInF007N83Ad3m8a/CbQ5TPzdnGT7workfHwuVjNVk= +github.com/go-openapi/errors v0.17.0/go.mod h1:LcZQpmvG4wyF5j4IhA73wkLFQg+QJXOQHVjmcZxhka0= +github.com/go-openapi/errors v0.18.0/go.mod h1:LcZQpmvG4wyF5j4IhA73wkLFQg+QJXOQHVjmcZxhka0= +github.com/go-openapi/errors v0.19.2/go.mod h1:qX0BLWsyaKfvhluLejVpVNwNRdXZhEbTA4kxxpKBC94= +github.com/go-openapi/errors v0.19.3/go.mod h1:qX0BLWsyaKfvhluLejVpVNwNRdXZhEbTA4kxxpKBC94= +github.com/go-openapi/errors v0.19.6/go.mod h1:cM//ZKUKyO06HSwqAelJ5NsEMMcpa6VpXe8DOa1Mi1M= +github.com/go-openapi/errors v0.19.7/go.mod h1:cM//ZKUKyO06HSwqAelJ5NsEMMcpa6VpXe8DOa1Mi1M= +github.com/go-openapi/errors v0.19.8/go.mod h1:cM//ZKUKyO06HSwqAelJ5NsEMMcpa6VpXe8DOa1Mi1M= +github.com/go-openapi/errors v0.19.9 h1:9SnKdGhiPZHF3ttwFMiCBEb8jQ4IDdrK+5+a0oTygA4= +github.com/go-openapi/errors v0.19.9/go.mod h1:cM//ZKUKyO06HSwqAelJ5NsEMMcpa6VpXe8DOa1Mi1M= +github.com/go-openapi/jsonpointer v0.17.0/go.mod h1:cOnomiV+CVVwFLk0A/MExoFMjwdsUdVpsRhURCKh+3M= +github.com/go-openapi/jsonpointer v0.18.0/go.mod h1:cOnomiV+CVVwFLk0A/MExoFMjwdsUdVpsRhURCKh+3M= +github.com/go-openapi/jsonpointer v0.19.2/go.mod h1:3akKfEdA7DF1sugOqz1dVQHBcuDBPKZGEoHC/NkiQRg= +github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= +github.com/go-openapi/jsonpointer v0.19.5 h1:gZr+CIYByUqjcgeLXnQu2gHYQC9o73G2XUeOFYEICuY= +github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= +github.com/go-openapi/jsonreference v0.17.0/go.mod h1:g4xxGn04lDIRh0GJb5QlpE3HfopLOL6uZrK/VgnsK9I= +github.com/go-openapi/jsonreference v0.18.0/go.mod h1:g4xxGn04lDIRh0GJb5QlpE3HfopLOL6uZrK/VgnsK9I= +github.com/go-openapi/jsonreference v0.19.2/go.mod h1:jMjeRr2HHw6nAVajTXJ4eiUwohSTlpa0o73RUL1owJc= +github.com/go-openapi/jsonreference v0.19.3/go.mod h1:rjx6GuL8TTa9VaixXglHmQmIL98+wF9xc8zWvFonSJ8= +github.com/go-openapi/jsonreference v0.19.5 h1:1WJP/wi4OjB4iV8KVbH73rQaoialJrqv8gitZLxGLtM= +github.com/go-openapi/jsonreference v0.19.5/go.mod h1:RdybgQwPxbL4UEjuAruzK1x3nE69AqPYEJeo/TWfEeg= +github.com/go-openapi/loads v0.17.0/go.mod h1:72tmFy5wsWx89uEVddd0RjRWPZm92WRLhf7AC+0+OOU= +github.com/go-openapi/loads v0.18.0/go.mod h1:72tmFy5wsWx89uEVddd0RjRWPZm92WRLhf7AC+0+OOU= +github.com/go-openapi/loads v0.19.0/go.mod h1:72tmFy5wsWx89uEVddd0RjRWPZm92WRLhf7AC+0+OOU= +github.com/go-openapi/loads v0.19.2/go.mod h1:QAskZPMX5V0C2gvfkGZzJlINuP7Hx/4+ix5jWFxsNPs= +github.com/go-openapi/loads v0.19.3/go.mod h1:YVfqhUCdahYwR3f3iiwQLhicVRvLlU/WO5WPaZvcvSI= +github.com/go-openapi/loads v0.19.5/go.mod h1:dswLCAdonkRufe/gSUC3gN8nTSaB9uaS2es0x5/IbjY= +github.com/go-openapi/loads v0.19.6/go.mod h1:brCsvE6j8mnbmGBh103PT/QLHfbyDxA4hsKvYBNEGVc= +github.com/go-openapi/loads v0.19.7/go.mod h1:brCsvE6j8mnbmGBh103PT/QLHfbyDxA4hsKvYBNEGVc= +github.com/go-openapi/loads v0.20.0 h1:Pymw1O8zDmWeNv4kVsHd0W3cvgdp8juRa4U/U/8D/Pk= +github.com/go-openapi/loads v0.20.0/go.mod h1:2LhKquiE513rN5xC6Aan6lYOSddlL8Mp20AW9kpviM4= +github.com/go-openapi/runtime v0.0.0-20180920151709-4f900dc2ade9/go.mod h1:6v9a6LTXWQCdL8k1AO3cvqx5OtZY/Y9wKTgaoP6YRfA= +github.com/go-openapi/runtime v0.19.0/go.mod h1:OwNfisksmmaZse4+gpV3Ne9AyMOlP1lt4sK4FXt0O64= +github.com/go-openapi/runtime v0.19.4/go.mod h1:X277bwSUBxVlCYR3r7xgZZGKVvBd/29gLDlFGtJ8NL4= +github.com/go-openapi/runtime v0.19.15/go.mod h1:dhGWCTKRXlAfGnQG0ONViOZpjfg0m2gUt9nTQPQZuoo= +github.com/go-openapi/runtime v0.19.16/go.mod h1:5P9104EJgYcizotuXhEuUrzVc+j1RiSjahULvYmlv98= +github.com/go-openapi/runtime v0.19.24 h1:TqagMVlRAOTwllE/7hNKx6rQ10O6T8ZzeJdMjSTKaD4= +github.com/go-openapi/runtime v0.19.24/go.mod h1:Lm9YGCeecBnUUkFTxPC4s1+lwrkJ0pthx8YvyjCfkgk= +github.com/go-openapi/spec v0.17.0/go.mod h1:XkF/MOi14NmjsfZ8VtAKf8pIlbZzyoTvZsdfssdxcBI= +github.com/go-openapi/spec v0.18.0/go.mod h1:XkF/MOi14NmjsfZ8VtAKf8pIlbZzyoTvZsdfssdxcBI= +github.com/go-openapi/spec v0.19.2/go.mod h1:sCxk3jxKgioEJikev4fgkNmwS+3kuYdJtcsZsD5zxMY= +github.com/go-openapi/spec v0.19.3/go.mod h1:FpwSN1ksY1eteniUU7X0N/BgJ7a4WvBFVA8Lj9mJglo= +github.com/go-openapi/spec v0.19.6/go.mod h1:Hm2Jr4jv8G1ciIAo+frC/Ft+rR2kQDh8JHKHb3gWUSk= +github.com/go-openapi/spec v0.19.8/go.mod h1:Hm2Jr4jv8G1ciIAo+frC/Ft+rR2kQDh8JHKHb3gWUSk= +github.com/go-openapi/spec v0.19.15/go.mod h1:+81FIL1JwC5P3/Iuuozq3pPE9dXdIEGxFutcFKaVbmU= +github.com/go-openapi/spec v0.20.0 h1:HGLc8AJ7ynOxwv0Lq4TsnwLsWMawHAYiJIFzbcML86I= +github.com/go-openapi/spec v0.20.0/go.mod h1:+81FIL1JwC5P3/Iuuozq3pPE9dXdIEGxFutcFKaVbmU= +github.com/go-openapi/strfmt v0.17.0/go.mod h1:P82hnJI0CXkErkXi8IKjPbNBM6lV6+5pLP5l494TcyU= +github.com/go-openapi/strfmt v0.18.0/go.mod h1:P82hnJI0CXkErkXi8IKjPbNBM6lV6+5pLP5l494TcyU= +github.com/go-openapi/strfmt v0.19.0/go.mod h1:+uW+93UVvGGq2qGaZxdDeJqSAqBqBdl+ZPMF/cC8nDY= +github.com/go-openapi/strfmt v0.19.2/go.mod h1:0yX7dbo8mKIvc3XSKp7MNfxw4JytCfCD6+bY1AVL9LU= +github.com/go-openapi/strfmt v0.19.3/go.mod h1:0yX7dbo8mKIvc3XSKp7MNfxw4JytCfCD6+bY1AVL9LU= +github.com/go-openapi/strfmt v0.19.4/go.mod h1:eftuHTlB/dI8Uq8JJOyRlieZf+WkkxUuk0dgdHXr2Qk= +github.com/go-openapi/strfmt v0.19.5/go.mod h1:eftuHTlB/dI8Uq8JJOyRlieZf+WkkxUuk0dgdHXr2Qk= +github.com/go-openapi/strfmt v0.19.11 h1:0+YvbNh05rmBkgztd6zHp4OCFn7Mtu30bn46NQo2ZRw= +github.com/go-openapi/strfmt v0.19.11/go.mod h1:UukAYgTaQfqJuAFlNxxMWNvMYiwiXtLsF2VwmoFtbtc= +github.com/go-openapi/swag v0.17.0/go.mod h1:AByQ+nYG6gQg71GINrmuDXCPWdL640yX49/kXLo40Tg= +github.com/go-openapi/swag v0.18.0/go.mod h1:AByQ+nYG6gQg71GINrmuDXCPWdL640yX49/kXLo40Tg= +github.com/go-openapi/swag v0.19.2/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= +github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= +github.com/go-openapi/swag v0.19.7/go.mod h1:ao+8BpOPyKdpQz3AOJfbeEVpLmWAvlT1IfTe5McPyhY= +github.com/go-openapi/swag v0.19.9/go.mod h1:ao+8BpOPyKdpQz3AOJfbeEVpLmWAvlT1IfTe5McPyhY= +github.com/go-openapi/swag v0.19.12 h1:Bc0bnY2c3AoF7Gc+IMIAQQsD8fLHjHpc19wXvYuayQI= +github.com/go-openapi/swag v0.19.12/go.mod h1:eFdyEBkTdoAf/9RXBvj4cr1nH7GD8Kzo5HTt47gr72M= +github.com/go-openapi/validate v0.18.0/go.mod h1:Uh4HdOzKt19xGIGm1qHf/ofbX1YQ4Y+MYsct2VUrAJ4= +github.com/go-openapi/validate v0.19.2/go.mod h1:1tRCw7m3jtI8eNWEEliiAqUIcBztB2KDnRCRMUi7GTA= +github.com/go-openapi/validate v0.19.3/go.mod h1:90Vh6jjkTn+OT1Eefm0ZixWNFjhtOH7vS9k0lo6zwJo= +github.com/go-openapi/validate v0.19.10/go.mod h1:RKEZTUWDkxKQxN2jDT7ZnZi2bhZlbNMAuKvKB+IaGx8= +github.com/go-openapi/validate v0.19.12/go.mod h1:Rzou8hA/CBw8donlS6WNEUQupNvUZ0waH08tGe6kAQ4= +github.com/go-openapi/validate v0.19.15 h1:oUHZO8jD7p5oRLANlXF0U8ic9ePBUkDQyRZdN0EhL6M= +github.com/go-openapi/validate v0.19.15/go.mod h1:tbn/fdOwYHgrhPBzidZfJC2MIVvs9GA7monOmWBbeCI= +github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= +github.com/go-stack/stack v1.8.0 h1:5SgMzNM5HxrEjV0ww2lTmX6E2Izsfxas4+YHWRs3Lsk= +github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/gobuffalo/attrs v0.0.0-20190224210810-a9411de4debd/go.mod h1:4duuawTqi2wkkpB4ePgWMaai6/Kc6WEz83bhFwpHzj0= +github.com/gobuffalo/depgen v0.0.0-20190329151759-d478694a28d3/go.mod h1:3STtPUQYuzV0gBVOY3vy6CfMm/ljR4pABfrTeHNLHUY= +github.com/gobuffalo/depgen v0.1.0/go.mod h1:+ifsuy7fhi15RWncXQQKjWS9JPkdah5sZvtHc2RXGlg= +github.com/gobuffalo/envy v1.6.15/go.mod h1:n7DRkBerg/aorDM8kbduw5dN3oXGswK5liaSCx4T5NI= +github.com/gobuffalo/envy v1.7.0/go.mod h1:n7DRkBerg/aorDM8kbduw5dN3oXGswK5liaSCx4T5NI= +github.com/gobuffalo/flect v0.1.0/go.mod h1:d2ehjJqGOH/Kjqcoz+F7jHTBbmDb38yXA598Hb50EGs= +github.com/gobuffalo/flect v0.1.1/go.mod h1:8JCgGVbRjJhVgD6399mQr4fx5rRfGKVzFjbj6RE/9UI= +github.com/gobuffalo/flect v0.1.3/go.mod h1:8JCgGVbRjJhVgD6399mQr4fx5rRfGKVzFjbj6RE/9UI= +github.com/gobuffalo/genny v0.0.0-20190329151137-27723ad26ef9/go.mod h1:rWs4Z12d1Zbf19rlsn0nurr75KqhYp52EAGGxTbBhNk= +github.com/gobuffalo/genny v0.0.0-20190403191548-3ca520ef0d9e/go.mod h1:80lIj3kVJWwOrXWWMRzzdhW3DsrdjILVil/SFKBzF28= +github.com/gobuffalo/genny v0.1.0/go.mod h1:XidbUqzak3lHdS//TPu2OgiFB+51Ur5f7CSnXZ/JDvo= +github.com/gobuffalo/genny v0.1.1/go.mod h1:5TExbEyY48pfunL4QSXxlDOmdsD44RRq4mVZ0Ex28Xk= +github.com/gobuffalo/gitgen v0.0.0-20190315122116-cc086187d211/go.mod h1:vEHJk/E9DmhejeLeNt7UVvlSGv3ziL+djtTr3yyzcOw= +github.com/gobuffalo/gogen v0.0.0-20190315121717-8f38393713f5/go.mod h1:V9QVDIxsgKNZs6L2IYiGR8datgMhB577vzTDqypH360= +github.com/gobuffalo/gogen v0.1.0/go.mod h1:8NTelM5qd8RZ15VjQTFkAW6qOMx5wBbW4dSCS3BY8gg= +github.com/gobuffalo/gogen v0.1.1/go.mod h1:y8iBtmHmGc4qa3urIyo1shvOD8JftTtfcKi+71xfDNE= +github.com/gobuffalo/logger v0.0.0-20190315122211-86e12af44bc2/go.mod h1:QdxcLw541hSGtBnhUc4gaNIXRjiDppFGaDqzbrBd3v8= +github.com/gobuffalo/mapi v1.0.1/go.mod h1:4VAGh89y6rVOvm5A8fKFxYG+wIW6LO1FMTG9hnKStFc= +github.com/gobuffalo/mapi v1.0.2/go.mod h1:4VAGh89y6rVOvm5A8fKFxYG+wIW6LO1FMTG9hnKStFc= +github.com/gobuffalo/packd v0.0.0-20190315124812-a385830c7fc0/go.mod h1:M2Juc+hhDXf/PnmBANFCqx4DM3wRbgDvnVWeG2RIxq4= +github.com/gobuffalo/packd v0.1.0/go.mod h1:M2Juc+hhDXf/PnmBANFCqx4DM3wRbgDvnVWeG2RIxq4= +github.com/gobuffalo/packr/v2 v2.0.9/go.mod h1:emmyGweYTm6Kdper+iywB6YK5YzuKchGtJQZ0Odn4pQ= +github.com/gobuffalo/packr/v2 v2.2.0/go.mod h1:CaAwI0GPIAv+5wKLtv8Afwl+Cm78K/I/VCm/3ptBN+0= +github.com/gobuffalo/syncx v0.0.0-20190224160051-33c29581e754/go.mod h1:HhnNqWY95UYwwW3uSASeV7vtgYkT2t16hJgV3AEPUpw= +github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= +github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= +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/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/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.5.2 h1:X2ev0eStA3AbceY54o37/0PQ/UWqKEiiO2dKL5OPaFM= +github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= +github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= +github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY= +github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= +github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= +github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8= +github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= +github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= +github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= +github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= +github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q= +github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8= +github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= +github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= +github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= +github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU= +github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU= +github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4= +github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90= +github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= +github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= +github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64= +github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ= +github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I= +github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc= +github.com/huandu/xstrings v1.3.2 h1:L18LIDzqlW6xN2rEkpdV8+oL/IXWJ1APd+vsdYy4Wdw= +github.com/huandu/xstrings v1.3.2/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= +github.com/imdario/mergo v0.3.9 h1:UauaLniWCFHWd+Jp9oCEkTBj8VO/9DKg3PV3VCNMDIg= +github.com/imdario/mergo v0.3.9/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= +github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM= +github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= +github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= +github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U= +github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg= +github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= +github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= +github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= +github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= +github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo= +github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= +github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/karrick/godirwalk v1.8.0/go.mod h1:H5KPZjojv4lE+QYImBI8xVtrBRgYrIVsaRPx4tDPEn4= +github.com/karrick/godirwalk v1.10.3/go.mod h1:RoGL9dQei4vP9ilrpETWE8CLOZ1kiN0LhBygSwrAsHA= +github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= +github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= +github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/klauspost/compress v1.9.5/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/pty v1.1.5/go.mod h1:9r2w37qlBe7rQ6e1fg1S/9xpWHSnaqNdHD3WcMdbPDA= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/magiconair/properties v1.8.1 h1:ZC2Vc7/ZFkGmsVC9KvOjumD+G5lXy2RtTKyzRKO2BQ4= +github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= +github.com/mailru/easyjson v0.0.0-20180823135443-60711f1a8329/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/mailru/easyjson v0.0.0-20190312143242-1de009706dbe/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +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.1/go.mod h1:KAzv3t3aY1NaHWoQz1+4F1ccyAH66Jk7yos7ldAVICs= +github.com/mailru/easyjson v0.7.6 h1:8yTIVnZgCoiM1TgqoeTl+LfU5Jg6/xL3QhGQnimLYnA= +github.com/mailru/easyjson v0.7.6/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= +github.com/markbates/oncer v0.0.0-20181203154359-bf2de49a0be2/go.mod h1:Ld9puTsIW75CHf65OeIOkyKbteujpZVXDpWK6YGZbxE= +github.com/markbates/safe v1.0.1/go.mod h1:nAqgmRi7cY2nqMc92/bSEeQA+R4OheNU2T1kNSCBdG0= +github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= +github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= +github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= +github.com/mitchellh/copystructure v1.0.0 h1:Laisrj+bAB6b/yJwB5Bt3ITZhGJdqmxquMKeZ+mmkFQ= +github.com/mitchellh/copystructure v1.0.0/go.mod h1:SNtv71yrdKgLRyLFxmLdkAbkKEFWgYaq1OVrnRcwhnw= +github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= +github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg= +github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY= +github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= +github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= +github.com/mitchellh/mapstructure v1.3.2/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/mapstructure v1.3.3/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/mapstructure v1.4.0 h1:7ks8ZkOP5/ujthUsT07rNv+nkLXCQWKNHuwzOAesEks= +github.com/mitchellh/mapstructure v1.4.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/reflectwalk v1.0.0 h1:9D+8oIskB4VJBN5SFlmc27fSlIBZaov1Wpk/IfikLNY= +github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe/go.mod h1:wL8QJuTMNUDYhXwkmfOly8iTdp5TEcJFWZD2D7SIkUc= +github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= +github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= +github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= +github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k= +github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= +github.com/pelletier/go-toml v1.4.0/go.mod h1:PN7xzY2wHTK0K9p34ErDQMlFxa51Fk0OUruD3k1mMwo= +github.com/pelletier/go-toml v1.7.0/go.mod h1:vwGMzjaWMwyfHwgIBhI2YUM4fB6nL6lVAvS1LBMMhTE= +github.com/pelletier/go-toml v1.8.0 h1:Keo9qb7iRJs2voHvunFtuuYFsbWeOBh8/P9v/kVMFtw= +github.com/pelletier/go-toml v1.8.0/go.mod h1:D6yutnOGMveHEPV7VQOuvI/gXY61bv+9bAOTRnLElKs= +github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +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/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso= +github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= +github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= +github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= +github.com/rogpeppe/go-internal v1.1.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/rogpeppe/go-internal v1.2.2/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= +github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= +github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= +github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= +github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/sirupsen/logrus v1.4.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= +github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= +github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= +github.com/smartystreets/assertions v1.0.0 h1:UVQPSSmc3qtTi+zPPkCXvZX9VvW/xT/NsRvKfwY81a8= +github.com/smartystreets/assertions v1.0.0/go.mod h1:kHHU4qYBaI3q23Pp3VPrmWhuIUrLW/7eUrw0BU5VaoM= +github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIKYqbNC9s= +github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= +github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= +github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= +github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= +github.com/spf13/afero v1.2.2 h1:5jhuqJyZCZf2JRofRvN/nIFgIWNzPa3/Vz8mYylgbWc= +github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk= +github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= +github.com/spf13/cast v1.3.1 h1:nFm6S0SMdyzrzcmThSipiEubIDy8WEXKNZ0UOgiRpng= +github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= +github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= +github.com/spf13/cobra v1.1.1 h1:KfztREH0tPxJJ+geloSLaAkaPkr4ki2Er5quFV1TDo4= +github.com/spf13/cobra v1.1.1/go.mod h1:WnodtKOvamDL/PwE2M4iKs8aMDBZ5Q5klgD3qfVJQMI= +github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= +github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk= +github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo= +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/spf13/viper v1.7.0/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg= +github.com/spf13/viper v1.7.1 h1:pM5oEahlgWv/WnHXpgbKz7iLIxRf65tye2Ci+XFK5sk= +github.com/spf13/viper v1.7.1/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg= +github.com/stoewer/go-strcase v1.2.0 h1:Z2iHWqGXH00XYgqDmNgQbIBxf3wrNq0F3feEy0ainaU= +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/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= +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= +github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= +github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0= +github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/subosito/gotenv v1.2.0 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s= +github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= +github.com/tidwall/pretty v1.0.0 h1:HsD+QiTn7sK6flMKIvNmpqz1qrpP3Ps6jOKIKMooyg4= +github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= +github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= +github.com/vektah/gqlparser v1.1.2/go.mod h1:1ycwN7Ij5njmMkPPAOaRFY4rET2Enx7IkVv3vaXspKw= +github.com/xdg/scram v0.0.0-20180814205039-7eeb5667e42c/go.mod h1:lB8K/P019DLNhemzwFU4jHLhdvlE6uDZjXFejJXr49I= +github.com/xdg/stringprep v0.0.0-20180714160509-73f8eece6fdc/go.mod h1:Jhud4/sHMO4oL310DaZAKk9ZaJ08SJfe+sJh0HrGL1Y= +github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= +go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= +go.mongodb.org/mongo-driver v1.0.3/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM= +go.mongodb.org/mongo-driver v1.1.1/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM= +go.mongodb.org/mongo-driver v1.3.0/go.mod h1:MSWZXKOynuguX+JSvwP8i+58jYCXxbia8HS3gZBapIE= +go.mongodb.org/mongo-driver v1.3.4/go.mod h1:MSWZXKOynuguX+JSvwP8i+58jYCXxbia8HS3gZBapIE= +go.mongodb.org/mongo-driver v1.4.3/go.mod h1:WcMNYLx/IlOxLe6JRJiv2uXuCz6zBLndR4SoGjYphSc= +go.mongodb.org/mongo-driver v1.4.4 h1:bsPHfODES+/yx2PCWzUYMH8xj6PVniPI8DQrsJuSXSs= +go.mongodb.org/mongo-driver v1.4.4/go.mod h1:WcMNYLx/IlOxLe6JRJiv2uXuCz6zBLndR4SoGjYphSc= +go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= +go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= +go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= +go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= +go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= +golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/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-20190320223903-b7391e95e576/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190422162423-af44ce270edf/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE= +golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190530122614-20be4c3c3ed5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190617133340-57b3e21c3d56/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a h1:vclmkQCjlDX5OydZ9wv8rBCcS0QyQY66Mpf/7BZbInM= +golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= +golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= +golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= +golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= +golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +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-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= +golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= +golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= +golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= +golang.org/x/net v0.0.0-20180724234803-3673e40ba225/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-20181005035420-146acd28ed58/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181220203305-927f97764cc3/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-20190320064053-1272bf9dcd53/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/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-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200202094626-16171245cfb2/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-20200602114024-627f9648deb9/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201202161906-c7110b5ffcbb h1:eBmm0M9fYhWpKZLjQUUKka/LtIxf46G4fxeEz5KJr9U= +golang.org/x/net v0.0.0-20201202161906-c7110b5ffcbb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +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-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190412183630-56d357773e84/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/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +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-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/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-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190321052220-f7bb7a8bee54/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190419153524-e8e3143a4f4a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190531175056-4c3a928424d2/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f h1:+Nyd8tzPX9R7BWHguqsrbFdRx3WQ/1ib8I44HXV5yTA= +golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +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= +golang.org/x/text v0.3.4 h1:0YWbFKbhXG/wIiuHDSKpS0Iy7FSA+u45VtBMfQcFTTc= +golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190125232054-d66bd3c5d5a6/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-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190329151228-23e29df326fe/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190416151739-9c9e1878f421/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190420181800-aa740d480789/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190531172133-b3315ee88b7d/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190614205625-5aca471b1d59/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190617190820-da514acc4774/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= +google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= +google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= +google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= +google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +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.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= +google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= +google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= +google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= +google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= +gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU= +gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= +gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= +gopkg.in/ini.v1 v1.56.0 h1:DPMeDvGTM54DXbPkVIZsp19fp/I2K7zwA/itHYHKo8Y= +gopkg.in/ini.v1 v1.56.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= +gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= +gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +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-20200605160147-a5ece683394c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776 h1:tQIYjPdBoyREyB9XMu+nnTclpTYkz2zFM+lzLJFO4gQ= +gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= +rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= diff --git a/infra/gen-resourcesdocs/hack/reference-api.sh b/infra/gen-resourcesdocs/hack/reference-api.sh new file mode 100755 index 00000000..54658328 --- /dev/null +++ b/infra/gen-resourcesdocs/hack/reference-api.sh @@ -0,0 +1,49 @@ +#!/usr/bin/env bash +# Copyright 2025 The Karmada Authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +set -o errexit +set -o nounset +set -o pipefail + +# This script used to generate the Karmada API reference document and update the website content. +# 1. used by document releasing. +# 2. used when the Karmada API is updated. + +function usage() { + echo "Usage:" + echo " hack/reference-api.sh [-h]" + echo "Args:" + echo " h: print help information" +} + +MODULE_ROOT=$(dirname "${BASH_SOURCE[0]}")/.. +REPO_ROOT=$MODULE_ROOT/../.. + +GITHUB_RAW_URL="https://raw.githubusercontent.com/karmada-io/karmada/master/api/openapi-spec/swagger.json" +LOCAL_FILENAME=$MODULE_ROOT/api/current/swagger.json + +mkdir -p $MODULE_ROOT/api/current +curl -o "$LOCAL_FILENAME" "$GITHUB_RAW_URL" + +VERSION="current" make + +sed -i 's/\r//g' `find $MODULE_ROOT/kwebsite -name "*.md"` +# remove the redundant linefeed (LF) +sed -i '/^$/N;/^\n$/D' `find $MODULE_ROOT/kwebsite -name "*.md"` + +rm -rf $REPO_ROOT/docs/reference/karmada-api +mv -f $MODULE_ROOT/kwebsite/content/en/docs $REPO_ROOT/docs/reference/karmada-api +rm -rf $MODULE_ROOT/kwebsite +rm -rf $MODULE_ROOT/api diff --git a/infra/gen-resourcesdocs/pkg/config/categories.go b/infra/gen-resourcesdocs/pkg/config/categories.go new file mode 100644 index 00000000..06d9f646 --- /dev/null +++ b/infra/gen-resourcesdocs/pkg/config/categories.go @@ -0,0 +1,51 @@ +package config + +import ( + "io/ioutil" + + "github.com/karmada-io/website/infra/gen-resourcesdocs/pkg/kubernetes" + + "gopkg.in/yaml.v2" +) + +// FieldCategory is a list of fields regrouped in the same category +type FieldCategory struct { + Name string `yaml:"name"` + Fields []string `yaml:"fields"` +} + +// Category is the list of fields categories for a specific definition +type Category struct { + Definition kubernetes.Key `yaml:"definition"` + FieldCategories []FieldCategory `yaml:"field_categories"` +} + +// Categories is the list of fields categories for all definitions +type Categories []Category + +// LoadCategories from a configuration file +func LoadCategories(filenames []string) (Categories, error) { + var result Categories + for _, filename := range filenames { + var fileCats Categories + content, err := ioutil.ReadFile(filename) + if err != nil { + return result, err + } + err = yaml.Unmarshal(content, &fileCats) + if err != nil { + return result, err + } + result = append(result, fileCats...) + } + return result, nil +} + +func (o Categories) Find(key kubernetes.Key) []FieldCategory { + for _, category := range o { + if category.Definition == key { + return category.FieldCategories + } + } + return nil +} diff --git a/infra/gen-resourcesdocs/pkg/config/chapter.go b/infra/gen-resourcesdocs/pkg/config/chapter.go new file mode 100644 index 00000000..e0b32195 --- /dev/null +++ b/infra/gen-resourcesdocs/pkg/config/chapter.go @@ -0,0 +1,146 @@ +package config + +import ( + "fmt" + + "github.com/go-openapi/spec" + + "github.com/karmada-io/website/infra/gen-resourcesdocs/pkg/kubernetes" +) + +// Chapter contains a definition of a main resource and its associated resources and definitions +type Chapter struct { + Name string `yaml:"name"` + Group *kubernetes.APIGroup `yaml:"group"` + Version *kubernetes.APIVersion `yaml:"version"` + Key kubernetes.Key `yaml:"key"` + OtherDefinitions []string `yaml:"otherDefinitions"` + Sections []*Section +} + +func (o *Chapter) isResource() bool { + return o.Group != nil && o.Version != nil +} + +func (o *Chapter) populate(part *Part, toc *TOC, thespec *kubernetes.Spec) error { + var main *spec.Schema + var newSection *Section + if o.isResource() { + if o.Key, main = thespec.GetResource(*o.Group, *o.Version, kubernetes.APIKind(o.Name), true); main == nil { + return fmt.Errorf("Resource %s/%s/%s not found in spec", o.Group, o.Version.String(), kubernetes.APIKind(o.Name)) + } + newSection = NewSection(o.Name, main, o.Group, o.Version) + } else { + if main = thespec.GetDefinition(o.Key); main == nil { + return fmt.Errorf("Resource %s/%s/%s not found in spec", o.Group, o.Version.String(), kubernetes.APIKind(o.Name)) + } + newSection = NewSectionForDefinition(o.Name, main, o.Key) + } + + o.Sections = []*Section{ + newSection, + } + le := o.Name + if o.Version.String() != "" { + le += "-" + o.Version.String() + } + toc.LinkEnds.Add(o.Key, []string{part.Name, le, newSection.Name}) + toc.DocumentedDefinitions[o.Key] = []string{o.Name} + + if o.isResource() { + if o.OtherDefinitions == nil { + o.searchDefinitionsFromResource([]string{"Spec", "Status"}, part, toc, thespec) + o.searchResourcesFromResource([]string{"List"}, part, toc, thespec) + } else { + for _, definition := range o.OtherDefinitions { + o.addDefinitionFromResource(definition, part, toc, thespec) + } + } + } else { + if o.OtherDefinitions == nil { + o.searchDefinitionsFromDefinition([]string{"Status"}, part, toc, thespec) + } else { + for _, definition := range o.OtherDefinitions { + o.addDefinitionFromDefinition(definition, part, toc, thespec) + } + } + } + return nil +} + +func (o *Chapter) addDefinitionFromResource(definition string, part *Part, toc *TOC, thespec *kubernetes.Spec) { + gvRes := kubernetes.Resource{ + GVKExtension: kubernetes.GVKExtension{ + Group: *o.Group, + Version: *o.Version, + }, + } + keys := thespec.GVToKey[gvRes.GetGV()] + for _, key := range keys { + resourceKey := kubernetes.Key(key + "." + definition) + o.addDefinition(definition, resourceKey, part, toc, thespec) + } + // Mark the resource as documented + thespec.GetResource(*o.Group, *o.Version, kubernetes.APIKind(definition), true) +} + +func (o *Chapter) addDefinitionFromDefinition(definition string, part *Part, toc *TOC, thespec *kubernetes.Spec) { + newKey := kubernetes.Key(o.Key.RemoveResourceName() + "." + definition) + o.addDefinition(definition, newKey, part, toc, thespec) +} + +func (o *Chapter) searchDefinitionsFromResource(suffixes []string, part *Part, toc *TOC, thespec *kubernetes.Spec) { + for _, suffix := range suffixes { + resourceName := o.Name + suffix + gvRes := kubernetes.Resource{ + GVKExtension: kubernetes.GVKExtension{ + Group: *o.Group, + Version: *o.Version, + }, + } + keys := thespec.GVToKey[gvRes.GetGV()] + for _, key := range keys { + resourceKey := kubernetes.Key(key + "." + resourceName) + o.addDefinition(resourceName, resourceKey, part, toc, thespec) + } + } +} + +func (o *Chapter) searchResourcesFromResource(suffixes []string, part *Part, toc *TOC, thespec *kubernetes.Spec) { + for _, suffix := range suffixes { + resourceName := o.Name + suffix + key, resource := thespec.GetResource(*o.Group, *o.Version, kubernetes.APIKind(resourceName), true) + if resource != nil { + newSection := NewSection(resourceName, resource, o.Group, o.Version) + o.Sections = append(o.Sections, newSection) + le := o.Name + if o.Version.String() != "" { + le += "-" + o.Version.String() + } + toc.LinkEnds.Add(key, []string{part.Name, le, newSection.Name}) + toc.DocumentedDefinitions[key] = []string{resourceName} + } + } +} + +func (o *Chapter) searchDefinitionsFromDefinition(suffixes []string, part *Part, toc *TOC, thespec *kubernetes.Spec) { + for _, suffix := range suffixes { + resourceName := o.Name + suffix + resourceKey := kubernetes.Key(o.Key.String() + suffix) + o.addDefinition(resourceName, resourceKey, part, toc, thespec) + } +} + +func (o *Chapter) addDefinition(resourceName string, resourceKey kubernetes.Key, part *Part, toc *TOC, thespec *kubernetes.Spec) { + resource := thespec.GetDefinition(resourceKey) + if resource != nil { + newSection := NewSectionForDefinition(resourceName, resource, resourceKey) + o.Sections = append(o.Sections, newSection) + le := o.Name + if o.Version.String() != "" { + le += "-" + o.Version.String() + } + toc.LinkEnds.Add(resourceKey, []string{part.Name, le, newSection.Name}) + toc.DocumentedDefinitions[resourceKey] = []string{resourceName} + } +} diff --git a/infra/gen-resourcesdocs/pkg/config/helpers.go b/infra/gen-resourcesdocs/pkg/config/helpers.go new file mode 100644 index 00000000..c3f12609 --- /dev/null +++ b/infra/gen-resourcesdocs/pkg/config/helpers.go @@ -0,0 +1,8 @@ +package config + +import "strings" + +func getEscapedFirstPhrase(s string) string { + description := strings.Split(s, ".")[0] + "." + return strings.ReplaceAll(description, "\"", "\\\"") +} diff --git a/infra/gen-resourcesdocs/pkg/config/output.go b/infra/gen-resourcesdocs/pkg/config/output.go new file mode 100644 index 00000000..45732d5e --- /dev/null +++ b/infra/gen-resourcesdocs/pkg/config/output.go @@ -0,0 +1,366 @@ +package config + +import ( + "fmt" + "sort" + "strings" + + "github.com/go-openapi/spec" + + "github.com/karmada-io/website/infra/gen-resourcesdocs/pkg/kubernetes" + "github.com/karmada-io/website/infra/gen-resourcesdocs/pkg/outputs" +) + +// OutputDocument outputs contents using output +func (o *TOC) OutputDocument(output outputs.Output) error { + for p, tocPart := range o.Parts { + err := o.OutputPart(p, tocPart, output) + if err != nil { + return err + } + } + + o.OutputCommonParameters(len(o.Parts), output) + + err := output.Terminate() + if err != nil { + return err + } + return nil +} + +// OutputPart outputs a Part +func (o *TOC) OutputPart(i int, part *Part, output outputs.Output) error { + outputPart, err := output.AddPart(i, part.Name) + if err != nil { + return err + } + + for c, tocChapter := range part.Chapters { + err = o.OutputChapter(c, tocChapter, outputPart) + if err != nil { + return err + } + } + return nil +} + +// OutputChapter outputs a chapter of the part +func (o *TOC) OutputChapter(i int, chapter *Chapter, outputPart outputs.Part) error { + description := "" + if len(chapter.Sections) > 0 { + description = getEscapedFirstPhrase(chapter.Sections[0].Definition.Description) + } + gv := "" + if chapter.Group != nil && chapter.Version != nil { + gv = GetGV(*chapter.Group, *chapter.Version) + } + outputChapter, err := outputPart.AddChapter(i, chapter.Name, gv, chapter.Version, description, chapter.Key.GoImportPrefix()) + if err != nil { + return err + } + + if chapter.Group != nil && chapter.Version != nil { + err = outputChapter.SetAPIVersion(GetGV(*chapter.Group, *chapter.Version)) + if err != nil { + return err + } + } + err = outputChapter.SetGoImport(chapter.Key.GoImportPrefix()) + if err != nil { + return err + } + + for s, tocSection := range chapter.Sections { + err = o.OutputSection(s, tocSection, outputChapter) + if err != nil { + return err + } + } + + if chapter.Group != nil && chapter.Version != nil { + gvkString := chapter.Group.String() + "." + chapter.Version.String() + "." + chapter.Name + actions := o.Actions.Get(gvkString) + if actions != nil { + o.OutputOperations(len(chapter.Sections), outputChapter, &actions) + } + } + + outputChapter.Write() + return nil +} + +// OutputSection outputs a section of the chapter +func (o *TOC) OutputSection(i int, section *Section, outputChapter outputs.Chapter) error { + var apiVersion *string + if section.Group != nil && section.Version != nil { + a := GetGV(*section.Group, *section.Version) + apiVersion = &a + } + outputSection, err := outputChapter.AddSection(i, section.Name, apiVersion) + if err != nil { + return err + } + err = outputSection.AddDefinitionIndexEntry(section.Name) + if err != nil { + return err + } + err = outputSection.AddContent(section.Definition.Description) + if err != nil { + return err + } + + err = o.OutputProperties(section.Name, section.Definition, outputSection, []string{}, section.Group, section.Version, section.Key) + if err != nil { + return err + } + return nil +} + +// OutputProperties outputs the properties of a definition +func (o *TOC) OutputProperties(defname string, definition spec.Schema, outputSection outputs.Section, prefix []string, group *kubernetes.APIGroup, version *kubernetes.APIVersion, key *kubernetes.Key) error { + requiredProperties := definition.Required + + var apiVersion *string + if group != nil && version != nil { + a := GetGV(*group, *version) + apiVersion = &a + } + + // Search configured categories + var fieldCategories []FieldCategory + if key != nil { + fieldCategories = o.Categories.Find(*key) + + if fieldCategories != nil { + if err := checkAllFieldsPresent(fieldCategories, definition.Properties); err != nil { + return fmt.Errorf("error on fields configuration: %s", err) + } + } + } + + if fieldCategories == nil { + // Categories config not found, create a default one + ordered := orderedPropertyKeys(requiredProperties, definition.Properties, apiVersion != nil) + fieldCategories = []FieldCategory{ + { + Name: "", + Fields: ordered, + }, + } + } + + for _, fieldCategory := range fieldCategories { + + if len(prefix) == 0 { + // NOTE: category names are not displayed for sub-fields (that would be a hell of a mess...) + if fieldCategory.Name != "" { + outputSection.AddFieldCategory(fieldCategory.Name) + } + + outputSection.StartPropertyList() + } + + for _, name := range fieldCategory.Fields { + if apiVersion != nil && (name == "apiVersion" || name == "kind") { + var property *kubernetes.Property + if name == "apiVersion" { + property = kubernetes.NewHardCodedValueProperty(name, *apiVersion) + } else if name == "kind" { + property = kubernetes.NewHardCodedValueProperty(name, defname) + } + err := outputSection.AddProperty(name, property, []string{}, 0, defname, name) + if err != nil { + return err + } + continue + } + + details := definition.Properties[name] + property, err := kubernetes.NewProperty(name, details, requiredProperties) + if err != nil { + return err + } + var linkend []string + if property.TypeKey != nil { + linkend = o.LinkEnds[*property.TypeKey] + } + completeName := prefix + completeName = append(completeName, name) + err = outputSection.AddProperty(strings.Join(completeName, "."), property, linkend, len(prefix), defname, name) + if err != nil { + return err + } + if property.TypeKey != nil && len(linkend) == 0 { + // The type is documented inline + if target, found := (*o.Definitions)[property.TypeKey.String()]; found { + o.setDocumentedDefinition(property.TypeKey, defname+"/"+strings.Join(completeName, ".")) + + indexedType := property.Type + if strings.HasPrefix(indexedType, "[]") { + indexedType = indexedType[2:] + } + if strings.HasPrefix(indexedType, "map[string]") { + indexedType = indexedType[11:] + } + err = outputSection.AddDefinitionIndexEntry(indexedType) + if err != nil { + return err + } + + err = outputSection.AddTypeDefinition(property.TypeKey.ResourceName(), target.Description) + if err != nil { + return err + } + + sublist := false + if len(prefix) == 0 { + sublist = true + outputSection.StartPropertyList() + } else { + err = outputSection.EndProperty() + } + + o.OutputProperties(defname, target, outputSection, append(prefix, name), nil, nil, property.TypeKey) + if sublist { + outputSection.EndPropertyList() + } + } + } + err = outputSection.EndProperty() + if err != nil { + return err + } + } + if len(prefix) == 0 { + outputSection.EndPropertyList() + } + } + return nil +} + +func (o *TOC) setDocumentedDefinition(key *kubernetes.Key, from string) { + if _, found := o.DocumentedDefinitions[*key]; found { + o.DocumentedDefinitions[*key] = append(o.DocumentedDefinitions[*key], from) + } else { + o.DocumentedDefinitions[*key] = []string{from} + } +} + +// OutputOperations outputs the Operations chapter +func (o *TOC) OutputOperations(i int, outputChapter outputs.Chapter, operations *kubernetes.ActionInfoList) error { + operationsSection, err := outputChapter.AddSection(i, "Operations", nil) + if err != nil { + return err + } + for i, operation := range *operations { + o.OutputOperation(i, operationsSection, &operation) + _ = operation + } + return nil +} + +// OutputOperation outputs details of an Operation +func (o *TOC) OutputOperation(i int, outputSection outputs.Section, operation *kubernetes.ActionInfo) error { + outputSection.AddOperation(operation, o.LinkEnds) + return nil +} + +// OutputCommonParameters outputs the parameters in common +func (o *TOC) OutputCommonParameters(i int, output outputs.Output) error { + outputPart, err := output.NewPart(i, "Common Parameters") + if err != nil { + return err + } + + outputChapter, err := outputPart.AddChapter(i, "Common Parameters", "", nil, "", "") + + params := make([]string, len(kubernetes.ParametersAnnex)) + j := 0 + for k := range kubernetes.ParametersAnnex { + params[j] = k + j++ + } + sort.Strings(params) + for i, param := range params { + if len(kubernetes.ResourcesDescriptions[param][0].Description) == 0 { + continue + } + outputSection, err := outputChapter.AddSection(i, param, nil) + if err != nil { + return err + } + err = outputSection.AddContent(kubernetes.ResourcesDescriptions[param][0].Description) + } + outputChapter.Write() + return nil +} + +// orderedPropertyKeys returns the keys of m alphabetically ordered +// keys in required will be placed first +func orderedPropertyKeys(required []string, m map[string]spec.Schema, isResource bool) []string { + sort.Strings(required) + + if isResource { + mkeys := make(map[string]struct{}) + for k := range m { + mkeys[k] = struct{}{} + } + for _, special := range []string{"metadata", "kind", "apiVersion"} { + if !isRequired(special, required) { + if _, ok := mkeys[special]; ok { + required = append([]string{special}, required...) + } + } + } + } + + keys := make([]string, len(m)-len(required)) + i := 0 + for k := range m { + if !isRequired(k, required) { + keys[i] = k + i++ + } + } + sort.Strings(keys) + return append(required, keys...) +} + +// isRequired returns true if k is in the required array +func isRequired(k string, required []string) bool { + for _, r := range required { + if r == k { + return true + } + } + return false +} + +func checkAllFieldsPresent(configuredFields []FieldCategory, definedFields map[string]spec.Schema) error { + already := map[string]struct{}{} + + count := 0 + for _, category := range configuredFields { + for _, field := range category.Fields { + if _, found := already[field]; found { + return fmt.Errorf("field %s found twice", field) + } + already[field] = struct{}{} + if _, found := definedFields[field]; !found { + return fmt.Errorf("field %s not defined in Spec", field) + } + count++ + } + } + if len(definedFields) != count { + forgotten := []string{} + for defined := range definedFields { + if _, found := already[defined]; !found { + forgotten = append(forgotten, defined) + } + } + return fmt.Errorf("%d fields configured but %d fields in Spec, missing %v", count, len(definedFields), forgotten) + } + return nil +} diff --git a/infra/gen-resourcesdocs/pkg/config/output_test.go b/infra/gen-resourcesdocs/pkg/config/output_test.go new file mode 100644 index 00000000..2c6983c4 --- /dev/null +++ b/infra/gen-resourcesdocs/pkg/config/output_test.go @@ -0,0 +1,76 @@ +package config_test + +import ( + "testing" + + "github.com/karmada-io/website/infra/gen-resourcesdocs/pkg/config" + "github.com/karmada-io/website/infra/gen-resourcesdocs/pkg/kubernetes" + "github.com/karmada-io/website/infra/gen-resourcesdocs/pkg/outputs" +) + +type FakeOutput struct{} + +func (o FakeOutput) Prepare() error { return nil } +func (o FakeOutput) NewPart(i int, name string) (outputs.Part, error) { return FakePart{}, nil } +func (o FakeOutput) AddPart(i int, name string) (outputs.Part, error) { return FakePart{}, nil } +func (o FakeOutput) Terminate() error { return nil } + +type FakePart struct{} + +func (o FakePart) AddChapter(i int, name string, gv string, version *kubernetes.APIVersion, description string, importPrefix string) (outputs.Chapter, error) { + return FakeChapter{}, nil +} + +type FakeChapter struct{} + +func (o FakeChapter) SetAPIVersion(s string) error { return nil } +func (o FakeChapter) SetGoImport(s string) error { return nil } +func (o FakeChapter) AddSection(i int, name string, apiVersion *string) (outputs.Section, error) { + return FakeSection{}, nil +} +func (o FakeChapter) Write() error { return nil } + +type FakeSection struct{} + +func (o FakeSection) AddContent(s string) error { return nil } +func (o FakeSection) AddTypeDefinition(typ string, description string) error { return nil } +func (o FakeSection) AddFieldCategory(name string) error { return nil } + +func (o FakeSection) AddProperty(name string, property *kubernetes.Property, linkend []string, indent int, defname string, shortName string) error { + return nil +} +func (o FakeSection) EndProperty() error { return nil } +func (o FakeSection) StartPropertyList() error { return nil } +func (o FakeSection) EndPropertyList() error { return nil } +func (o FakeSection) AddOperation(operation *kubernetes.ActionInfo, linkends kubernetes.LinkEnds) error { + return nil +} +func (o FakeSection) AddDefinitionIndexEntry(d string) error { return nil } + +func TestOutputDocumentV119(t *testing.T) { + outputDocumentVersion(t, "v1.19") +} + +func TestOutputDocumentV120(t *testing.T) { + outputDocumentVersion(t, "v1.20") +} + +func outputDocumentVersion(t *testing.T, version string) { + spec, err := kubernetes.NewSpec("../../api/" + version + "/swagger.json") + if err != nil { + t.Errorf("Error loading swagger file") + } + + toc, err := config.LoadTOC("../../config/" + version + "/toc.yaml") + if err != nil { + t.Errorf("LoadTOC should not fail") + } + + err = toc.PopulateAssociates(spec) + if err != nil { + t.Errorf("%s", err) + } + toc.Definitions = &spec.Swagger.Definitions + toc.OutputDocument(FakeOutput{}) + +} diff --git a/infra/gen-resourcesdocs/pkg/config/toc.go b/infra/gen-resourcesdocs/pkg/config/toc.go new file mode 100644 index 00000000..a4ef873b --- /dev/null +++ b/infra/gen-resourcesdocs/pkg/config/toc.go @@ -0,0 +1,186 @@ +package config + +import ( + "fmt" + "io" + "io/ioutil" + "os" + "sort" + + "github.com/go-openapi/spec" + "gopkg.in/yaml.v2" + + "github.com/karmada-io/website/infra/gen-resourcesdocs/pkg/kubernetes" + "github.com/karmada-io/website/infra/gen-resourcesdocs/pkg/outputs/kwebsite" +) + +// TOC is the table of contents of the documentation +type TOC struct { + Parts []*Part `yaml:"parts"` + SkippedResources []kubernetes.APIKind `yaml:"skippedResources"` + Definitions *spec.Definitions + LinkEnds kubernetes.LinkEnds + DocumentedDefinitions map[kubernetes.Key][]string + Actions kubernetes.Actions + Categories Categories +} + +// Part contains chapters +type Part struct { + Name string `yaml:"name"` + Chapters []*Chapter `yaml:"chapters"` +} + +// Section contains a definition of a Kind for a given Group/Version +type Section struct { + Name string + Group *kubernetes.APIGroup + Version *kubernetes.APIVersion + Definition spec.Schema + Key *kubernetes.Key +} + +// NewSection returns a Section +func NewSection(name string, definition *spec.Schema, group *kubernetes.APIGroup, version *kubernetes.APIVersion) *Section { + return &Section{ + Name: name, + Group: group, + Version: version, + Definition: *definition, + } +} + +// NewSectionForDefinition returns a Section for a definition +func NewSectionForDefinition(name string, definition *spec.Schema, key kubernetes.Key) *Section { + return &Section{ + Name: name, + Key: &key, + Definition: *definition, + } +} + +// LoadTOC loads a config file containing the TOC definition +func LoadTOC(filename string) (*TOC, error) { + var result TOC + + f, err := os.Open(filename) + if err != nil { + return nil, err + } + + content, err := ioutil.ReadAll(f) + if err != nil { + return nil, err + } + + err = yaml.Unmarshal(content, &result) + if err != nil { + return nil, err + } + + result.DocumentedDefinitions = map[kubernetes.Key][]string{} + return &result, nil +} + +// PopulateAssociates adds sections to the chapters found in the spec +func (o *TOC) PopulateAssociates(thespec *kubernetes.Spec) error { + o.LinkEnds = make(kubernetes.LinkEnds) + + for _, part := range o.Parts { + for _, chapter := range part.Chapters { + err := chapter.populate(part, o, thespec) + if err != nil { + return err + } + } + } + return nil +} + +// AddOtherResources adds not documented and not replaced resources to a new Part +func (o *TOC) AddOtherResources(spec *kubernetes.Spec) { + part := &Part{} + part.Name = "Other Resources" + part.Chapters = []*Chapter{} + + for k, resource := range *spec.Resources { + for _, v := range resource { + if v.ReplacedBy == nil && !v.Documented && !o.skippedResource(k) { + part.Chapters = append(part.Chapters, &Chapter{ + Name: v.Kind.String(), + Group: &v.Group, + Version: &v.Version, + Key: v.Key, + }) + } + } + } + sort.Slice(part.Chapters, func(i, j int) bool { + return part.Chapters[i].Name < part.Chapters[j].Name + }) + if len(part.Chapters) > 0 { + o.Parts = append(o.Parts, part) + } +} + +// ToMarkdown writes a Markdown representation of the TOC +func (o *TOC) ToMarkdown(w io.Writer) { + for _, part := range o.Parts { + fmt.Fprintf(w, "\n## %s\n", part.Name) + for _, chapter := range part.Chapters { + fmt.Fprintf(w, "### %s\n", chapter.Name) + for _, section := range chapter.Sections { + fmt.Fprintf(w, "#### %s\n", section.Name) + } + } + } +} + +// GetGV returns the group/version for a resource and version (used for apiVersion:) +func GetGV(group kubernetes.APIGroup, version kubernetes.APIVersion) string { + if group == "" { + return version.String() + } + return fmt.Sprintf("%s/%s", group, version.String()) +} + +// ToKWebsite outputs documentation in Markdown format for k/website in dir directory +func (o *TOC) ToKWebsite(outputDir string, templatesDir string) error { + kw := kwebsite.NewKWebsite(outputDir, templatesDir) + return o.OutputDocument(kw) +} + +// OutputDocumentedDefinitions outputs the list of definitions +// and on which properties they are defined +func (o *TOC) OutputDocumentedDefinitions() { + for k, v := range o.DocumentedDefinitions { + if len(v) != 1 { + fmt.Printf("%s:\n", k) + for _, s := range v { + fmt.Printf(" - %s\n", s) + } + } + } + for k, v := range o.DocumentedDefinitions { + if len(v) == 1 { + fmt.Printf("%s:\n", k) + for _, s := range v { + fmt.Printf(" - %s\n", s) + } + } + } + for k := range *o.Definitions { + if _, found := o.DocumentedDefinitions[kubernetes.Key(k)]; !found { + fmt.Printf("%s\n", k) + } + } +} + +func (o *TOC) skippedResource(k kubernetes.APIKind) bool { + for _, skip := range o.SkippedResources { + if skip == k { + return true + } + } + return false +} diff --git a/infra/gen-resourcesdocs/pkg/config/toc_test.go b/infra/gen-resourcesdocs/pkg/config/toc_test.go new file mode 100644 index 00000000..39f5456e --- /dev/null +++ b/infra/gen-resourcesdocs/pkg/config/toc_test.go @@ -0,0 +1,48 @@ +package config_test + +import ( + "testing" + + "github.com/karmada-io/website/infra/gen-resourcesdocs/pkg/config" + "github.com/karmada-io/website/infra/gen-resourcesdocs/pkg/kubernetes" +) + +func TestLoadTOCv119(t *testing.T) { + toc, err := config.LoadTOC("../../config/v1.19/toc.yaml") + if err != nil { + t.Errorf("should not get an error but got: %s", err) + } + if len(toc.Parts) != 9 { + t.Errorf("Should get %d parts but got %d", 9, len(toc.Parts)) + } +} + +func TestPopulateAssociatesv119(t *testing.T) { + spec, err := kubernetes.NewSpec("../../api/v1.19/swagger.json") + if err != nil { + t.Errorf("Error loading swagger file") + } + + if len(spec.Swagger.Definitions) != 617 { + t.Errorf("Spec should contain %d definition but contains %d", 617, len(spec.Swagger.Definitions)) + } + + toc, err := config.LoadTOC("../../config/v1.19/toc.yaml") + if err != nil { + t.Errorf("Error loading toc file") + } + + err = toc.PopulateAssociates(spec) + if err != nil { + t.Errorf("%s", err) + } + + l := len(toc.Parts[0].Chapters[0].Sections) + if l != 4 { + t.Errorf("Pod chapter should contain %d sections but contains %d sections", 4, l) + } + + if toc.Parts[0].Chapters[0].Key != "io.k8s.api.core.v1.Pod" { + t.Errorf("Key of first chapter should be %s but is %s", "io.k8s.api.core.v1.Pod", toc.Parts[0].Chapters[0].Key) + } +} diff --git a/infra/gen-resourcesdocs/pkg/kubernetes/actions.go b/infra/gen-resourcesdocs/pkg/kubernetes/actions.go new file mode 100644 index 00000000..a02d2170 --- /dev/null +++ b/infra/gen-resourcesdocs/pkg/kubernetes/actions.go @@ -0,0 +1,226 @@ +package kubernetes + +import ( + "fmt" + "os" + "sort" + "strings" + + "github.com/go-openapi/spec" +) + +// ActionExtension represents the OpenAPI extension x-bubernetes-action +type ActionExtension string + +const ( + // ActionConnect is the "connect" Kubernetes action + // DELETE, GET, HEAD, OPTIONS, PATCH, POST, PUT + ActionConnect = "connect" + // ActionDelete is the "delete" Kubernetes action + // DELETE + ActionDelete = "delete" + // ActionDeleteCollection is the "deletecollection" Kubernetes action + // DELETE + ActionDeleteCollection = "deletecollection" + // ActionGet is the "get" Kubernetes action + // GET + ActionGet = "get" + // ActionList is the "list" Kubernetes action + // GET + ActionList = "list" + // ActionPatch is the "patch" Kubernetes action + // PATCH + ActionPatch = "patch" + // ActionCreate is the "post" Kubernetes action + // POST + ActionCreate = "post" + // ActionUpdate is the "put" Kubernetes action + // PUT + ActionUpdate = "put" + // ActionWatch is the "watch" Kubernetes action + // GET + ActionWatch = "watch" + // ActionWatchList is the "watchlist" Kubernetes action + // GET + ActionWatchList = "watchlist" +) + +var ( + // ActionsOrder indicates the natural order of actions + actionsOrder = map[ActionExtension]int8{ + ActionGet: 0, + ActionWatch: 1, + ActionList: 2, + ActionWatchList: 3, + ActionCreate: 4, + ActionUpdate: 5, + ActionPatch: 6, + ActionDelete: 7, + ActionDeleteCollection: 8, + ActionConnect: 9, + } + + actionsVerb = map[ActionExtension]string{ + ActionGet: "get", + ActionWatch: "watch", + ActionList: "list", + ActionWatchList: "watchlist", + ActionCreate: "create", + ActionUpdate: "update", + ActionPatch: "patch", + ActionDelete: "delete", + ActionDeleteCollection: "deletecollection", + ActionConnect: "connect", + } +) + +// String returns the string representation of an ActionExtension +func (o ActionExtension) String() string { + return string(o) +} + +// LessThan returns true if o appears before p in natural order +func (o ActionExtension) LessThan(p ActionExtension) bool { + return actionsOrder[o] < actionsOrder[p] +} + +// Verb returns the verb associated with the action +func (o ActionExtension) Verb() string { + return actionsVerb[o] +} + +// ActionPath represents the path of an action +type ActionPath string + +func (o ActionPath) String() string { + return string(o) +} + +func (o ActionPath) isNamespaced() bool { + return strings.Contains(o.String(), "/namespaces/{namespace}") +} + +// LessThan returns true if o appears before p in natural order +func (o ActionPath) LessThan(p ActionPath) bool { + if o.isNamespaced() && !p.isNamespaced() { + return true + } + if !o.isNamespaced() && p.isNamespaced() { + return false + } + return o.String() < p.String() +} + +// ActionInfo contains information about a specific endpoint +type ActionInfo struct { + // Path of the endpoint + Path ActionPath + // Kubernetes action mapped to the endpoint + Action ActionExtension + // Definition of the action + Operation *spec.Operation + // HTTP Method + HTTPMethod string + // Parameters of the actions at path level plus operation level + Parameters ParametersList +} + +// ActionInfoList represents a list of actions info +type ActionInfoList []ActionInfo + +func (a ActionInfoList) Len() int { return len(a) } +func (a ActionInfoList) Swap(i, j int) { a[i], a[j] = a[j], a[i] } +func (a ActionInfoList) Less(i, j int) bool { + if a[i].Action.LessThan(a[j].Action) { + return true + } + if a[j].Action.LessThan(a[i].Action) { + return false + } + return a[i].Path.LessThan(a[j].Path) +} + +// Actions represents a map of ActionInfo, mapped by GVK +type Actions map[string]ActionInfoList + +// Add an action to the collection of actions +func (o Actions) Add(specParameters map[string]spec.Parameter, key string, operation *spec.Operation, httpMethod string, pathParameters []spec.Parameter) { + + desc := operation.Description + if strings.Contains(strings.ToLower(desc), "deprecated") { + return + } + + action, err := getActionExtension(operation.Extensions) + if err != nil { + fmt.Fprintf(os.Stderr, "Error getting extension") + return + } + if action != nil { + + gvk, found, err := getGVKExtension(operation.Extensions) + if err != nil { + //fmt.Fprintf(os.Stderr, "Error getting GVK extension for %s|%s: %s\n", key, httpMethod, err) + } else if !found { + //fmt.Fprintf(os.Stderr, "GVK extension not found for %s|%s\n", key, httpMethod) + } else { + gvkString := gvk.Group.String() + "." + gvk.Version.String() + "." + gvk.Kind.String() + + list := new(ParametersList) + for _, pathParam := range pathParameters { + list.Add(specParameters, pathParam) + } + for _, opParam := range operation.Parameters { + list.Add(specParameters, opParam) + } + sort.Sort(list) + + newActionInfo := ActionInfo{ + Path: ActionPath(key), + Action: *action, + Operation: operation, + HTTPMethod: httpMethod, + Parameters: *list, + } + if o[gvkString] != nil { + o[gvkString] = append(o[gvkString], newActionInfo) + } else { + o[gvkString] = []ActionInfo{newActionInfo} + } + } + } else { + //fmt.Fprintf(os.Stderr, "No action for %s|%s\n", key, httpMethod) + } +} + +// Get the actions for a specific GVK +func (o Actions) Get(gvk string) ActionInfoList { + return o[gvk] +} + +// Sort sorts the list of actions for each GVK +func (o Actions) Sort() { + for k := range o { + sort.Sort(o[k]) + } +} + +func (o Actions) findCommonParameters() { + for _, actionList := range o { + for _, action := range actionList { + ResourcesDescriptions.addActionParameters(&action.Parameters) + } + } + for k, list := range ResourcesDescriptions { + if len(list) == 1 && list[0].count > 10 { + ParametersAnnex[k] = struct{}{} + } else if len(list) == 2 && k == "fieldManager" { + ParametersAnnex[k] = struct{}{} + if len(list[0].Description) > len(list[1].Description) { + list = []descriptionInfo{list[0]} + } else { + list = []descriptionInfo{list[1]} + } + } + } +} diff --git a/infra/gen-resourcesdocs/pkg/kubernetes/apigroup.go b/infra/gen-resourcesdocs/pkg/kubernetes/apigroup.go new file mode 100644 index 00000000..def1388d --- /dev/null +++ b/infra/gen-resourcesdocs/pkg/kubernetes/apigroup.go @@ -0,0 +1,28 @@ +package kubernetes + +// APIGroup represents the group of a Kubernetes API +type APIGroup string + +func (o APIGroup) String() string { + return string(o) +} + +// Replaces returns true if 'o' group is replaced by 'p' group +func (o APIGroup) Replaces(p APIGroup) bool { + // * replaces extensions + if o.String() != "extensions" && p.String() == "extensions" { + return true + } + + // events replaces core + if o.String() == "events.k8s.io" && p.String() == "" { + return true + } + + // autoscaling replaces apps + if o.String() == "autoscaling" && p.String() == "apps" { + return true + } + + return false +} diff --git a/infra/gen-resourcesdocs/pkg/kubernetes/apigroup_test.go b/infra/gen-resourcesdocs/pkg/kubernetes/apigroup_test.go new file mode 100644 index 00000000..5f54f9e3 --- /dev/null +++ b/infra/gen-resourcesdocs/pkg/kubernetes/apigroup_test.go @@ -0,0 +1,25 @@ +package kubernetes_test + +import ( + "testing" + + "github.com/karmada-io/website/infra/gen-resourcesdocs/pkg/kubernetes" +) + +func TestAPIGroupReplaces(t *testing.T) { + tests := []struct { + Group1 kubernetes.APIGroup + Group2 kubernetes.APIGroup + Expected bool + }{ + {"networking", "extensions", true}, + {"events.k8s.io", "", true}, + } + + for _, test := range tests { + result := test.Group1.Replaces(test.Group2) + if result != test.Expected { + t.Errorf("%s replaces %s: expected %v but got %v", test.Group1, test.Group2, test.Expected, result) + } + } +} diff --git a/infra/gen-resourcesdocs/pkg/kubernetes/apikind.go b/infra/gen-resourcesdocs/pkg/kubernetes/apikind.go new file mode 100644 index 00000000..455ddd11 --- /dev/null +++ b/infra/gen-resourcesdocs/pkg/kubernetes/apikind.go @@ -0,0 +1,8 @@ +package kubernetes + +// APIKind represents the Kind of a Kubernetes resource +type APIKind string + +func (o APIKind) String() string { + return string(o) +} diff --git a/infra/gen-resourcesdocs/pkg/kubernetes/apiversion.go b/infra/gen-resourcesdocs/pkg/kubernetes/apiversion.go new file mode 100644 index 00000000..bc6ad6f4 --- /dev/null +++ b/infra/gen-resourcesdocs/pkg/kubernetes/apiversion.go @@ -0,0 +1,128 @@ +package kubernetes + +import ( + "fmt" + "log" + "regexp" + "strconv" +) + +// VersionStage represents the stage of the version: alpha, beta, ga +type VersionStage int + +const ( + // StageAlpha is the first stage during development + StageAlpha VersionStage = iota + // StageBeta is the next stage + StageBeta + // StageGA is the latest stage + StageGA +) + +var stageName = map[VersionStage]string{ + StageAlpha: "alpha", + StageBeta: "beta", + StageGA: "", +} + +// APIVersion represents the version of a Kubernetes API (v1alpha1, v1beta2, v1, v2, etc) +type APIVersion struct { + // Version is the *1* in v1alpha2 + Version int + // Stage is *alpha* in v1alpha2 + Stage VersionStage + // StageVersion is *2* in v1alpha2, or nil in v1 + StageVersion *int +} + +// NewAPIVersion creates a new APIVersion struct from the literal version (for example v1alpha1) +func NewAPIVersion(literal string) (apiversion *APIVersion, err error) { + re := regexp.MustCompile("^v(\\d+)((alpha|beta|)(\\d))?$") + parts := re.FindStringSubmatch(literal) + if parts == nil || len(parts) != 5 { + return nil, fmt.Errorf("Error parsing %s", literal) + } + + apiversion = &APIVersion{} + apiversion.Version, err = strconv.Atoi(parts[1]) + if err != nil { + log.Printf("Error parsing integer '%s'", parts[1]) + return nil, err + } + apiversion.Stage, err = getVersionStage(parts[3]) + if err != nil { + return nil, err + } + if apiversion.Stage != StageGA { + var res int + res, err = strconv.Atoi(parts[4]) + if err != nil { + return nil, err + } + apiversion.StageVersion = &res + } + return +} + +func getVersionStage(stage string) (VersionStage, error) { + switch stage { + case stageName[StageAlpha]: + return StageAlpha, nil + case stageName[StageBeta]: + return StageBeta, nil + case stageName[StageGA]: + return StageGA, nil + default: + return 0, fmt.Errorf("unknown stage %s", stage) + } +} + +// String returns the literal representation of an APIVersion +func (o *APIVersion) String() string { + if o == nil { + return "" + } + if o.Stage == StageGA { + return fmt.Sprintf("v%d", o.Version) + } + return fmt.Sprintf("v%d%s%d", o.Version, stageName[o.Stage], *o.StageVersion) +} + +// Equals returns true if 'o' and 'p' represent the same version +func (o *APIVersion) Equals(p *APIVersion) bool { + return o.String() == p.String() +} + +// LessThan returns true if 'o' version comes before 'p' version +func (o *APIVersion) LessThan(p *APIVersion) bool { + if o.Version != p.Version { + return o.Version < p.Version + } + if o.Stage != StageGA { + if o.Stage != p.Stage { + return o.Stage < p.Stage + } + return *o.StageVersion < *p.StageVersion + } + return false +} + +// Replaces returns true if 'o' version replaces 'p' version +func (o *APIVersion) Replaces(p *APIVersion) bool { + return o.Version == p.Version && p.LessThan(o) +} + +// UnmarshalYAML helps unmarshal APIVersion values from YAML +func (o *APIVersion) UnmarshalYAML(unmarshal func(interface{}) error) error { + var str string + err := unmarshal(&str) + if err != nil { + return err + } + v, err := NewAPIVersion(str) + if err != nil { + return err + } + *o = *v + return nil +} diff --git a/infra/gen-resourcesdocs/pkg/kubernetes/apiversion_test.go b/infra/gen-resourcesdocs/pkg/kubernetes/apiversion_test.go new file mode 100644 index 00000000..ed979b0c --- /dev/null +++ b/infra/gen-resourcesdocs/pkg/kubernetes/apiversion_test.go @@ -0,0 +1,190 @@ +package kubernetes_test + +import ( + "reflect" + "testing" + + "gopkg.in/yaml.v2" + + "github.com/karmada-io/website/infra/gen-resourcesdocs/pkg/kubernetes" +) + +var ( + two = 2 + three = 3 +) + +func TestNewAPIVersion(t *testing.T) { + tests := []struct { + Input string + Expected *kubernetes.APIVersion + ExpectedInErr bool + }{ + { + Input: "v1", + Expected: &kubernetes.APIVersion{ + Version: 1, + Stage: kubernetes.StageGA, + StageVersion: nil, + }, + ExpectedInErr: false, + }, + { + Input: "v1alpha2", + Expected: &kubernetes.APIVersion{ + Version: 1, + Stage: kubernetes.StageAlpha, + StageVersion: &two, + }, + ExpectedInErr: false, + }, + { + Input: "v2beta3", + Expected: &kubernetes.APIVersion{ + Version: 2, + Stage: kubernetes.StageBeta, + StageVersion: &three, + }, + ExpectedInErr: false, + }, + { + Input: "_v1_", + Expected: nil, + ExpectedInErr: true, + }, + { + Input: "v1alpha", + Expected: nil, + ExpectedInErr: true, + }, + { + Input: "va", + Expected: nil, + ExpectedInErr: true, + }, + { + Input: "v1gamma2", + Expected: nil, + ExpectedInErr: true, + }, + { + Input: "v1gamma", + Expected: nil, + ExpectedInErr: true, + }, + } + + for _, test := range tests { + result, err := kubernetes.NewAPIVersion(test.Input) + if (err != nil) != test.ExpectedInErr { + t.Errorf("%s: Expected error %v but got %v", test.Input, test.ExpectedInErr, err != nil) + } + if !reflect.DeepEqual(result, test.Expected) { + t.Errorf("%s: Expected result is %v but got %v", test.Input, test.Expected, result) + } + } +} + +func TestString(t *testing.T) { + tests := []struct { + Input *kubernetes.APIVersion + Expected string + }{ + { + Input: &kubernetes.APIVersion{ + Version: 1, + Stage: kubernetes.StageGA, + }, + Expected: "v1", + }, + { + Input: &kubernetes.APIVersion{ + Version: 1, + Stage: kubernetes.StageAlpha, + StageVersion: &two, + }, + Expected: "v1alpha2", + }, + { + Input: nil, + Expected: "", + }, + } + + for _, test := range tests { + result := test.Input.String() + if result != test.Expected { + t.Errorf("%#v: Expected %s but got %s", test.Input, test.Expected, result) + } + } +} + +func TestLessThan(t *testing.T) { + tests := []struct { + V1 string + V2 string + Expected bool + }{ + {"v1", "v2", true}, + {"v1", "v1alpha3", false}, + {"v1", "v1beta2", false}, + {"v1", "v1", false}, + {"v1", "v2alpha1", true}, + } + + for _, test := range tests { + v1 := newAPIVersionAssert(t, test.V1) + v2 := newAPIVersionAssert(t, test.V2) + result := v1.LessThan(v2) + if result != test.Expected { + t.Errorf("%s < %s: Expected %v but got %v", test.V1, test.V2, test.Expected, result) + } + } +} + +func TestReplaces(t *testing.T) { + tests := []struct { + V1 string + V2 string + Expected bool + }{ + {"v2", "v1", false}, + {"v1", "v2", false}, + {"v1", "v1alpha3", true}, + {"v1", "v1beta2", true}, + {"v1beta1", "v1alpha3", true}, + {"v1beta2", "v1beta1", true}, + {"v1", "v1", false}, + {"v1", "v2alpha1", false}, + {"v2alpha1", "v1", false}, + } + + for _, test := range tests { + v1 := newAPIVersionAssert(t, test.V1) + v2 := newAPIVersionAssert(t, test.V2) + result := v1.Replaces(v2) + if result != test.Expected { + t.Errorf("%s replaces %s: Expected %v but got %v", test.V1, test.V2, test.Expected, result) + } + } +} + +func TestUnmarshalYAML(t *testing.T) { + a := struct { + Version kubernetes.APIVersion `yaml:"version"` + }{} + yaml.Unmarshal([]byte("{ \"version\": \"v1alpha1\" }"), &a) + expected := newAPIVersionAssert(t, "v1alpha1") + if a.Version.String() != expected.String() { + t.Errorf("Should be %#v but is %#v", expected, a.Version) + } +} + +// newAPIVersionAssert returns the APIVersion built from s or raises an error +func newAPIVersionAssert(t *testing.T, s string) *kubernetes.APIVersion { + v, err := kubernetes.NewAPIVersion(s) + if err != nil { + t.Errorf("Creating an APIVersion with '%s' should work", s) + } + return v +} diff --git a/infra/gen-resourcesdocs/pkg/kubernetes/extensions.go b/infra/gen-resourcesdocs/pkg/kubernetes/extensions.go new file mode 100644 index 00000000..c17b0657 --- /dev/null +++ b/infra/gen-resourcesdocs/pkg/kubernetes/extensions.go @@ -0,0 +1,147 @@ +package kubernetes + +import ( + "errors" + "fmt" + + "github.com/go-openapi/spec" +) + +// GVKExtension represents the OpenAPI extension x-kubernetes-group-version-kind +type GVKExtension struct { + Group APIGroup + Version APIVersion + Kind APIKind +} + +// getGVKExtension returns the GVK Kubernetes extension of a definition, if found +func getGVKExtension(extensions spec.Extensions) (*GVKExtension, bool, error) { + extension, found := extensions["x-kubernetes-group-version-kind"] + if !found { + return nil, false, nil + } + + var gvkMap map[string]interface{} + + gvks, ok := extension.([]interface{}) + if ok { + if len(gvks) == 0 { + return nil, false, nil + } + + if len(gvks) > 1 { + // TODO DeleteOptions in all groups + return nil, false, nil + } + gvkMap, ok = (gvks[0]).(map[string]interface{}) + if !ok { + return nil, false, fmt.Errorf("Error getting GVK") + } + } else { + gvkMap, ok = extension.(map[string]interface{}) + if !ok { + return nil, false, fmt.Errorf("x-kubernetes-group-version-kind is not an array nor a GVK structure") + } + } + + group, ok := gvkMap["group"].(string) + if !ok { + return nil, false, fmt.Errorf("Error getting GVK apigroup") + } + + version, ok := gvkMap["version"].(string) + if !ok { + return nil, false, fmt.Errorf("Error getting GVK apiversion") + } + + apiversion, err := NewAPIVersion(version) + if err != nil { + return nil, false, fmt.Errorf("Error creating APIVersion") + } + + kind, ok := gvkMap["kind"].(string) + if !ok { + return nil, false, fmt.Errorf("Error getting GVK apikind") + } + return &GVKExtension{ + Group: APIGroup(group), + Version: *apiversion, + Kind: APIKind(kind), + }, true, nil +} + +// GetPatchStrategyExtension returns the PatchStrategy extension of a definition, or nil if not found +func GetPatchStrategyExtension(extensions spec.Extensions) (*string, error) { + extension, found := extensions["x-kubernetes-patch-strategy"] + if !found { + return nil, nil + } + value, ok := extension.(string) + if !ok { + return nil, errors.New("x-bubernetes-patch-strategy is not a string") + } + return &value, nil +} + +// GetPatchMergeKeyExtension returns the GetPatchMergeKey extension of a definition, or nil if not found +func GetPatchMergeKeyExtension(extensions spec.Extensions) (*string, error) { + extension, found := extensions["x-kubernetes-patch-merge-key"] + if !found { + return nil, nil + } + value, ok := extension.(string) + if !ok { + return nil, errors.New("x-bubernetes-patch-merge-key is not a string") + } + return &value, nil +} + +// GetListType returns the ListType extension of a definition, or nil if not found +func GetListType(definition spec.Schema) (*string, error) { + extensions := definition.Extensions + extension, found := extensions["x-kubernetes-list-type"] + if !found { + return nil, nil + } + value, ok := extension.(string) + if !ok { + return nil, errors.New("x-bubernetes-list-type is not a string") + } + return &value, nil +} + +// GetListMapKeys returns the ListMapKeys extension of a definition, or nil if not found +func GetListMapKeys(definition spec.Schema) ([]string, error) { + extensions := definition.Extensions + extension, found := extensions["x-kubernetes-list-map-keys"] + if !found { + return nil, nil + } + value, ok := extension.([]interface{}) + if !ok { + return nil, errors.New("x-bubernetes-list-map-keys is not an array") + } + var result []string + for _, val := range value { + v, ok := val.(string) + if !ok { + return nil, errors.New("x-bubernetes-list-map-keys value is not a string") + } + result = append(result, v) + } + return result, nil +} + +// GetActionExtension returns the Action extension of an operation, or nil if not found +func getActionExtension(extensions spec.Extensions) (*ActionExtension, error) { + extension, found := extensions["x-kubernetes-action"] + if !found { + return nil, nil + } + value, ok := extension.(string) + if !ok { + return nil, errors.New("x-bubernetes-action is not a string") + } + action := ActionExtension(value) + return &action, nil +} diff --git a/infra/gen-resourcesdocs/pkg/kubernetes/extensions_test.go b/infra/gen-resourcesdocs/pkg/kubernetes/extensions_test.go new file mode 100644 index 00000000..e9791d6e --- /dev/null +++ b/infra/gen-resourcesdocs/pkg/kubernetes/extensions_test.go @@ -0,0 +1,39 @@ +package kubernetes + +import ( + "testing" + + "github.com/go-openapi/spec" +) + +func TestGetGVKExtension(t *testing.T) { + definition := spec.Schema{ + VendorExtensible: spec.VendorExtensible{ + Extensions: spec.Extensions{ + "x-kubernetes-group-version-kind": []interface{}{ + map[string]interface{}{ + "group": "apps", + "version": "v1", + "kind": "Deployment", + }, + }, + }, + }, + } + extension, found, err := getGVKExtension(definition.Extensions) + if !found { + t.Errorf("Extension should be found") + } + if err != nil { + t.Errorf("Extension should be found without error") + } + if extension.Group != "apps" { + t.Errorf("Group should be %s but is %s", "apps", extension.Group) + } + if extension.Version.String() != "v1" { + t.Errorf("Version should be %s but is %s", "v1", extension.Version.String()) + } + if extension.Kind != "Deployment" { + t.Errorf("Kind should be %s but is %s", "Deployment", extension.Kind) + } +} diff --git a/infra/gen-resourcesdocs/pkg/kubernetes/key.go b/infra/gen-resourcesdocs/pkg/kubernetes/key.go new file mode 100644 index 00000000..1825a58f --- /dev/null +++ b/infra/gen-resourcesdocs/pkg/kubernetes/key.go @@ -0,0 +1,31 @@ +package kubernetes + +import ( + "strings" +) + +// Key of the resource in the OpenAPI definition (e.g. io.k8s.api.core.v1.Pod) +type Key string + +// GoImportPrefix returns the path to use for this group in go import +func (o Key) GoImportPrefix() string { + parts := strings.Split(o.String(), ".") + return parts[1] + "." + parts[0] + "/" + strings.Join(parts[2:len(parts)-1], "/") +} + +// RemoveResourceName removes the last part of the key corresponding to the resource name +func (o Key) RemoveResourceName() string { + parts := strings.Split(o.String(), ".") + return strings.Join(parts[:len(parts)-1], ".") +} + +// ResourceName returns the resource name part of a key +func (o Key) ResourceName() string { + parts := strings.Split(o.String(), ".") + return parts[len(parts)-1] +} + +// String returns a string representation of the Key +func (o Key) String() string { + return string(o) +} diff --git a/infra/gen-resourcesdocs/pkg/kubernetes/linkend.go b/infra/gen-resourcesdocs/pkg/kubernetes/linkend.go new file mode 100644 index 00000000..b97783f1 --- /dev/null +++ b/infra/gen-resourcesdocs/pkg/kubernetes/linkend.go @@ -0,0 +1,19 @@ +package kubernetes + +import ( + "fmt" +) + +// LinkEnds maps definition key to a link-end +type LinkEnds map[Key][]string + +// Add a new map between key and linkend +func (o LinkEnds) Add(key Key, linkend []string) { + o[key] = linkend +} + +func (o LinkEnds) Debug() { + for k, v := range o { + fmt.Printf("%s: %v\n", k, v) + } +} diff --git a/infra/gen-resourcesdocs/pkg/kubernetes/parameters.go b/infra/gen-resourcesdocs/pkg/kubernetes/parameters.go new file mode 100644 index 00000000..90d0de70 --- /dev/null +++ b/infra/gen-resourcesdocs/pkg/kubernetes/parameters.go @@ -0,0 +1,94 @@ +package kubernetes + +import ( + "strings" + + "github.com/go-openapi/spec" +) + +// ParameterIn represents the position of a parameter of an operation +type ParameterIn string + +var paramInOrder = map[ParameterIn]int8{ + "path": 0, + "body": 1, + "query": 2, +} + +// ParametersAnnex indicates the common parameters +// that are displayed in an annex +var ParametersAnnex = map[string]struct{}{} + +// LessThan returns true if o appears before p in the natural order +func (o ParameterIn) LessThan(p ParameterIn) bool { + return paramInOrder[o] < paramInOrder[p] +} + +// ParametersList is a list of parameters +type ParametersList []spec.Parameter + +func (a ParametersList) Len() int { return len(a) } +func (a ParametersList) Swap(i, j int) { a[i], a[j] = a[j], a[i] } +func (a ParametersList) Less(i, j int) bool { + if a[i].In == a[j].In { + return a[i].Name < a[j].Name + } + return ParameterIn(a[i].In).LessThan(ParameterIn(a[j].In)) +} + +// Add a parameter to the list +func (a *ParametersList) Add(specParameters map[string]spec.Parameter, parameter spec.Parameter) { + if !parameter.Ref.GetPointer().IsEmpty() { + key := Key(strings.TrimPrefix(parameter.Ref.GetPointer().String(), "/parameters/")) + parameter = specParameters[key.String()] + } + desc := parameter.Description + if strings.Contains(strings.ToLower(desc), "deprecated") { + return + } + *a = append(*a, parameter) +} + +// ParameterInAnnex returns true if param is displayed in annex +func ParameterInAnnex(param spec.Parameter) bool { + _, found := ParametersAnnex[param.Name] + return found +} + +type descriptionInfo struct { + Description string + count int +} + +type ResourcesMap map[string][]descriptionInfo + +var ResourcesDescriptions = ResourcesMap{} + +func (o *ResourcesMap) add(param spec.Parameter) { + if _, ok := (*o)[param.Name]; !ok { + (*o)[param.Name] = []descriptionInfo{ + { + Description: param.Description, + count: 1, + }, + } + } else { + list := (*o)[param.Name] + for k, descInfo := range list { + if descInfo.Description == param.Description { + (*o)[param.Name][k].count++ + return + } + } + (*o)[param.Name] = append((*o)[param.Name], descriptionInfo{ + Description: param.Description, + count: 1, + }) + } +} + +func (o ResourcesMap) addActionParameters(params *ParametersList) { + for _, param := range *params { + o.add(param) + } +} diff --git a/infra/gen-resourcesdocs/pkg/kubernetes/property.go b/infra/gen-resourcesdocs/pkg/kubernetes/property.go new file mode 100644 index 00000000..bb72ed72 --- /dev/null +++ b/infra/gen-resourcesdocs/pkg/kubernetes/property.go @@ -0,0 +1,142 @@ +package kubernetes + +import ( + "fmt" + "strings" + + "github.com/go-openapi/spec" +) + +// Property represents a property of a definition +type Property struct { + Name string + Type string + TypeKey *Key + Description string + Required bool + RetainKeysStrategy bool + MergeStrategyKey *string + ListType *string + ListMapKeys []string + HardCodedValue *string +} + +// NewHardCodedValueProperty returns a property with an hardcoded value (useful for apiVersion, Kind) +func NewHardCodedValueProperty(name string, value string) *Property { + return &Property{ + Name: name, + HardCodedValue: &value, + } +} + +// NewProperty returns a new Property from its swagger definition +func NewProperty(name string, details spec.Schema, required []string) (*Property, error) { + typ, key := GetTypeNameAndKey(details) + strategy, err := GetPatchStrategyExtension(details.Extensions) + if err != nil { + return nil, err + } + mergeKey, err := GetPatchMergeKeyExtension(details.Extensions) + if err != nil { + return nil, err + } + + var retainKeysStrategy bool + var mergeStrategyKey *string + if strategy != nil { + patchStrategies := strings.Split(*strategy, ",") + for _, patchStrategy := range patchStrategies { + if patchStrategy == "merge" { + mergeStrategyKey = mergeKey + } else if patchStrategy == "retainKeys" { + retainKeysStrategy = true + } + } + } + + listType, err := GetListType(details) + if err != nil { + return nil, err + } + var listMapKeys []string + if listType != nil && *listType == "map" { + listMapKeys, err = GetListMapKeys(details) + if err != nil { + return nil, err + } + } + + result := Property{ + Name: name, + Type: typ, + TypeKey: key, + Description: details.Description, + RetainKeysStrategy: retainKeysStrategy, + MergeStrategyKey: mergeStrategyKey, + ListType: listType, + ListMapKeys: listMapKeys, + } + result.Required = isRequired(name, required) + + return &result, nil +} + +// isRequired returns true if name appears in the required array +func isRequired(name string, required []string) bool { + for _, req := range required { + if req == name { + return true + } + } + return false +} + +// GetTypeNameAndKey returns the display name of a Schema. +// This is the api kind for definitions and the type for +// primitive types. +func GetTypeNameAndKey(s spec.Schema) (string, *Key) { + if isMap(s) { + typ, key := GetTypeNameAndKey(*s.AdditionalProperties.Schema) + return fmt.Sprintf("map[string]%s", typ), key + } + + // Get the reference for complex types + if isDefinition(s) { + key := Key(strings.TrimPrefix(s.SchemaProps.Ref.GetPointer().String(), "/definitions/")) + return key.ResourceName(), &key + } + + // Recurse if type is array + if isArray(s) { + typ, key := GetTypeNameAndKey(*s.Items.Schema) + return fmt.Sprintf("[]%s", typ), key + } + + // Get the value for primitive types + if len(s.Type) > 0 { + value := s.Type[0] + if len(s.Format) > 0 { + value = s.Format + if value == "byte" { + value = "[]byte" + } + } + return value, nil + } + + panic(fmt.Errorf("No type found for object %v", s)) +} + +// isDefinition returns true if Schema is a complex type that should have a Definition +func isDefinition(s spec.Schema) bool { + return len(s.SchemaProps.Ref.GetPointer().String()) > 0 +} + +// isArray returns true if the type is an array type +func isArray(s spec.Schema) bool { + return len(s.Type) > 0 && s.Type[0] == "array" +} + +func isMap(s spec.Schema) bool { + return len(s.Type) > 0 && s.Type[0] == "object" && s.AdditionalProperties != nil +} diff --git a/infra/gen-resourcesdocs/pkg/kubernetes/property_test.go b/infra/gen-resourcesdocs/pkg/kubernetes/property_test.go new file mode 100644 index 00000000..4a07b395 --- /dev/null +++ b/infra/gen-resourcesdocs/pkg/kubernetes/property_test.go @@ -0,0 +1,131 @@ +package kubernetes + +import ( + "reflect" + "testing" + + "github.com/go-openapi/jsonreference" + "github.com/go-openapi/spec" +) + +func TestIsRequired(t *testing.T) { + tests := []struct { + Name string + Required []string + Expected bool + }{ + { + Name: "found", + Required: []string{"a", "found", "c"}, + Expected: true, + }, + { + Name: "notfound", + Required: []string{"a", "b", "c"}, + }, + } + + for _, test := range tests { + result := isRequired(test.Name, test.Required) + if result != test.Expected { + t.Errorf("Should be %v but is %v", test.Expected, result) + } + } +} + +func TestGetTypeNameAndKey(t *testing.T) { + tests := []struct { + Definition spec.Schema + ExpectedName string + ExpectedKey *Key + }{ + { + Definition: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Type: spec.StringOrArray{ + "boolean", + }, + }, + }, + ExpectedName: "boolean", + ExpectedKey: nil, + }, + { + Definition: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Type: spec.StringOrArray{ + "array", + }, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Type: spec.StringOrArray{ + "string", + }, + }, + }, + }, + }, + }, + ExpectedName: "[]string", + ExpectedKey: nil, + }, + { + Definition: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Ref: spec.Ref{ + Ref: jsonreference.MustCreateRef("#/definitions/io.k8s.api.core.v1.PodSpec"), + }, + }, + }, + ExpectedName: "PodSpec", + ExpectedKey: func(k Key) *Key { return &k }("io.k8s.api.core.v1.PodSpec"), + }, + } + + for _, test := range tests { + resultName, resultKey := GetTypeNameAndKey(test.Definition) + if resultName != test.ExpectedName { + t.Errorf("Name should be %s but is %s", test.ExpectedName, resultName) + } + if !reflect.DeepEqual(resultKey, test.ExpectedKey) { + t.Errorf("Key should be %v but is %v", test.ExpectedKey, resultKey) + } + } +} + +func TestNewProperty(t *testing.T) { + tests := []struct { + Name string + Details spec.Schema + Required []string + Expected *Property + }{ + + { + Name: "onefield", + Details: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Type: spec.StringOrArray{ + "boolean", + }, + Description: "a description", + }, + }, + Required: []string{"a", "b"}, + Expected: &Property{ + Name: "onefield", + Type: "boolean", + TypeKey: nil, + Description: "a description", + }, + }, + } + + for _, test := range tests { + result, _ := NewProperty(test.Name, test.Details, test.Required) + if !reflect.DeepEqual(test.Expected, result) { + t.Errorf("Should be %#v but is %#v", test.Expected, result) + } + } +} diff --git a/infra/gen-resourcesdocs/pkg/kubernetes/resource.go b/infra/gen-resourcesdocs/pkg/kubernetes/resource.go new file mode 100644 index 00000000..7ecc242b --- /dev/null +++ b/infra/gen-resourcesdocs/pkg/kubernetes/resource.go @@ -0,0 +1,72 @@ +package kubernetes + +import ( + "fmt" + "sort" + + "github.com/go-openapi/spec" +) + +// Resource represent a Kubernetes API resource +type Resource struct { + Key Key + GVKExtension + Definition spec.Schema + + // Replaced indicates if this version is replaced by another one + ReplacedBy *Key + // Documented indicates if this resource was included in the TOC + Documented bool +} + +// LessThan returns true if 'o' is a newer version than 'p' +func (o *Resource) LessThan(p *Resource) bool { + return o.Group.Replaces(p.Group) || (o.Group == p.Group && p.Version.LessThan(&o.Version)) +} + +// Replaces returns true if 'o' replaces 'p' +func (o *Resource) Replaces(p *Resource) bool { + return o.Group.Replaces(p.Group) || o.Version.Replaces(&p.Version) +} + +// Equals returns true if a resource is referenced by group/version/kind +func (o *Resource) Equals(group APIGroup, version APIVersion, kind APIKind) bool { + return o.Group == group && o.Version.Equals(&version) && o.Kind == kind +} + +// GetGV returns the group/version of a resource (used for apiVersion:) +func (o *Resource) GetGV() string { + if o.Group == "" { + return o.Version.String() + } + return fmt.Sprintf("%s/%s", o.Group, o.Version.String()) +} + +// ResourceList is the list of resources for a given Kind +type ResourceList []*Resource + +func (a ResourceList) Len() int { return len(a) } +func (a ResourceList) Swap(i, j int) { a[i], a[j] = a[j], a[i] } +func (a ResourceList) Less(i, j int) bool { return a[i].LessThan(a[j]) } + +// ResourceMap contains a map of resources, classified by Kind +type ResourceMap map[APIKind]ResourceList + +// Add a resource to the resource list +func (o *ResourceMap) Add(resource *Resource) { + list, ok := (*o)[resource.Kind] + if ok { + for _, otherResource := range list { + if resource.Replaces(otherResource) { + otherResource.ReplacedBy = &resource.Key + } else if otherResource.Replaces(resource) { + resource.ReplacedBy = &otherResource.Key + } + } + list = append(list, resource) + } else { + list = []*Resource{resource} + } + sort.Sort(list) + (*o)[resource.Kind] = list +} diff --git a/infra/gen-resourcesdocs/pkg/kubernetes/resource_test.go b/infra/gen-resourcesdocs/pkg/kubernetes/resource_test.go new file mode 100644 index 00000000..a54b243e --- /dev/null +++ b/infra/gen-resourcesdocs/pkg/kubernetes/resource_test.go @@ -0,0 +1,235 @@ +package kubernetes_test + +import ( + "testing" + + "github.com/karmada-io/website/infra/gen-resourcesdocs/pkg/kubernetes" +) + +func TestResourceLessThan(t *testing.T) { + v1 := newAPIVersionAssert(t, "v1") + v1beta1 := newAPIVersionAssert(t, "v1beta1") + v2alpha1 := newAPIVersionAssert(t, "v2alpha1") + + tests := []struct { + R1 kubernetes.Resource + R2 kubernetes.Resource + Expected bool + }{ + // General case + { + R1: kubernetes.Resource{ + Key: "key1", + GVKExtension: kubernetes.GVKExtension{ + Group: kubernetes.APIGroup("apps"), + Version: *v1, + }, + }, + R2: kubernetes.Resource{ + Key: "key2", + GVKExtension: kubernetes.GVKExtension{ + Group: kubernetes.APIGroup("apps"), + Version: *v1beta1, + }, + }, + Expected: true, + }, + // Cronjob resource in v1.18 + { + R1: kubernetes.Resource{ + Key: "key1", + GVKExtension: kubernetes.GVKExtension{ + Group: kubernetes.APIGroup("batch"), + Version: *v2alpha1, + }, + }, + R2: kubernetes.Resource{ + Key: "key2", + GVKExtension: kubernetes.GVKExtension{ + Group: kubernetes.APIGroup("batch"), + Version: *v1beta1, + }, + }, + Expected: true, + }, + // Event resource in v1.18 + { + R1: kubernetes.Resource{ + Key: "key1", + GVKExtension: kubernetes.GVKExtension{ + Group: kubernetes.APIGroup(""), + Version: *v1, + }, + }, + R2: kubernetes.Resource{ + Key: "key2", + GVKExtension: kubernetes.GVKExtension{ + Group: kubernetes.APIGroup("events.k8s.io"), + Version: *v1, + }, + }, + Expected: false, + }, + // Ingress resource in v1.18 + { + R1: kubernetes.Resource{ + Key: "key1", + GVKExtension: kubernetes.GVKExtension{ + Group: kubernetes.APIGroup("networking.k8s.io"), + Version: *v1beta1, + }, + }, + R2: kubernetes.Resource{ + Key: "key2", + GVKExtension: kubernetes.GVKExtension{ + Group: kubernetes.APIGroup("extensions"), + Version: *v1beta1, + }, + }, + Expected: true, + }, + } + + for _, test := range tests { + result := test.R1.LessThan(&test.R2) + if result != test.Expected { + t.Errorf("%s < %s: expected %v but got %v", test.R1.GetGV(), test.R2.GetGV(), test.Expected, result) + } + } +} + +func TestResourceGetGV(t *testing.T) { + v1 := newAPIVersionAssert(t, "v1") + + tests := []struct { + Input kubernetes.Resource + Expected string + }{ + { + Input: kubernetes.Resource{ + Key: "key1", + GVKExtension: kubernetes.GVKExtension{ + Group: kubernetes.APIGroup("apps"), + Version: *v1, + }, + }, + Expected: "apps/v1", + }, + { + Input: kubernetes.Resource{ + Key: "key1", + GVKExtension: kubernetes.GVKExtension{ + Group: kubernetes.APIGroup(""), + Version: *v1, + }, + }, + Expected: "v1", + }, + { + Input: kubernetes.Resource{ + Key: "key1", + GVKExtension: kubernetes.GVKExtension{ + Group: kubernetes.APIGroup("storage.k8s.io"), + Version: *v1, + }, + }, + Expected: "storage.k8s.io/v1", + }, + } + + for _, test := range tests { + result := test.Input.GetGV() + if result != test.Expected { + t.Errorf("%#v: Expected %s but got %s", test.Input, test.Expected, result) + } + } +} + +func TestResourceAdd(t *testing.T) { + v1 := newAPIVersionAssert(t, "v1") + + resources := kubernetes.ResourceMap{} + resources.Add(&kubernetes.Resource{ + Key: "key1", + GVKExtension: kubernetes.GVKExtension{ + Group: kubernetes.APIGroup("extensions"), + Version: *v1, + Kind: kubernetes.APIKind("Kind1"), + }, + }) + resources.Add(&kubernetes.Resource{ + Key: "key1", + GVKExtension: kubernetes.GVKExtension{ + Group: kubernetes.APIGroup("apps"), + Version: *v1, + Kind: kubernetes.APIKind("Kind1"), + }, + }) + resources.Add(&kubernetes.Resource{ + Key: "key1", + GVKExtension: kubernetes.GVKExtension{ + Group: kubernetes.APIGroup("apps"), + Version: *v1, + Kind: kubernetes.APIKind("Kind2"), + }, + }) + if len(resources) != 2 { + t.Errorf("Len of resources should be %d but is %d", 2, len(resources)) + } + if _, ok := resources["Kind1"]; !ok { + t.Errorf("Key Kind1 should exist") + } + if _, ok := resources["Kind2"]; !ok { + t.Errorf("Key Kind2 should exist") + } + if len(resources["Kind1"]) != 2 { + t.Errorf("Len of versions for Kind1 should be %d but is %d", 2, len(resources["Kind1"])) + } + if len(resources["Kind2"]) != 1 { + t.Errorf("Len of versions for Kind2 should be %d but is %d", 1, len(resources["Kind2"])) + } + if resources["Kind1"][0].Group != "apps" { + t.Errorf("Recent version for Kind1 should be %s but is %s", "apps", resources["Kind1"][0].Group) + } + if resources["Kind1"][1].Group != "extensions" { + t.Errorf("Previous version for Kind1 should be %s but is %s", "extensions", resources["Kind1"][1].Group) + } +} + +func TestGoImportPrefix(t *testing.T) { + tests := []struct { + Key kubernetes.Key + Expected string + }{ + { + Key: "io.k8s.api.core.Pod", + Expected: "k8s.io/api/core", + }, + } + + for _, test := range tests { + result := test.Key.GoImportPrefix() + if result != test.Expected { + t.Errorf("%s: Expected %s but got %s", test.Key, test.Expected, result) + } + } +} + +func TestRemoveResourceName(t *testing.T) { + tests := []struct { + Key kubernetes.Key + Expected string + }{ + { + Key: "io.k8s.api.core.PodSpec", + Expected: "io.k8s.api.core", + }, + } + + for _, test := range tests { + result := test.Key.RemoveResourceName() + if result != test.Expected { + t.Errorf("%s: Expected %s but got %s", test.Key, test.Expected, result) + } + } +} diff --git a/infra/gen-resourcesdocs/pkg/kubernetes/spec.go b/infra/gen-resourcesdocs/pkg/kubernetes/spec.go new file mode 100644 index 00000000..4f02699e --- /dev/null +++ b/infra/gen-resourcesdocs/pkg/kubernetes/spec.go @@ -0,0 +1,161 @@ +package kubernetes + +import ( + "fmt" + "strings" + + "github.com/go-openapi/spec" + + "github.com/karmada-io/website/infra/gen-resourcesdocs/pkg/openapi" +) + +// Spec represents the Kubernetes API Specification +type Spec struct { + // Swagger is the openAPI representation of the k8s spec + // populated by calling getSwagger + Swagger *spec.Swagger + + // Resources is the list of K8s resources + // populated by calling getResources + Resources *ResourceMap + + // Actions is the list of endpoints defined in the API + Actions Actions + + // GVToKey maps between Kubernetes Group/Version and Swagger definition key + GVToKey GVToKeyMap +} + +// GVToKeyMap maps Kubernetes resource Group/Version with Spec Definition key (without Kind) +// e.g. GVToKey["v1"]: "io.k8s.api.core.v1" +type GVToKeyMap map[string][]string + +// Add adds a new match between key and resource GV +func (o GVToKeyMap) Add(key string, resource *Resource) { + parts := strings.Split(key, ".") + if len(parts) == 0 { + return + } + subkey := strings.Join(parts[0:len(parts)-1], ".") + gv := resource.GetGV() + if _, found := o[gv]; !found { + o[gv] = []string{subkey} + } else { + found := false + for _, k := range o[gv] { + if k == subkey { + found = true + } + } + if !found { + o[gv] = append(o[gv], subkey) + } + } +} + +// NewSpec creates a new Spec from a K8s spec file +func NewSpec(filename string) (*Spec, error) { + spec := &Spec{} + err := spec.getSwagger(filename) + if err != nil { + return nil, err + } + err = spec.getResources() + if err != nil { + return nil, err + } + + err = spec.getActions() + if err != nil { + return nil, err + } + + return spec, nil +} + +// GetSwagger populates the swagger representation of the Spec in file `filename` +func (o *Spec) getSwagger(filename string) error { + var err error + o.Swagger, err = openapi.LoadOpenAPISpec(filename) + return err +} + +// GetResources populates the resources defined in the spec +// and maps definitions keys to Resources GVs +func (o *Spec) getResources() error { + o.Resources = &ResourceMap{} + o.GVToKey = GVToKeyMap{} + + for key, definition := range o.Swagger.Definitions { + gvk, found, err := getGVKExtension(definition.Extensions) + if err != nil { + return fmt.Errorf("%s: %f", key, err) + } + if !found { + continue + } + resource := &Resource{ + Key: Key(key), + GVKExtension: *gvk, + Definition: definition, + } + o.Resources.Add(resource) + o.GVToKey.Add(key, resource) + } + return nil +} + +// GetResource returns the resource referenced by group/version/kind, or nil if not found +func (o *Spec) GetResource(group APIGroup, version APIVersion, kind APIKind, markAsDocumented bool) (Key, *spec.Schema) { + if resources, ok := (*o.Resources)[kind]; ok { + for r, resource := range resources { + if resource.Equals(group, version, kind) { + if markAsDocumented { + (*o.Resources)[kind][r].Documented = true + } + return resource.Key, &resource.Definition + } + } + } + return "", nil +} + +// GetDefinition returns the definition referenced by key +func (o *Spec) GetDefinition(key Key) *spec.Schema { + if s, found := o.Swagger.Definitions[key.String()]; found { + return &s + } + return nil +} + +func (o *Spec) getActions() error { + o.Actions = make(Actions) + + paths := o.Swagger.Paths.Paths + for key, path := range paths { + if path.Get != nil { + o.Actions.Add(o.Swagger.Parameters, key, path.Get, "GET", path.Parameters) + } + if path.Put != nil { + o.Actions.Add(o.Swagger.Parameters, key, path.Put, "PUT", path.Parameters) + } + if path.Post != nil { + o.Actions.Add(o.Swagger.Parameters, key, path.Post, "POST", path.Parameters) + } + if path.Delete != nil { + o.Actions.Add(o.Swagger.Parameters, key, path.Delete, "DELETE", path.Parameters) + } + if path.Options != nil { + o.Actions.Add(o.Swagger.Parameters, key, path.Options, "OPTIONS", path.Parameters) + } + if path.Head != nil { + o.Actions.Add(o.Swagger.Parameters, key, path.Head, "HEAD", path.Parameters) + } + if path.Patch != nil { + o.Actions.Add(o.Swagger.Parameters, key, path.Patch, "PATCH", path.Parameters) + } + } + + o.Actions.findCommonParameters() + return nil +} diff --git a/infra/gen-resourcesdocs/pkg/kubernetes/spec_test.go b/infra/gen-resourcesdocs/pkg/kubernetes/spec_test.go new file mode 100644 index 00000000..09146e86 --- /dev/null +++ b/infra/gen-resourcesdocs/pkg/kubernetes/spec_test.go @@ -0,0 +1,29 @@ +package kubernetes_test + +import ( + "testing" + + "github.com/karmada-io/website/infra/gen-resourcesdocs/pkg/kubernetes" +) + +func TestSpecV119(t *testing.T) { + spec, err := kubernetes.NewSpec("../../api/v1.19/swagger.json") + if err != nil { + t.Errorf("NewSpec should not return an errors but returns %s", err) + } + if len(*spec.Resources) != 112 { + t.Errorf("Spec should contain %d resources but contains %d", 112, len(*spec.Resources)) + } +} + +func TestGetResourceV119(t *testing.T) { + spec, err := kubernetes.NewSpec("../../api/v1.19/swagger.json") + if err != nil { + t.Errorf("NewSpec should not return an errors but returns %s", err) + } + v1 := newAPIVersionAssert(t, "v1") + _, res := spec.GetResource("", *v1, "Pod", false) + if res.Description != "Pod is a collection of containers that can run on a host. This resource is created by clients and scheduled onto hosts." { + t.Error("Error getting definition of Pod") + } +} diff --git a/infra/gen-resourcesdocs/pkg/openapi/openapi.go b/infra/gen-resourcesdocs/pkg/openapi/openapi.go new file mode 100644 index 00000000..655a148a --- /dev/null +++ b/infra/gen-resourcesdocs/pkg/openapi/openapi.go @@ -0,0 +1,15 @@ +package openapi + +import ( + "github.com/go-openapi/loads" + "github.com/go-openapi/spec" +) + +// LoadOpenAPISpec loads the open-api document +func LoadOpenAPISpec(filename string) (*spec.Swagger, error) { + d, err := loads.JSONSpec(filename) + if err != nil { + return nil, err + } + return d.Spec(), nil +} diff --git a/infra/gen-resourcesdocs/pkg/openapi/openapi_test.go b/infra/gen-resourcesdocs/pkg/openapi/openapi_test.go new file mode 100644 index 00000000..0c7c37df --- /dev/null +++ b/infra/gen-resourcesdocs/pkg/openapi/openapi_test.go @@ -0,0 +1,17 @@ +package openapi_test + +import ( + "testing" + + "github.com/karmada-io/website/infra/gen-resourcesdocs/pkg/openapi" +) + +func TestLoadOpenAPISpecV119(t *testing.T) { + spec, err := openapi.LoadOpenAPISpec("../../api/v1.19/swagger.json") + if err != nil { + t.Errorf("Failed to load spec") + } + if len(spec.Definitions) != 617 { + t.Errorf("Spec should contain %d definition but contains %d", 617, len(spec.Definitions)) + } +} diff --git a/infra/gen-resourcesdocs/pkg/outputs/interface.go b/infra/gen-resourcesdocs/pkg/outputs/interface.go new file mode 100644 index 00000000..48d7caa3 --- /dev/null +++ b/infra/gen-resourcesdocs/pkg/outputs/interface.go @@ -0,0 +1,36 @@ +package outputs + +import "github.com/karmada-io/website/infra/gen-resourcesdocs/pkg/kubernetes" + +// Output is an interface for output formats +type Output interface { + AddPart(i int, name string) (Part, error) + NewPart(i int, name string) (Part, error) + Terminate() error +} + +// Part is an interface to a part of an output +type Part interface { + AddChapter(i int, name string, gv string, version *kubernetes.APIVersion, description string, importPrefix string) (Chapter, error) +} + +// Chapter is an interface to a chapter of an output +type Chapter interface { + SetAPIVersion(s string) error + SetGoImport(s string) error + AddSection(i int, name string, apiVersion *string) (Section, error) + Write() error +} + +// Section is an interface to a section of an output +type Section interface { + AddContent(s string) error + AddTypeDefinition(typ string, description string) error + StartPropertyList() error + AddFieldCategory(name string) error + AddProperty(name string, property *kubernetes.Property, linkend []string, indent int, defname string, shortName string) error + EndProperty() error + EndPropertyList() error + AddOperation(operation *kubernetes.ActionInfo, linkends kubernetes.LinkEnds) error + AddDefinitionIndexEntry(d string) error +} diff --git a/infra/gen-resourcesdocs/pkg/outputs/kwebsite/chapter.go b/infra/gen-resourcesdocs/pkg/outputs/kwebsite/chapter.go new file mode 100644 index 00000000..6f093dd5 --- /dev/null +++ b/infra/gen-resourcesdocs/pkg/outputs/kwebsite/chapter.go @@ -0,0 +1,118 @@ +package kwebsite + +import ( + "os" + "path/filepath" + "text/template" + + "github.com/Masterminds/sprig" + + "github.com/karmada-io/website/infra/gen-resourcesdocs/pkg/outputs" +) + +// Chapter of a KWebsite output +// implements the outputs.Chapter interface +type Chapter struct { + kwebsite *KWebsite + part *Part + name string + data *ChapterData +} + +type ChapterData struct { + ApiVersion string + Version string + Import string + Kind string + Metadata ChapterMetadata + ChapterName string + Sections []SectionData +} + +type ChapterMetadata struct { + Description string + Title string + Weight int +} + +type SectionData struct { + Name string + Description string + Fields []FieldData + FieldCategories []FieldCategoryData + Operations []OperationData +} + +type FieldCategoryData struct { + Name string + Fields []FieldData +} + +type FieldData struct { + Name string + Value string + Description string + Type string + TypeDefinition string + Indent int +} + +type OperationData struct { + Verb string + Title string + RequestMethod string + RequestPath string + Parameters []ParameterData + Responses []ResponseData +} + +type ParameterData struct { + Title string + Description string +} + +type ResponseData struct { + Code int + Type string + Description string +} + +// SetAPIVersion writes the APIVersion for a chapter +func (o Chapter) SetAPIVersion(s string) error { + return nil +} + +// SetGoImport writes the Go import for a chapter +func (o Chapter) SetGoImport(s string) error { + return nil +} + +// AddSection adds a section to the chapter +func (o Chapter) AddSection(i int, name string, apiVersion *string) (outputs.Section, error) { + o.data.Sections = append(o.data.Sections, SectionData{ + Name: name, + }) + + return Section{ + kwebsite: o.kwebsite, + part: o.part, + chapter: &o, + }, nil +} + +func (o Chapter) Write() error { + chaptername := escapeName(o.data.ChapterName, o.data.Version) + filename := filepath.Join(o.kwebsite.Directory, o.part.name, chaptername) + ".md" + f, err := os.Create(filename) + if err != nil { + return err + } + defer f.Close() + + templateFile := "chapter.tmpl" + if len(o.data.Sections) == 1 { + templateFile = "chapter-single-definition.tmpl" + } + t := template.Must(template.New(templateFile).Funcs(sprig.TxtFuncMap()).ParseFiles(filepath.Join(o.kwebsite.TemplatesDir, templateFile))) + return t.Execute(f, o.data) +} diff --git a/infra/gen-resourcesdocs/pkg/outputs/kwebsite/files.go b/infra/gen-resourcesdocs/pkg/outputs/kwebsite/files.go new file mode 100644 index 00000000..36a4cb6a --- /dev/null +++ b/infra/gen-resourcesdocs/pkg/outputs/kwebsite/files.go @@ -0,0 +1,55 @@ +package kwebsite + +import ( + "os" + "path/filepath" + "strings" + "text/template" + + "github.com/stoewer/go-strcase" +) + +type PartIndex struct { + Title string + Weight int +} + +func (o *KWebsite) addPartIndex(subdir string, name string, weight int) error { + dirname := filepath.Join(o.Directory, subdir) + err := os.Mkdir(dirname, 0755) + if err != nil { + return err + } + + t := template.Must(template.ParseFiles(filepath.Join(o.TemplatesDir, "part-index.tmpl"))) + data := PartIndex{ + Title: name, + Weight: weight, + } + + filename := filepath.Join(o.Directory, subdir, "_index.md") + f, err := os.Create(filename) + if err != nil { + return err + } + defer f.Close() + + return t.Execute(f, data) +} + +// escapeName returns a name usable as file name +func escapeName(parts ...string) string { + result := []string{} + for _, s := range parts { + if s != "" { + result = append(result, strcase.KebabCase(s)) + } + } + return strings.Join(result, "-") +} + +// headingID returns the ID built by hugo for a given header +func headingID(s string) string { + result := strings.ReplaceAll(s, " ", "-") + return result +} diff --git a/infra/gen-resourcesdocs/pkg/outputs/kwebsite/kwebsite.go b/infra/gen-resourcesdocs/pkg/outputs/kwebsite/kwebsite.go new file mode 100644 index 00000000..290bc8d5 --- /dev/null +++ b/infra/gen-resourcesdocs/pkg/outputs/kwebsite/kwebsite.go @@ -0,0 +1,53 @@ +package kwebsite + +import ( + "fmt" + "os" + "path/filepath" + + "github.com/karmada-io/website/infra/gen-resourcesdocs/pkg/outputs" +) + +// KWebsite output +// implements the Output interface +type KWebsite struct { + Directory string + TemplatesDir string +} + +// NewKWebsite returns a new KWebsite +func NewKWebsite(dir string, templatesDir string) *KWebsite { + return &KWebsite{Directory: dir, TemplatesDir: templatesDir} +} + +// NewPart creates a new part for the output +func (o *KWebsite) NewPart(i int, name string) (outputs.Part, error) { + partname := escapeName(name) + dirname := filepath.Join(o.Directory, partname) + err := os.Mkdir(dirname, 0755) + if err != nil { + return nil, err + } + return Part{ + kwebsite: o, + name: partname, + }, nil +} + +// AddPart adds a part to the output +func (o *KWebsite) AddPart(i int, name string) (outputs.Part, error) { + partname := escapeName(name) + err := o.addPartIndex(partname, name, i+1) + if err != nil { + return Part{}, fmt.Errorf("Error writing index file for part %s: %s", name, err) + } + return Part{ + kwebsite: o, + name: partname, + }, nil +} + +// Terminate kwebsite document +func (o *KWebsite) Terminate() error { + return nil +} diff --git a/infra/gen-resourcesdocs/pkg/outputs/kwebsite/links.go b/infra/gen-resourcesdocs/pkg/outputs/kwebsite/links.go new file mode 100644 index 00000000..8b68e5e7 --- /dev/null +++ b/infra/gen-resourcesdocs/pkg/outputs/kwebsite/links.go @@ -0,0 +1,26 @@ +package kwebsite + +import ( + "fmt" + "strings" +) + +// LinkEnd returns a link to a section in a part/chapter +// s is an array containing partname / chaptername +func (o *KWebsite) LinkEnd(s []string, name string) string { + typename := name + mapprefix := "" + array := "" + + if strings.HasPrefix(typename, "map[string]") { + mapprefix = "map[string]" + typename = strings.TrimPrefix(name, mapprefix) + } + + if strings.HasPrefix(typename, "[]") { + array = "[]" + typename = strings.TrimPrefix(name, array) + } + + return fmt.Sprintf("%s%s[%s](../%s/%s#%s)", mapprefix, array, typename, escapeName(s[0]), escapeName(s[1]), strings.ToLower(headingID(typename))) +} diff --git a/infra/gen-resourcesdocs/pkg/outputs/kwebsite/part.go b/infra/gen-resourcesdocs/pkg/outputs/kwebsite/part.go new file mode 100644 index 00000000..feca98c6 --- /dev/null +++ b/infra/gen-resourcesdocs/pkg/outputs/kwebsite/part.go @@ -0,0 +1,41 @@ +package kwebsite + +import ( + "github.com/karmada-io/website/infra/gen-resourcesdocs/pkg/kubernetes" + "github.com/karmada-io/website/infra/gen-resourcesdocs/pkg/outputs" +) + +// Part of a KWebsite output +// implements the outputs.Part interface +type Part struct { + kwebsite *KWebsite + name string +} + +// AddChapter adds a chapter to the Part +func (o Part) AddChapter(i int, name string, gv string, version *kubernetes.APIVersion, description string, importPrefix string) (outputs.Chapter, error) { + title := name + if version != nil && version.Stage != kubernetes.StageGA { + title += " " + version.String() + } + chaptername := escapeName(name, version.String()) + data := ChapterData{ + ApiVersion: gv, + Version: version.String(), + Import: importPrefix, + Kind: name, + Metadata: ChapterMetadata{ + Description: description, + Title: title, + Weight: i + 1, + }, + ChapterName: name, + } + + return Chapter{ + kwebsite: o.kwebsite, + part: &o, + name: chaptername, + data: &data, + }, nil +} diff --git a/infra/gen-resourcesdocs/pkg/outputs/kwebsite/section.go b/infra/gen-resourcesdocs/pkg/outputs/kwebsite/section.go new file mode 100644 index 00000000..bd4d2d1a --- /dev/null +++ b/infra/gen-resourcesdocs/pkg/outputs/kwebsite/section.go @@ -0,0 +1,247 @@ +package kwebsite + +import ( + "fmt" + "sort" + "strings" + + "github.com/karmada-io/website/infra/gen-resourcesdocs/pkg/kubernetes" +) + +// Section of a Hugo output +// implements the outputs.Section interface +type Section struct { + kwebsite *KWebsite + part *Part + chapter *Chapter +} + +// AddContent adds content to a section +func (o Section) AddContent(s string) error { + i := len(o.chapter.data.Sections) + o.chapter.data.Sections[i-1].Description = s + return nil +} + +// AddTypeDefinition adds the definition of a type to a section +func (o Section) AddTypeDefinition(typ string, description string) error { + i := len(o.chapter.data.Sections) + cats := o.chapter.data.Sections[i-1].FieldCategories + var fields *[]FieldData + if len(cats) == 0 { + fields = &o.chapter.data.Sections[i-1].Fields + } else { + fields = &cats[len(cats)-1].Fields + } + j := len(*fields) + (*fields)[j-1].Type = typ + (*fields)[j-1].TypeDefinition = "*" + description + "*" + return nil +} + +// StartPropertyList starts the list of properties +func (o Section) StartPropertyList() error { + return nil +} + +func (o Section) AddFieldCategory(name string) error { + i := len(o.chapter.data.Sections) + o.chapter.data.Sections[i-1].FieldCategories = append(o.chapter.data.Sections[i-1].FieldCategories, FieldCategoryData{ + Name: name, + }) + return nil +} + +// AddProperty adds a property to the section +func (o Section) AddProperty(name string, property *kubernetes.Property, linkend []string, indent int, defname string, shortName string) error { + if property.HardCodedValue != nil { + i := len(o.chapter.data.Sections) + cats := o.chapter.data.Sections[i-1].FieldCategories + var fields *[]FieldData + if len(cats) == 0 { + fields = &o.chapter.data.Sections[i-1].Fields + } else { + fields = &cats[len(cats)-1].Fields + } + *fields = append(*fields, FieldData{ + Name: "**" + name + "**", + Value: *property.HardCodedValue, + Indent: 0, + }) + return nil + } + + required := "" + if property.Required { + required = ", required" + } + + typ := property.Type + if property.TypeKey != nil && len(linkend) > 0 { + typ = o.kwebsite.LinkEnd(linkend, property.Type) + } + title := fmt.Sprintf("**%s** (%s)%s", name, typ, required) + + description := property.Description + + listType := "" + if property.ListType != nil { + if *property.ListType == "atomic" { + listType = "Atomic: will be replaced during a merge" + } else if *property.ListType == "set" { + listType = "Set: unique values will be kept during a merge" + } else if *property.ListType == "map" { + if len(property.ListMapKeys) == 1 { + listType = "Map: unique values on key " + property.ListMapKeys[0] + " will be kept during a merge" + } else { + listType = "Map: unique values on keys `" + strings.Join(property.ListMapKeys, ", ") + "` will be kept during a merge" + } + } + } + if len(listType) > 0 { + description = "*" + listType + "*\n\n" + description + } + + var patches string + if property.MergeStrategyKey != nil && property.RetainKeysStrategy { + patches = fmt.Sprintf("Patch strategies: retainKeys, merge on key `%s`", *property.MergeStrategyKey) + } else if property.MergeStrategyKey != nil { + patches = fmt.Sprintf("Patch strategy: merge on key `%s`", *property.MergeStrategyKey) + } else if property.RetainKeysStrategy { + patches = "Patch strategy: retainKeys" + } + + if len(patches) > 0 { + description = "*" + patches + "*\n\n" + description + } + + i := len(o.chapter.data.Sections) + cats := o.chapter.data.Sections[i-1].FieldCategories + var fields *[]FieldData + if len(cats) == 0 { + fields = &o.chapter.data.Sections[i-1].Fields + } else { + fields = &cats[len(cats)-1].Fields + } + *fields = append(*fields, FieldData{ + Name: title, + Description: description, + Indent: indent, + }) + if indent > 3 { + fmt.Printf("Warning: %s/%s indentation is %d\n", o.chapter.name, name, indent) + } + return nil +} + +// EndProperty ends a property +func (o Section) EndProperty() error { + return nil +} + +// EndPropertyList ends the list of properties +func (o Section) EndPropertyList() error { + return nil +} + +// AddOperation adds an operation +func (o Section) AddOperation(operation *kubernetes.ActionInfo, linkends kubernetes.LinkEnds) error { + sentences := strings.Split(operation.Operation.Description, ".") + + if len(sentences) > 1 { + fmt.Printf("SHOULD NOT HAPPEN, sentences: %d\n", len(sentences)) + } + + dataParams := []ParameterData{} + for _, param := range operation.Parameters { + + required := "" + if param.Required { + required = ", required" + } + + typ := param.Type + if param.Schema != nil { + t, typeKey := kubernetes.GetTypeNameAndKey(*param.Schema) + linkend, found := linkends[*typeKey] + if found { + typ = o.kwebsite.LinkEnd(linkend, t) + } else { + typ = t + fmt.Printf("SHOULD NOT HAPPEN: %s\n", typeKey) + } + } + + desc := param.Description + if len(desc) > 0 && kubernetes.ParameterInAnnex(param) { + desc = o.kwebsite.LinkEnd([]string{"common-parameters", "common-parameters"}, param.Name) + } + + dataParams = append(dataParams, ParameterData{ + Title: paramName(param.Name, param.In) + ": " + typ + required, + Description: desc, + }) + } + + codes := make([]int, len(operation.Operation.Responses.StatusCodeResponses)) + i := 0 + for code := range operation.Operation.Responses.StatusCodeResponses { + codes[i] = code + i++ + } + sort.Ints(codes) + responsesData := []ResponseData{} + for _, code := range codes { + response := operation.Operation.Responses.StatusCodeResponses[code] + + typ := "" + if response.Schema != nil { + t, typeKey := kubernetes.GetTypeNameAndKey(*response.Schema) + if typeKey != nil { + linkend, found := linkends[*typeKey] + if found { + typ = o.kwebsite.LinkEnd(linkend, t) + } else { + typ = t + fmt.Printf("SHOULD NOT HAPPEN: %s\n", typeKey) + } + } else { + typ = t + } + } + + responsesData = append(responsesData, ResponseData{ + Code: code, + Type: typ, + Description: response.Description, + }) + } + + i = len(o.chapter.data.Sections) + ops := &o.chapter.data.Sections[i-1].Operations + *ops = append(*ops, OperationData{ + Verb: operation.Action.Verb(), + Title: sentences[0], + RequestMethod: operation.HTTPMethod, + RequestPath: operation.Path.String(), + Parameters: dataParams, + Responses: responsesData, + }) + + return nil +} + +func (o Section) AddDefinitionIndexEntry(d string) error { + return nil +} + +func paramName(s string, in string) string { + switch in { + case "path": + return fmt.Sprintf("**%s** (*in path*)", s) + case "query": + return fmt.Sprintf("**%s** (*in query*)", s) + default: + return fmt.Sprintf("**%s**", s) + } +} diff --git a/infra/gen-resourcesdocs/templates/chapter-single-definition.tmpl b/infra/gen-resourcesdocs/templates/chapter-single-definition.tmpl new file mode 100644 index 00000000..ab75c35d --- /dev/null +++ b/infra/gen-resourcesdocs/templates/chapter-single-definition.tmpl @@ -0,0 +1,78 @@ +--- +api_metadata: + apiVersion: "{{.ApiVersion}}" + import: "{{.Import}}" + kind: "{{.Kind}}" +content_type: "api_reference" +description: "{{.Metadata.Description}}" +title: "{{.Metadata.Title}}" +weight: {{.Metadata.Weight}} +auto_generated: true +--- + +[//]: # (The file is auto-generated from the Go source code of the component using a generic generator,) +[//]: # (which is forked from [reference-docs](https://github.com/kubernetes-sigs/reference-docs.) +[//]: # (To update the reference content, please follow the `reference-api.sh`.) + +{{if .ApiVersion}}`apiVersion: {{.ApiVersion}}`{{end}} + +{{if .Import}}`import "{{.Import}}"`{{end}} + +{{range .Sections}} +{{.Description | replace "<" "\\<" }} + +
+{{range .Fields}} +{{ "" | indent .Indent | indent .Indent}}- {{.Name}}{{if .Value}}: {{.Value}}{{end}} +{{if .Description}} +{{.Description | replace "<" "\\<" | indent 2 | indent .Indent | indent .Indent}} +{{- end}} +{{if .TypeDefinition}} +{{ "" | indent .Indent | indent .Indent}} + +{{.TypeDefinition | indent 2 | indent .Indent | indent .Indent}} +{{end}} +{{- end}}{{/* range .Fields */}} + +{{range .FieldCategories}} +### {{.Name}} {{/* explicitly set fragment to keep capitalization */}} + +{{range .Fields}} +{{ "" | indent .Indent | indent .Indent}}- {{.Name}}{{if .Value}}: {{.Value}}{{end}} +{{if .Description}} +{{.Description | replace "<" "\\<" | indent 2 | indent .Indent | indent .Indent}} +{{- end}} +{{if .TypeDefinition}} +{{ "" | indent .Indent | indent .Indent}} + +{{.TypeDefinition | indent 2 | indent .Indent | indent .Indent}} +{{end}} +{{- end}}{{/* range .Fields */}} + +{{- end}}{{/* range .FieldCategories */}} + +{{range .Operations}} + +### `{{.Verb}}` {{.Title}} + +#### HTTP Request + +{{.RequestMethod}} {{.RequestPath}} + +#### Parameters + +{{range .Parameters}} +- {{.Title}} + +{{.Description | indent 2}} + +{{end}}{{/* range .Parameters */}} + +#### Response + +{{range .Responses}} +{{.Code}}{{if .Type}} ({{.Type}}){{end}}: {{.Description}} +{{end}}{{/* range .Responses */}} + +{{- end}}{{/* range .Operations */}} +{{- end}}{{/* range .Sections */}} diff --git a/infra/gen-resourcesdocs/templates/chapter.tmpl b/infra/gen-resourcesdocs/templates/chapter.tmpl new file mode 100644 index 00000000..2f2f216f --- /dev/null +++ b/infra/gen-resourcesdocs/templates/chapter.tmpl @@ -0,0 +1,80 @@ +--- +api_metadata: + apiVersion: "{{.ApiVersion}}" + import: "{{.Import}}" + kind: "{{.Kind}}" +content_type: "api_reference" +description: "{{.Metadata.Description}}" +title: "{{.Metadata.Title}}" +weight: {{.Metadata.Weight}} +auto_generated: true +--- + +[//]: # (The file is auto-generated from the Go source code of the component using a generic generator,) +[//]: # (which is forked from [reference-docs](https://github.com/kubernetes-sigs/reference-docs.) +[//]: # (To update the reference content, please follow the `reference-api.sh`.) + +{{if .ApiVersion}}`apiVersion: {{.ApiVersion}}`{{end}} + +{{if .Import}}`import "{{.Import}}"`{{end}} + +{{range .Sections}} +## {{.Name}} {{/* explicitly set fragment to keep capitalization */}} + +{{.Description | replace "<" "\\<" }} + +
+{{range .Fields}} +{{ "" | indent .Indent | indent .Indent}}- {{.Name}}{{if .Value}}: {{.Value}}{{end}} +{{if .Description}} +{{.Description | replace "<" "\\<" | indent 2 | indent .Indent | indent .Indent}} +{{- end}} +{{if .TypeDefinition}} +{{ "" | indent .Indent | indent .Indent}} + +{{.TypeDefinition | indent 2 | indent .Indent | indent .Indent}} +{{end}} +{{- end}}{{/* range .Fields */}} + +{{range .FieldCategories}} +### {{.Name}} + +{{range .Fields}} +{{ "" | indent .Indent | indent .Indent}}- {{.Name}}{{if .Value}}: {{.Value}}{{end}} +{{if .Description}} +{{.Description | replace "<" "\\<" | indent 2 | indent .Indent | indent .Indent}} +{{- end}} +{{if .TypeDefinition}} +{{ "" | indent .Indent | indent .Indent}} + +{{.TypeDefinition | indent 2 | indent .Indent | indent .Indent}} +{{end}} +{{- end}}{{/* range .Fields */}} + +{{- end}}{{/* range .FieldCategories */}} + +{{range .Operations}} + +### `{{.Verb}}` {{.Title}} + +#### HTTP Request + +{{.RequestMethod}} {{.RequestPath}} + +#### Parameters + +{{range .Parameters}} +- {{.Title}} + +{{.Description | indent 2}} + +{{end}}{{/* range .Parameters */}} + +#### Response + +{{range .Responses}} +{{.Code}}{{if .Type}} ({{.Type}}){{end}}: {{.Description}} +{{end}}{{/* range .Responses */}} + +{{- end}}{{/* range .Operations */}} +{{- end}}{{/* range .Sections */}} diff --git a/infra/gen-resourcesdocs/templates/part-index.tmpl b/infra/gen-resourcesdocs/templates/part-index.tmpl new file mode 100644 index 00000000..d43787c0 --- /dev/null +++ b/infra/gen-resourcesdocs/templates/part-index.tmpl @@ -0,0 +1,9 @@ +--- +title: "{{.Title}}" +weight: {{.Weight}} +auto_generated: true +--- + +[//]: # (The file is auto-generated from the Go source code of the component using a generic generator,) +[//]: # (which is forked from [reference-docs](https://github.com/kubernetes-sigs/reference-docs.) +[//]: # (To update the reference content, please follow the `reference-api.sh`.) diff --git a/versioned_docs/version-v1.13/reference/karmada-api/policy-resources/cluster-propagation-policy-v1alpha1.md b/versioned_docs/version-v1.13/reference/karmada-api/policy-resources/cluster-propagation-policy-v1alpha1.md index a9407b9b..24b5c762 100644 --- a/versioned_docs/version-v1.13/reference/karmada-api/policy-resources/cluster-propagation-policy-v1alpha1.md +++ b/versioned_docs/version-v1.13/reference/karmada-api/policy-resources/cluster-propagation-policy-v1alpha1.md @@ -438,11 +438,9 @@ ClusterPropagationPolicy represents the cluster-wide policy that propagates a gr Behavior of PriorityClassName: - For KubePriorityClass: - When specified: Uses the named Kubernetes PriorityClass. - When empty: Uses the cluster's default PriorityClass (i.e., the PriorityClass marked as the global default in the cluster). - If neither exists: Sets priority=0 and preemptionPolicy=Never. + For KubePriorityClass: - When specified: Uses the named Kubernetes PriorityClass. - For PodPriorityClass: - Uses PriorityClassName from the PodTemplate. - If the specified PriorityClass is not found, falls back to the cluster's default PriorityClass - (i.e., the PriorityClass marked as the global default in the cluster). - - If no valid PriorityClass is found: Sets priority=0 and preemptionPolicy=Never. - Not yet implemented. + For PodPriorityClass: - Uses PriorityClassName from the PodTemplate. - Not yet implemented. For FederatedPriorityClass: - Not yet implemented. diff --git a/versioned_docs/version-v1.13/reference/karmada-api/policy-resources/propagation-policy-v1alpha1.md b/versioned_docs/version-v1.13/reference/karmada-api/policy-resources/propagation-policy-v1alpha1.md index ec178c11..410fb152 100644 --- a/versioned_docs/version-v1.13/reference/karmada-api/policy-resources/propagation-policy-v1alpha1.md +++ b/versioned_docs/version-v1.13/reference/karmada-api/policy-resources/propagation-policy-v1alpha1.md @@ -438,11 +438,9 @@ PropagationPolicy represents the policy that propagates a group of resources to Behavior of PriorityClassName: - For KubePriorityClass: - When specified: Uses the named Kubernetes PriorityClass. - When empty: Uses the cluster's default PriorityClass (i.e., the PriorityClass marked as the global default in the cluster). - If neither exists: Sets priority=0 and preemptionPolicy=Never. + For KubePriorityClass: - When specified: Uses the named Kubernetes PriorityClass. - For PodPriorityClass: - Uses PriorityClassName from the PodTemplate. - If the specified PriorityClass is not found, falls back to the cluster's default PriorityClass - (i.e., the PriorityClass marked as the global default in the cluster). - - If no valid PriorityClass is found: Sets priority=0 and preemptionPolicy=Never. - Not yet implemented. + For PodPriorityClass: - Uses PriorityClassName from the PodTemplate. - Not yet implemented. For FederatedPriorityClass: - Not yet implemented. From 4e5887a4c28ebe34c66511760e098dbb5adaecfc Mon Sep 17 00:00:00 2001 From: RainbowMango Date: Tue, 18 Mar 2025 17:57:40 +0800 Subject: [PATCH 02/15] Explain the difference between Push and Pull mode in details Signed-off-by: RainbowMango --- .../clustermanager/cluster-registration.md | 35 ++++++++++++++++--- .../clustermanager/cluster-registration.md | 35 ++++++++++++------- 2 files changed, 52 insertions(+), 18 deletions(-) diff --git a/docs/userguide/clustermanager/cluster-registration.md b/docs/userguide/clustermanager/cluster-registration.md index 6d91b6cd..cfa9325c 100644 --- a/docs/userguide/clustermanager/cluster-registration.md +++ b/docs/userguide/clustermanager/cluster-registration.md @@ -4,19 +4,44 @@ title: Cluster Registration ## Overview of cluster mode -Karmada supports both `Push` and `Pull` modes to manage the member clusters. -The main difference between `Push` and `Pull` modes is the way they access member clusters when deploying manifests. +Karmada supports both `Push` and `Pull` modes to manage the member clusters. The main difference between the +two modes is the way the Karmada control plane accesses member clusters when deploying manifests, fetching manifests +status and cluster status. The two modes fit different network and operational requirements, balancing simplicity, +scalability, and flexibility. ### Push mode -Karmada control plane will access member cluster's `kube-apiserver` directly to get cluster status and deploy manifests. + +In Push Mode, the Karmada control plane directly manages member clusters by establishing connections to their +kube-apiservers, pushing resources to member clusters, monitoring member cluster status, fetching resources +status, and so on. + +This mode is suitable for scenarios where the Karmada control plane can access member clusters directly (or +indirectly via a proxy) with low network latency, such as managing clusters within the same data center. ### Pull mode -Karmada control plane will not access member cluster but delegate it to an extra component named `karmada-agent`. + +In Pull mode, member clusters use the [karmada-agent](https://karmada.io/docs/core-concepts/components#karmada-agent) +component to pull manifests from the Karmada control plane and report the status of manifests and member +cluster status. Each `karmada-agent` serves a cluster and takes responsibility for: - Registering cluster to Karmada (creates the `Cluster` object) - Maintaining cluster status and reporting to Karmada (updates the status of `Cluster` object) -- Watching manifests from Karmada execution space (namespace, `karmada-es-`) and deploying the watched resources to the cluster the agent serves. +- Watching manifests from Karmada execution space (namespace, `karmada-es-`) and deploying the + watched resources to the cluster the agent serves. + +This mode requires deploying a `karmada-agent` component for each member cluster (it can be deployed anywhere +as long as it can access both the member cluster and the Karmada control plane). Compared to Push mode, it +introduces additional operational overhead but offers better performance because the `karmada-agent` offloads +part of the pressure from the Karmada control plane. It is particularly suited for special network environments, +such as when member clusters are behind NAT or gateways and the Karmada control plane cannot directly access +them or want to manage large-scale clusters. + +Note that in most cases, Karmada does not require direct access to member clusters. However, certain advanced +features, such as [Aggregated Kubernetes API Endpoint](https://karmada.io/docs/userguide/globalview/aggregated-api-endpoint/) +, [Proxy Global Resources](https://karmada.io/docs/userguide/globalview/proxy-global-resource/), the Karmada +control plane still needs to access member clusters. In such a case, users can configure `karmada-agent` by +providing the access endpoints of the member clusters when registering them, otherwise these functions will be restricted. ## Register cluster with 'Push' mode diff --git a/i18n/zh/docusaurus-plugin-content-docs/current/userguide/clustermanager/cluster-registration.md b/i18n/zh/docusaurus-plugin-content-docs/current/userguide/clustermanager/cluster-registration.md index 1132ced1..a9b8584a 100644 --- a/i18n/zh/docusaurus-plugin-content-docs/current/userguide/clustermanager/cluster-registration.md +++ b/i18n/zh/docusaurus-plugin-content-docs/current/userguide/clustermanager/cluster-registration.md @@ -4,19 +4,28 @@ title: 集群注册 ## 集群模式概述 -Karmada 支持通过 `Push` 和 `Pull` 两种模式来管理成员集群。 -`Push` 和 `Pull` 模式的主要区别在于部署资源清单时,访问成员集群的方式。 +Karmada 支持通过 `Push` 和 `Pull` 两种模式来管理成员集群。 二者的核心区别在于 Karmada 控制面访问成员集群的方式,包括部署资源、 +获取资源状态和集群健康状态等操作。两种模式适用于不同的网络环境和运维需求,在简单性、扩展性和灵活性之间实现平衡。 ### Push 模式 -Karmada 控制平面将直接访问成员集群的 `kube-apiserver`,以获取集群状态并部署资源清单。 +在 Push 模式下,Karmada 控制面通过直接连接成员集群的 kube-apiserver 以进行推送资源至成员集群、监控成员集群状态、获取资源状态等。 +此模式适用于 Karmada 控制面可直接访问成员集群(或通过代理间接访问)且网络延迟较低的场景,例如同一数据中心内的集群管理。 ### Pull 模式 -Karmada 控制平面不会直接访问成员集群,而是将其请求下放给名为 `karmada-agent` 的额外组件处理。 +在 Pull 模式下,成员集群通过部署的 [karmada-agent](https://karmada.io/docs/core-concepts/components#karmada-agent) 组件 +从 Karmada 控制面拉取清单,并向控制面报告清单状态和集群状态。 -每个 `karmada-agent` 服务于一个集群,并承担以下职责: -- 将集群注册到 Karmada 中(创建 `Cluster` 对象) -- 维护集群状态并向 Karmada 报告(更新 `Cluster` 对象的状态) -- 监听来自 Karmada 执行空间(命名空间,格式为 `karmada-es-`)的资源清单,并将监听到的资源部署到其所服务的集群中。 +每个 `karmada-agent` 对应一个集群,其职责包括: +- 向 Karmada 控制面注册集群(创建 Cluster 对象) +- 维护集群状态并上报给 Karmada 控制面(更新 Cluster 对象状态) +- 监控 Karmada 执行空间(命名空间 karmada-es-<集群名称>)中的清单,并将这些资源部署到其所服务的集群。 +此模式需要为每个成员集群部署一个 `karmada-agent` 组件(部署位置需能同时访问成员集群和 Karmada 控制面)。相比 Push 模式,Pull 模式 +引入了额外的运维开销,但因为 `karmada-agent` 分担了控制面的压力,性能更优。它特别适用于特殊的网络环境,比如成员集群位于 NAT 或网关后方, +Karmada 控制面无法直接访问,或者需要管理超大规模集群。 + +需要说明的是,该模式大多数情况下,Karmada 无需直接访问成员集群。但某些高级功能,比如 [Aggregated Kubernetes API Endpoint](https://karmada.io/docs/userguide/globalview/aggregated-api-endpoint/) +和 [Proxy Global Resources](https://karmada.io/docs/userguide/globalview/proxy-global-resource/),仍需要控制面直接访问 +成员集群。此时,用户需要通过 `karmada-agent` 在注册集群时提供成员集群的访问入口,否则这些功能将受限。 ## 使用 'Push' 模式注册集群 @@ -67,14 +76,14 @@ karmadactl unjoin member1 --kubeconfig= --cluster-kubeconfig ### 通过命令行工具注册集群 -`karmadactl register` 命令用于以 PULL 模式将成员集群注册到 Karmada 控制平面。 -与采用 `Push` 模式注册集群的 `karmadactl join` 命令不同,`karmadactl register` 以 `Pull` 模式将集群注册到 Karmada 控制平面。 +`karmadactl register` 命令用于以 PULL 模式将成员集群注册到 Karmada 控制面。 +与采用 `Push` 模式注册集群的 `karmadactl join` 命令不同,`karmadactl register` 以 `Pull` 模式将集群注册到 Karmada 控制面。 > 注意: 使用此功能需要在 Karmada 控制面部署 ConfigMap `kube-public/cluster-info` 来暴露成员集群可访问的 Karmada Apiserver Server 以及根 CA。 -#### 在 Karmada 控制平面中创建引导令牌 +#### 在 Karmada 控制面中创建引导令牌 -在 Karmada 控制平面中,我们可以使用 `karmadactl token create` 命令来创建引导令牌(bootstrap tokens),这些令牌的默认有效期(TTL)为24小时。 +在 Karmada 控制面中,我们可以使用 `karmadactl token create` 命令来创建引导令牌(bootstrap tokens),这些令牌的默认有效期(TTL)为24小时。 ```bash karmadactl token create --print-register-command --kubeconfig /etc/karmada/karmada-apiserver.config @@ -90,7 +99,7 @@ karmadactl register 10.10.x.x:32443 --token t2jgtm.9nybj0526mjw1jbf --discovery- #### 在成员集群中执行 `karmadactl register` -在成员集群的 Kubernetes 控制平面中,我们同样需要成员集群的 `kubeconfig` 文件。紧接着,我们需要执行上述提供的 `karmadactl register` 命令的输出内容。 +在成员集群的 Kubernetes 控制面中,我们同样需要成员集群的 `kubeconfig` 文件。紧接着,我们需要执行上述提供的 `karmadactl register` 命令的输出内容。 ```bash karmadactl register 10.10.x.x:32443 --token t2jgtm.9nybj0526mjw1jbf --discovery-token-ca-cert-hash sha256:f5a5a43869bb44577dba582e794c3e3750f2050d62f1b1dc80fd3d6a371b6ed4 From 0003e8eab74ff8e1c4e9e16aca9d34f91928e13c Mon Sep 17 00:00:00 2001 From: Arhell Date: Wed, 19 Mar 2025 10:42:04 +0200 Subject: [PATCH 03/15] update semi-ui Signed-off-by: Arhell --- package-lock.json | 150 +++++++++++++++++++++++----------------------- package.json | 6 +- 2 files changed, 78 insertions(+), 78 deletions(-) diff --git a/package-lock.json b/package-lock.json index 5c647948..95e54f2f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -14,7 +14,7 @@ "@docusaurus/plugin-content-pages": "^2.4.3", "@docusaurus/plugin-sitemap": "^2.4.3", "@docusaurus/preset-classic": "2.4.3", - "@douyinfe/semi-ui": "^2.76.0", + "@douyinfe/semi-ui": "^2.76.1", "asciinema-player": "^3.9.0", "clsx": "^2.1.1", "react": "^17.0.2", @@ -2764,35 +2764,35 @@ } }, "node_modules/@douyinfe/semi-animation": { - "version": "2.76.0", - "resolved": "https://registry.npmjs.org/@douyinfe/semi-animation/-/semi-animation-2.76.0.tgz", - "integrity": "sha512-h6cTNik/9URcLK/brTGVADdibDV7OjQMUj3z+x1f7R9g5Vg21a2wvDV7ii3w7ofajtPxfSiHLahZXIMDcDgcqQ==", + "version": "2.76.1", + "resolved": "https://registry.npmjs.org/@douyinfe/semi-animation/-/semi-animation-2.76.1.tgz", + "integrity": "sha512-8ghwnFe5Iq/xYd1hnA0/efesrAspdGiSgIjl1C8x2y1LjUWwlNjTwhhTTI1TPaJTT41m5YpWbp0G+Eg1syVq7A==", "dependencies": { "bezier-easing": "^2.1.0" } }, "node_modules/@douyinfe/semi-animation-react": { - "version": "2.76.0", - "resolved": "https://registry.npmjs.org/@douyinfe/semi-animation-react/-/semi-animation-react-2.76.0.tgz", - "integrity": "sha512-zxLlagOkGBXRLJSqa3ewPb4/cRHX51W2jL3mY2ajOmNVBdP7VX1XjCy7On4t+R04GtUq2C6FHDs6g/5uY8mGSw==", + "version": "2.76.1", + "resolved": "https://registry.npmjs.org/@douyinfe/semi-animation-react/-/semi-animation-react-2.76.1.tgz", + "integrity": "sha512-Cyu3ZhiE5qyvY+9yRBHg8pHL8Tkq7bR304TWGowz7r65F1viV+88NpDdx7f2foGIxyGjIS7IOa6EFJtV/9pu/w==", "dependencies": { - "@douyinfe/semi-animation": "2.76.0", - "@douyinfe/semi-animation-styled": "2.76.0", + "@douyinfe/semi-animation": "2.76.1", + "@douyinfe/semi-animation-styled": "2.76.1", "classnames": "^2.2.6" } }, "node_modules/@douyinfe/semi-animation-styled": { - "version": "2.76.0", - "resolved": "https://registry.npmjs.org/@douyinfe/semi-animation-styled/-/semi-animation-styled-2.76.0.tgz", - "integrity": "sha512-p9GTrcL6F4p1matKATPyDo+YDpeAql0KoZnbZVoGN7hsu56fMpmIHY8qnlSQ6R+4wwYO8N+9iuXnVj6ygpAN1A==" + "version": "2.76.1", + "resolved": "https://registry.npmjs.org/@douyinfe/semi-animation-styled/-/semi-animation-styled-2.76.1.tgz", + "integrity": "sha512-Rm8DX5uYHkJnuRab2nYydu4E7zPFuBZK0Qr/xrcA89lM/J+5XnmOA7NlaIxUoN37lwRxErNr0Vljs3RhMPfsMw==" }, "node_modules/@douyinfe/semi-foundation": { - "version": "2.76.0", - "resolved": "https://registry.npmjs.org/@douyinfe/semi-foundation/-/semi-foundation-2.76.0.tgz", - "integrity": "sha512-5rgTfFiohyLQOF9eO7GIDu7yGRmsVQGjKpy8q7S6dVS+WS2UmzP8ni95sLjSpslsmmk01s9fNoTdCtLCdZkr7Q==", + "version": "2.76.1", + "resolved": "https://registry.npmjs.org/@douyinfe/semi-foundation/-/semi-foundation-2.76.1.tgz", + "integrity": "sha512-u9KGP6p5N/KCa6EHZolSZ2OVpKAjdDJ0tV9HcW4DGYb/rHaq2rFQlITO47mbKx24dsflOuwjyTCsyYlFXYTwqw==", "dependencies": { - "@douyinfe/semi-animation": "2.76.0", - "@douyinfe/semi-json-viewer-core": "2.76.0", + "@douyinfe/semi-animation": "2.76.1", + "@douyinfe/semi-json-viewer-core": "2.76.1", "@mdx-js/mdx": "^3.0.1", "async-validator": "^3.5.0", "classnames": "^2.2.6", @@ -3033,9 +3033,9 @@ } }, "node_modules/@douyinfe/semi-icons": { - "version": "2.76.0", - "resolved": "https://registry.npmjs.org/@douyinfe/semi-icons/-/semi-icons-2.76.0.tgz", - "integrity": "sha512-drDf+Pq8PD7320wCBHGWaQYbYhCcUCT3IzdVHLHtMTN860L8Yr9cwP5RGlBuuYoxaeY1yjkWfcX6qmVmuET1kA==", + "version": "2.76.1", + "resolved": "https://registry.npmjs.org/@douyinfe/semi-icons/-/semi-icons-2.76.1.tgz", + "integrity": "sha512-3eK4fdIjwhA4w8ez7FOkI+FCTNwd3qMKqIHvlngtR7/NboMkwDugDimejJoABChLB3ZgosmnF/FjYnq/n8dSPw==", "dependencies": { "classnames": "^2.2.6" }, @@ -3044,40 +3044,40 @@ } }, "node_modules/@douyinfe/semi-illustrations": { - "version": "2.76.0", - "resolved": "https://registry.npmjs.org/@douyinfe/semi-illustrations/-/semi-illustrations-2.76.0.tgz", - "integrity": "sha512-o+9hj92OHcFazX0tdT/aX+Bg6xzbRi4tzSdKCI5NZZt75hD8zFSLAqrUO7l6yGbmO+/Xe2xGcTnvweit6Kagzw==", + "version": "2.76.1", + "resolved": "https://registry.npmjs.org/@douyinfe/semi-illustrations/-/semi-illustrations-2.76.1.tgz", + "integrity": "sha512-wC4iKtKXETZjjB3iQ87PiYmsyS26/2PwsD5dX5d1MPntcjtuv+u1isCH1ZHRTuOUw3Qcb3sckxchwwoHgjUQhg==", "peerDependencies": { "react": ">=16.0.0" } }, "node_modules/@douyinfe/semi-json-viewer-core": { - "version": "2.76.0", - "resolved": "https://registry.npmjs.org/@douyinfe/semi-json-viewer-core/-/semi-json-viewer-core-2.76.0.tgz", - "integrity": "sha512-CwbxbjD7ik6UdE6LFSRAdfrMiEYdzzMVBlRvqhgFKRQLpKJWLyEJNbqcpM/NdVrQVoGxVWclXTrMVCgPsMs1yQ==", + "version": "2.76.1", + "resolved": "https://registry.npmjs.org/@douyinfe/semi-json-viewer-core/-/semi-json-viewer-core-2.76.1.tgz", + "integrity": "sha512-MOPpYhJcAPX0k1RN9RogZA/jwsDJ5eXgw0nAJZ+mc++pRF6IPovbT17ztldxaLOX6MrYgzN6cll+dK6FCBwlEw==", "dependencies": { "jsonc-parser": "^3.3.1" } }, "node_modules/@douyinfe/semi-theme-default": { - "version": "2.76.0", - "resolved": "https://registry.npmjs.org/@douyinfe/semi-theme-default/-/semi-theme-default-2.76.0.tgz", - "integrity": "sha512-zvaRx6UkAuMSEUSC8TRWztVOwa+lu7uFM9pge2bUk8p9LqD/1GXKQ6pBf6XcAs/CtTrIlttBKEWHuankb5t/rQ==" + "version": "2.76.1", + "resolved": "https://registry.npmjs.org/@douyinfe/semi-theme-default/-/semi-theme-default-2.76.1.tgz", + "integrity": "sha512-rl4hyh0ePPMPy/lo68hmiU4EcbzFX6F4pzka0njcCior2b2jjCZ24OA6l4E9xbNJskSINy7BzpNhasBhJ95wAQ==" }, "node_modules/@douyinfe/semi-ui": { - "version": "2.76.0", - "resolved": "https://registry.npmjs.org/@douyinfe/semi-ui/-/semi-ui-2.76.0.tgz", - "integrity": "sha512-h1d99NOB7u4ypo9aq57p85e4BZUh0OsKpgBnqLla7nDwiirmEx08aQzB/xdDOpCWbuAY6xYaCWpPAA+vbNV4/g==", + "version": "2.76.1", + "resolved": "https://registry.npmjs.org/@douyinfe/semi-ui/-/semi-ui-2.76.1.tgz", + "integrity": "sha512-78WKNIolD8v8aEdga2o77NL9x8bcfqM7mM0Y54h4rzt+miCB7lnTjX+ryGoEgNXEJFgjkMF5vadFjWTLqG2a6w==", "dependencies": { "@dnd-kit/core": "^6.0.8", "@dnd-kit/sortable": "^7.0.2", "@dnd-kit/utilities": "^3.2.1", - "@douyinfe/semi-animation": "2.76.0", - "@douyinfe/semi-animation-react": "2.76.0", - "@douyinfe/semi-foundation": "2.76.0", - "@douyinfe/semi-icons": "2.76.0", - "@douyinfe/semi-illustrations": "2.76.0", - "@douyinfe/semi-theme-default": "2.76.0", + "@douyinfe/semi-animation": "2.76.1", + "@douyinfe/semi-animation-react": "2.76.1", + "@douyinfe/semi-foundation": "2.76.1", + "@douyinfe/semi-icons": "2.76.1", + "@douyinfe/semi-illustrations": "2.76.1", + "@douyinfe/semi-theme-default": "2.76.1", "async-validator": "^3.5.0", "classnames": "^2.2.6", "copy-text-to-clipboard": "^2.1.1", @@ -17396,35 +17396,35 @@ } }, "@douyinfe/semi-animation": { - "version": "2.76.0", - "resolved": "https://registry.npmjs.org/@douyinfe/semi-animation/-/semi-animation-2.76.0.tgz", - "integrity": "sha512-h6cTNik/9URcLK/brTGVADdibDV7OjQMUj3z+x1f7R9g5Vg21a2wvDV7ii3w7ofajtPxfSiHLahZXIMDcDgcqQ==", + "version": "2.76.1", + "resolved": "https://registry.npmjs.org/@douyinfe/semi-animation/-/semi-animation-2.76.1.tgz", + "integrity": "sha512-8ghwnFe5Iq/xYd1hnA0/efesrAspdGiSgIjl1C8x2y1LjUWwlNjTwhhTTI1TPaJTT41m5YpWbp0G+Eg1syVq7A==", "requires": { "bezier-easing": "^2.1.0" } }, "@douyinfe/semi-animation-react": { - "version": "2.76.0", - "resolved": "https://registry.npmjs.org/@douyinfe/semi-animation-react/-/semi-animation-react-2.76.0.tgz", - "integrity": "sha512-zxLlagOkGBXRLJSqa3ewPb4/cRHX51W2jL3mY2ajOmNVBdP7VX1XjCy7On4t+R04GtUq2C6FHDs6g/5uY8mGSw==", + "version": "2.76.1", + "resolved": "https://registry.npmjs.org/@douyinfe/semi-animation-react/-/semi-animation-react-2.76.1.tgz", + "integrity": "sha512-Cyu3ZhiE5qyvY+9yRBHg8pHL8Tkq7bR304TWGowz7r65F1viV+88NpDdx7f2foGIxyGjIS7IOa6EFJtV/9pu/w==", "requires": { - "@douyinfe/semi-animation": "2.76.0", - "@douyinfe/semi-animation-styled": "2.76.0", + "@douyinfe/semi-animation": "2.76.1", + "@douyinfe/semi-animation-styled": "2.76.1", "classnames": "^2.2.6" } }, "@douyinfe/semi-animation-styled": { - "version": "2.76.0", - "resolved": "https://registry.npmjs.org/@douyinfe/semi-animation-styled/-/semi-animation-styled-2.76.0.tgz", - "integrity": "sha512-p9GTrcL6F4p1matKATPyDo+YDpeAql0KoZnbZVoGN7hsu56fMpmIHY8qnlSQ6R+4wwYO8N+9iuXnVj6ygpAN1A==" + "version": "2.76.1", + "resolved": "https://registry.npmjs.org/@douyinfe/semi-animation-styled/-/semi-animation-styled-2.76.1.tgz", + "integrity": "sha512-Rm8DX5uYHkJnuRab2nYydu4E7zPFuBZK0Qr/xrcA89lM/J+5XnmOA7NlaIxUoN37lwRxErNr0Vljs3RhMPfsMw==" }, "@douyinfe/semi-foundation": { - "version": "2.76.0", - "resolved": "https://registry.npmjs.org/@douyinfe/semi-foundation/-/semi-foundation-2.76.0.tgz", - "integrity": "sha512-5rgTfFiohyLQOF9eO7GIDu7yGRmsVQGjKpy8q7S6dVS+WS2UmzP8ni95sLjSpslsmmk01s9fNoTdCtLCdZkr7Q==", + "version": "2.76.1", + "resolved": "https://registry.npmjs.org/@douyinfe/semi-foundation/-/semi-foundation-2.76.1.tgz", + "integrity": "sha512-u9KGP6p5N/KCa6EHZolSZ2OVpKAjdDJ0tV9HcW4DGYb/rHaq2rFQlITO47mbKx24dsflOuwjyTCsyYlFXYTwqw==", "requires": { - "@douyinfe/semi-animation": "2.76.0", - "@douyinfe/semi-json-viewer-core": "2.76.0", + "@douyinfe/semi-animation": "2.76.1", + "@douyinfe/semi-json-viewer-core": "2.76.1", "@mdx-js/mdx": "^3.0.1", "async-validator": "^3.5.0", "classnames": "^2.2.6", @@ -17606,46 +17606,46 @@ } }, "@douyinfe/semi-icons": { - "version": "2.76.0", - "resolved": "https://registry.npmjs.org/@douyinfe/semi-icons/-/semi-icons-2.76.0.tgz", - "integrity": "sha512-drDf+Pq8PD7320wCBHGWaQYbYhCcUCT3IzdVHLHtMTN860L8Yr9cwP5RGlBuuYoxaeY1yjkWfcX6qmVmuET1kA==", + "version": "2.76.1", + "resolved": "https://registry.npmjs.org/@douyinfe/semi-icons/-/semi-icons-2.76.1.tgz", + "integrity": "sha512-3eK4fdIjwhA4w8ez7FOkI+FCTNwd3qMKqIHvlngtR7/NboMkwDugDimejJoABChLB3ZgosmnF/FjYnq/n8dSPw==", "requires": { "classnames": "^2.2.6" } }, "@douyinfe/semi-illustrations": { - "version": "2.76.0", - "resolved": "https://registry.npmjs.org/@douyinfe/semi-illustrations/-/semi-illustrations-2.76.0.tgz", - "integrity": "sha512-o+9hj92OHcFazX0tdT/aX+Bg6xzbRi4tzSdKCI5NZZt75hD8zFSLAqrUO7l6yGbmO+/Xe2xGcTnvweit6Kagzw==", + "version": "2.76.1", + "resolved": "https://registry.npmjs.org/@douyinfe/semi-illustrations/-/semi-illustrations-2.76.1.tgz", + "integrity": "sha512-wC4iKtKXETZjjB3iQ87PiYmsyS26/2PwsD5dX5d1MPntcjtuv+u1isCH1ZHRTuOUw3Qcb3sckxchwwoHgjUQhg==", "requires": {} }, "@douyinfe/semi-json-viewer-core": { - "version": "2.76.0", - "resolved": "https://registry.npmjs.org/@douyinfe/semi-json-viewer-core/-/semi-json-viewer-core-2.76.0.tgz", - "integrity": "sha512-CwbxbjD7ik6UdE6LFSRAdfrMiEYdzzMVBlRvqhgFKRQLpKJWLyEJNbqcpM/NdVrQVoGxVWclXTrMVCgPsMs1yQ==", + "version": "2.76.1", + "resolved": "https://registry.npmjs.org/@douyinfe/semi-json-viewer-core/-/semi-json-viewer-core-2.76.1.tgz", + "integrity": "sha512-MOPpYhJcAPX0k1RN9RogZA/jwsDJ5eXgw0nAJZ+mc++pRF6IPovbT17ztldxaLOX6MrYgzN6cll+dK6FCBwlEw==", "requires": { "jsonc-parser": "^3.3.1" } }, "@douyinfe/semi-theme-default": { - "version": "2.76.0", - "resolved": "https://registry.npmjs.org/@douyinfe/semi-theme-default/-/semi-theme-default-2.76.0.tgz", - "integrity": "sha512-zvaRx6UkAuMSEUSC8TRWztVOwa+lu7uFM9pge2bUk8p9LqD/1GXKQ6pBf6XcAs/CtTrIlttBKEWHuankb5t/rQ==" + "version": "2.76.1", + "resolved": "https://registry.npmjs.org/@douyinfe/semi-theme-default/-/semi-theme-default-2.76.1.tgz", + "integrity": "sha512-rl4hyh0ePPMPy/lo68hmiU4EcbzFX6F4pzka0njcCior2b2jjCZ24OA6l4E9xbNJskSINy7BzpNhasBhJ95wAQ==" }, "@douyinfe/semi-ui": { - "version": "2.76.0", - "resolved": "https://registry.npmjs.org/@douyinfe/semi-ui/-/semi-ui-2.76.0.tgz", - "integrity": "sha512-h1d99NOB7u4ypo9aq57p85e4BZUh0OsKpgBnqLla7nDwiirmEx08aQzB/xdDOpCWbuAY6xYaCWpPAA+vbNV4/g==", + "version": "2.76.1", + "resolved": "https://registry.npmjs.org/@douyinfe/semi-ui/-/semi-ui-2.76.1.tgz", + "integrity": "sha512-78WKNIolD8v8aEdga2o77NL9x8bcfqM7mM0Y54h4rzt+miCB7lnTjX+ryGoEgNXEJFgjkMF5vadFjWTLqG2a6w==", "requires": { "@dnd-kit/core": "^6.0.8", "@dnd-kit/sortable": "^7.0.2", "@dnd-kit/utilities": "^3.2.1", - "@douyinfe/semi-animation": "2.76.0", - "@douyinfe/semi-animation-react": "2.76.0", - "@douyinfe/semi-foundation": "2.76.0", - "@douyinfe/semi-icons": "2.76.0", - "@douyinfe/semi-illustrations": "2.76.0", - "@douyinfe/semi-theme-default": "2.76.0", + "@douyinfe/semi-animation": "2.76.1", + "@douyinfe/semi-animation-react": "2.76.1", + "@douyinfe/semi-foundation": "2.76.1", + "@douyinfe/semi-icons": "2.76.1", + "@douyinfe/semi-illustrations": "2.76.1", + "@douyinfe/semi-theme-default": "2.76.1", "async-validator": "^3.5.0", "classnames": "^2.2.6", "copy-text-to-clipboard": "^2.1.1", diff --git a/package.json b/package.json index 2467ab42..d41d0a2e 100644 --- a/package.json +++ b/package.json @@ -5,9 +5,9 @@ "scripts": { "docusaurus": "docusaurus", "start": "docusaurus start", - "build": "NODE_OPTIONS=\"--max-old-space-size=4096\" docusaurus build", + "build": "NODE_OPTIONS=\"--max-old-space-size=8192\" docusaurus build", "swizzle": "docusaurus swizzle", - "deploy": "NODE_OPTIONS=\"--max-old-space-size=4096\" docusaurus deploy", + "deploy": "NODE_OPTIONS=\"--max-old-space-size=8192\" docusaurus deploy", "clear": "docusaurus clear", "serve": "docusaurus serve", "write-translations": "docusaurus write-translations", @@ -21,7 +21,7 @@ "@docusaurus/plugin-content-pages": "^2.4.3", "@docusaurus/plugin-sitemap": "^2.4.3", "@docusaurus/preset-classic": "2.4.3", - "@douyinfe/semi-ui": "^2.76.0", + "@douyinfe/semi-ui": "^2.76.1", "asciinema-player": "^3.9.0", "clsx": "^2.1.1", "react": "^17.0.2", From 6ab58821807be84a8859be527a1b342f9bc32a7e Mon Sep 17 00:00:00 2001 From: zhzhuang-zju Date: Fri, 21 Mar 2025 17:09:15 +0800 Subject: [PATCH 04/15] improve document-releasing process Signed-off-by: zhzhuang-zju --- docs/developers/document-releasing.md | 25 +++++++++++++------ .../current/developers/document-releasing.md | 25 +++++++++++++------ 2 files changed, 34 insertions(+), 16 deletions(-) diff --git a/docs/developers/document-releasing.md b/docs/developers/document-releasing.md index 1565f204..2a1eb32a 100644 --- a/docs/developers/document-releasing.md +++ b/docs/developers/document-releasing.md @@ -16,7 +16,7 @@ This issue is to track documents which needs to sync zh for release 1.x: ## Update Reference Documents(manually) -Before releasing, we need to update reference docs in the website, which includes CLI references and component references. The whole process is done by scripts automatically. +Before releasing, we need to update reference docs in the website, which includes CLI references, component references and API documentation. The whole process is done by scripts automatically. Follow these steps to update reference docs. 1. Clone `karmada-io/karmada` and `karmada-io/website` to the local environment. It's recommended to step up these two projects in the same folder. @@ -32,7 +32,7 @@ $ tree -L 1 #├── website ``` -2. Run generate command in karmada root dir. +2. Run generate command in karmada root dir to generate CLI references. ```shell cd karmada/ @@ -46,11 +46,20 @@ go run ./hack/tools/genkarmadactldocs/gen_karmadactl_docs.go ../website/i18n/zh/ cd karmada/ go build ./hack/tools/gencomponentdocs/. -components=(karmada-controller-manager karmada-scheduler karmada-agent karmada-aggregated-apiserver karmada-descheduler karmada-search karmada-scheduler-estimator karmada-webhook karmada-metrics-adapter) -for component in ${components};do - ./gencomponentdocs ../website/docs/reference/components/ $component - ./gencomponentdocs ../website/i18n/zh/docusaurus-plugin-content-docs/current/reference/components/ $component -done +./gencomponentdocs ../website/docs/reference/components/ all +./gencomponentdocs ../website/i18n/zh/docusaurus-plugin-content-docs/current/reference/components/ all +``` + +4. Generate API docs. + +Enter the website/infra/gen-resourcesdocs directory. +```shell +cd website/infra/gen-resourcesdocs +``` +Modify the file `config/current/toc.yaml` according to the guidance in `README.md`. +Run the script `hack/reference-api.sh`. +```shell +hack/reference-api.sh ``` ## Setup release-1.x(manually) @@ -82,7 +91,7 @@ cp versioned_sidebars/version-v1.4-sidebars.json versioned_sidebars/version-v1.5 sed -i'' -e "s/version-v1.4/version-v1.5/g" versioned_sidebars/version-v1.5-sidebars.json ``` -Then, update `version-v1.5-sidebars.json` based on `sidebars.js`. +**Note: update `version-v1.5-sidebars.json` based on `sidebars.js`.** 4. Update versioned_docs for zh diff --git a/i18n/zh/docusaurus-plugin-content-docs/current/developers/document-releasing.md b/i18n/zh/docusaurus-plugin-content-docs/current/developers/document-releasing.md index 0a28dec1..9033cde4 100644 --- a/i18n/zh/docusaurus-plugin-content-docs/current/developers/document-releasing.md +++ b/i18n/zh/docusaurus-plugin-content-docs/current/developers/document-releasing.md @@ -15,7 +15,7 @@ This issue is to track documents which needs to sync zh for release 1.x: ## 更新参考文档(手动) -在发布之前,我们需要更新网站中的参考文档,包括 CLI 引用和组件引用。整个过程由脚本自动完成。按照以下步骤更新参考文档。 +在发布之前,我们需要更新网站中的参考文档,包括 CLI 引用,组件引用和 API 文档。整个过程由脚本自动完成。按照以下步骤更新参考文档。 1. 将 `karmada-io/karmada` 和 `karmada-io/website` 克隆到本地环境。建议将这两个项目放在同一个文件夹中。 @@ -30,7 +30,7 @@ $ tree -L 1 #├── website ``` -2. 在 karmada 根目录下执行 generate 命令。 +2. 在 karmada 根目录下执行 generate 命令来生成 CLI 引用。 ```shell cd karmada/ @@ -44,11 +44,20 @@ go run ./hack/tools/genkarmadactldocs/gen_karmadactl_docs.go ../website/i18n/zh/ cd karmada/ go build ./hack/tools/gencomponentdocs/. -components=(karmada-controller-manager karmada-scheduler karmada-agent karmada-aggregated-apiserver karmada-descheduler karmada-search karmada-scheduler-estimator karmada-webhook karmada-metrics-adapter) -for component in ${components};do - ./gencomponentdocs ../website/docs/reference/components/ $component - ./gencomponentdocs ../website/i18n/zh/docusaurus-plugin-content-docs/current/reference/components/ $component -done +./gencomponentdocs ../website/docs/reference/components/ all +./gencomponentdocs ../website/i18n/zh/docusaurus-plugin-content-docs/current/reference/components/ all +``` + +4. 生成 API 文档。 + +进入 website/infra/gen-resourcesdocs 目录。 +```shell +cd website/infra/gen-resourcesdocs +``` +按照 `README.md` 中的指导修改文件 `config/current/toc.yaml`。 +执行脚本 `hack/reference-api.sh`。 +```shell +hack/reference-api.sh ``` ## 建立 release-1.x(手动) @@ -80,7 +89,7 @@ cp versioned_sidebars/version-v1.4-sidebars.json versioned_sidebars/version-v1.5 sed -i'' -e "s/version-v1.4/version-v1.5/g" versioned_sidebars/version-v1.5-sidebars.json ``` -然后,对照 `sidebars.js` 更新 `version-v1.5-sidebars.json` +**注意:完成后需对照 `sidebars.js` 更新 `version-v1.5-sidebars.json`。** 4. 更新中文的 versioned_docs From 5c4abde0ca4c3e8067683a24159d6e7875449b04 Mon Sep 17 00:00:00 2001 From: zhzhuang-zju Date: Mon, 24 Mar 2025 15:08:40 +0800 Subject: [PATCH 05/15] update install-binary.md to adjust the installation order Signed-off-by: zhzhuang-zju --- docs/installation/install-binary.md | 43 ++++++++++--------- .../current/installation/install-binary.md | 43 ++++++++++--------- .../installation/install-binary.md | 43 ++++++++++--------- .../installation/install-binary.md | 43 ++++++++++--------- .../installation/install-binary.md | 43 ++++++++++--------- .../installation/install-binary.md | 43 ++++++++++--------- .../installation/install-binary.md | 43 ++++++++++--------- .../installation/install-binary.md | 43 ++++++++++--------- 8 files changed, 184 insertions(+), 160 deletions(-) diff --git a/docs/installation/install-binary.md b/docs/installation/install-binary.md index 12655031..87975382 100644 --- a/docs/installation/install-binary.md +++ b/docs/installation/install-binary.md @@ -673,6 +673,29 @@ livez check passed ###### karmada-aggregated-apiserver check success ``` +## Prepare Karmada CRDs Resources + +Execute operations at `karmada-01`. + +```bash +git clone https://github.com/karmada-io/karmada +cd karmada/charts/karmada/_crds/bases + +kubectl apply -f . + +cd ../patches/ +ca_string=$(cat /etc/karmada/pki/server-ca.crt | base64 | tr "\n" " "|sed s/[[:space:]]//g) +sed -i "s/{{caBundle}}/${ca_string}/g" webhook_in_resourcebindings.yaml +sed -i "s/{{caBundle}}/${ca_string}/g" webhook_in_clusterresourcebindings.yaml +# You need to change 172.31.209.245:4443 to your Load Balancer host:port. +sed -i 's/karmada-webhook.karmada-system.svc:443/172.31.209.245:4443/g' webhook_in_resourcebindings.yaml +sed -i 's/karmada-webhook.karmada-system.svc:443/172.31.209.245:4443/g' webhook_in_clusterresourcebindings.yaml + +kubectl patch CustomResourceDefinition resourcebindings.work.karmada.io --patch-file webhook_in_resourcebindings.yaml +kubectl patch CustomResourceDefinition clusterresourcebindings.work.karmada.io --patch-file webhook_in_clusterresourcebindings.yaml +cd ../../../../.. +``` + ## Install kube-controller-manager Execute operations at `karmada-01` `karmada-02` `karmada-03`. Take `karmada-01` as an example. @@ -965,26 +988,6 @@ ok ## Initialize Karmada -Execute operations at `karmada-01`. - -```bash -git clone https://github.com/karmada-io/karmada -cd karmada/charts/karmada/_crds/bases - -kubectl apply -f . - -cd ../patches/ -ca_string=$(cat /etc/karmada/pki/server-ca.crt | base64 | tr "\n" " "|sed s/[[:space:]]//g) -sed -i "s/{{caBundle}}/${ca_string}/g" webhook_in_resourcebindings.yaml -sed -i "s/{{caBundle}}/${ca_string}/g" webhook_in_clusterresourcebindings.yaml -# You need to change 172.31.209.245:4443 to your Load Balancer host:port. -sed -i 's/karmada-webhook.karmada-system.svc:443/172.31.209.245:4443/g' webhook_in_resourcebindings.yaml -sed -i 's/karmada-webhook.karmada-system.svc:443/172.31.209.245:4443/g' webhook_in_clusterresourcebindings.yaml - -kubectl patch CustomResourceDefinition resourcebindings.work.karmada.io --patch-file webhook_in_resourcebindings.yaml -kubectl patch CustomResourceDefinition clusterresourcebindings.work.karmada.io --patch-file webhook_in_clusterresourcebindings.yaml -``` - Now, all the required components have been installed, and the member clusters could join Karmada control plane. If you want to use `karmadactl` to query, please run following command: ```sh diff --git a/i18n/zh/docusaurus-plugin-content-docs/current/installation/install-binary.md b/i18n/zh/docusaurus-plugin-content-docs/current/installation/install-binary.md index a9296f17..2e572722 100644 --- a/i18n/zh/docusaurus-plugin-content-docs/current/installation/install-binary.md +++ b/i18n/zh/docusaurus-plugin-content-docs/current/installation/install-binary.md @@ -676,6 +676,29 @@ livez check passed ###### karmada-aggregated-apiserver 检查成功 ``` +## 准备 Karmada CRDs 资源 + +对 `karmada-01` 执行以下操作。 + +```bash +git clone https://github.com/karmada-io/karmada +cd karmada/charts/karmada/_crds/bases + +kubectl apply -f . + +cd ../patches/ +ca_string=$(cat /etc/karmada/pki/server-ca.crt | base64 | tr "\n" " "|sed s/[[:space:]]//g) +sed -i "s/{{caBundle}}/${ca_string}/g" webhook_in_resourcebindings.yaml +sed -i "s/{{caBundle}}/${ca_string}/g" webhook_in_clusterresourcebindings.yaml +# You need to change 172.31.209.245:4443 to your Load Balancer host:port. +sed -i 's/karmada-webhook.karmada-system.svc:443/172.31.209.245:4443/g' webhook_in_resourcebindings.yaml +sed -i 's/karmada-webhook.karmada-system.svc:443/172.31.209.245:4443/g' webhook_in_clusterresourcebindings.yaml + +kubectl patch CustomResourceDefinition resourcebindings.work.karmada.io --patch-file webhook_in_resourcebindings.yaml +kubectl patch CustomResourceDefinition clusterresourcebindings.work.karmada.io --patch-file webhook_in_clusterresourcebindings.yaml +cd ../../../../.. +``` + ## 安装 kube-controller-manager 对 `karmada-01`、`karmada-02`、`karmada-03` 执行操作。以 `karmada-01` 为例。 @@ -968,26 +991,6 @@ ok ## 初始化 Karmada -对 `karmada-01` 执行以下操作。 - -```bash -git clone https://github.com/karmada-io/karmada -cd karmada/charts/karmada/_crds/bases - -kubectl apply -f . - -cd ../patches/ -ca_string=$(cat /etc/karmada/pki/server-ca.crt | base64 | tr "\n" " "|sed s/[[:space:]]//g) -sed -i "s/{{caBundle}}/${ca_string}/g" webhook_in_resourcebindings.yaml -sed -i "s/{{caBundle}}/${ca_string}/g" webhook_in_clusterresourcebindings.yaml -# 你需要将 172.31.209.245:4443 更改为你的负载均衡器 host:port。 -sed -i 's/karmada-webhook.karmada-system.svc:443/172.31.209.245:4443/g' webhook_in_resourcebindings.yaml -sed -i 's/karmada-webhook.karmada-system.svc:443/172.31.209.245:4443/g' webhook_in_clusterresourcebindings.yaml - -kubectl patch CustomResourceDefinition resourcebindings.work.karmada.io --patch-file webhook_in_resourcebindings.yaml -kubectl patch CustomResourceDefinition clusterresourcebindings.work.karmada.io --patch-file webhook_in_clusterresourcebindings.yaml -``` - 此时,Karmada基础组件已经安装完毕,此时,你可以接入集群;如果想使用karmadactl聚合查询,需要运行如下命令: ```sh cat < Date: Tue, 25 Mar 2025 20:55:01 +0800 Subject: [PATCH 06/15] Add rednote to adopters MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: 宋阳 --- i18n/zh/docusaurus-plugin-content-pages/adopters.md | 1 + src/pages/adopters.md | 1 + 2 files changed, 2 insertions(+) diff --git a/i18n/zh/docusaurus-plugin-content-pages/adopters.md b/i18n/zh/docusaurus-plugin-content-pages/adopters.md index 00cf806a..bbbf3f70 100644 --- a/i18n/zh/docusaurus-plugin-content-pages/adopters.md +++ b/i18n/zh/docusaurus-plugin-content-pages/adopters.md @@ -39,6 +39,7 @@ hide_table_of_contents: true | Neen S.p.A | https://www.neen.it/ | 使用 Karmada 管理多 region 集群中的故障切换。 | | | 网易 | https://www.netease.com/ | 使用 Karmada 构建分布式高可用中间件平台。 | | | 奇虎 360 | https://www.360.cn | 使用 Karmada 跨集群调度离线训练任务,实现算力分享。 | | +| 小红书 | https://www.xiaohongshu.com | 使用 Karmada 构建面向混合云的高可用弹性架构。 | [KubeCon China 2024: 多集群助力小红书打造面向混合云的高可用弹性架构](https://www.youtube.com/watch?v=05M7bqj2VJE) | | Shopee | https://shopee.com | 使用 Karmada 实现多集群管理与应用分发。 | [Karmada 在 Shopee 的落地实践](https://www.youtube.com/watch?v=jZg6TmyciyI ) | | 新浪 | http://www.sina.com.cn | 使用Karmada构建用于运行数据库服务的多K8s集群平台。 | | | 同程旅行 | https://www.ly.com | 使用 Karmada 构建一个基于多云和多集群的统一平台。 | | diff --git a/src/pages/adopters.md b/src/pages/adopters.md index e08e20e2..b3e12d0b 100644 --- a/src/pages/adopters.md +++ b/src/pages/adopters.md @@ -39,6 +39,7 @@ All organisations are sorted alphabetically by the first letter of their English | Neen S.p.A | https://www.neen.it/ | Use Karmada to manage failover in a multi-region cluster. | | | Netease | https://www.netease.com/ | Use Karmada to build distributed and high availability middleware platform. | | | Qihoo 360 | https://www.360.com | Use Karmada to distribute batch training workloads across clusters to achieve computational resource sharing. | | +| RedNote | https://xiaohongshu.com | Build an elastic, hybrid cloud-oriented architecture based on Karmada. | [KubeCon China 2024: Leveraging Multi-Cluster Architecture for Resilient and Elastic Hybrid Cloud at Xiaohongshu](https://www.youtube.com/watch?v=05M7bqj2VJE) | | Shopee | https://shopee.com | Use Karmada to manage multi-cluster application delivery. | [Karmada in Shopee](https://www.youtube.com/watch?v=jZg6TmyciyI ) | | Sina | http://www.sina.com.cn | Use Karmada to build multi-clusters that running database. | | | Tongcheng Travel | https://www.ly.com | Use Karmada to build a unified platform based on multi-cloud and multiple clusters. | | From 8e0c4f249eda96338ded9c22dbb28cd73a8b1398 Mon Sep 17 00:00:00 2001 From: changzhen Date: Fri, 21 Mar 2025 16:52:18 +0800 Subject: [PATCH 07/15] add binding address configuration for security considerations Signed-off-by: changzhen --- .../security/security-considerations.md | 66 +++++++++++++++++++ .../security/security-considerations.md | 66 +++++++++++++++++++ 2 files changed, 132 insertions(+) diff --git a/docs/administrator/security/security-considerations.md b/docs/administrator/security/security-considerations.md index 06a48433..430ce35c 100644 --- a/docs/administrator/security/security-considerations.md +++ b/docs/administrator/security/security-considerations.md @@ -30,3 +30,69 @@ To avoid the use of insecure algorithms such as 3DES during the communication pr Set Golang's secure cipher suite to etcd's cipher suite. They are obtained through the return value of the function "CipherSuites()" under the "go/src/crypto/tls/cipher_suites.go" package. Consistent with the "preferred value" of the k8s default cipher suite. +#### Binding Address Configuration + +Karmada components provide configurable parameters for users to configure listening addresses and ports. When a user deploys a Karmada component, the Karmada component will use the default listening address and port if the listening-related parameters are not configured. The default listening address of the Karmada component is `0.0.0.0`, which means that the component will listen to all network interfaces on the server (for a container, this is a virtual network interface that is managed by the container runtime, such as Docker). + +The following are the configurable parameters provided by the Karmada component: + +- karmada-controller-manager + - `--metrics-bind-address`: default is `:8080`. + - `--health-probe-bind-address`: default is `:10357`. +- karmada-scheduler + - `--metrics-bind-address`: default is `:8080`. + - `--health-probe-bind-address`: default is `:10351`. +- karmada-scheduler-estimator + - `--metrics-bind-address`: default is `:8080`. + - `--health-probe-bind-address`: default is `:10351`. +- karmada-descheduler + - `--metrics-bind-address`: default is `:8080`. + - `--health-probe-bind-address`: default is `:10358`. +- karmada-aggregated-apiserver + - `--bind-address`: default is `0.0.0.0`. + - `--secure-port`: default is `443`. +- karmada-metrics-adapter + - `--metrics-bind-address`: default is `:8080`. + - `--bind-address`: default is `0.0.0.0`. + - `--secure-port`: default is `443`. +- karmada-webhook + - `--metrics-bind-address`: default is `:8080`. + - `--health-probe-bind-address`: default is `:8000`. + - `--bind-address`: default is `0.0.0.0`. + - `--secure-port`: default is `8443`. +- karmada-search + - `--bind-address`: default is `0.0.0.0`. + - `--secure-port`: default is `443`. +- karmada-agent + - `--metrics-bind-address`: default is `:8080`. + - `--health-probe-bind-address`: default is `:10357`. + +Users can configure the listening address as a Pod IP value. For example, you can configure the metrics interface of the `karmada-controller-manager` component as follows: + +```yaml +apiVersion: apps/v1 +kind: Deployment +metadata: + name: karmada-controller-manager + namespace: karmada-system +spec: + replicas: 1 + selector: + matchLabels: + app: karmada-controller-manager + template: + metadata: + labels: + app: karmada-controller-manager + spec: + containers: + - name: my-container + env: + - name: POD_IP + valueFrom: + fieldRef: + fieldPath: status.podIP + command: + - /bin/karmada-controller-manager + - --metrics-bind-address=${POD_IP}:8080 +``` diff --git a/i18n/zh/docusaurus-plugin-content-docs/current/administrator/security/security-considerations.md b/i18n/zh/docusaurus-plugin-content-docs/current/administrator/security/security-considerations.md index f018050a..5d84383a 100644 --- a/i18n/zh/docusaurus-plugin-content-docs/current/administrator/security/security-considerations.md +++ b/i18n/zh/docusaurus-plugin-content-docs/current/administrator/security/security-considerations.md @@ -30,3 +30,69 @@ Karmada 各组件通过启动参数`--tls-min-version`和`--cipher-suites`来设 其中,将 Golang 的`secure cipher suites`设置为 etcd 的`cipher suites`。与 k8s 默认`cipher suites`的首选值一致。 +#### 绑定地址配置 + +Karmada 各组件为用户配置监听地址和端口提供了可配置的参数。当用户部署 Karmada 组件时,若未配置监听相关参数时,Karmada 组件会使用默认的监听地址和端口。Karmada 组件默认监听地址为 `0.0.0.0` ,这意味着该组件将监听服务器上的所有网络接口(对于容器来说,这是一个虚拟网络接口,由容器运行时管理,如 Docker)。 + +以下是 Karmada 组件提供的可配置参数: + +- karmada-controller-manager + - `--metrics-bind-address`:默认值为 `:8080`。 + - `--health-probe-bind-address`:默认值为 `:10357`。 +- karmada-scheduler + - `--metrics-bind-address`:默认值为 `:8080`。 + - `--health-probe-bind-address`:默认值为 `:10351`。 +- karmada-scheduler-estimator + - `--metrics-bind-address`:默认值为 `:8080`。 + - `--health-probe-bind-address`:默认值为 `:10351`。 +- karmada-descheduler + - `--metrics-bind-address`:默认值为 `:8080`。 + - `--health-probe-bind-address`:默认值为 `:10358`。 +- karmada-aggregated-apiserver + - `--bind-address`:默认值为 `0.0.0.0`。 + - `--secure-port`:默认值为 `443`。 +- karmada-metrics-adapter + - `--metrics-bind-address`:默认值为 `:8080`。 + - `--bind-address`:默认值为 `0.0.0.0`。 + - `--secure-port`:默认值为 `443`。 +- karmada-webhook + - `--metrics-bind-address`:默认值为 `:8080`。 + - `--health-probe-bind-address`:默认值为 `:8000`。 + - `--bind-address`:默认值为 `0.0.0.0`。 + - `--secure-port`:默认值为 `8443`。 +- karmada-search + - `--bind-address`:默认值为 `0.0.0.0`。 + - `--secure-port`:默认值为 `443`。 +- karmada-agent + - `--metrics-bind-address`:默认值为 `:8080`。 + - `--health-probe-bind-address`:默认值为 `:10357`。 + +用户可以将监听地址配置为 Pod IP 值。 例如,您可以按照以下方式配置 `karmada-controller-manager` 组件的 `metrics` 接口: + +```yaml +apiVersion: apps/v1 +kind: Deployment +metadata: + name: karmada-controller-manager + namespace: karmada-system +spec: + replicas: 1 + selector: + matchLabels: + app: karmada-controller-manager + template: + metadata: + labels: + app: karmada-controller-manager + spec: + containers: + - name: my-container + env: + - name: POD_IP + valueFrom: + fieldRef: + fieldPath: status.podIP + command: + - /bin/karmada-controller-manager + - --metrics-bind-address=${POD_IP}:8080 +``` From daf0274646be670b5ac594c2e01fbf4f2ffa9526 Mon Sep 17 00:00:00 2001 From: changzhen Date: Mon, 31 Mar 2025 15:28:22 +0800 Subject: [PATCH 08/15] add more description for op/cop resourceSelectors Signed-off-by: changzhen --- docs/userguide/scheduling/override-policy.md | 33 ++++++++++++++++--- .../userguide/scheduling/override-policy.md | 31 ++++++++++++++--- 2 files changed, 55 insertions(+), 9 deletions(-) diff --git a/docs/userguide/scheduling/override-policy.md b/docs/userguide/scheduling/override-policy.md index 4b3de2e5..666cf563 100644 --- a/docs/userguide/scheduling/override-policy.md +++ b/docs/userguide/scheduling/override-policy.md @@ -14,21 +14,23 @@ ResourceSelectors restrict resource types that the override policy applies to. I Resource Selector requires the `apiVersion` field which represents the API version of the target resources and `kind` which represents the kind of the target resources. The allowed selectors are as follows: -- `namespace`: namespace of the target resource. -- `name`: name of the target resource. -- `labelSelector`: a label query over a set of resources. +- `namespace`: namespace of the target resource. Default is empty, which means inherit from the parent object scope. +- `name`: name of the target resource. Default is empty, which means selecting all resources. +- `labelSelector`: a label query over a set of resources. If name is not empty, labelSelector will be ignored. #### Examples + +**Example 1: select deployment kind resources** ```yaml apiVersion: policy.karmada.io/v1alpha1 kind: OverridePolicy metadata: name: example + namespace: test spec: resourceSelectors: - apiVersion: apps/v1 kind: Deployment - name: nginx namespace: test labelSelector: matchLabels: @@ -36,7 +38,28 @@ spec: overrideRules: #... ``` -Override rules above will only be applied to the `Deployment` named nginx in test namespace and has the `app: nginx` label. +Override rules above will be applied to the `Deployment` which has the `app: nginx` label in test namespace. + +**Example 2: select more than one kind resource** +```yaml +apiVersion: policy.karmada.io/v1alpha1 +kind: OverridePolicy +metadata: + name: example + namespace: test +spec: + resourceSelectors: + - apiVersion: apps/v1 + kind: Deployment + name: nginx + - apiVersion: v1 + kind: Service + name: nginx-svc + overrideRules: + #... +``` + +Override rules above will be applied to the `Deployment` named nginx and the `Service` named nginx-svc in test namespace. This indicates that all resources hit by resourceSelectors will be applied. ## Target Cluster diff --git a/i18n/zh/docusaurus-plugin-content-docs/current/userguide/scheduling/override-policy.md b/i18n/zh/docusaurus-plugin-content-docs/current/userguide/scheduling/override-policy.md index 513c6a15..94745edb 100644 --- a/i18n/zh/docusaurus-plugin-content-docs/current/userguide/scheduling/override-policy.md +++ b/i18n/zh/docusaurus-plugin-content-docs/current/userguide/scheduling/override-policy.md @@ -14,21 +14,23 @@ ResourceSelectors restricts resource types that this override policy applies to. Resource Selector required `apiVersion` field which represents the API version of the target resources and `kind` which represents the Kind of the target resources. The allowed selectors are as follows: -- `namespace`: namespace of the target resource. -- `name`: name of the target resource -- `labelSelector`: A label query over a set of resources. +- `namespace`: namespace of the target resource. Default is empty, which means inherit from the parent object scope. +- `name`: name of the target resource. Default is empty, which means selecting all resources. +- `labelSelector`: a label query over a set of resources. If name is not empty, labelSelector will be ignored. #### Examples + +**Example 1: select one deployment kind resources** ```yaml apiVersion: policy.karmada.io/v1alpha1 kind: OverridePolicy metadata: name: example + namespace: test spec: resourceSelectors: - apiVersion: apps/v1 kind: Deployment - name: nginx namespace: test labelSelector: matchLabels: @@ -38,6 +40,27 @@ spec: ``` It means override rules above will only be applied to `Deployment` which is named nginx in test namespace and has labels with `app: nginx`. +**Example 2: select more than one kind resource** +```yaml +apiVersion: policy.karmada.io/v1alpha1 +kind: OverridePolicy +metadata: + name: example + namespace: test +spec: + resourceSelectors: + - apiVersion: apps/v1 + kind: Deployment + name: nginx + - apiVersion: v1 + kind: Service + name: nginx-svc + overrideRules: + #... +``` + +Override rules above will be applied to the `Deployment` named nginx and the `Service` named nginx-svc in test namespace. This indicates that all resources hit by resourceSelectors will be applied. + ## Target Cluster Target Cluster defines restrictions on the override policy that only applies to resources propagated to the matching clusters. If you ignore this field it means matching all clusters. From 41a1ed7d206c3dbb2d480ca272731eb46f872e0b Mon Sep 17 00:00:00 2001 From: Arhell Date: Thu, 3 Apr 2025 00:32:45 +0300 Subject: [PATCH 09/15] bump semi-ui to 2.77.1 Signed-off-by: Arhell --- package-lock.json | 218 +++++++++++++++++++++------------------------- package.json | 2 +- 2 files changed, 100 insertions(+), 120 deletions(-) diff --git a/package-lock.json b/package-lock.json index 95e54f2f..f1da5b1c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -14,7 +14,7 @@ "@docusaurus/plugin-content-pages": "^2.4.3", "@docusaurus/plugin-sitemap": "^2.4.3", "@docusaurus/preset-classic": "2.4.3", - "@douyinfe/semi-ui": "^2.76.1", + "@douyinfe/semi-ui": "^2.77.1", "asciinema-player": "^3.9.0", "clsx": "^2.1.1", "react": "^17.0.2", @@ -2764,35 +2764,35 @@ } }, "node_modules/@douyinfe/semi-animation": { - "version": "2.76.1", - "resolved": "https://registry.npmjs.org/@douyinfe/semi-animation/-/semi-animation-2.76.1.tgz", - "integrity": "sha512-8ghwnFe5Iq/xYd1hnA0/efesrAspdGiSgIjl1C8x2y1LjUWwlNjTwhhTTI1TPaJTT41m5YpWbp0G+Eg1syVq7A==", + "version": "2.77.1", + "resolved": "https://registry.npmjs.org/@douyinfe/semi-animation/-/semi-animation-2.77.1.tgz", + "integrity": "sha512-Q1D7whvQe0D+mPov8hXeH/e1uR/iBhpGGcW1LCTL2pSVMEZEYGJLf2KeXTTiCIgRVWm0PRH3Sux7auJ64zg7vw==", "dependencies": { "bezier-easing": "^2.1.0" } }, "node_modules/@douyinfe/semi-animation-react": { - "version": "2.76.1", - "resolved": "https://registry.npmjs.org/@douyinfe/semi-animation-react/-/semi-animation-react-2.76.1.tgz", - "integrity": "sha512-Cyu3ZhiE5qyvY+9yRBHg8pHL8Tkq7bR304TWGowz7r65F1viV+88NpDdx7f2foGIxyGjIS7IOa6EFJtV/9pu/w==", + "version": "2.77.1", + "resolved": "https://registry.npmjs.org/@douyinfe/semi-animation-react/-/semi-animation-react-2.77.1.tgz", + "integrity": "sha512-imELR02pufgGFkZURfTd9oBUtZPYhHvXv9WsYoRvEoBM9U7yzxrR6Fb/Lc3TH+WHVJ2oZHH2S0APS5t1MceEOw==", "dependencies": { - "@douyinfe/semi-animation": "2.76.1", - "@douyinfe/semi-animation-styled": "2.76.1", + "@douyinfe/semi-animation": "2.77.1", + "@douyinfe/semi-animation-styled": "2.77.1", "classnames": "^2.2.6" } }, "node_modules/@douyinfe/semi-animation-styled": { - "version": "2.76.1", - "resolved": "https://registry.npmjs.org/@douyinfe/semi-animation-styled/-/semi-animation-styled-2.76.1.tgz", - "integrity": "sha512-Rm8DX5uYHkJnuRab2nYydu4E7zPFuBZK0Qr/xrcA89lM/J+5XnmOA7NlaIxUoN37lwRxErNr0Vljs3RhMPfsMw==" + "version": "2.77.1", + "resolved": "https://registry.npmjs.org/@douyinfe/semi-animation-styled/-/semi-animation-styled-2.77.1.tgz", + "integrity": "sha512-FBRroqVJroel1CXmBgV58ulZHG2xUVInJF7k0FAag54noKKaToEobSxRjiTJ6JHne3ZDU1M6sBqpbzYJElFnPQ==" }, "node_modules/@douyinfe/semi-foundation": { - "version": "2.76.1", - "resolved": "https://registry.npmjs.org/@douyinfe/semi-foundation/-/semi-foundation-2.76.1.tgz", - "integrity": "sha512-u9KGP6p5N/KCa6EHZolSZ2OVpKAjdDJ0tV9HcW4DGYb/rHaq2rFQlITO47mbKx24dsflOuwjyTCsyYlFXYTwqw==", + "version": "2.77.1", + "resolved": "https://registry.npmjs.org/@douyinfe/semi-foundation/-/semi-foundation-2.77.1.tgz", + "integrity": "sha512-DAXRy8ryLNzbKAiTAv+RrivGCoMU0asv2cO7PNV5aBq0ICB8XXn97FHyZo6Wb5NpqpyMhOaOr8Ro1bfpd0FeaA==", "dependencies": { - "@douyinfe/semi-animation": "2.76.1", - "@douyinfe/semi-json-viewer-core": "2.76.1", + "@douyinfe/semi-animation": "2.77.1", + "@douyinfe/semi-json-viewer-core": "2.77.1", "@mdx-js/mdx": "^3.0.1", "async-validator": "^3.5.0", "classnames": "^2.2.6", @@ -3033,9 +3033,9 @@ } }, "node_modules/@douyinfe/semi-icons": { - "version": "2.76.1", - "resolved": "https://registry.npmjs.org/@douyinfe/semi-icons/-/semi-icons-2.76.1.tgz", - "integrity": "sha512-3eK4fdIjwhA4w8ez7FOkI+FCTNwd3qMKqIHvlngtR7/NboMkwDugDimejJoABChLB3ZgosmnF/FjYnq/n8dSPw==", + "version": "2.77.1", + "resolved": "https://registry.npmjs.org/@douyinfe/semi-icons/-/semi-icons-2.77.1.tgz", + "integrity": "sha512-IbGqYzbjzCoSd+//HlO/Gn1c3XmbulQwGys+JgDfQhYIbPeGyhQfLk56Q7ku3vJGC8BGy7dUmR9MbeTf1UQGtw==", "dependencies": { "classnames": "^2.2.6" }, @@ -3044,40 +3044,40 @@ } }, "node_modules/@douyinfe/semi-illustrations": { - "version": "2.76.1", - "resolved": "https://registry.npmjs.org/@douyinfe/semi-illustrations/-/semi-illustrations-2.76.1.tgz", - "integrity": "sha512-wC4iKtKXETZjjB3iQ87PiYmsyS26/2PwsD5dX5d1MPntcjtuv+u1isCH1ZHRTuOUw3Qcb3sckxchwwoHgjUQhg==", + "version": "2.77.1", + "resolved": "https://registry.npmjs.org/@douyinfe/semi-illustrations/-/semi-illustrations-2.77.1.tgz", + "integrity": "sha512-FlESLOPaY0SadiSIFcP4gqJUk+CYkd4rHK6YP9bfjmU26v7h1S02H7pGLLV1lS0WnY4j0ad4zqRV9tbXFvba9g==", "peerDependencies": { "react": ">=16.0.0" } }, "node_modules/@douyinfe/semi-json-viewer-core": { - "version": "2.76.1", - "resolved": "https://registry.npmjs.org/@douyinfe/semi-json-viewer-core/-/semi-json-viewer-core-2.76.1.tgz", - "integrity": "sha512-MOPpYhJcAPX0k1RN9RogZA/jwsDJ5eXgw0nAJZ+mc++pRF6IPovbT17ztldxaLOX6MrYgzN6cll+dK6FCBwlEw==", + "version": "2.77.1", + "resolved": "https://registry.npmjs.org/@douyinfe/semi-json-viewer-core/-/semi-json-viewer-core-2.77.1.tgz", + "integrity": "sha512-LOW+7ga2OzFIL9pGKftwHfl1kKLTV3x6Cs857iyvq9GIF/GHbAboiHcKUy2OZIHfy66zvP+Focs+yhfZG7IcZw==", "dependencies": { "jsonc-parser": "^3.3.1" } }, "node_modules/@douyinfe/semi-theme-default": { - "version": "2.76.1", - "resolved": "https://registry.npmjs.org/@douyinfe/semi-theme-default/-/semi-theme-default-2.76.1.tgz", - "integrity": "sha512-rl4hyh0ePPMPy/lo68hmiU4EcbzFX6F4pzka0njcCior2b2jjCZ24OA6l4E9xbNJskSINy7BzpNhasBhJ95wAQ==" + "version": "2.77.1", + "resolved": "https://registry.npmjs.org/@douyinfe/semi-theme-default/-/semi-theme-default-2.77.1.tgz", + "integrity": "sha512-Rug75C7jjSqmCP2L2tBI0K4dnXuo4GardzwSzdSjxDkiaIXwOwR5KE0K1FRbKWkQ7xmxbyRu4S6Pff+CDEJ/lA==" }, "node_modules/@douyinfe/semi-ui": { - "version": "2.76.1", - "resolved": "https://registry.npmjs.org/@douyinfe/semi-ui/-/semi-ui-2.76.1.tgz", - "integrity": "sha512-78WKNIolD8v8aEdga2o77NL9x8bcfqM7mM0Y54h4rzt+miCB7lnTjX+ryGoEgNXEJFgjkMF5vadFjWTLqG2a6w==", + "version": "2.77.1", + "resolved": "https://registry.npmjs.org/@douyinfe/semi-ui/-/semi-ui-2.77.1.tgz", + "integrity": "sha512-eIy7kr9OleCwlNRby3VICSGScHM23Zt2u7TJpID68qN3WrfQowGaB4wQ/0k5bvpLzv463HQnVWFk5aak+v46yw==", "dependencies": { "@dnd-kit/core": "^6.0.8", "@dnd-kit/sortable": "^7.0.2", "@dnd-kit/utilities": "^3.2.1", - "@douyinfe/semi-animation": "2.76.1", - "@douyinfe/semi-animation-react": "2.76.1", - "@douyinfe/semi-foundation": "2.76.1", - "@douyinfe/semi-icons": "2.76.1", - "@douyinfe/semi-illustrations": "2.76.1", - "@douyinfe/semi-theme-default": "2.76.1", + "@douyinfe/semi-animation": "2.77.1", + "@douyinfe/semi-animation-react": "2.77.1", + "@douyinfe/semi-foundation": "2.77.1", + "@douyinfe/semi-icons": "2.77.1", + "@douyinfe/semi-illustrations": "2.77.1", + "@douyinfe/semi-theme-default": "2.77.1", "async-validator": "^3.5.0", "classnames": "^2.2.6", "copy-text-to-clipboard": "^2.1.1", @@ -3619,14 +3619,6 @@ "node": ">=10.13.0" } }, - "node_modules/@types/acorn": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/@types/acorn/-/acorn-4.0.6.tgz", - "integrity": "sha512-veQTnWP+1D/xbxVrPC3zHnCZRjSrKfhbMUlEA43iMZLu7EsnTtkJklIuwrCPbOi8YkvDQAiW05VQQFvvz9oieQ==", - "dependencies": { - "@types/estree": "*" - } - }, "node_modules/@types/body-parser": { "version": "1.19.2", "resolved": "https://registry.npmmirror.com/@types/body-parser/-/body-parser-1.19.2.tgz", @@ -9453,9 +9445,9 @@ } }, "node_modules/micromark-extension-mdx-expression": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/micromark-extension-mdx-expression/-/micromark-extension-mdx-expression-3.0.0.tgz", - "integrity": "sha512-sI0nwhUDz97xyzqJAbHQhp5TfaxEvZZZ2JDqUo+7NvyIYG6BZ5CPPqj2ogUoPJlmXHBnyZUzISg9+oUmU6tUjQ==", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/micromark-extension-mdx-expression/-/micromark-extension-mdx-expression-3.0.1.tgz", + "integrity": "sha512-dD/ADLJ1AeMvSAKBwO22zG22N4ybhe7kFIZ3LsDI0GlsNr2A3KYxb0LdC1u5rj4Nw+CHKY0RVdnHX8vj8ejm4Q==", "funding": [ { "type": "GitHub Sponsors", @@ -9478,11 +9470,10 @@ } }, "node_modules/micromark-extension-mdx-jsx": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/micromark-extension-mdx-jsx/-/micromark-extension-mdx-jsx-3.0.1.tgz", - "integrity": "sha512-vNuFb9czP8QCtAQcEJn0UJQJZA8Dk6DXKBqx+bg/w0WGuSxDxNr7hErW89tHUY31dUW4NqEOWwmEUNhjTFmHkg==", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/micromark-extension-mdx-jsx/-/micromark-extension-mdx-jsx-3.0.2.tgz", + "integrity": "sha512-e5+q1DjMh62LZAJOnDraSSbDMvGJ8x3cbjygy2qFEi7HCeUT4BDKCvMozPozcD6WmOt6sVvYDNBKhFSz3kjOVQ==", "dependencies": { - "@types/acorn": "^4.0.0", "@types/estree": "^1.0.0", "devlop": "^1.0.0", "estree-util-is-identifier-name": "^3.0.0", @@ -9652,9 +9643,9 @@ } }, "node_modules/micromark-factory-mdx-expression": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/micromark-factory-mdx-expression/-/micromark-factory-mdx-expression-2.0.2.tgz", - "integrity": "sha512-5E5I2pFzJyg2CtemqAbcyCktpHXuJbABnsb32wX2U8IQKhhVFBqkcZR5LRm1WVoFqa4kTueZK4abep7wdo9nrw==", + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/micromark-factory-mdx-expression/-/micromark-factory-mdx-expression-2.0.3.tgz", + "integrity": "sha512-kQnEtA3vzucU2BkrIa8/VaSAsP+EJ3CKOvhMuJgOEGg9KDC6OAY6nSnNDVRiVNRqj7Y4SlSzcStaH/5jge8JdQ==", "funding": [ { "type": "GitHub Sponsors", @@ -9899,9 +9890,9 @@ ] }, "node_modules/micromark-util-events-to-acorn": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/micromark-util-events-to-acorn/-/micromark-util-events-to-acorn-2.0.2.tgz", - "integrity": "sha512-Fk+xmBrOv9QZnEDguL9OI9/NQQp6Hz4FuQ4YmCb/5V7+9eAh1s6AYSvL20kHkD67YIg7EpE54TiSlcsf3vyZgA==", + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/micromark-util-events-to-acorn/-/micromark-util-events-to-acorn-2.0.3.tgz", + "integrity": "sha512-jmsiEIiZ1n7X1Rr5k8wVExBQCg5jy4UXVADItHmNk1zkwEVhBuIUKRu3fqv+hs4nxLISi2DQGlqIOGiFxgbfHg==", "funding": [ { "type": "GitHub Sponsors", @@ -9913,7 +9904,6 @@ } ], "dependencies": { - "@types/acorn": "^4.0.0", "@types/estree": "^1.0.0", "@types/unist": "^3.0.0", "devlop": "^1.0.0", @@ -17396,35 +17386,35 @@ } }, "@douyinfe/semi-animation": { - "version": "2.76.1", - "resolved": "https://registry.npmjs.org/@douyinfe/semi-animation/-/semi-animation-2.76.1.tgz", - "integrity": "sha512-8ghwnFe5Iq/xYd1hnA0/efesrAspdGiSgIjl1C8x2y1LjUWwlNjTwhhTTI1TPaJTT41m5YpWbp0G+Eg1syVq7A==", + "version": "2.77.1", + "resolved": "https://registry.npmjs.org/@douyinfe/semi-animation/-/semi-animation-2.77.1.tgz", + "integrity": "sha512-Q1D7whvQe0D+mPov8hXeH/e1uR/iBhpGGcW1LCTL2pSVMEZEYGJLf2KeXTTiCIgRVWm0PRH3Sux7auJ64zg7vw==", "requires": { "bezier-easing": "^2.1.0" } }, "@douyinfe/semi-animation-react": { - "version": "2.76.1", - "resolved": "https://registry.npmjs.org/@douyinfe/semi-animation-react/-/semi-animation-react-2.76.1.tgz", - "integrity": "sha512-Cyu3ZhiE5qyvY+9yRBHg8pHL8Tkq7bR304TWGowz7r65F1viV+88NpDdx7f2foGIxyGjIS7IOa6EFJtV/9pu/w==", + "version": "2.77.1", + "resolved": "https://registry.npmjs.org/@douyinfe/semi-animation-react/-/semi-animation-react-2.77.1.tgz", + "integrity": "sha512-imELR02pufgGFkZURfTd9oBUtZPYhHvXv9WsYoRvEoBM9U7yzxrR6Fb/Lc3TH+WHVJ2oZHH2S0APS5t1MceEOw==", "requires": { - "@douyinfe/semi-animation": "2.76.1", - "@douyinfe/semi-animation-styled": "2.76.1", + "@douyinfe/semi-animation": "2.77.1", + "@douyinfe/semi-animation-styled": "2.77.1", "classnames": "^2.2.6" } }, "@douyinfe/semi-animation-styled": { - "version": "2.76.1", - "resolved": "https://registry.npmjs.org/@douyinfe/semi-animation-styled/-/semi-animation-styled-2.76.1.tgz", - "integrity": "sha512-Rm8DX5uYHkJnuRab2nYydu4E7zPFuBZK0Qr/xrcA89lM/J+5XnmOA7NlaIxUoN37lwRxErNr0Vljs3RhMPfsMw==" + "version": "2.77.1", + "resolved": "https://registry.npmjs.org/@douyinfe/semi-animation-styled/-/semi-animation-styled-2.77.1.tgz", + "integrity": "sha512-FBRroqVJroel1CXmBgV58ulZHG2xUVInJF7k0FAag54noKKaToEobSxRjiTJ6JHne3ZDU1M6sBqpbzYJElFnPQ==" }, "@douyinfe/semi-foundation": { - "version": "2.76.1", - "resolved": "https://registry.npmjs.org/@douyinfe/semi-foundation/-/semi-foundation-2.76.1.tgz", - "integrity": "sha512-u9KGP6p5N/KCa6EHZolSZ2OVpKAjdDJ0tV9HcW4DGYb/rHaq2rFQlITO47mbKx24dsflOuwjyTCsyYlFXYTwqw==", + "version": "2.77.1", + "resolved": "https://registry.npmjs.org/@douyinfe/semi-foundation/-/semi-foundation-2.77.1.tgz", + "integrity": "sha512-DAXRy8ryLNzbKAiTAv+RrivGCoMU0asv2cO7PNV5aBq0ICB8XXn97FHyZo6Wb5NpqpyMhOaOr8Ro1bfpd0FeaA==", "requires": { - "@douyinfe/semi-animation": "2.76.1", - "@douyinfe/semi-json-viewer-core": "2.76.1", + "@douyinfe/semi-animation": "2.77.1", + "@douyinfe/semi-json-viewer-core": "2.77.1", "@mdx-js/mdx": "^3.0.1", "async-validator": "^3.5.0", "classnames": "^2.2.6", @@ -17606,46 +17596,46 @@ } }, "@douyinfe/semi-icons": { - "version": "2.76.1", - "resolved": "https://registry.npmjs.org/@douyinfe/semi-icons/-/semi-icons-2.76.1.tgz", - "integrity": "sha512-3eK4fdIjwhA4w8ez7FOkI+FCTNwd3qMKqIHvlngtR7/NboMkwDugDimejJoABChLB3ZgosmnF/FjYnq/n8dSPw==", + "version": "2.77.1", + "resolved": "https://registry.npmjs.org/@douyinfe/semi-icons/-/semi-icons-2.77.1.tgz", + "integrity": "sha512-IbGqYzbjzCoSd+//HlO/Gn1c3XmbulQwGys+JgDfQhYIbPeGyhQfLk56Q7ku3vJGC8BGy7dUmR9MbeTf1UQGtw==", "requires": { "classnames": "^2.2.6" } }, "@douyinfe/semi-illustrations": { - "version": "2.76.1", - "resolved": "https://registry.npmjs.org/@douyinfe/semi-illustrations/-/semi-illustrations-2.76.1.tgz", - "integrity": "sha512-wC4iKtKXETZjjB3iQ87PiYmsyS26/2PwsD5dX5d1MPntcjtuv+u1isCH1ZHRTuOUw3Qcb3sckxchwwoHgjUQhg==", + "version": "2.77.1", + "resolved": "https://registry.npmjs.org/@douyinfe/semi-illustrations/-/semi-illustrations-2.77.1.tgz", + "integrity": "sha512-FlESLOPaY0SadiSIFcP4gqJUk+CYkd4rHK6YP9bfjmU26v7h1S02H7pGLLV1lS0WnY4j0ad4zqRV9tbXFvba9g==", "requires": {} }, "@douyinfe/semi-json-viewer-core": { - "version": "2.76.1", - "resolved": "https://registry.npmjs.org/@douyinfe/semi-json-viewer-core/-/semi-json-viewer-core-2.76.1.tgz", - "integrity": "sha512-MOPpYhJcAPX0k1RN9RogZA/jwsDJ5eXgw0nAJZ+mc++pRF6IPovbT17ztldxaLOX6MrYgzN6cll+dK6FCBwlEw==", + "version": "2.77.1", + "resolved": "https://registry.npmjs.org/@douyinfe/semi-json-viewer-core/-/semi-json-viewer-core-2.77.1.tgz", + "integrity": "sha512-LOW+7ga2OzFIL9pGKftwHfl1kKLTV3x6Cs857iyvq9GIF/GHbAboiHcKUy2OZIHfy66zvP+Focs+yhfZG7IcZw==", "requires": { "jsonc-parser": "^3.3.1" } }, "@douyinfe/semi-theme-default": { - "version": "2.76.1", - "resolved": "https://registry.npmjs.org/@douyinfe/semi-theme-default/-/semi-theme-default-2.76.1.tgz", - "integrity": "sha512-rl4hyh0ePPMPy/lo68hmiU4EcbzFX6F4pzka0njcCior2b2jjCZ24OA6l4E9xbNJskSINy7BzpNhasBhJ95wAQ==" + "version": "2.77.1", + "resolved": "https://registry.npmjs.org/@douyinfe/semi-theme-default/-/semi-theme-default-2.77.1.tgz", + "integrity": "sha512-Rug75C7jjSqmCP2L2tBI0K4dnXuo4GardzwSzdSjxDkiaIXwOwR5KE0K1FRbKWkQ7xmxbyRu4S6Pff+CDEJ/lA==" }, "@douyinfe/semi-ui": { - "version": "2.76.1", - "resolved": "https://registry.npmjs.org/@douyinfe/semi-ui/-/semi-ui-2.76.1.tgz", - "integrity": "sha512-78WKNIolD8v8aEdga2o77NL9x8bcfqM7mM0Y54h4rzt+miCB7lnTjX+ryGoEgNXEJFgjkMF5vadFjWTLqG2a6w==", + "version": "2.77.1", + "resolved": "https://registry.npmjs.org/@douyinfe/semi-ui/-/semi-ui-2.77.1.tgz", + "integrity": "sha512-eIy7kr9OleCwlNRby3VICSGScHM23Zt2u7TJpID68qN3WrfQowGaB4wQ/0k5bvpLzv463HQnVWFk5aak+v46yw==", "requires": { "@dnd-kit/core": "^6.0.8", "@dnd-kit/sortable": "^7.0.2", "@dnd-kit/utilities": "^3.2.1", - "@douyinfe/semi-animation": "2.76.1", - "@douyinfe/semi-animation-react": "2.76.1", - "@douyinfe/semi-foundation": "2.76.1", - "@douyinfe/semi-icons": "2.76.1", - "@douyinfe/semi-illustrations": "2.76.1", - "@douyinfe/semi-theme-default": "2.76.1", + "@douyinfe/semi-animation": "2.77.1", + "@douyinfe/semi-animation-react": "2.77.1", + "@douyinfe/semi-foundation": "2.77.1", + "@douyinfe/semi-icons": "2.77.1", + "@douyinfe/semi-illustrations": "2.77.1", + "@douyinfe/semi-theme-default": "2.77.1", "async-validator": "^3.5.0", "classnames": "^2.2.6", "copy-text-to-clipboard": "^2.1.1", @@ -18049,14 +18039,6 @@ "resolved": "https://registry.npmmirror.com/@trysound/sax/-/sax-0.2.0.tgz", "integrity": "sha512-L7z9BgrNEcYyUYtF+HaEfiS5ebkh9jXqbszz7pC0hRBPaatV0XjSD3+eHrpqFemQfgwiFF0QPIarnIihIDn7OA==" }, - "@types/acorn": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/@types/acorn/-/acorn-4.0.6.tgz", - "integrity": "sha512-veQTnWP+1D/xbxVrPC3zHnCZRjSrKfhbMUlEA43iMZLu7EsnTtkJklIuwrCPbOi8YkvDQAiW05VQQFvvz9oieQ==", - "requires": { - "@types/estree": "*" - } - }, "@types/body-parser": { "version": "1.19.2", "resolved": "https://registry.npmmirror.com/@types/body-parser/-/body-parser-1.19.2.tgz", @@ -22635,9 +22617,9 @@ } }, "micromark-extension-mdx-expression": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/micromark-extension-mdx-expression/-/micromark-extension-mdx-expression-3.0.0.tgz", - "integrity": "sha512-sI0nwhUDz97xyzqJAbHQhp5TfaxEvZZZ2JDqUo+7NvyIYG6BZ5CPPqj2ogUoPJlmXHBnyZUzISg9+oUmU6tUjQ==", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/micromark-extension-mdx-expression/-/micromark-extension-mdx-expression-3.0.1.tgz", + "integrity": "sha512-dD/ADLJ1AeMvSAKBwO22zG22N4ybhe7kFIZ3LsDI0GlsNr2A3KYxb0LdC1u5rj4Nw+CHKY0RVdnHX8vj8ejm4Q==", "requires": { "@types/estree": "^1.0.0", "devlop": "^1.0.0", @@ -22650,11 +22632,10 @@ } }, "micromark-extension-mdx-jsx": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/micromark-extension-mdx-jsx/-/micromark-extension-mdx-jsx-3.0.1.tgz", - "integrity": "sha512-vNuFb9czP8QCtAQcEJn0UJQJZA8Dk6DXKBqx+bg/w0WGuSxDxNr7hErW89tHUY31dUW4NqEOWwmEUNhjTFmHkg==", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/micromark-extension-mdx-jsx/-/micromark-extension-mdx-jsx-3.0.2.tgz", + "integrity": "sha512-e5+q1DjMh62LZAJOnDraSSbDMvGJ8x3cbjygy2qFEi7HCeUT4BDKCvMozPozcD6WmOt6sVvYDNBKhFSz3kjOVQ==", "requires": { - "@types/acorn": "^4.0.0", "@types/estree": "^1.0.0", "devlop": "^1.0.0", "estree-util-is-identifier-name": "^3.0.0", @@ -22776,9 +22757,9 @@ } }, "micromark-factory-mdx-expression": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/micromark-factory-mdx-expression/-/micromark-factory-mdx-expression-2.0.2.tgz", - "integrity": "sha512-5E5I2pFzJyg2CtemqAbcyCktpHXuJbABnsb32wX2U8IQKhhVFBqkcZR5LRm1WVoFqa4kTueZK4abep7wdo9nrw==", + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/micromark-factory-mdx-expression/-/micromark-factory-mdx-expression-2.0.3.tgz", + "integrity": "sha512-kQnEtA3vzucU2BkrIa8/VaSAsP+EJ3CKOvhMuJgOEGg9KDC6OAY6nSnNDVRiVNRqj7Y4SlSzcStaH/5jge8JdQ==", "requires": { "@types/estree": "^1.0.0", "devlop": "^1.0.0", @@ -22907,11 +22888,10 @@ "integrity": "sha512-c3cVx2y4KqUnwopcO9b/SCdo2O67LwJJ/UyqGfbigahfegL9myoEFoDYZgkT7f36T0bLrM9hZTAaAyH+PCAXjw==" }, "micromark-util-events-to-acorn": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/micromark-util-events-to-acorn/-/micromark-util-events-to-acorn-2.0.2.tgz", - "integrity": "sha512-Fk+xmBrOv9QZnEDguL9OI9/NQQp6Hz4FuQ4YmCb/5V7+9eAh1s6AYSvL20kHkD67YIg7EpE54TiSlcsf3vyZgA==", + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/micromark-util-events-to-acorn/-/micromark-util-events-to-acorn-2.0.3.tgz", + "integrity": "sha512-jmsiEIiZ1n7X1Rr5k8wVExBQCg5jy4UXVADItHmNk1zkwEVhBuIUKRu3fqv+hs4nxLISi2DQGlqIOGiFxgbfHg==", "requires": { - "@types/acorn": "^4.0.0", "@types/estree": "^1.0.0", "@types/unist": "^3.0.0", "devlop": "^1.0.0", diff --git a/package.json b/package.json index d41d0a2e..f42d02fa 100644 --- a/package.json +++ b/package.json @@ -21,7 +21,7 @@ "@docusaurus/plugin-content-pages": "^2.4.3", "@docusaurus/plugin-sitemap": "^2.4.3", "@docusaurus/preset-classic": "2.4.3", - "@douyinfe/semi-ui": "^2.76.1", + "@douyinfe/semi-ui": "^2.77.1", "asciinema-player": "^3.9.0", "clsx": "^2.1.1", "react": "^17.0.2", From a25dc9bfcf34a76358a7f9850bef8884ae0b09f3 Mon Sep 17 00:00:00 2001 From: Arhell Date: Thu, 10 Apr 2025 00:54:12 +0300 Subject: [PATCH 10/15] update semi-ui to 2.78.0 Signed-off-by: Arhell --- package-lock.json | 162 +++++++++++++++++++++++----------------------- package.json | 2 +- 2 files changed, 82 insertions(+), 82 deletions(-) diff --git a/package-lock.json b/package-lock.json index f1da5b1c..dd817ce9 100644 --- a/package-lock.json +++ b/package-lock.json @@ -14,7 +14,7 @@ "@docusaurus/plugin-content-pages": "^2.4.3", "@docusaurus/plugin-sitemap": "^2.4.3", "@docusaurus/preset-classic": "2.4.3", - "@douyinfe/semi-ui": "^2.77.1", + "@douyinfe/semi-ui": "^2.78.0", "asciinema-player": "^3.9.0", "clsx": "^2.1.1", "react": "^17.0.2", @@ -2764,35 +2764,35 @@ } }, "node_modules/@douyinfe/semi-animation": { - "version": "2.77.1", - "resolved": "https://registry.npmjs.org/@douyinfe/semi-animation/-/semi-animation-2.77.1.tgz", - "integrity": "sha512-Q1D7whvQe0D+mPov8hXeH/e1uR/iBhpGGcW1LCTL2pSVMEZEYGJLf2KeXTTiCIgRVWm0PRH3Sux7auJ64zg7vw==", + "version": "2.78.0", + "resolved": "https://registry.npmjs.org/@douyinfe/semi-animation/-/semi-animation-2.78.0.tgz", + "integrity": "sha512-M54Typ1mHU4BIT/em/WlpmKM0V1yk2EFoVy9qtTr0+vkIgTfE+w53A7/NX2cyWq97FHCD9k4jQGGK31Z1YqMQg==", "dependencies": { "bezier-easing": "^2.1.0" } }, "node_modules/@douyinfe/semi-animation-react": { - "version": "2.77.1", - "resolved": "https://registry.npmjs.org/@douyinfe/semi-animation-react/-/semi-animation-react-2.77.1.tgz", - "integrity": "sha512-imELR02pufgGFkZURfTd9oBUtZPYhHvXv9WsYoRvEoBM9U7yzxrR6Fb/Lc3TH+WHVJ2oZHH2S0APS5t1MceEOw==", + "version": "2.78.0", + "resolved": "https://registry.npmjs.org/@douyinfe/semi-animation-react/-/semi-animation-react-2.78.0.tgz", + "integrity": "sha512-81DUulQUnjjuWeAw73gOay+BHLEHchCcvGhyWZVL1s/CYi73AoivmraWc5GrCWdZzT8nMxSAJ85hesXnwGVHgg==", "dependencies": { - "@douyinfe/semi-animation": "2.77.1", - "@douyinfe/semi-animation-styled": "2.77.1", + "@douyinfe/semi-animation": "2.78.0", + "@douyinfe/semi-animation-styled": "2.78.0", "classnames": "^2.2.6" } }, "node_modules/@douyinfe/semi-animation-styled": { - "version": "2.77.1", - "resolved": "https://registry.npmjs.org/@douyinfe/semi-animation-styled/-/semi-animation-styled-2.77.1.tgz", - "integrity": "sha512-FBRroqVJroel1CXmBgV58ulZHG2xUVInJF7k0FAag54noKKaToEobSxRjiTJ6JHne3ZDU1M6sBqpbzYJElFnPQ==" + "version": "2.78.0", + "resolved": "https://registry.npmjs.org/@douyinfe/semi-animation-styled/-/semi-animation-styled-2.78.0.tgz", + "integrity": "sha512-NYMuI4SOl4+fV4/S8qJfL8ip1EkjO+G6rtlWTmtvc77ENHoBsf6C+qLxupi5e+IKGBy/Vfr52hPDOsOC8FWokQ==" }, "node_modules/@douyinfe/semi-foundation": { - "version": "2.77.1", - "resolved": "https://registry.npmjs.org/@douyinfe/semi-foundation/-/semi-foundation-2.77.1.tgz", - "integrity": "sha512-DAXRy8ryLNzbKAiTAv+RrivGCoMU0asv2cO7PNV5aBq0ICB8XXn97FHyZo6Wb5NpqpyMhOaOr8Ro1bfpd0FeaA==", + "version": "2.78.0", + "resolved": "https://registry.npmjs.org/@douyinfe/semi-foundation/-/semi-foundation-2.78.0.tgz", + "integrity": "sha512-LVBcVUDM74FMmzx/L6b/Vk/W9b4MnQCb1+1t7Q2BU3v5DC4dfhgRpbloxj3JmAyOgAcxJz2VDE07Sgzt9mS6ww==", "dependencies": { - "@douyinfe/semi-animation": "2.77.1", - "@douyinfe/semi-json-viewer-core": "2.77.1", + "@douyinfe/semi-animation": "2.78.0", + "@douyinfe/semi-json-viewer-core": "2.78.0", "@mdx-js/mdx": "^3.0.1", "async-validator": "^3.5.0", "classnames": "^2.2.6", @@ -3033,9 +3033,9 @@ } }, "node_modules/@douyinfe/semi-icons": { - "version": "2.77.1", - "resolved": "https://registry.npmjs.org/@douyinfe/semi-icons/-/semi-icons-2.77.1.tgz", - "integrity": "sha512-IbGqYzbjzCoSd+//HlO/Gn1c3XmbulQwGys+JgDfQhYIbPeGyhQfLk56Q7ku3vJGC8BGy7dUmR9MbeTf1UQGtw==", + "version": "2.78.0", + "resolved": "https://registry.npmjs.org/@douyinfe/semi-icons/-/semi-icons-2.78.0.tgz", + "integrity": "sha512-8Sugn7lgAqgHThX3EJT9npyQ2tXFIEZoV6KkYMNFdewOlZ23O1VYEHwh4ktdNVsgtw5CTQ5+UQrsuM3mqszAVw==", "dependencies": { "classnames": "^2.2.6" }, @@ -3044,40 +3044,40 @@ } }, "node_modules/@douyinfe/semi-illustrations": { - "version": "2.77.1", - "resolved": "https://registry.npmjs.org/@douyinfe/semi-illustrations/-/semi-illustrations-2.77.1.tgz", - "integrity": "sha512-FlESLOPaY0SadiSIFcP4gqJUk+CYkd4rHK6YP9bfjmU26v7h1S02H7pGLLV1lS0WnY4j0ad4zqRV9tbXFvba9g==", + "version": "2.78.0", + "resolved": "https://registry.npmjs.org/@douyinfe/semi-illustrations/-/semi-illustrations-2.78.0.tgz", + "integrity": "sha512-690Llbnqsf1OZYuFvHhFWLpJkj6Gk5fjnWjJzUUcgfS5Apn/FBRHH2tkGyn4eU2iBihta1zzC6/G7Orp7qID5A==", "peerDependencies": { "react": ">=16.0.0" } }, "node_modules/@douyinfe/semi-json-viewer-core": { - "version": "2.77.1", - "resolved": "https://registry.npmjs.org/@douyinfe/semi-json-viewer-core/-/semi-json-viewer-core-2.77.1.tgz", - "integrity": "sha512-LOW+7ga2OzFIL9pGKftwHfl1kKLTV3x6Cs857iyvq9GIF/GHbAboiHcKUy2OZIHfy66zvP+Focs+yhfZG7IcZw==", + "version": "2.78.0", + "resolved": "https://registry.npmjs.org/@douyinfe/semi-json-viewer-core/-/semi-json-viewer-core-2.78.0.tgz", + "integrity": "sha512-htbOfZp079wxoKaZkGwxd7pFfxU+tfzihGMmTy3b3Dneut3cPQmRVkyCSbJjuYwOkNEyHQ7Cva6KFbNhfeKxqw==", "dependencies": { "jsonc-parser": "^3.3.1" } }, "node_modules/@douyinfe/semi-theme-default": { - "version": "2.77.1", - "resolved": "https://registry.npmjs.org/@douyinfe/semi-theme-default/-/semi-theme-default-2.77.1.tgz", - "integrity": "sha512-Rug75C7jjSqmCP2L2tBI0K4dnXuo4GardzwSzdSjxDkiaIXwOwR5KE0K1FRbKWkQ7xmxbyRu4S6Pff+CDEJ/lA==" + "version": "2.78.0", + "resolved": "https://registry.npmjs.org/@douyinfe/semi-theme-default/-/semi-theme-default-2.78.0.tgz", + "integrity": "sha512-LtF6G+cmGNNjDE08K5VCG2n2cOi/hPIBTCfvwwXot8druEw94RGQ16rnAKNDMhASWJbiAzaVWKGhDQLDCwfZvg==" }, "node_modules/@douyinfe/semi-ui": { - "version": "2.77.1", - "resolved": "https://registry.npmjs.org/@douyinfe/semi-ui/-/semi-ui-2.77.1.tgz", - "integrity": "sha512-eIy7kr9OleCwlNRby3VICSGScHM23Zt2u7TJpID68qN3WrfQowGaB4wQ/0k5bvpLzv463HQnVWFk5aak+v46yw==", + "version": "2.78.0", + "resolved": "https://registry.npmjs.org/@douyinfe/semi-ui/-/semi-ui-2.78.0.tgz", + "integrity": "sha512-S8AvtfwLwb147mRzX83WmnW4op5YXoD0RSdnDzWrWDNNQyszV7VkV6+f2VIg27e4rReexYkMG1SzJLdzgoZKGQ==", "dependencies": { "@dnd-kit/core": "^6.0.8", "@dnd-kit/sortable": "^7.0.2", "@dnd-kit/utilities": "^3.2.1", - "@douyinfe/semi-animation": "2.77.1", - "@douyinfe/semi-animation-react": "2.77.1", - "@douyinfe/semi-foundation": "2.77.1", - "@douyinfe/semi-icons": "2.77.1", - "@douyinfe/semi-illustrations": "2.77.1", - "@douyinfe/semi-theme-default": "2.77.1", + "@douyinfe/semi-animation": "2.78.0", + "@douyinfe/semi-animation-react": "2.78.0", + "@douyinfe/semi-foundation": "2.78.0", + "@douyinfe/semi-icons": "2.78.0", + "@douyinfe/semi-illustrations": "2.78.0", + "@douyinfe/semi-theme-default": "2.78.0", "async-validator": "^3.5.0", "classnames": "^2.2.6", "copy-text-to-clipboard": "^2.1.1", @@ -12669,9 +12669,9 @@ } }, "node_modules/remark-rehype": { - "version": "11.1.1", - "resolved": "https://registry.npmjs.org/remark-rehype/-/remark-rehype-11.1.1.tgz", - "integrity": "sha512-g/osARvjkBXb6Wo0XvAeXQohVta8i84ACbenPpoSsxTOQH/Ae0/RGP4WZgnMH5pMLpsj4FG7OHmcIcXxpza8eQ==", + "version": "11.1.2", + "resolved": "https://registry.npmjs.org/remark-rehype/-/remark-rehype-11.1.2.tgz", + "integrity": "sha512-Dh7l57ianaEoIpzbp0PC9UKAdCSVklD8E5Rpw7ETfbTl3FqcOOgq5q2LVDhgGCkaBv7p24JXikPdvhhmHvKMsw==", "dependencies": { "@types/hast": "^3.0.0", "@types/mdast": "^4.0.0", @@ -17386,35 +17386,35 @@ } }, "@douyinfe/semi-animation": { - "version": "2.77.1", - "resolved": "https://registry.npmjs.org/@douyinfe/semi-animation/-/semi-animation-2.77.1.tgz", - "integrity": "sha512-Q1D7whvQe0D+mPov8hXeH/e1uR/iBhpGGcW1LCTL2pSVMEZEYGJLf2KeXTTiCIgRVWm0PRH3Sux7auJ64zg7vw==", + "version": "2.78.0", + "resolved": "https://registry.npmjs.org/@douyinfe/semi-animation/-/semi-animation-2.78.0.tgz", + "integrity": "sha512-M54Typ1mHU4BIT/em/WlpmKM0V1yk2EFoVy9qtTr0+vkIgTfE+w53A7/NX2cyWq97FHCD9k4jQGGK31Z1YqMQg==", "requires": { "bezier-easing": "^2.1.0" } }, "@douyinfe/semi-animation-react": { - "version": "2.77.1", - "resolved": "https://registry.npmjs.org/@douyinfe/semi-animation-react/-/semi-animation-react-2.77.1.tgz", - "integrity": "sha512-imELR02pufgGFkZURfTd9oBUtZPYhHvXv9WsYoRvEoBM9U7yzxrR6Fb/Lc3TH+WHVJ2oZHH2S0APS5t1MceEOw==", + "version": "2.78.0", + "resolved": "https://registry.npmjs.org/@douyinfe/semi-animation-react/-/semi-animation-react-2.78.0.tgz", + "integrity": "sha512-81DUulQUnjjuWeAw73gOay+BHLEHchCcvGhyWZVL1s/CYi73AoivmraWc5GrCWdZzT8nMxSAJ85hesXnwGVHgg==", "requires": { - "@douyinfe/semi-animation": "2.77.1", - "@douyinfe/semi-animation-styled": "2.77.1", + "@douyinfe/semi-animation": "2.78.0", + "@douyinfe/semi-animation-styled": "2.78.0", "classnames": "^2.2.6" } }, "@douyinfe/semi-animation-styled": { - "version": "2.77.1", - "resolved": "https://registry.npmjs.org/@douyinfe/semi-animation-styled/-/semi-animation-styled-2.77.1.tgz", - "integrity": "sha512-FBRroqVJroel1CXmBgV58ulZHG2xUVInJF7k0FAag54noKKaToEobSxRjiTJ6JHne3ZDU1M6sBqpbzYJElFnPQ==" + "version": "2.78.0", + "resolved": "https://registry.npmjs.org/@douyinfe/semi-animation-styled/-/semi-animation-styled-2.78.0.tgz", + "integrity": "sha512-NYMuI4SOl4+fV4/S8qJfL8ip1EkjO+G6rtlWTmtvc77ENHoBsf6C+qLxupi5e+IKGBy/Vfr52hPDOsOC8FWokQ==" }, "@douyinfe/semi-foundation": { - "version": "2.77.1", - "resolved": "https://registry.npmjs.org/@douyinfe/semi-foundation/-/semi-foundation-2.77.1.tgz", - "integrity": "sha512-DAXRy8ryLNzbKAiTAv+RrivGCoMU0asv2cO7PNV5aBq0ICB8XXn97FHyZo6Wb5NpqpyMhOaOr8Ro1bfpd0FeaA==", + "version": "2.78.0", + "resolved": "https://registry.npmjs.org/@douyinfe/semi-foundation/-/semi-foundation-2.78.0.tgz", + "integrity": "sha512-LVBcVUDM74FMmzx/L6b/Vk/W9b4MnQCb1+1t7Q2BU3v5DC4dfhgRpbloxj3JmAyOgAcxJz2VDE07Sgzt9mS6ww==", "requires": { - "@douyinfe/semi-animation": "2.77.1", - "@douyinfe/semi-json-viewer-core": "2.77.1", + "@douyinfe/semi-animation": "2.78.0", + "@douyinfe/semi-json-viewer-core": "2.78.0", "@mdx-js/mdx": "^3.0.1", "async-validator": "^3.5.0", "classnames": "^2.2.6", @@ -17596,46 +17596,46 @@ } }, "@douyinfe/semi-icons": { - "version": "2.77.1", - "resolved": "https://registry.npmjs.org/@douyinfe/semi-icons/-/semi-icons-2.77.1.tgz", - "integrity": "sha512-IbGqYzbjzCoSd+//HlO/Gn1c3XmbulQwGys+JgDfQhYIbPeGyhQfLk56Q7ku3vJGC8BGy7dUmR9MbeTf1UQGtw==", + "version": "2.78.0", + "resolved": "https://registry.npmjs.org/@douyinfe/semi-icons/-/semi-icons-2.78.0.tgz", + "integrity": "sha512-8Sugn7lgAqgHThX3EJT9npyQ2tXFIEZoV6KkYMNFdewOlZ23O1VYEHwh4ktdNVsgtw5CTQ5+UQrsuM3mqszAVw==", "requires": { "classnames": "^2.2.6" } }, "@douyinfe/semi-illustrations": { - "version": "2.77.1", - "resolved": "https://registry.npmjs.org/@douyinfe/semi-illustrations/-/semi-illustrations-2.77.1.tgz", - "integrity": "sha512-FlESLOPaY0SadiSIFcP4gqJUk+CYkd4rHK6YP9bfjmU26v7h1S02H7pGLLV1lS0WnY4j0ad4zqRV9tbXFvba9g==", + "version": "2.78.0", + "resolved": "https://registry.npmjs.org/@douyinfe/semi-illustrations/-/semi-illustrations-2.78.0.tgz", + "integrity": "sha512-690Llbnqsf1OZYuFvHhFWLpJkj6Gk5fjnWjJzUUcgfS5Apn/FBRHH2tkGyn4eU2iBihta1zzC6/G7Orp7qID5A==", "requires": {} }, "@douyinfe/semi-json-viewer-core": { - "version": "2.77.1", - "resolved": "https://registry.npmjs.org/@douyinfe/semi-json-viewer-core/-/semi-json-viewer-core-2.77.1.tgz", - "integrity": "sha512-LOW+7ga2OzFIL9pGKftwHfl1kKLTV3x6Cs857iyvq9GIF/GHbAboiHcKUy2OZIHfy66zvP+Focs+yhfZG7IcZw==", + "version": "2.78.0", + "resolved": "https://registry.npmjs.org/@douyinfe/semi-json-viewer-core/-/semi-json-viewer-core-2.78.0.tgz", + "integrity": "sha512-htbOfZp079wxoKaZkGwxd7pFfxU+tfzihGMmTy3b3Dneut3cPQmRVkyCSbJjuYwOkNEyHQ7Cva6KFbNhfeKxqw==", "requires": { "jsonc-parser": "^3.3.1" } }, "@douyinfe/semi-theme-default": { - "version": "2.77.1", - "resolved": "https://registry.npmjs.org/@douyinfe/semi-theme-default/-/semi-theme-default-2.77.1.tgz", - "integrity": "sha512-Rug75C7jjSqmCP2L2tBI0K4dnXuo4GardzwSzdSjxDkiaIXwOwR5KE0K1FRbKWkQ7xmxbyRu4S6Pff+CDEJ/lA==" + "version": "2.78.0", + "resolved": "https://registry.npmjs.org/@douyinfe/semi-theme-default/-/semi-theme-default-2.78.0.tgz", + "integrity": "sha512-LtF6G+cmGNNjDE08K5VCG2n2cOi/hPIBTCfvwwXot8druEw94RGQ16rnAKNDMhASWJbiAzaVWKGhDQLDCwfZvg==" }, "@douyinfe/semi-ui": { - "version": "2.77.1", - "resolved": "https://registry.npmjs.org/@douyinfe/semi-ui/-/semi-ui-2.77.1.tgz", - "integrity": "sha512-eIy7kr9OleCwlNRby3VICSGScHM23Zt2u7TJpID68qN3WrfQowGaB4wQ/0k5bvpLzv463HQnVWFk5aak+v46yw==", + "version": "2.78.0", + "resolved": "https://registry.npmjs.org/@douyinfe/semi-ui/-/semi-ui-2.78.0.tgz", + "integrity": "sha512-S8AvtfwLwb147mRzX83WmnW4op5YXoD0RSdnDzWrWDNNQyszV7VkV6+f2VIg27e4rReexYkMG1SzJLdzgoZKGQ==", "requires": { "@dnd-kit/core": "^6.0.8", "@dnd-kit/sortable": "^7.0.2", "@dnd-kit/utilities": "^3.2.1", - "@douyinfe/semi-animation": "2.77.1", - "@douyinfe/semi-animation-react": "2.77.1", - "@douyinfe/semi-foundation": "2.77.1", - "@douyinfe/semi-icons": "2.77.1", - "@douyinfe/semi-illustrations": "2.77.1", - "@douyinfe/semi-theme-default": "2.77.1", + "@douyinfe/semi-animation": "2.78.0", + "@douyinfe/semi-animation-react": "2.78.0", + "@douyinfe/semi-foundation": "2.78.0", + "@douyinfe/semi-icons": "2.78.0", + "@douyinfe/semi-illustrations": "2.78.0", + "@douyinfe/semi-theme-default": "2.78.0", "async-validator": "^3.5.0", "classnames": "^2.2.6", "copy-text-to-clipboard": "^2.1.1", @@ -24873,9 +24873,9 @@ } }, "remark-rehype": { - "version": "11.1.1", - "resolved": "https://registry.npmjs.org/remark-rehype/-/remark-rehype-11.1.1.tgz", - "integrity": "sha512-g/osARvjkBXb6Wo0XvAeXQohVta8i84ACbenPpoSsxTOQH/Ae0/RGP4WZgnMH5pMLpsj4FG7OHmcIcXxpza8eQ==", + "version": "11.1.2", + "resolved": "https://registry.npmjs.org/remark-rehype/-/remark-rehype-11.1.2.tgz", + "integrity": "sha512-Dh7l57ianaEoIpzbp0PC9UKAdCSVklD8E5Rpw7ETfbTl3FqcOOgq5q2LVDhgGCkaBv7p24JXikPdvhhmHvKMsw==", "requires": { "@types/hast": "^3.0.0", "@types/mdast": "^4.0.0", diff --git a/package.json b/package.json index f42d02fa..301e98c5 100644 --- a/package.json +++ b/package.json @@ -21,7 +21,7 @@ "@docusaurus/plugin-content-pages": "^2.4.3", "@docusaurus/plugin-sitemap": "^2.4.3", "@docusaurus/preset-classic": "2.4.3", - "@douyinfe/semi-ui": "^2.77.1", + "@douyinfe/semi-ui": "^2.78.0", "asciinema-player": "^3.9.0", "clsx": "^2.1.1", "react": "^17.0.2", From 5c2a5de9d6e11d12e2988d8e10d709b633b8e58e Mon Sep 17 00:00:00 2001 From: zhzhuang-zju Date: Mon, 14 Apr 2025 17:13:54 +0800 Subject: [PATCH 11/15] add karmadactl operation scope docs Signed-off-by: zhzhuang-zju --- docs/reference/karmadactl/operation-scope.md | 131 ++++++++++++++++++ .../karmadactl/command-context.drawio | 96 +++++++++++++ .../reference/karmadactl/command-context.png | Bin 0 -> 47015 bytes .../karmadactl/operation-scope.drawio | 121 ++++++++++++++++ .../reference/karmadactl/operation-scope.png | Bin 0 -> 53863 bytes .../reference/karmadactl/operation-scope.md | 131 ++++++++++++++++++ .../karmadactl/command-context.drawio | 96 +++++++++++++ .../reference/karmadactl/command-context.png | Bin 0 -> 47015 bytes .../karmadactl/operation-scope.drawio | 121 ++++++++++++++++ .../reference/karmadactl/operation-scope.png | Bin 0 -> 53863 bytes sidebars.js | 1 + 11 files changed, 697 insertions(+) create mode 100644 docs/reference/karmadactl/operation-scope.md create mode 100644 docs/resources/reference/karmadactl/command-context.drawio create mode 100644 docs/resources/reference/karmadactl/command-context.png create mode 100644 docs/resources/reference/karmadactl/operation-scope.drawio create mode 100644 docs/resources/reference/karmadactl/operation-scope.png create mode 100644 i18n/zh/docusaurus-plugin-content-docs/current/reference/karmadactl/operation-scope.md create mode 100644 i18n/zh/docusaurus-plugin-content-docs/current/resources/reference/karmadactl/command-context.drawio create mode 100644 i18n/zh/docusaurus-plugin-content-docs/current/resources/reference/karmadactl/command-context.png create mode 100644 i18n/zh/docusaurus-plugin-content-docs/current/resources/reference/karmadactl/operation-scope.drawio create mode 100644 i18n/zh/docusaurus-plugin-content-docs/current/resources/reference/karmadactl/operation-scope.png diff --git a/docs/reference/karmadactl/operation-scope.md b/docs/reference/karmadactl/operation-scope.md new file mode 100644 index 00000000..e06fb107 --- /dev/null +++ b/docs/reference/karmadactl/operation-scope.md @@ -0,0 +1,131 @@ +--- +title: Switching Cluster Perspective in Karmadactl + +--- + +# Switching Cluster Perspective in Karmadactl + +Karmadactl introduces the flag `operation-scope` to specify the operation scope of Karmadactl commands. The value of the flag `operation-scope` is of enum type, with each enum value and its meaning as follows: + +- karmada: the operation scope of karmadactl is Karmada control plane. +- members: the operation scope of karmadactl is member clusters. +- all: the operation scope of karmadactl includes Karmada control plane and member clusters. + +> *Note that the operation-scope enumeration values supported by different commands are different, please refer to karmadactl [command] --help for details.* + +The introduction of `operation-scope` provides a flexible way to implement Karmadactl cluster perspective switching. Compared to Kubectl, Karmadactl can manage different target clusters without switching contexts. In addition, with Karmada's multi-cluster resource view, Karmadactl can access resource information of multiple target clusters at the same time, which greatly simplifies the daily operation and maintenance in multi-cluster scenarios. + +![command-context](../../resources/reference/karmadactl/command-context.png) + +## How to Use + +This section describes the application of the flag `operation-scope` to the various Karmadactl commands and uses `karmadactl get` as an example of how to see the distribution of resources across different clusters by switching cluster perspectives. + +### get + +The command `karmadactl get` can be used to view the resources of a control plane or member cluster. In combination with the flag `operation-scope` and `clusters`, `karmadactl get` can display information about the resources of a cluster or clusters. + +- `operation-scope`:The enumeration values `karmada`, `members`, and `all` are supported. Defaults to `karmada`. +- `clusters`:Used to specify target member clusters and only takes effect when the command's operation scope is `members` or `all`. + +![operation-scope](../../resources/reference/karmadactl/operation-scope.png) + +Assume that the Karmada control plane manages three member clusters, member1, member2, and member3 and that the Karmada control plane's Deployment resource, `nginx`, is distributed to all three of these member clusters. Then, we can: + +- View the distribution of resources across the control plane and all member clusters. + + ```bash + $ karmadactl get deployment nginx --operation-scope all + NAME CLUSTER READY UP-TO-DATE AVAILABLE AGE ADOPTION + nginx Karmada 0/2 6 0 18h - + nginx member1 0/2 2 0 37s Y + nginx member2 0/2 2 0 36s Y + nginx member3 0/2 2 0 37s Y + ``` + + > *The CLUSTER column represents the cluster in which the resource resides, and the ADOPTION column represents whether the resource has been taken over by the Karmada control plane.* + +- View the distribution of resources across the control plane and some of the member clusters. + + ```bash + $ karmadactl get deployment nginx --operation-scope all --clusters member1,member2 + NAME CLUSTER READY UP-TO-DATE AVAILABLE AGE ADOPTION + nginx Karmada 4/2 6 4 18h - + nginx member1 2/2 2 2 2m37s Y + nginx member2 0/2 2 0 2m36s Y + ``` + + When `--clusters member1,member2` is set, the member cluster perspective of the command will be limited to clusters member1 and member2. + +- View the resource of Karmada control plane. + + ```bash + $ karmadactl get deployment nginx + NAME CLUSTER READY UP-TO-DATE AVAILABLE AGE ADOPTION + nginx Karmada 6/2 6 6 18h - + $ karmadactl get deployment nginx --operation-scope karmada + NAME CLUSTER READY UP-TO-DATE AVAILABLE AGE ADOPTION + nginx Karmada 6/2 6 6 18h - + ``` + +- View the distribution of resources across all member clusters. + + ```bash + $ karmadactl get deployment nginx --operation-scope members + NAME CLUSTER READY UP-TO-DATE AVAILABLE AGE ADOPTION + nginx member2 2/2 2 2 8m10s Y + nginx member1 2/2 2 2 8m11s Y + nginx member3 2/2 2 2 8m10s Y + ``` + +- View the distribution of resources across some of the member clusters. + + ```bash + $ karmadactl get deployment nginx --operation-scope members --clusters member1,member2 + NAME CLUSTER READY UP-TO-DATE AVAILABLE AGE ADOPTION + nginx member1 2/2 2 2 9m7s Y + nginx member2 2/2 2 2 9m6s Y + ``` + +### describes + +In combination with the flag `operation-scope` and `cluster`, the `karmadactl describe` command can be used to display details of resources in Karmada control plane or a member cluster. + +- `operation-scope`:The enumeration values `karmada` and `members` are supported. Default to `karmada`. +- `cluster`:Used to specify a target member cluster and only takes effect when the command's operation scope is `members`. + +### attach + +In combination with the flag `operation-scope` and `cluster`, the `karmadactl attach` command can attach to a running container in Karmada control plane or a member cluster. + +- `operation-scope`:The enumeration values `karmada` and `members` are supported. Default to `karmada`. + +- `cluster`:Used to specify a target member cluster and only takes effect when the command's operation scope is `members`. + +### explain + +In combination with the flag `operation-scope` and `cluster`, the `karmadactl explain` command can get documentation for a resource in Karmada control plane or a member cluster. This is especially convenient for scenarios where member cluster resources are differentially configured via `OverridePolicy`. + +- `operation-scope`:The enumeration values `karmada` and `members` are supported. Default to `karmada`. +- `cluster`:Used to specify a target member cluster and only takes effect when the command's operation scope is `members`. + +### exec + +In combination with the flag `operation-scope` and `cluster`, the `karmadactl exec` command can execute a command in a container in Karmada control plane or a member cluster. + +- `operation-scope`:The enumeration values `karmada` and `members` are supported. Default to `karmada`. +- `cluster`:Used to specify a target member cluster and only takes effect when the command's operation scope is `members`. + +### api-resources + +In combination with the flag `operation-scope` and `cluster`, the `karmadactl api-resources` command can print the supported API resources on the server in Karmada control plane or a member cluster. + +- `operation-scope`:The enumeration values `karmada` and `members` are supported. Default to `karmada`. +- `cluster`:Used to specify a target member cluster and only takes effect when the command's operation scope is `members`. + +### api-versions + +In combination with the flag `operation-scope` and `cluster`, the `karmadactl api-versions` command can print the supported API versions on the server in Karmada control plane or a member cluster. + +- `operation-scope`:The enumeration values `karmada` and `members` are supported. Default to `karmada`. +- `cluster`:Used to specify a target member cluster and only takes effect when the command's operation scope is `members`. diff --git a/docs/resources/reference/karmadactl/command-context.drawio b/docs/resources/reference/karmadactl/command-context.drawio new file mode 100644 index 00000000..ea14dc10 --- /dev/null +++ b/docs/resources/reference/karmadactl/command-context.drawio @@ -0,0 +1,96 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/resources/reference/karmadactl/command-context.png b/docs/resources/reference/karmadactl/command-context.png new file mode 100644 index 0000000000000000000000000000000000000000..1498fa274f34d8ff67f7098036ae9aac4d0216c7 GIT binary patch literal 47015 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 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/resources/reference/karmadactl/operation-scope.png b/docs/resources/reference/karmadactl/operation-scope.png new file mode 100644 index 0000000000000000000000000000000000000000..d8c1fd095bc1da28cf3bd988b7ec96cf9e7c93c7 GIT binary patch literal 53863 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 BE`I<3 literal 0 HcmV?d00001 diff --git a/i18n/zh/docusaurus-plugin-content-docs/current/reference/karmadactl/operation-scope.md b/i18n/zh/docusaurus-plugin-content-docs/current/reference/karmadactl/operation-scope.md new file mode 100644 index 00000000..87b8468c --- /dev/null +++ b/i18n/zh/docusaurus-plugin-content-docs/current/reference/karmadactl/operation-scope.md @@ -0,0 +1,131 @@ +--- +title: 集群视角切换 + +--- + +# Karmadactl 集群视角切换 + +Karmadactl 引入了 `operation-scope` 参数来指定命令的集群操作范围。`operation-scope` 参数的取值为枚举类型,每个枚举值及其含义如下: + +- karmada: karmadactl 命令的操作范围是 Karmada 控制面。 +- members: karmadactl 命令的操作范围是成员集群。 +- all: karmadactl 命令的操作范围包括 Karmada 控制面和成员集群。 + +> *请注意,不同命令所支持的枚举值是不同的,详情请参考karmadactl [command] --help。* + +`operation-scope`的引入为 Karmadactl 集群视角的切换提供了一种灵活的方式。与Kubectl相比,Karmadactl无需切换上下文即可管理不同的目标集群。此外,借助Karmada的多集群资源视图, +Karmadactl 能够同时访问多个目标集群的资源信息,这极大地简化了多集群场景下的日常运维工作。 + +![command-context](../../resources/reference/karmadactl/command-context.png) + +## 如何使用参数 operation-scope + +本节阐述了`operation-scope` 参数在各种 Karmadactl 命令中的应用,并以`karmadactl get`为例,展示了如何通过切换集群视角来查看资源在不同集群间的分布情况。 + +### get + +命令`karmadactl get`可用于查看控制面或成员集群的资源。结合参数 `operation-scope` 与 `clusters`,`karmadactl get`能够展示一个或多个集群的资源信息。 + +- `operation-scope`:支持枚举值`karmada`、`members`和`all`,默认为`karmada`。 +- `clusters`:用于指定目标成员集群,仅在命令的操作范围为`members`或`all`时生效。 + +![operation-scope](../../resources/reference/karmadactl/operation-scope.png) + +假设 Karmada 控制面管理着三个成员集群:`member1`、`member2` 和 `member3`,并且 Karmada 控制面的 Deployment 资源 `nginx` 已分发至这三个成员集群。那么,我们可以进行如下操作: + +- 查看 Karmada 控制面和所有成员集群资源的分布情况 + + ```bash + $ karmadactl get deployment nginx --operation-scope all + NAME CLUSTER READY UP-TO-DATE AVAILABLE AGE ADOPTION + nginx Karmada 0/2 6 0 18h - + nginx member1 0/2 2 0 37s Y + nginx member2 0/2 2 0 36s Y + nginx member3 0/2 2 0 37s Y + ``` + + > *CLUSTER 列表示资源所在的集群,而 ADOPTION 列则表示该资源是否已被 Karmada 控制面接管。* + +- 查看 Karmada 控制面和部分成员集群资源的分布情况 + + ```bash + $ karmadactl get deployment nginx --operation-scope all --clusters member1,member2 + NAME CLUSTER READY UP-TO-DATE AVAILABLE AGE ADOPTION + nginx Karmada 4/2 6 4 18h - + nginx member1 2/2 2 2 2m37s Y + nginx member2 0/2 2 0 2m36s Y + ``` + + 当设置 `--clusters` 为 `member1,member2` 时,成员集群的视角将被限制为 `member1` 和 `member2`。 + +- 查看 Karmada 控制面资源的分布情况 + + ```bash + $ karmadactl get deployment nginx + NAME CLUSTER READY UP-TO-DATE AVAILABLE AGE ADOPTION + nginx Karmada 6/2 6 6 18h - + $ karmadactl get deployment nginx --operation-scope karmada + NAME CLUSTER READY UP-TO-DATE AVAILABLE AGE ADOPTION + nginx Karmada 6/2 6 6 18h - + ``` + +- 查看所有成员集群资源的分布情况 + + ```bash + $ karmadactl get deployment nginx --operation-scope members + NAME CLUSTER READY UP-TO-DATE AVAILABLE AGE ADOPTION + nginx member2 2/2 2 2 8m10s Y + nginx member1 2/2 2 2 8m11s Y + nginx member3 2/2 2 2 8m10s Y + ``` + +- 查看部分成员集群资源的分布情况 + + ```bash + $ karmadactl get deployment nginx --operation-scope members --clusters member1,member2 + NAME CLUSTER READY UP-TO-DATE AVAILABLE AGE ADOPTION + nginx member1 2/2 2 2 9m7s Y + nginx member2 2/2 2 2 9m6s Y + ``` + +### describes + +结合参数 `operation-scope` 和 `cluster`,`karmadactl describe` 命令可用于显示 Karmada 控制面或成员集群中资源的详细信息。 + +- `operation-scope`:支持枚举值`karmada`和`members`,默认为`karmada`。 +- `cluster`:用于指定目标成员集群,仅在命令的操作范围为`members`时生效。 + +### attach + +结合参数 `operation-scope` 和 `cluster`,`karmadactl attach` 命令可以连接到 Karmada 控制面或成员集群中正在运行的容器。 + +- `operation-scope`:支持枚举值`karmada`和`members`,默认为`karmada`。 +- `cluster`:用于指定目标成员集群,仅在命令的操作范围为`members`时生效。 + +### explain + +结合参数 `operation-scope` 和 `cluster`,`karmadactl explain` 命令可以获取 Karmada 控制面或成员集群中 API 对象字段的描述。这对于查看通过 `OverridePolicy` 进行成员集群差异化配置后的资源尤为方便。 + +- `operation-scope`:支持枚举值`karmada`和`members`,默认为`karmada`。 +- `cluster`:用于指定目标成员集群,仅在命令的操作范围为`members`时生效。 + +### exec + +结合参数 `operation-scope` 和 `cluster`,`karmadactl exec` 命令可以在 Karmada 控制面或成员集群的容器中执行命令。 + +- `operation-scope`:支持枚举值`karmada`和`members`,默认为`karmada`。 +- `cluster`:用于指定目标成员集群,仅在命令的操作范围为`members`时生效。 + +### api-resources + +结合参数 `operation-scope` 和 `cluster`,`karmadactl api-resources` 命令可以输出 Karmada 控制面或成员集群支持的 API 资源。 + +- `operation-scope`:支持枚举值`karmada`和`members`,默认为`karmada`。 +- `cluster`:用于指定目标成员集群,仅在命令的操作范围为`members`时生效。 + +### api-versions + +结合参数 `operation-scope` 和 `cluster`,`karmadactl api-versions` 命令可以输出 Karmada 控制面或成员集群支持的 API 版本。 + +- `operation-scope`:支持枚举值`karmada`和`members`,默认为`karmada`。 +- `cluster`:用于指定目标成员集群,仅在命令的操作范围为`members`时生效。 diff --git a/i18n/zh/docusaurus-plugin-content-docs/current/resources/reference/karmadactl/command-context.drawio b/i18n/zh/docusaurus-plugin-content-docs/current/resources/reference/karmadactl/command-context.drawio new file mode 100644 index 00000000..ea14dc10 --- /dev/null +++ b/i18n/zh/docusaurus-plugin-content-docs/current/resources/reference/karmadactl/command-context.drawio @@ -0,0 +1,96 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/i18n/zh/docusaurus-plugin-content-docs/current/resources/reference/karmadactl/command-context.png b/i18n/zh/docusaurus-plugin-content-docs/current/resources/reference/karmadactl/command-context.png new file mode 100644 index 0000000000000000000000000000000000000000..1498fa274f34d8ff67f7098036ae9aac4d0216c7 GIT binary patch literal 47015 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 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/i18n/zh/docusaurus-plugin-content-docs/current/resources/reference/karmadactl/operation-scope.png b/i18n/zh/docusaurus-plugin-content-docs/current/resources/reference/karmadactl/operation-scope.png new file mode 100644 index 0000000000000000000000000000000000000000..d8c1fd095bc1da28cf3bd988b7ec96cf9e7c93c7 GIT binary patch literal 53863 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 BE`I<3 literal 0 HcmV?d00001 diff --git a/sidebars.js b/sidebars.js index fa9cd61e..de97fb88 100644 --- a/sidebars.js +++ b/sidebars.js @@ -288,6 +288,7 @@ module.exports = { "reference/karmadactl/karmadactl-commands/karmadactl", "reference/karmadactl/karmadactl-usage-conventions", "reference/karmadactl/karmadactl-config.v1alpha1", + "reference/karmadactl/operation-scope", ], }, { From 7734373fc988da62955a32afea9330106ae5f3be Mon Sep 17 00:00:00 2001 From: changzhen Date: Mon, 14 Apr 2025 19:44:06 +0800 Subject: [PATCH 12/15] add secure coding specifications Signed-off-by: changzhen --- docs/developers/secure-coding-specifications.md | 15 +++++++++++++++ .../developers/secure-coding-specifications.md | 15 +++++++++++++++ sidebars.js | 3 ++- 3 files changed, 32 insertions(+), 1 deletion(-) create mode 100644 docs/developers/secure-coding-specifications.md create mode 100644 i18n/zh/docusaurus-plugin-content-docs/current/developers/secure-coding-specifications.md diff --git a/docs/developers/secure-coding-specifications.md b/docs/developers/secure-coding-specifications.md new file mode 100644 index 00000000..56483015 --- /dev/null +++ b/docs/developers/secure-coding-specifications.md @@ -0,0 +1,15 @@ +--- +title: Secure Coding Specifications +--- + +This article is a checklist. When you write code, you need to check whether the new code violates the following items. + +1. It is prohibited to have authentication credentials that cannot be modified (e.g., hard-coded passwords in process binaries). +2. If implemented using interpreted languages (such as Shell/Python/Perl scripts, JSP, HTML, etc.), for functions that do not meet the requirement of undisclosed interfaces and need to be cleaned up, they must be completely deleted. It is strictly prohibited to use forms such as comment lines to merely disable the functions. +3. It is prohibited to use private cryptographic algorithms for encryption and decryption, including: + - Cryptographic algorithms designed independently without being evaluated by professional institutions; + - Self-defined data conversion algorithms executed through methods such as deformation/character shifting/replacement; + - Pseudo-encryption implementations that use encoding methods (such as Base64 encoding) to achieve the purpose of data encryption. + Note: In scenarios other than encryption and decryption, the use of encoding methods such as Base64 or algorithms such as deformation/shifting/replacement for legitimate business purposes does not violate this provision. +4. The random numbers used in cryptographic algorithms must be secure random numbers in the cryptographic sense. +5. It is prohibited to print authentication credentials (passwords/private keys/pre-shared keys) in plain text in system-stored logs, debugging information, and error prompts. diff --git a/i18n/zh/docusaurus-plugin-content-docs/current/developers/secure-coding-specifications.md b/i18n/zh/docusaurus-plugin-content-docs/current/developers/secure-coding-specifications.md new file mode 100644 index 00000000..53d9616c --- /dev/null +++ b/i18n/zh/docusaurus-plugin-content-docs/current/developers/secure-coding-specifications.md @@ -0,0 +1,15 @@ +--- +title: 安全编码规范 +--- + +本文是一个检查列表,当您编写代码时,您需要检查新增代码是否违反了以下列表: + +1. 禁止存在无法修改的认证凭据(如:进程二进制中硬编码口令)。 +2. 如果采用解释性语言(如 Shell/Python/Perl 脚本、JSP、HTML等)实现,对于不满足未公开接口并需要清理的功能,必须彻底删除,严禁使用注释行等形式仅使功能失效。 +3. 禁止使用私有密码算法实现加解密,包括: + - 未经过专业机构评估的、自行设计的密码算法; + - 自行定义的通过变形/字符移位/替换等方式执行的数据转换算法; + - 用编码的方式(如 Base64 编码)实现数据加密的目的的伪加密实现。 + 说明:在非加解密场景,出于正常业务目的使用 Base64 等编码方式或变形/移位/替换等算法不违反此条。 +4. 密码算法中使用到的随机数必须是密码学意义上的安全随机数。 +5. 禁止在系统中存储的日志、调试信息、错误提示中明文打印认证凭据(口令/私钥/预共享密钥)。 diff --git a/sidebars.js b/sidebars.js index fa9cd61e..73d00b82 100644 --- a/sidebars.js +++ b/sidebars.js @@ -233,7 +233,8 @@ module.exports = { "developers/releasing", "developers/customize-karmada-scheduler", "developers/document-releasing", - "developers/add-new-api" + "developers/add-new-api", + "developers/secure-coding-specifications" ], }, { From 6ccc2c06aed91c1943b34e3b84cf1b93c2d683f6 Mon Sep 17 00:00:00 2001 From: wei-chenglai Date: Mon, 14 Apr 2025 12:43:08 -0400 Subject: [PATCH 13/15] Fix syntax for referencing POD_IP Signed-off-by: wei-chenglai --- docs/administrator/security/security-considerations.md | 2 +- .../current/administrator/security/security-considerations.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/administrator/security/security-considerations.md b/docs/administrator/security/security-considerations.md index 430ce35c..6b726044 100644 --- a/docs/administrator/security/security-considerations.md +++ b/docs/administrator/security/security-considerations.md @@ -94,5 +94,5 @@ spec: fieldPath: status.podIP command: - /bin/karmada-controller-manager - - --metrics-bind-address=${POD_IP}:8080 + - --metrics-bind-address=$(POD_IP):8080 ``` diff --git a/i18n/zh/docusaurus-plugin-content-docs/current/administrator/security/security-considerations.md b/i18n/zh/docusaurus-plugin-content-docs/current/administrator/security/security-considerations.md index 5d84383a..22e94454 100644 --- a/i18n/zh/docusaurus-plugin-content-docs/current/administrator/security/security-considerations.md +++ b/i18n/zh/docusaurus-plugin-content-docs/current/administrator/security/security-considerations.md @@ -94,5 +94,5 @@ spec: fieldPath: status.podIP command: - /bin/karmada-controller-manager - - --metrics-bind-address=${POD_IP}:8080 + - --metrics-bind-address=$(POD_IP):8080 ``` From dedf5a4bca956bd68c897a87e6f404f9aa7437db Mon Sep 17 00:00:00 2001 From: yibing Date: Wed, 16 Apr 2025 10:52:52 +0800 Subject: [PATCH 14/15] Add dewu to adopters Signed-off-by: yibing --- i18n/zh/docusaurus-plugin-content-pages/adopters.md | 3 ++- src/pages/adopters.md | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/i18n/zh/docusaurus-plugin-content-pages/adopters.md b/i18n/zh/docusaurus-plugin-content-pages/adopters.md index bbbf3f70..8c24ffc1 100644 --- a/i18n/zh/docusaurus-plugin-content-pages/adopters.md +++ b/i18n/zh/docusaurus-plugin-content-pages/adopters.md @@ -52,4 +52,5 @@ hide_table_of_contents: true | 之江实验室 | https://www.zhejianglab.com/ | 使用 Karmada 构建多集群平台。 | | | 中通快递 | https://www.zto.com | 使用 Karmada 构建多集群平台。 | | | WPS | https://www.wps.cn | 使用 Karmada 构建多云多集群 AI 平台。 | | -| 星环科技 | https://www.transwarp.cn/ | 使用Karmda构建多集群大数据平台 | | \ No newline at end of file +| 星环科技 | https://www.transwarp.cn/ | 使用Karmda构建多集群大数据平台 | | +| 得物 | https://www.dewu.com/ | 使用 Karmada 构建多集群平台。 | | \ No newline at end of file diff --git a/src/pages/adopters.md b/src/pages/adopters.md index b3e12d0b..03d7f2c3 100644 --- a/src/pages/adopters.md +++ b/src/pages/adopters.md @@ -53,3 +53,4 @@ All organisations are sorted alphabetically by the first letter of their English | ZTO | https://www.zto.com | Use Karmada to build multi-cluster platform. | | | WPS | https://www.wps.cn | Use Karmada to build a multi-cluster and multi-cloud AI platform. | | | Transwarp | https://www.transwarp.cn/ | Use Karmada to build a multi-cloud big data platform. | | +| Dewu | https://www.dewu.com/ | Use Karmada to build multi-cluster platform. | | From f0b8b171fa5919572e98dc423acdebd96a372f83 Mon Sep 17 00:00:00 2001 From: chaosi-zju Date: Wed, 16 Apr 2025 17:19:09 +0800 Subject: [PATCH 15/15] add new supporters Signed-off-by: chaosi-zju --- src/data/supporters.js | 25 ++++++++++++++++++++++ static/img/supporters/coozila.png | Bin 0 -> 31912 bytes static/img/supporters/dewu.png | Bin 0 -> 2237 bytes static/img/supporters/iflytek.png | Bin 0 -> 7051 bytes static/img/supporters/tongchengtravel.png | Bin 0 -> 8623 bytes static/img/supporters/trip.png | Bin 0 -> 20500 bytes 6 files changed, 25 insertions(+) create mode 100644 static/img/supporters/coozila.png create mode 100644 static/img/supporters/dewu.png create mode 100644 static/img/supporters/iflytek.png create mode 100644 static/img/supporters/tongchengtravel.png create mode 100644 static/img/supporters/trip.png diff --git a/src/data/supporters.js b/src/data/supporters.js index b32c209d..2cdc322a 100644 --- a/src/data/supporters.js +++ b/src/data/supporters.js @@ -16,6 +16,11 @@ import zhejianglab from "../../static/img/supporters/zhejianglab.png" import daocloud from "../../static/img/supporters/DaoCloud.png" import CECloud from "../../static/img/supporters/CECloud.png" import wps from "../../static/img/supporters/wps.png" +import coozila from "../../static/img/supporters/coozila.png" +import dewu from "../../static/img/supporters/dewu.png" +import iflytek from "../../static/img/supporters/iflytek.png" +import tongchengtravel from "../../static/img/supporters/tongchengtravel.png" +import trip from "../../static/img/supporters/trip.png" const supportersData = [ { @@ -90,6 +95,26 @@ const supportersData = [ logo: wps, alt: 'WPS', }, + { + logo: coozila, + alt: 'coozila', + }, + { + logo: dewu, + alt: 'dewu', + }, + { + logo: iflytek, + alt: 'iflytek', + }, + { + logo: tongchengtravel, + alt: 'tongchengtravel', + }, + { + logo: trip, + alt: 'trip', + }, ] export default supportersData diff --git a/static/img/supporters/coozila.png b/static/img/supporters/coozila.png new file mode 100644 index 0000000000000000000000000000000000000000..e593228181a970be5b12b13909f08e88b40d860a GIT binary patch literal 31912 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 JREe1c|38OQKNSD~ literal 0 HcmV?d00001 diff --git a/static/img/supporters/dewu.png b/static/img/supporters/dewu.png new file mode 100644 index 0000000000000000000000000000000000000000..91cdf025eb09465d7a595bbf8baba0498a5647c2 GIT binary patch literal 2237 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 VU4S}U`1tQKeQjf{QVsjN{{fPD!i)d_ literal 0 HcmV?d00001 diff --git a/static/img/supporters/tongchengtravel.png b/static/img/supporters/tongchengtravel.png new file mode 100644 index 0000000000000000000000000000000000000000..4d772c64372862039645c26b87ca9ff2b8f164ff GIT binary patch literal 8623 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 literal 0 HcmV?d00001 diff --git a/static/img/supporters/trip.png b/static/img/supporters/trip.png new file mode 100644 index 0000000000000000000000000000000000000000..0e05ea4be3414c0d1b652132883b22fa89d48f45 GIT binary patch literal 20500 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 b1;XC})Rq#fU9ie^00000NkvXXu0mjfFC5Y0 literal 0 HcmV?d00001