diff --git a/.gitmodules b/.gitmodules index 13bd12486..8e9233b67 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,4 +1,4 @@ [submodule "addons"] path = addons url = https://github.com/apecloud/kubeblocks-addons.git - branch = main \ No newline at end of file + branch = release-0.9 \ No newline at end of file diff --git a/Makefile b/Makefile index c2258493e..e1a808ebe 100644 --- a/Makefile +++ b/Makefile @@ -164,7 +164,7 @@ goimports: goimportstool ## Run goimports against code. ##@ CLI -K3S_VERSION ?= v1.23.8+k3s1 +K3S_VERSION ?= v1.30.2+k3s2 K3D_VERSION ?= 5.4.4 K3S_IMG_TAG ?= $(subst +,-,$(K3S_VERSION)) FETCH_ADDON_ENABLED ?= true @@ -200,8 +200,8 @@ create-kbcli-embed-charts-dir: build-single-kbcli-embed-chart.%: chart=$(word 2,$(subst ., ,$@)) build-single-kbcli-embed-chart.%: - $(HELM) dependency update addons/addons/$(chart) --skip-refresh - $(HELM) package addons/addons/$(chart) + $(HELM) dependency update addons/addons-cluster/$(chart) --skip-refresh + $(HELM) package addons/addons-cluster/$(chart) - bash -c "diff <($(HELM) template $(chart)-*.tgz) <($(HELM) template pkg/cluster/charts/$(chart).tgz)" > chart.diff @if [ -s chart.diff ]; then \ mv $(chart)-*.tgz pkg/cluster/charts/$(chart).tgz; \ @@ -218,7 +218,9 @@ build-kbcli-embed-chart: helmtool fetch-addons create-kbcli-embed-charts-dir \ build-single-kbcli-embed-chart.kafka-cluster \ build-single-kbcli-embed-chart.mongodb-cluster \ build-single-kbcli-embed-chart.llm-cluster \ - build-single-kbcli-embed-chart.xinference-cluster + build-single-kbcli-embed-chart.xinference-cluster \ + build-single-kbcli-embed-chart.elasticsearch-cluster \ + build-single-kbcli-embed-chart.qdrant-cluster .PHONY: kbcli kbcli: build-checks kbcli-fast ## Build bin/kbcli. diff --git a/addons b/addons index a33d64047..dd1528854 160000 --- a/addons +++ b/addons @@ -1 +1 @@ -Subproject commit a33d64047247388fa8671b83e67aa2fecf4e8978 +Subproject commit dd15288541830243209bdc54fa0d47845cedd1db diff --git a/docs/user_docs/cli/cli.md b/docs/user_docs/cli/cli.md index c53b20771..31a176dd9 100644 --- a/docs/user_docs/cli/cli.md +++ b/docs/user_docs/cli/cli.md @@ -19,17 +19,6 @@ Addon command. * [kbcli addon upgrade](kbcli_addon_upgrade.md) - Upgrade an existed addon to latest version or a specified version -## [alert](kbcli_alert.md) - -Manage alert receiver, include add, list and delete receiver. - -* [kbcli alert add-receiver](kbcli_alert_add-receiver.md) - Add alert receiver, such as email, slack, webhook and so on. -* [kbcli alert config-smtpserver](kbcli_alert_config-smtpserver.md) - Set smtp server config -* [kbcli alert delete-receiver](kbcli_alert_delete-receiver.md) - Delete alert receiver. -* [kbcli alert list-receivers](kbcli_alert_list-receivers.md) - List all alert receivers. -* [kbcli alert list-smtpserver](kbcli_alert_list-smtpserver.md) - List alert smtp servers config. - - ## [backuprepo](kbcli_backuprepo.md) BackupRepo command. @@ -52,18 +41,11 @@ Run a benchmark. * [kbcli bench redis-benchmark](kbcli_bench_redis-benchmark.md) - Run redis-benchmark on a cluster * [kbcli bench sysbench](kbcli_bench_sysbench.md) - run a SysBench benchmark * [kbcli bench tpcc](kbcli_bench_tpcc.md) - Run tpcc benchmark +* [kbcli bench tpcds](kbcli_bench_tpcds.md) - Run TPC-DS benchmark * [kbcli bench tpch](kbcli_bench_tpch.md) - Run tpch benchmark * [kbcli bench ycsb](kbcli_bench_ycsb.md) - Run YCSB benchmark on a cluster -## [builder](kbcli_builder.md) - -builder command. - -* [kbcli builder migrate-scripts](kbcli_builder_migrate-scripts.md) - migrate - a developer tool. -* [kbcli builder template](kbcli_builder_template.md) - tpl - a developer tool integrated with KubeBlocks that can help developers quickly generate rendered configurations or scripts based on Helm templates, and discover errors in the template before creating the database cluster. - - ## [cluster](kbcli_cluster.md) Cluster command. @@ -157,30 +139,6 @@ Data protection command. * [kbcli dataprotection restore](kbcli_dataprotection_restore.md) - Restore a new cluster from backup -## [environment](kbcli_environment.md) - -kbcli environment allows you to manage cloud environment. This command is currently only applicable to cloud, and currently does not support switching the environment of the local k8s cluster. - -* [kbcli environment current](kbcli_environment_current.md) - Get the currently used environment. -* [kbcli environment describe](kbcli_environment_describe.md) - Get the description information of a environment. -* [kbcli environment list](kbcli_environment_list.md) - List all created environments. -* [kbcli environment use](kbcli_environment_use.md) - Use another environment that you have already created. - - -## [fault](kbcli_fault.md) - -Inject faults to pod. - -* [kbcli fault delete](kbcli_fault_delete.md) - Delete chaos resources. -* [kbcli fault io](kbcli_fault_io.md) - IO chaos. -* [kbcli fault list](kbcli_fault_list.md) - List chaos resources. -* [kbcli fault network](kbcli_fault_network.md) - Network chaos. -* [kbcli fault node](kbcli_fault_node.md) - Node chaos. -* [kbcli fault pod](kbcli_fault_pod.md) - Pod chaos. -* [kbcli fault stress](kbcli_fault_stress.md) - Add memory pressure or CPU load to the system. -* [kbcli fault time](kbcli_fault_time.md) - Clock skew failure. - - ## [kubeblocks](kbcli_kubeblocks.md) KubeBlocks operation commands. @@ -196,46 +154,12 @@ KubeBlocks operation commands. * [kbcli kubeblocks upgrade](kbcli_kubeblocks_upgrade.md) - Upgrade KubeBlocks. -## [login](kbcli_login.md) - -Authenticate with the KubeBlocks Cloud - - - -## [logout](kbcli_logout.md) - -Log out of the KubeBlocks Cloud - - - -## [migration](kbcli_migration.md) - -Data migration between two data sources. - -* [kbcli migration create](kbcli_migration_create.md) - Create a migration task. -* [kbcli migration describe](kbcli_migration_describe.md) - Show details of a specific migration task. -* [kbcli migration list](kbcli_migration_list.md) - List migration tasks. -* [kbcli migration logs](kbcli_migration_logs.md) - Access migration task log file. -* [kbcli migration templates](kbcli_migration_templates.md) - List migration templates. -* [kbcli migration terminate](kbcli_migration_terminate.md) - Delete migration task. - - ## [options](kbcli_options.md) Print the list of flags inherited by all commands. -## [org](kbcli_org.md) - -kbcli org is used to manage cloud organizations and is only suitable for interacting with cloud. - -* [kbcli org current](kbcli_org_current.md) - Get current organization. -* [kbcli org describe](kbcli_org_describe.md) - Get the description information of an organization. -* [kbcli org list](kbcli_org_list.md) - List all organizations you have joined. -* [kbcli org switch](kbcli_org_switch.md) - Switch to another organization you are already a member of. - - ## [playground](kbcli_playground.md) Bootstrap or destroy a playground KubeBlocks in local host or cloud. @@ -261,7 +185,7 @@ Provides utilities for interacting with plugins. ## [report](kbcli_report.md) -report kubeblocks or cluster info. +Report kubeblocks or cluster info. * [kbcli report cluster](kbcli_report_cluster.md) - Report Cluster information * [kbcli report kubeblocks](kbcli_report_kubeblocks.md) - Report KubeBlocks information, including deployments, events, logs, etc. diff --git a/docs/user_docs/cli/kbcli.md b/docs/user_docs/cli/kbcli.md index bca36db9d..af043bedf 100644 --- a/docs/user_docs/cli/kbcli.md +++ b/docs/user_docs/cli/kbcli.md @@ -55,26 +55,18 @@ kbcli [flags] ### SEE ALSO * [kbcli addon](kbcli_addon.md) - Addon command. -* [kbcli alert](kbcli_alert.md) - Manage alert receiver, include add, list and delete receiver. * [kbcli backuprepo](kbcli_backuprepo.md) - BackupRepo command. * [kbcli bench](kbcli_bench.md) - Run a benchmark. -* [kbcli builder](kbcli_builder.md) - builder command. * [kbcli cluster](kbcli_cluster.md) - Cluster command. * [kbcli clusterdefinition](kbcli_clusterdefinition.md) - ClusterDefinition command. * [kbcli clusterversion](kbcli_clusterversion.md) - ClusterVersion command. * [kbcli dashboard](kbcli_dashboard.md) - List and open the KubeBlocks dashboards. * [kbcli dataprotection](kbcli_dataprotection.md) - Data protection command. -* [kbcli environment](kbcli_environment.md) - kbcli environment allows you to manage cloud environment. This command is currently only applicable to cloud, and currently does not support switching the environment of the local k8s cluster. -* [kbcli fault](kbcli_fault.md) - Inject faults to pod. * [kbcli kubeblocks](kbcli_kubeblocks.md) - KubeBlocks operation commands. -* [kbcli login](kbcli_login.md) - Authenticate with the KubeBlocks Cloud -* [kbcli logout](kbcli_logout.md) - Log out of the KubeBlocks Cloud -* [kbcli migration](kbcli_migration.md) - Data migration between two data sources. * [kbcli options](kbcli_options.md) - Print the list of flags inherited by all commands. -* [kbcli org](kbcli_org.md) - kbcli org is used to manage cloud organizations and is only suitable for interacting with cloud. * [kbcli playground](kbcli_playground.md) - Bootstrap or destroy a playground KubeBlocks in local host or cloud. * [kbcli plugin](kbcli_plugin.md) - Provides utilities for interacting with plugins. -* [kbcli report](kbcli_report.md) - report kubeblocks or cluster info. +* [kbcli report](kbcli_report.md) - Report kubeblocks or cluster info. * [kbcli version](kbcli_version.md) - Print the version information, include kubernetes, KubeBlocks and kbcli version. #### Go Back to [CLI Overview](cli.md) Homepage. diff --git a/docs/user_docs/cli/kbcli_bench.md b/docs/user_docs/cli/kbcli_bench.md index 21a0ebebe..0e6f8ac6b 100644 --- a/docs/user_docs/cli/kbcli_bench.md +++ b/docs/user_docs/cli/kbcli_bench.md @@ -44,6 +44,7 @@ Run a benchmark. * [kbcli bench redis-benchmark](kbcli_bench_redis-benchmark.md) - Run redis-benchmark on a cluster * [kbcli bench sysbench](kbcli_bench_sysbench.md) - run a SysBench benchmark * [kbcli bench tpcc](kbcli_bench_tpcc.md) - Run tpcc benchmark +* [kbcli bench tpcds](kbcli_bench_tpcds.md) - Run TPC-DS benchmark * [kbcli bench tpch](kbcli_bench_tpch.md) - Run tpch benchmark * [kbcli bench ycsb](kbcli_bench_ycsb.md) - Run YCSB benchmark on a cluster diff --git a/docs/user_docs/cli/kbcli_bench_pgbench.md b/docs/user_docs/cli/kbcli_bench_pgbench.md index 7fa7f69cf..be39436ef 100644 --- a/docs/user_docs/cli/kbcli_bench_pgbench.md +++ b/docs/user_docs/cli/kbcli_bench_pgbench.md @@ -15,7 +15,7 @@ kbcli bench pgbench [Step] [BenchmarkName] [flags] kbcli bench pgbench mytest --cluster pgcluster --database postgres --user xxx --password xxx # pgbench run on a cluster, but with cpu and memory limits set - kbcli bench pgbench mytest --cluster pgcluster --database postgres --user xxx --password xxx --cpu 1 --memory 1Gi + kbcli bench pgbench mytest --cluster pgcluster --database postgres --user xxx --password xxx --limit-cpu 1 --limit-memory 1Gi # pgbench run on a cluster with cleanup, only cleanup by deleting the testdata kbcli bench pgbench cleanup mytest --cluster pgcluster --database postgres --user xxx --password xxx diff --git a/docs/user_docs/cli/kbcli_bench_redis-benchmark.md b/docs/user_docs/cli/kbcli_bench_redis-benchmark.md index 6baae5950..9ae80505a 100644 --- a/docs/user_docs/cli/kbcli_bench_redis-benchmark.md +++ b/docs/user_docs/cli/kbcli_bench_redis-benchmark.md @@ -15,7 +15,7 @@ kbcli bench redis-benchmark [flags] kbcli bench redis-benchmark mytest --cluster rediscluster --clients 50 --requests 10000 --password xxx # redis-benchmark run on a cluster, but with cpu and memory limits set - kbcli bench redis-benchmark mytest --cluster rediscluster --clients 50 --requests 10000 --cpu 1 --memory 1Gi --password xxx + kbcli bench redis-benchmark mytest --cluster rediscluster --clients 50 --requests 10000 --limit-cpu 1 --limit-memory 1Gi --password xxx # redis-benchmark run on a cluster, just test set/get kbcli bench redis-benchmark mytest --cluster rediscluster --clients 50 --requests 10000 --tests set,get --password xxx diff --git a/docs/user_docs/cli/kbcli_bench_sysbench.md b/docs/user_docs/cli/kbcli_bench_sysbench.md index 3eb9ae71a..57c858bc1 100644 --- a/docs/user_docs/cli/kbcli_bench_sysbench.md +++ b/docs/user_docs/cli/kbcli_bench_sysbench.md @@ -15,7 +15,7 @@ kbcli bench sysbench [Step] [BenchmarkName] [flags] kbcli bench sysbench mytest --cluster mycluster --user xxx --password xxx --database mydb # sysbench on a cluster, but with cpu and memory limits set - kbcli bench sysbench mytest --cluster mycluster --user xxx --password xxx --database mydb --cpu 1 --memory 1Gi + kbcli bench sysbench mytest --cluster mycluster --user xxx --password xxx --database mydb --limit-cpu 1 --limit-memory 1Gi # sysbench run on a cluster with cleanup, only cleanup by deleting the testdata kbcli bench sysbench cleanup mytest --cluster mycluster --user xxx --password xxx --database mydb diff --git a/docs/user_docs/cli/kbcli_bench_tpcc.md b/docs/user_docs/cli/kbcli_bench_tpcc.md index dc6050d4c..b0c02cfcd 100644 --- a/docs/user_docs/cli/kbcli_bench_tpcc.md +++ b/docs/user_docs/cli/kbcli_bench_tpcc.md @@ -15,7 +15,7 @@ kbcli bench tpcc [Step] [BenchmarkName] [flags] kbcli bench tpcc mytest --cluster mycluster --user xxx --password xxx --database mydb # tpcc on a cluster, but with cpu and memory limits set - kbcli bench tpcc mytest --cluster mycluster --user xxx --password xxx --database mydb --cpu 1 --memory 1Gi + kbcli bench tpcc mytest --cluster mycluster --user xxx --password xxx --database mydb --limit-cpu 1 --limit-memory 1Gi # tpcc on a cluster with cleanup, only cleanup by deleting the testdata kbcli bench tpcc cleanup mytest --cluster mycluster --user xxx --password xxx --database mydb diff --git a/docs/user_docs/cli/kbcli_fault_list.md b/docs/user_docs/cli/kbcli_bench_tpcds.md similarity index 55% rename from docs/user_docs/cli/kbcli_fault_list.md rename to docs/user_docs/cli/kbcli_bench_tpcds.md index d1a168638..5d1efc78b 100644 --- a/docs/user_docs/cli/kbcli_fault_list.md +++ b/docs/user_docs/cli/kbcli_bench_tpcds.md @@ -1,31 +1,45 @@ --- -title: kbcli fault list +title: kbcli bench tpcds --- -List chaos resources. +Run TPC-DS benchmark ``` -kbcli fault list [flags] +kbcli bench tpcds [Step] [Benchmark] [flags] ``` ### Examples ``` - # List all chaos resources - kbcli fault list + # tpcds on a cluster, that will exec for all steps, cleanup, prepare and run + kbcli bench tpcds mytest --cluster mycluster --user xxx --password xxx --database mydb - # List all chaos kind - kbcli fault list --kind + # tpcds on a cluster, but with cpu and memory limits set + kbcli bench tpcds mytest --cluster mycluster --user xxx --password xxx --database mydb --limit-cpu 1 --limit-memory 1Gi - # List specific chaos resources. Use 'kbcli fault list --kind' to get chaos kind. - kbcli fault list podchaos + # tpcds on a cluster with 10GB data + kbcli bench tpcds mytest --cluster mycluster --user xxx --password xxx --database mydb --size 10 ``` ### Options ``` - -h, --help help for list - --kind Print chaos resource kind. + --cluster string the cluster of database + --database string database name + --driver string the driver of database + --extra-args strings extra arguments for benchmark + -h, --help help for tpcds + --host string the host of database + --limit-cpu string the limit cpu of benchmark + --limit-memory string the limit memory of benchmark + --password string the password of database + --port int the port of database + --request-cpu string the request cpu of benchmark + --request-memory string the request memory of benchmark + --size int specify the scale factor of the benchmark, 1 means 1GB data (default 1) + --tolerations strings Tolerations for benchmark, such as '"dev=true:NoSchedule,large=true:NoSchedule"' + --use-key specify whether to create pk and fk, it will take extra time to create the keys + --user string the user of database ``` ### Options inherited from parent commands @@ -38,7 +52,6 @@ kbcli fault list [flags] --certificate-authority string Path to a cert file for the certificate authority --client-certificate string Path to a client certificate file for TLS --client-key string Path to a client key file for TLS - --cluster string The name of the kubeconfig cluster to use --context string The name of the kubeconfig context to use --disable-compression If true, opt-out of response compression for all requests to the server --insecure-skip-tls-verify If true, the server's certificate will not be checked for validity. This will make your HTTPS connections insecure @@ -49,12 +62,11 @@ kbcli fault list [flags] -s, --server string The address and port of the Kubernetes API server --tls-server-name string Server name to use for server certificate validation. If it is not provided, the hostname used to contact the server is used --token string Bearer token for authentication to the API server - --user string The name of the kubeconfig user to use ``` ### SEE ALSO -* [kbcli fault](kbcli_fault.md) - Inject faults to pod. +* [kbcli bench](kbcli_bench.md) - Run a benchmark. #### Go Back to [CLI Overview](cli.md) Homepage. diff --git a/docs/user_docs/cli/kbcli_bench_tpch.md b/docs/user_docs/cli/kbcli_bench_tpch.md index 7e3285cfc..e7fad2e67 100644 --- a/docs/user_docs/cli/kbcli_bench_tpch.md +++ b/docs/user_docs/cli/kbcli_bench_tpch.md @@ -15,7 +15,7 @@ kbcli bench tpch [Step] [BenchmarkName] [flags] kbcli bench tpch mytest --cluster mycluster --user xxx --password xxx --database mydb # tpch on a cluster, but with cpu and memory limits set - kbcli bench tpch mytest --cluster mycluster --user xxx --password xxx --database mydb --cpu 1 --memory 1Gi + kbcli bench tpch mytest --cluster mycluster --user xxx --password xxx --database mydb --limit-cpu 1 --limit-memory 1Gi # tpch on a cluster with run, just run by running the test kbcli bench tpch run mytest --cluster mycluster --user xxx --password xxx --database mydb @@ -36,6 +36,7 @@ kbcli bench tpch [Step] [BenchmarkName] [flags] --port int the port of database --request-cpu string the request cpu of benchmark --request-memory string the request memory of benchmark + --size int specify the overall database size scaling parameter, 1 means 1GB (default 1) --tolerations strings Tolerations for benchmark, such as '"dev=true:NoSchedule,large=true:NoSchedule"' --user string the user of database ``` diff --git a/docs/user_docs/cli/kbcli_bench_ycsb.md b/docs/user_docs/cli/kbcli_bench_ycsb.md index 598e24d4a..4e3322410 100644 --- a/docs/user_docs/cli/kbcli_bench_ycsb.md +++ b/docs/user_docs/cli/kbcli_bench_ycsb.md @@ -15,7 +15,7 @@ kbcli bench ycsb [Step] [BenchmarkName] [flags] kbcli bench ycsb mytest --cluster mycluster --user xxx --password xxx --database mydb # ycsb on a cluster, but with cpu and memory limits set - kbcli bench ycsb mytest --cluster mycluster --user xxx --password xxx --database mydb --cpu 1 --memory 1Gi + kbcli bench ycsb mytest --cluster mycluster --user xxx --password xxx --database mydb --limit-cpu 1 --limit-memory 1Gi # ycsb on a cluster with cleanup, only cleanup by deleting the testdata kbcli bench ycsb cleanup mytest --cluster mycluster --user xxx --password xxx --database mydb diff --git a/docs/user_docs/cli/kbcli_builder.md b/docs/user_docs/cli/kbcli_builder.md deleted file mode 100644 index c7eed2340..000000000 --- a/docs/user_docs/cli/kbcli_builder.md +++ /dev/null @@ -1,44 +0,0 @@ ---- -title: kbcli builder ---- - -builder command. - -### Options - -``` - -h, --help help for builder -``` - -### Options inherited from parent commands - -``` - --as string Username to impersonate for the operation. User could be a regular user or a service account in a namespace. - --as-group stringArray Group to impersonate for the operation, this flag can be repeated to specify multiple groups. - --as-uid string UID to impersonate for the operation. - --cache-dir string Default cache directory (default "$HOME/.kube/cache") - --certificate-authority string Path to a cert file for the certificate authority - --client-certificate string Path to a client certificate file for TLS - --client-key string Path to a client key file for TLS - --cluster string The name of the kubeconfig cluster to use - --context string The name of the kubeconfig context to use - --disable-compression If true, opt-out of response compression for all requests to the server - --insecure-skip-tls-verify If true, the server's certificate will not be checked for validity. This will make your HTTPS connections insecure - --kubeconfig string Path to the kubeconfig file to use for CLI requests. - --match-server-version Require server version to match client version - -n, --namespace string If present, the namespace scope for this CLI request - --request-timeout string The length of time to wait before giving up on a single server request. Non-zero values should contain a corresponding time unit (e.g. 1s, 2m, 3h). A value of zero means don't timeout requests. (default "0") - -s, --server string The address and port of the Kubernetes API server - --tls-server-name string Server name to use for server certificate validation. If it is not provided, the hostname used to contact the server is used - --token string Bearer token for authentication to the API server - --user string The name of the kubeconfig user to use -``` - -### SEE ALSO - - -* [kbcli builder migrate-scripts](kbcli_builder_migrate-scripts.md) - migrate - a developer tool. -* [kbcli builder template](kbcli_builder_template.md) - tpl - a developer tool integrated with KubeBlocks that can help developers quickly generate rendered configurations or scripts based on Helm templates, and discover errors in the template before creating the database cluster. - -#### Go Back to [CLI Overview](cli.md) Homepage. - diff --git a/docs/user_docs/cli/kbcli_builder_migrate-scripts.md b/docs/user_docs/cli/kbcli_builder_migrate-scripts.md deleted file mode 100644 index cb080ff34..000000000 --- a/docs/user_docs/cli/kbcli_builder_migrate-scripts.md +++ /dev/null @@ -1,57 +0,0 @@ ---- -title: kbcli builder migrate-scripts ---- - -migrate - a developer tool. - -``` -kbcli builder migrate-scripts [flags] -``` - -### Examples - -``` - -``` - -### Options - -``` - --configmap string specify the configmap name - --force whether overwrite the exists file - --helm string specify the helm template dir - -h, --help help for migrate-scripts - --output string specify the scripts output path - --regex string specify the regex for configmap -``` - -### Options inherited from parent commands - -``` - --as string Username to impersonate for the operation. User could be a regular user or a service account in a namespace. - --as-group stringArray Group to impersonate for the operation, this flag can be repeated to specify multiple groups. - --as-uid string UID to impersonate for the operation. - --cache-dir string Default cache directory (default "$HOME/.kube/cache") - --certificate-authority string Path to a cert file for the certificate authority - --client-certificate string Path to a client certificate file for TLS - --client-key string Path to a client key file for TLS - --cluster string The name of the kubeconfig cluster to use - --context string The name of the kubeconfig context to use - --disable-compression If true, opt-out of response compression for all requests to the server - --insecure-skip-tls-verify If true, the server's certificate will not be checked for validity. This will make your HTTPS connections insecure - --kubeconfig string Path to the kubeconfig file to use for CLI requests. - --match-server-version Require server version to match client version - -n, --namespace string If present, the namespace scope for this CLI request - --request-timeout string The length of time to wait before giving up on a single server request. Non-zero values should contain a corresponding time unit (e.g. 1s, 2m, 3h). A value of zero means don't timeout requests. (default "0") - -s, --server string The address and port of the Kubernetes API server - --tls-server-name string Server name to use for server certificate validation. If it is not provided, the hostname used to contact the server is used - --token string Bearer token for authentication to the API server - --user string The name of the kubeconfig user to use -``` - -### SEE ALSO - -* [kbcli builder](kbcli_builder.md) - builder command. - -#### Go Back to [CLI Overview](cli.md) Homepage. - diff --git a/docs/user_docs/cli/kbcli_builder_template.md b/docs/user_docs/cli/kbcli_builder_template.md deleted file mode 100644 index 621a3c0ec..000000000 --- a/docs/user_docs/cli/kbcli_builder_template.md +++ /dev/null @@ -1,68 +0,0 @@ ---- -title: kbcli builder template ---- - -tpl - a developer tool integrated with KubeBlocks that can help developers quickly generate rendered configurations or scripts based on Helm templates, and discover errors in the template before creating the database cluster. - -``` -kbcli builder template [flags] -``` - -### Examples - -``` - # builder template: Provides a mechanism to rendered template for ComponentConfigSpec and ComponentScriptSpec in the ClusterComponentDefinition. - # builder template --helm deploy/redis --memory=64Gi --cpu=16 --replicas=3 --component-name=redis --config-spec=redis-replication-config - - # build all configspec - kbcli builder template --helm deploy/redis -a -``` - -### Options - -``` - --clean specify whether to clear the output dir - --cluster string the cluster yaml file - --cluster-definition string specify the cluster definition name - --cluster-version string specify the cluster version name - --component-name string specify the component name of the clusterdefinition - --config-spec string specify the config spec to be rendered - --cpu string specify the cpu of the component - --helm string specify the helm template dir - --helm-output string specify the helm template output dir - -h, --help help for template - --memory string specify the memory of the component - -o, --output-dir string specify the output directory - -r, --replicas int32 specify the replicas of the component (default 1) - --volume-name string specify the data volume name of the component -``` - -### Options inherited from parent commands - -``` - --as string Username to impersonate for the operation. User could be a regular user or a service account in a namespace. - --as-group stringArray Group to impersonate for the operation, this flag can be repeated to specify multiple groups. - --as-uid string UID to impersonate for the operation. - --cache-dir string Default cache directory (default "$HOME/.kube/cache") - --certificate-authority string Path to a cert file for the certificate authority - --client-certificate string Path to a client certificate file for TLS - --client-key string Path to a client key file for TLS - --context string The name of the kubeconfig context to use - --disable-compression If true, opt-out of response compression for all requests to the server - --insecure-skip-tls-verify If true, the server's certificate will not be checked for validity. This will make your HTTPS connections insecure - --kubeconfig string Path to the kubeconfig file to use for CLI requests. - --match-server-version Require server version to match client version - -n, --namespace string If present, the namespace scope for this CLI request - --request-timeout string The length of time to wait before giving up on a single server request. Non-zero values should contain a corresponding time unit (e.g. 1s, 2m, 3h). A value of zero means don't timeout requests. (default "0") - -s, --server string The address and port of the Kubernetes API server - --tls-server-name string Server name to use for server certificate validation. If it is not provided, the hostname used to contact the server is used - --token string Bearer token for authentication to the API server - --user string The name of the kubeconfig user to use -``` - -### SEE ALSO - -* [kbcli builder](kbcli_builder.md) - builder command. - -#### Go Back to [CLI Overview](cli.md) Homepage. - diff --git a/docs/user_docs/cli/kbcli_class.md b/docs/user_docs/cli/kbcli_class.md deleted file mode 100644 index fc5536db4..000000000 --- a/docs/user_docs/cli/kbcli_class.md +++ /dev/null @@ -1,45 +0,0 @@ ---- -title: kbcli class ---- - -Manage classes - -### Options - -``` - -h, --help help for class -``` - -### Options inherited from parent commands - -``` - --as string Username to impersonate for the operation. User could be a regular user or a service account in a namespace. - --as-group stringArray Group to impersonate for the operation, this flag can be repeated to specify multiple groups. - --as-uid string UID to impersonate for the operation. - --cache-dir string Default cache directory (default "$HOME/.kube/cache") - --certificate-authority string Path to a cert file for the certificate authority - --client-certificate string Path to a client certificate file for TLS - --client-key string Path to a client key file for TLS - --cluster string The name of the kubeconfig cluster to use - --context string The name of the kubeconfig context to use - --disable-compression If true, opt-out of response compression for all requests to the server - --insecure-skip-tls-verify If true, the server's certificate will not be checked for validity. This will make your HTTPS connections insecure - --kubeconfig string Path to the kubeconfig file to use for CLI requests. - --match-server-version Require server version to match client version - -n, --namespace string If present, the namespace scope for this CLI request - --request-timeout string The length of time to wait before giving up on a single server request. Non-zero values should contain a corresponding time unit (e.g. 1s, 2m, 3h). A value of zero means don't timeout requests. (default "0") - -s, --server string The address and port of the Kubernetes API server - --tls-server-name string Server name to use for server certificate validation. If it is not provided, the hostname used to contact the server is used - --token string Bearer token for authentication to the API server - --user string The name of the kubeconfig user to use -``` - -### SEE ALSO - - -* [kbcli class create](kbcli_class_create.md) - Create a class -* [kbcli class list](kbcli_class_list.md) - List classes -* [kbcli class template](kbcli_class_template.md) - Generate class definition template - -#### Go Back to [CLI Overview](cli.md) Homepage. - diff --git a/docs/user_docs/cli/kbcli_class_create.md b/docs/user_docs/cli/kbcli_class_create.md deleted file mode 100644 index c45743c2a..000000000 --- a/docs/user_docs/cli/kbcli_class_create.md +++ /dev/null @@ -1,61 +0,0 @@ ---- -title: kbcli class create ---- - -Create a class - -``` -kbcli class create [NAME] [flags] -``` - -### Examples - -``` - # Create a class for component mysql in cluster definition apecloud-mysql, which has 1 CPU core and 1Gi memory - kbcli class create custom-1c1g --cluster-definition apecloud-mysql --type mysql --cpu 1 --memory 1Gi - - # Create classes for component mysql in cluster definition apecloud-mysql, with classes defined in file - kbcli class create --cluster-definition apecloud-mysql --type mysql --file ./classes.yaml -``` - -### Options - -``` - --cluster-definition string Specify cluster definition, run "kbcli clusterdefinition list" to show all available cluster definitions - --cpu string Specify component CPU cores - --file string Specify file path of class definition YAML - -h, --help help for create - --memory string Specify component memory size - --type string Specify component type -``` - -### Options inherited from parent commands - -``` - --as string Username to impersonate for the operation. User could be a regular user or a service account in a namespace. - --as-group stringArray Group to impersonate for the operation, this flag can be repeated to specify multiple groups. - --as-uid string UID to impersonate for the operation. - --cache-dir string Default cache directory (default "$HOME/.kube/cache") - --certificate-authority string Path to a cert file for the certificate authority - --client-certificate string Path to a client certificate file for TLS - --client-key string Path to a client key file for TLS - --cluster string The name of the kubeconfig cluster to use - --context string The name of the kubeconfig context to use - --disable-compression If true, opt-out of response compression for all requests to the server - --insecure-skip-tls-verify If true, the server's certificate will not be checked for validity. This will make your HTTPS connections insecure - --kubeconfig string Path to the kubeconfig file to use for CLI requests. - --match-server-version Require server version to match client version - -n, --namespace string If present, the namespace scope for this CLI request - --request-timeout string The length of time to wait before giving up on a single server request. Non-zero values should contain a corresponding time unit (e.g. 1s, 2m, 3h). A value of zero means don't timeout requests. (default "0") - -s, --server string The address and port of the Kubernetes API server - --tls-server-name string Server name to use for server certificate validation. If it is not provided, the hostname used to contact the server is used - --token string Bearer token for authentication to the API server - --user string The name of the kubeconfig user to use -``` - -### SEE ALSO - -* [kbcli class](kbcli_class.md) - Manage classes - -#### Go Back to [CLI Overview](cli.md) Homepage. - diff --git a/docs/user_docs/cli/kbcli_class_list.md b/docs/user_docs/cli/kbcli_class_list.md deleted file mode 100644 index c44de63f0..000000000 --- a/docs/user_docs/cli/kbcli_class_list.md +++ /dev/null @@ -1,54 +0,0 @@ ---- -title: kbcli class list ---- - -List classes - -``` -kbcli class list [flags] -``` - -### Examples - -``` - # List all components classes in cluster definition apecloud-mysql - kbcli class list --cluster-definition apecloud-mysql -``` - -### Options - -``` - --cluster-definition string Specify cluster definition, run "kbcli clusterdefinition list" to show all available cluster definition - -h, --help help for list -``` - -### Options inherited from parent commands - -``` - --as string Username to impersonate for the operation. User could be a regular user or a service account in a namespace. - --as-group stringArray Group to impersonate for the operation, this flag can be repeated to specify multiple groups. - --as-uid string UID to impersonate for the operation. - --cache-dir string Default cache directory (default "$HOME/.kube/cache") - --certificate-authority string Path to a cert file for the certificate authority - --client-certificate string Path to a client certificate file for TLS - --client-key string Path to a client key file for TLS - --cluster string The name of the kubeconfig cluster to use - --context string The name of the kubeconfig context to use - --disable-compression If true, opt-out of response compression for all requests to the server - --insecure-skip-tls-verify If true, the server's certificate will not be checked for validity. This will make your HTTPS connections insecure - --kubeconfig string Path to the kubeconfig file to use for CLI requests. - --match-server-version Require server version to match client version - -n, --namespace string If present, the namespace scope for this CLI request - --request-timeout string The length of time to wait before giving up on a single server request. Non-zero values should contain a corresponding time unit (e.g. 1s, 2m, 3h). A value of zero means don't timeout requests. (default "0") - -s, --server string The address and port of the Kubernetes API server - --tls-server-name string Server name to use for server certificate validation. If it is not provided, the hostname used to contact the server is used - --token string Bearer token for authentication to the API server - --user string The name of the kubeconfig user to use -``` - -### SEE ALSO - -* [kbcli class](kbcli_class.md) - Manage classes - -#### Go Back to [CLI Overview](cli.md) Homepage. - diff --git a/docs/user_docs/cli/kbcli_class_template.md b/docs/user_docs/cli/kbcli_class_template.md deleted file mode 100644 index 92af595ad..000000000 --- a/docs/user_docs/cli/kbcli_class_template.md +++ /dev/null @@ -1,47 +0,0 @@ ---- -title: kbcli class template ---- - -Generate class definition template - -``` -kbcli class template [flags] -``` - -### Options - -``` - -h, --help help for template - -o, --output string Output class definition template to a file -``` - -### Options inherited from parent commands - -``` - --as string Username to impersonate for the operation. User could be a regular user or a service account in a namespace. - --as-group stringArray Group to impersonate for the operation, this flag can be repeated to specify multiple groups. - --as-uid string UID to impersonate for the operation. - --cache-dir string Default cache directory (default "$HOME/.kube/cache") - --certificate-authority string Path to a cert file for the certificate authority - --client-certificate string Path to a client certificate file for TLS - --client-key string Path to a client key file for TLS - --cluster string The name of the kubeconfig cluster to use - --context string The name of the kubeconfig context to use - --disable-compression If true, opt-out of response compression for all requests to the server - --insecure-skip-tls-verify If true, the server's certificate will not be checked for validity. This will make your HTTPS connections insecure - --kubeconfig string Path to the kubeconfig file to use for CLI requests. - --match-server-version Require server version to match client version - -n, --namespace string If present, the namespace scope for this CLI request - --request-timeout string The length of time to wait before giving up on a single server request. Non-zero values should contain a corresponding time unit (e.g. 1s, 2m, 3h). A value of zero means don't timeout requests. (default "0") - -s, --server string The address and port of the Kubernetes API server - --tls-server-name string Server name to use for server certificate validation. If it is not provided, the hostname used to contact the server is used - --token string Bearer token for authentication to the API server - --user string The name of the kubeconfig user to use -``` - -### SEE ALSO - -* [kbcli class](kbcli_class.md) - Manage classes - -#### Go Back to [CLI Overview](cli.md) Homepage. - diff --git a/docs/user_docs/cli/kbcli_cluster_create.md b/docs/user_docs/cli/kbcli_cluster_create.md index 0daafdfe2..e7032ce9c 100644 --- a/docs/user_docs/cli/kbcli_cluster_create.md +++ b/docs/user_docs/cli/kbcli_cluster_create.md @@ -110,13 +110,13 @@ kbcli cluster create [NAME] [flags] --cluster-version string Specify cluster version, run "kbcli cv list" to show all available cluster versions, use the latest version if not specified --cpu-oversell-ratio float Set oversell ratio of CPU, set to 10 means 10 times oversell (default 1) --create-only-set Create components exclusively configured in 'set' + --disable-exporter Enable or disable monitoring (default true) --dry-run string[="unchanged"] Must be "client", or "server". If with client strategy, only print the object that would be sent, and no data is actually sent. If with server strategy, submit the server-side request, but no data is persistent. (default "none") --edit Edit the API resource before creating --enable-all-logs Enable advanced application all log extraction, set to true will ignore enabledLogs of component level, default is false -h, --help help for create --label stringArray Set labels for cluster resources --memory-oversell-ratio float Set oversell ratio of memory, set to 10 means 10 times oversell (default 1) - --monitoring-interval uint8 The monitoring interval of cluster, 0 is disabled, the unit is second, any non-zero value means enabling monitoring. --node-labels stringToString Node label selector (default []) -o, --output format Prints the output in the specified format. Allowed values: JSON and YAML (default yaml) --pitr-enabled Specify whether enabled point in time recovery @@ -125,7 +125,7 @@ kbcli cluster create [NAME] [flags] --rbac-enabled Specify whether rbac resources will be created by kbcli, otherwise KubeBlocks server will try to create rbac resources --restore-to-time string Set a time for point in time recovery --service-reference stringArray Set the other KubeBlocks cluster dependencies, each '--service-reference' corresponds to a cluster service. (e.g --service-reference name=pulsarZookeeper,cluster=zookeeper,namespace=default) - --set stringArray Set the cluster resource including cpu, memory, replicas and storage, each set corresponds to a component.(e.g. --set cpu=1,memory=1Gi,replicas=3,storage=20Gi or --set class=general-1c1g) + --set stringArray Set the cluster resource including cpu, memory, replicas and storage, each set corresponds to a component.(e.g. --set cpu=1,memory=1Gi,replicas=3,storage=20Gi) -f, --set-file string Use yaml file, URL, or stdin to set the cluster resource --tenancy string Tenancy options, one of: (SharedNode, DedicatedNode) (default "SharedNode") --termination-policy string Termination policy, one of: (DoNotTerminate, Halt, Delete, WipeOut) (default "Delete") @@ -161,11 +161,13 @@ kbcli cluster create [NAME] [flags] ### SEE ALSO * [kbcli cluster](kbcli_cluster.md) - Cluster command. +* [kbcli cluster create elasticsearch](kbcli_cluster_create_elasticsearch.md) - Create a elasticsearch cluster. * [kbcli cluster create kafka](kbcli_cluster_create_kafka.md) - Create a kafka cluster. * [kbcli cluster create llm](kbcli_cluster_create_llm.md) - Create a llm cluster. * [kbcli cluster create mongodb](kbcli_cluster_create_mongodb.md) - Create a mongodb cluster. * [kbcli cluster create mysql](kbcli_cluster_create_mysql.md) - Create a mysql cluster. * [kbcli cluster create postgresql](kbcli_cluster_create_postgresql.md) - Create a postgresql cluster. +* [kbcli cluster create qdrant](kbcli_cluster_create_qdrant.md) - Create a qdrant cluster. * [kbcli cluster create redis](kbcli_cluster_create_redis.md) - Create a redis cluster. * [kbcli cluster create xinference](kbcli_cluster_create_xinference.md) - Create a xinference cluster. diff --git a/docs/user_docs/cli/kbcli_fault_node_detach-volume.md b/docs/user_docs/cli/kbcli_cluster_create_elasticsearch.md similarity index 56% rename from docs/user_docs/cli/kbcli_fault_node_detach-volume.md rename to docs/user_docs/cli/kbcli_cluster_create_elasticsearch.md index 5a3757e44..fc62a97e3 100644 --- a/docs/user_docs/cli/kbcli_fault_node_detach-volume.md +++ b/docs/user_docs/cli/kbcli_cluster_create_elasticsearch.md @@ -1,52 +1,40 @@ --- -title: kbcli fault node detach-volume +title: kbcli cluster create elasticsearch --- -Detach volume +Create a elasticsearch cluster. ``` -kbcli fault node detach-volume [flags] +kbcli cluster create elasticsearch NAME [flags] ``` ### Examples ``` - # Stop a specified EC2 instance. - kbcli fault node stop node1 -c=aws --region=cn-northwest-1 --duration=3m + # Create a cluster with the default values + kbcli cluster create elasticsearch - # Stop two specified EC2 instances. - kbcli fault node stop node1 node2 -c=aws --region=cn-northwest-1 --duration=3m - - # Restart two specified EC2 instances. - kbcli fault node restart node1 node2 -c=aws --region=cn-northwest-1 --duration=3m - - # Detach two specified volume from two specified EC2 instances. - kbcli fault node detach-volume node1 node2 -c=aws --region=cn-northwest-1 --duration=1m --volume-id=v1,v2 --device-name=/d1,/d2 - - # Stop two specified GCK instances. - kbcli fault node stop node1 node2 -c=gcp --region=us-central1-c --project=apecloud-platform-engineering - - # Restart two specified GCK instances. - kbcli fault node restart node1 node2 -c=gcp --region=us-central1-c --project=apecloud-platform-engineering - - # Detach two specified volume from two specified GCK instances. - kbcli fault node detach-volume node1 node2 -c=gcp --region=us-central1-c --project=apecloud-platform-engineering --device-name=/d1,/d2 + # Create a cluster with the specified cpu, memory and storage + kbcli cluster create elasticsearch --cpu 1 --memory 2 --storage 10 ``` ### Options ``` - --auto-approve Skip interactive approval before create secret. - -c, --cloud-provider string Cloud provider type, one of [aws gcp] - --device-name strings The device name of the volume. - --dry-run string[="unchanged"] Must be "client", or "server". If with client strategy, only print the object that would be sent, and no data is actually sent. If with server strategy, submit the server-side request, but no data is persistent. (default "none") - --duration string Supported formats of the duration are: ms / s / m / h. (default "30s") - -h, --help help for detach-volume - -o, --output format Prints the output in the specified format. Allowed values: JSON and YAML (default yaml) - --project string The name of the GCP project. Only available when cloud-provider=gcp. - --region string The region of the node. - --secret string The name of the secret containing cloud provider specific credentials. - --volume-id strings The volume ids of the ec2. Only available when cloud-provider=aws. + --availability-policy string The availability policy of cluster. Legal values [none, node, zone]. (default "node") + --cpu float CPU cores. Value range [0.5, 64]. (default 1) + --disable-exporter Enable or disable monitor. (default true) + -h, --help help for elasticsearch + --host-network-accessible Specify whether the cluster can be accessed from within the VPC. + --memory float Memory, the unit is Gi. Value range [1, 1000]. (default 2) + --mode string Mode for ElasticSearch Legal values [single-node, multi-node]. (default "multi-node") + --publicly-accessible Specify whether the cluster can be accessed from the public internet. + --rbac-enabled Specify whether rbac resources will be created by client, otherwise KubeBlocks server will try to create rbac resources. + --replicas int The number of replicas, for single-node mode, the replicas is 1, for multi-node mode, the default replicas is 3. Value range [1, 5]. (default 1) + --service-version string The version of ElasticSearch. (default "8.8.2") + --storage float Storage size, the unit is Gi. Value range [1, 10000]. (default 20) + --tenancy string The tenancy of cluster. Legal values [SharedNode, DedicatedNode]. (default "SharedNode") + --termination-policy string The termination policy of cluster. Legal values [DoNotTerminate, Halt, Delete, WipeOut]. (default "Delete") ``` ### Options inherited from parent commands @@ -62,10 +50,13 @@ kbcli fault node detach-volume [flags] --cluster string The name of the kubeconfig cluster to use --context string The name of the kubeconfig context to use --disable-compression If true, opt-out of response compression for all requests to the server + --dry-run string[="unchanged"] Must be "client", or "server". If with client strategy, only print the object that would be sent, and no data is actually sent. If with server strategy, submit the server-side request, but no data is persistent. (default "none") + --edit Edit the API resource before creating --insecure-skip-tls-verify If true, the server's certificate will not be checked for validity. This will make your HTTPS connections insecure --kubeconfig string Path to the kubeconfig file to use for CLI requests. --match-server-version Require server version to match client version -n, --namespace string If present, the namespace scope for this CLI request + -o, --output format Prints the output in the specified format. Allowed values: JSON and YAML (default yaml) --request-timeout string The length of time to wait before giving up on a single server request. Non-zero values should contain a corresponding time unit (e.g. 1s, 2m, 3h). A value of zero means don't timeout requests. (default "0") -s, --server string The address and port of the Kubernetes API server --tls-server-name string Server name to use for server certificate validation. If it is not provided, the hostname used to contact the server is used @@ -75,7 +66,7 @@ kbcli fault node detach-volume [flags] ### SEE ALSO -* [kbcli fault node](kbcli_fault_node.md) - Node chaos. +* [kbcli cluster create](kbcli_cluster_create.md) - Create a cluster. #### Go Back to [CLI Overview](cli.md) Homepage. diff --git a/docs/user_docs/cli/kbcli_cluster_create_kafka.md b/docs/user_docs/cli/kbcli_cluster_create_kafka.md index f432f570b..2791494e2 100644 --- a/docs/user_docs/cli/kbcli_cluster_create_kafka.md +++ b/docs/user_docs/cli/kbcli_cluster_create_kafka.md @@ -27,6 +27,7 @@ kbcli cluster create kafka NAME [flags] --controller-heap string Kafka controller's jvm heap setting for separated mode (default "-XshowSettings:vm -XX:MaxRAMPercentage=100 -Ddepth=64") --controller-replicas int The number of Kafka controller replicas for separated mode. Legal values [1, 3, 5]. (default 1) --cpu float CPU cores. Value range [0.5, 64]. (default 0.5) + --disable-exporter Enable or disable monitor. (default true) -h, --help help for kafka --host-network-accessible Specify whether the cluster can be accessed from within the VPC. --memory float Memory, the unit is Gi. Value range [0.5, 1000]. (default 0.5) @@ -35,7 +36,6 @@ kbcli cluster create kafka NAME [flags] --mode string Mode for Kafka kraft cluster, 'combined' is combined Kafka controller and broker,'separated' is broker and controller running independently. Legal values [combined, separated]. (default "combined") --monitor-enable Enable monitor for Kafka. (default true) --monitor-replicas int The number of Kafka monitor replicas. Value range [1, 5]. (default 1) - --monitoring-interval int The monitoring interval of cluster, 0 is disabled, the unit is second. Value range [0, 60]. --node-port-enabled Whether NodePort service is enabled, default is false --publicly-accessible Specify whether the cluster can be accessed from the public internet. --rbac-enabled Specify whether rbac resources will be created by client, otherwise KubeBlocks server will try to create rbac resources. diff --git a/docs/user_docs/cli/kbcli_cluster_create_llm.md b/docs/user_docs/cli/kbcli_cluster_create_llm.md index 9be93f12d..58d7f7304 100644 --- a/docs/user_docs/cli/kbcli_cluster_create_llm.md +++ b/docs/user_docs/cli/kbcli_cluster_create_llm.md @@ -23,14 +23,14 @@ kbcli cluster create llm NAME [flags] ``` --availability-policy string The availability policy of cluster. Legal values [none, node, zone]. (default "node") --cpu float CPU cores. Value range [0, 64]. - --cpu-mode Set to true if no GPU is available + --cpu-mode Set to true if no GPU is available, default true (default true) + --disable-exporter Enable or disable monitor. (default true) --extra-args string extra arguments that will be passed to run model (default "--trust-remote-code") --gpu float GPU cores. Value range [0, 64]. (default 1) -h, --help help for llm --host-network-accessible Specify whether the cluster can be accessed from within the VPC. --memory float Memory, the unit is Gi. Value range [0, 1000]. --model string Model name (default "facebook/opt-125m") - --monitoring-interval int The monitoring interval of cluster, 0 is disabled, the unit is second. Value range [0, 60]. --publicly-accessible Specify whether the cluster can be accessed from the public internet. --quantize string Model's quantized file name, only work for CPU mode --rbac-enabled Specify whether rbac resources will be created by client, otherwise KubeBlocks server will try to create rbac resources. diff --git a/docs/user_docs/cli/kbcli_cluster_create_mongodb.md b/docs/user_docs/cli/kbcli_cluster_create_mongodb.md index 880f4ce8f..8e56911d4 100644 --- a/docs/user_docs/cli/kbcli_cluster_create_mongodb.md +++ b/docs/user_docs/cli/kbcli_cluster_create_mongodb.md @@ -23,15 +23,16 @@ kbcli cluster create mongodb NAME [flags] ``` --availability-policy string The availability policy of cluster. Legal values [none, node, zone]. (default "node") --cpu float CPU cores. Value range [0.5, 64]. (default 0.5) + --disable-exporter Enable or disable monitor. (default true) -h, --help help for mongodb --host-network-accessible Specify whether the cluster can be accessed from within the VPC. --memory float Memory, the unit is Gi. Value range [0.5, 1000]. (default 0.5) --mode string Cluster topology mode. Legal values [standalone, replicaset]. (default "standalone") - --monitoring-interval int The monitoring interval of cluster, 0 is disabled, the unit is second. Value range [0, 60]. --publicly-accessible Specify whether the cluster can be accessed from the public internet. --rbac-enabled Specify whether rbac resources will be created by client, otherwise KubeBlocks server will try to create rbac resources. --replicas int The number of replicas, for standalone mode, the replicas is 1, for replicaset mode, the default replicas is 3. Value range [1, 5]. (default 1) --storage float Storage size, the unit is Gi. Value range [1, 10000]. (default 20) + --storage-class-name string Storage class name of the data volume --tenancy string The tenancy of cluster. Legal values [SharedNode, DedicatedNode]. (default "SharedNode") --termination-policy string The termination policy of cluster. Legal values [DoNotTerminate, Halt, Delete, WipeOut]. (default "Delete") --version string Cluster version. diff --git a/docs/user_docs/cli/kbcli_cluster_create_mysql.md b/docs/user_docs/cli/kbcli_cluster_create_mysql.md index 28737701d..40f345d60 100644 --- a/docs/user_docs/cli/kbcli_cluster_create_mysql.md +++ b/docs/user_docs/cli/kbcli_cluster_create_mysql.md @@ -23,16 +23,17 @@ kbcli cluster create mysql NAME [flags] ``` --availability-policy string The availability policy of cluster. Legal values [none, node, zone]. (default "node") --cpu float CPU cores. Value range [0.5, 64]. (default 0.5) + --disable-exporter Enable or disable monitor. (default true) -h, --help help for mysql --host-network-accessible Specify whether the cluster can be accessed from within the VPC. --memory float Memory, the unit is Gi. Value range [0.5, 1000]. (default 0.5) --mode string Cluster topology mode. Legal values [standalone, raftGroup]. (default "standalone") - --monitoring-interval int The monitoring interval of cluster, 0 is disabled, the unit is second. Value range [0, 60]. --proxy-enabled Enable proxy or not. --publicly-accessible Specify whether the cluster can be accessed from the public internet. --rbac-enabled Specify whether rbac resources will be created by client, otherwise KubeBlocks server will try to create rbac resources. --replicas int The number of replicas, for standalone mode, the replicas is 1, for raftGroup mode, the default replicas is 3. Value range [1, 5]. (default 1) --storage float Storage size, the unit is Gi. Value range [1, 10000]. (default 20) + --storage-class-name string Storage class name of the data volume --tenancy string The tenancy of cluster. Legal values [SharedNode, DedicatedNode]. (default "SharedNode") --termination-policy string The termination policy of cluster. Legal values [DoNotTerminate, Halt, Delete, WipeOut]. (default "Delete") --version string Cluster version. diff --git a/docs/user_docs/cli/kbcli_fault_network_dns_error.md b/docs/user_docs/cli/kbcli_cluster_create_oriol.md similarity index 55% rename from docs/user_docs/cli/kbcli_fault_network_dns_error.md rename to docs/user_docs/cli/kbcli_cluster_create_oriol.md index d399fdad7..2f279d43e 100644 --- a/docs/user_docs/cli/kbcli_fault_network_dns_error.md +++ b/docs/user_docs/cli/kbcli_cluster_create_oriol.md @@ -1,39 +1,43 @@ --- -title: kbcli fault network dns error +title: kbcli cluster create oriol --- -Make DNS return an error when resolving external domain names. +Create a oriol cluster. ``` -kbcli fault network dns error [flags] +kbcli cluster create oriol NAME [flags] ``` ### Examples ``` - // Inject DNS faults into all pods under the default namespace, so that any IP is returned when accessing the bing.com domain name. - kbcli fault dns random --patterns=bing.com --duration=1m + # Create a cluster with the default values + kbcli cluster create oriol - // Inject DNS faults into all pods under the default namespace, so that error is returned when accessing the bing.com domain name. - kbcli fault dns error --patterns=bing.com --duration=1m + # Create a cluster with the specified cpu, memory and storage + kbcli cluster create oriol --cpu 1 --memory 2 --storage 10 ``` ### Options ``` - --annotation stringToString Select the pod to inject the fault according to Annotation. (default []) - --dry-run string[="unchanged"] Must be "client", or "server". If with client strategy, only print the object that would be sent, and no data is actually sent. If with server strategy, submit the server-side request, but no data is persistent. (default "none") - --duration string Supported formats of the duration are: ms / s / m / h. (default "10s") - -h, --help help for error - --label stringToString label for pod, such as '"app.kubernetes.io/component=mysql, statefulset.kubernetes.io/pod-name=mycluster-mysql-0. (default []) - --mode string You can select "one", "all", "fixed", "fixed-percent", "random-max-percent", Specify the experimental mode, that is, which Pods to experiment with. (default "all") - --node stringArray Inject faults into pods in the specified node. - --node-label stringToString label for node, such as '"kubernetes.io/arch=arm64,kubernetes.io/hostname=minikube-m03,kubernetes.io/os=linux. (default []) - --ns-fault stringArray Specifies the namespace into which you want to inject faults. (default [default]) - -o, --output format Prints the output in the specified format. Allowed values: JSON and YAML (default yaml) - --patterns stringArray Select the domain name template that matching the failure behavior & supporting placeholders ? and wildcards *. - --phase stringArray Specify the pod that injects the fault by the state of the pod. - --value string If you choose mode=fixed or fixed-percent or random-max-percent, you can enter a value to specify the number or percentage of pods you want to inject. + --availability-policy string The availability policy of cluster. Legal values [none, node, zone]. (default "node") + --cpu float CPU cores. Value range [0.5, 64]. (default 0.5) + --etcd.cluster string The patroni dependency etcd cluster name (default "etcd") + --etcd.namespace string The patroni dependency etcd cluster namespace (default "default") + -h, --help help for oriol + --host-network-accessible Specify whether the cluster can be accessed from within the VPC. + --memory float Memory, the unit is Gi. Value range [0.5, 1000]. (default 0.5) + --mode string Legal values [standalone, replication]. (default "standalone") + --monitor-enabled Enable or disable monitor. + --publicly-accessible Specify whether the cluster can be accessed from the public internet. + --rbac-enabled Specify whether rbac resources will be created by client, otherwise KubeBlocks server will try to create rbac resources. + --replicas int Value range [1, 5]. (default 1) + --storage float Storage size, the unit is Gi. Value range [1, 10000]. (default 20) + --storage-class-name string Storage class name of the data volume + --tenancy string The tenancy of cluster. Legal values [SharedNode, DedicatedNode]. (default "SharedNode") + --termination-policy string The termination policy of cluster. Legal values [DoNotTerminate, Halt, Delete, WipeOut]. (default "Delete") + --version string ``` ### Options inherited from parent commands @@ -49,10 +53,13 @@ kbcli fault network dns error [flags] --cluster string The name of the kubeconfig cluster to use --context string The name of the kubeconfig context to use --disable-compression If true, opt-out of response compression for all requests to the server + --dry-run string[="unchanged"] Must be "client", or "server". If with client strategy, only print the object that would be sent, and no data is actually sent. If with server strategy, submit the server-side request, but no data is persistent. (default "none") + --edit Edit the API resource before creating --insecure-skip-tls-verify If true, the server's certificate will not be checked for validity. This will make your HTTPS connections insecure --kubeconfig string Path to the kubeconfig file to use for CLI requests. --match-server-version Require server version to match client version -n, --namespace string If present, the namespace scope for this CLI request + -o, --output format Prints the output in the specified format. Allowed values: JSON and YAML (default yaml) --request-timeout string The length of time to wait before giving up on a single server request. Non-zero values should contain a corresponding time unit (e.g. 1s, 2m, 3h). A value of zero means don't timeout requests. (default "0") -s, --server string The address and port of the Kubernetes API server --tls-server-name string Server name to use for server certificate validation. If it is not provided, the hostname used to contact the server is used @@ -62,7 +69,7 @@ kbcli fault network dns error [flags] ### SEE ALSO -* [kbcli fault network dns](kbcli_fault_network_dns.md) - Inject faults into DNS server. +* [kbcli cluster create](kbcli_cluster_create.md) - Create a cluster. #### Go Back to [CLI Overview](cli.md) Homepage. diff --git a/docs/user_docs/cli/kbcli_cluster_create_postgresql.md b/docs/user_docs/cli/kbcli_cluster_create_postgresql.md index d356e840a..15ce187fe 100644 --- a/docs/user_docs/cli/kbcli_cluster_create_postgresql.md +++ b/docs/user_docs/cli/kbcli_cluster_create_postgresql.md @@ -23,15 +23,16 @@ kbcli cluster create postgresql NAME [flags] ``` --availability-policy string The availability policy of cluster. Legal values [none, node, zone]. (default "node") --cpu float CPU cores. Value range [0.5, 64]. (default 0.5) + --disable-exporter Enable or disable monitor. (default true) -h, --help help for postgresql --host-network-accessible Specify whether the cluster can be accessed from within the VPC. --memory float Memory, the unit is Gi. Value range [0.5, 1000]. (default 0.5) --mode string Cluster topology mode. Legal values [standalone, replication]. (default "standalone") - --monitoring-interval int The monitoring interval of cluster, 0 is disabled, the unit is second. Value range [0, 60]. --publicly-accessible Specify whether the cluster can be accessed from the public internet. --rbac-enabled Specify whether rbac resources will be created by client, otherwise KubeBlocks server will try to create rbac resources. --replicas int The number of replicas, for standalone mode, the replicas is 1, for replication mode, the default replicas is 2. Value range [1, 5]. (default 1) --storage float Storage size, the unit is Gi. Value range [1, 10000]. (default 20) + --storage-class-name string Storage class name of the data volume --tenancy string The tenancy of cluster. Legal values [SharedNode, DedicatedNode]. (default "SharedNode") --termination-policy string The termination policy of cluster. Legal values [DoNotTerminate, Halt, Delete, WipeOut]. (default "Delete") --version string Cluster version. diff --git a/docs/user_docs/cli/kbcli_cluster_create_qdrant.md b/docs/user_docs/cli/kbcli_cluster_create_qdrant.md index 5424d4264..5747c55a8 100644 --- a/docs/user_docs/cli/kbcli_cluster_create_qdrant.md +++ b/docs/user_docs/cli/kbcli_cluster_create_qdrant.md @@ -22,19 +22,19 @@ kbcli cluster create qdrant NAME [flags] ``` --availability-policy string The availability policy of cluster. Legal values [none, node, zone]. (default "node") - --cpu float CPU cores. Value range [0.5, 64]. (default 0.5) + --cpu float CPU cores. Value range [0.5, 64]. (default 1) + --disable-exporter Enable or disable monitor. (default true) -h, --help help for qdrant --host-network-accessible Specify whether the cluster can be accessed from within the VPC. --memory float Memory, the unit is Gi. Value range [0.5, 1000]. (default 2) - --mode string Cluster topology mode. Legal values [standalone, replication]. (default "standalone") - --monitoring-interval int The monitoring interval of cluster, 0 is disabled, the unit is second. Value range [0, 60]. --publicly-accessible Specify whether the cluster can be accessed from the public internet. --rbac-enabled Specify whether rbac resources will be created by client, otherwise KubeBlocks server will try to create rbac resources. - --replicas int The number of replicas, for standalone mode, the replicas is 1, for replication mode, the default replicas is 2. Value range [1, 5]. (default 1) + --replicas int The number of replicas. Value range [1, 16]. (default 1) + --service-version string The version of Qdrant. (default "1.10.1") --storage float Storage size, the unit is Gi. Value range [1, 10000]. (default 20) + --storage-class-name string Storage class name of the data volume --tenancy string The tenancy of cluster. Legal values [SharedNode, DedicatedNode]. (default "SharedNode") --termination-policy string The termination policy of cluster. Legal values [DoNotTerminate, Halt, Delete, WipeOut]. (default "Delete") - --version string Cluster version. ``` ### Options inherited from parent commands diff --git a/docs/user_docs/cli/kbcli_cluster_create_redis.md b/docs/user_docs/cli/kbcli_cluster_create_redis.md index 73b610088..13f130ea2 100644 --- a/docs/user_docs/cli/kbcli_cluster_create_redis.md +++ b/docs/user_docs/cli/kbcli_cluster_create_redis.md @@ -23,11 +23,11 @@ kbcli cluster create redis NAME [flags] ``` --availability-policy string The availability policy of cluster. Legal values [none, node, zone]. (default "node") --cpu float CPU cores. Value range [0.5, 64]. (default 0.5) + --disable-exporter Enable or disable monitor. (default true) -h, --help help for redis --host-network-accessible Specify whether the cluster can be accessed from within the VPC. --memory float Memory, the unit is Gi. Value range [0.5, 1000]. (default 0.5) - --mode string Cluster topology mode. Legal values [standalone, replication, cluster]. (default "replication") - --monitoring-interval int The monitoring interval of cluster, 0 is disabled, the unit is second. Value range [0, 60]. + --mode string Cluster topology mode. Legal values [standalone, replication, cluster, sentinel, replication-twemproxy]. (default "replication") --node-port-enabled Whether NodePort service is enabled, default is true --publicly-accessible Specify whether the cluster can be accessed from the public internet. --rbac-enabled Specify whether rbac resources will be created by client, otherwise KubeBlocks server will try to create rbac resources. @@ -39,6 +39,7 @@ kbcli cluster create redis NAME [flags] --sentinel.replicas float Sentinel component replicas Value range [1, 5]. (default 3) --sentinel.storage float Sentinel component storage size, the unit is Gi. Value range [1, 1024]. (default 20) --storage float Storage size, the unit is Gi. Value range [1, 10000]. (default 20) + --storage-class-name string Storage class name of the data volume --tenancy string The tenancy of cluster. Legal values [SharedNode, DedicatedNode]. (default "SharedNode") --termination-policy string The termination policy of cluster. Legal values [DoNotTerminate, Halt, Delete, WipeOut]. (default "Delete") --twemproxy.cpu float twemproxy component cpu cores. Value range [0.1, 8]. (default 0.2) diff --git a/docs/user_docs/cli/kbcli_fault_node_restart.md b/docs/user_docs/cli/kbcli_cluster_create_tidb.md similarity index 59% rename from docs/user_docs/cli/kbcli_fault_node_restart.md rename to docs/user_docs/cli/kbcli_cluster_create_tidb.md index 45bc50abf..554d51ddf 100644 --- a/docs/user_docs/cli/kbcli_fault_node_restart.md +++ b/docs/user_docs/cli/kbcli_cluster_create_tidb.md @@ -1,50 +1,38 @@ --- -title: kbcli fault node restart +title: kbcli cluster create tidb --- -Restart instance +Create a tidb cluster. ``` -kbcli fault node restart [flags] +kbcli cluster create tidb NAME [flags] ``` ### Examples ``` - # Stop a specified EC2 instance. - kbcli fault node stop node1 -c=aws --region=cn-northwest-1 --duration=3m + # Create a cluster with the default values + kbcli cluster create tidb - # Stop two specified EC2 instances. - kbcli fault node stop node1 node2 -c=aws --region=cn-northwest-1 --duration=3m - - # Restart two specified EC2 instances. - kbcli fault node restart node1 node2 -c=aws --region=cn-northwest-1 --duration=3m - - # Detach two specified volume from two specified EC2 instances. - kbcli fault node detach-volume node1 node2 -c=aws --region=cn-northwest-1 --duration=1m --volume-id=v1,v2 --device-name=/d1,/d2 - - # Stop two specified GCK instances. - kbcli fault node stop node1 node2 -c=gcp --region=us-central1-c --project=apecloud-platform-engineering - - # Restart two specified GCK instances. - kbcli fault node restart node1 node2 -c=gcp --region=us-central1-c --project=apecloud-platform-engineering - - # Detach two specified volume from two specified GCK instances. - kbcli fault node detach-volume node1 node2 -c=gcp --region=us-central1-c --project=apecloud-platform-engineering --device-name=/d1,/d2 + # Create a cluster with the specified cpu, memory and storage + kbcli cluster create tidb --cpu 1 --memory 2 --storage 10 ``` ### Options ``` - --auto-approve Skip interactive approval before create secret. - -c, --cloud-provider string Cloud provider type, one of [aws gcp] - --dry-run string[="unchanged"] Must be "client", or "server". If with client strategy, only print the object that would be sent, and no data is actually sent. If with server strategy, submit the server-side request, but no data is persistent. (default "none") - --duration string Supported formats of the duration are: ms / s / m / h. (default "30s") - -h, --help help for restart - -o, --output format Prints the output in the specified format. Allowed values: JSON and YAML (default yaml) - --project string The name of the GCP project. Only available when cloud-provider=gcp. - --region string The region of the node. - --secret string The name of the secret containing cloud provider specific credentials. + -h, --help help for tidb + --pd.cpu float CPU cores. Value range [2, 64]. (default 2) + --pd.memory float Memory, the unit is Gi. Value range [4, 1000]. (default 4) + --pd.replicas int The number of replicas Value range [1, 5]. (default 3) + --pd.storage float Storage size, the unit is Gi. Value range [1, 10000]. (default 20) + --termination-policy string The termination policy of cluster. Legal values [DoNotTerminate, Halt, Delete, WipeOut]. (default "Delete") + --tidb.cpu float CPU cores. Value range [2, 64]. (default 2) + --tidb.replicas int The number of replicas Value range [1, 5]. (default 2) + --tikv.cpu float CPU cores. Value range [2, 64]. (default 2) + --tikv.memory float Memory, the unit is Gi. Value range [4, 1000]. (default 4) + --tikv.replicas int The number of replicas Value range [1, 5]. (default 3) + --tikv.storage float Storage size, the unit is Gi. Value range [1, 10000]. (default 20) ``` ### Options inherited from parent commands @@ -60,10 +48,13 @@ kbcli fault node restart [flags] --cluster string The name of the kubeconfig cluster to use --context string The name of the kubeconfig context to use --disable-compression If true, opt-out of response compression for all requests to the server + --dry-run string[="unchanged"] Must be "client", or "server". If with client strategy, only print the object that would be sent, and no data is actually sent. If with server strategy, submit the server-side request, but no data is persistent. (default "none") + --edit Edit the API resource before creating --insecure-skip-tls-verify If true, the server's certificate will not be checked for validity. This will make your HTTPS connections insecure --kubeconfig string Path to the kubeconfig file to use for CLI requests. --match-server-version Require server version to match client version -n, --namespace string If present, the namespace scope for this CLI request + -o, --output format Prints the output in the specified format. Allowed values: JSON and YAML (default yaml) --request-timeout string The length of time to wait before giving up on a single server request. Non-zero values should contain a corresponding time unit (e.g. 1s, 2m, 3h). A value of zero means don't timeout requests. (default "0") -s, --server string The address and port of the Kubernetes API server --tls-server-name string Server name to use for server certificate validation. If it is not provided, the hostname used to contact the server is used @@ -73,7 +64,7 @@ kbcli fault node restart [flags] ### SEE ALSO -* [kbcli fault node](kbcli_fault_node.md) - Node chaos. +* [kbcli cluster create](kbcli_cluster_create.md) - Create a cluster. #### Go Back to [CLI Overview](cli.md) Homepage. diff --git a/docs/user_docs/cli/kbcli_cluster_create_xinference.md b/docs/user_docs/cli/kbcli_cluster_create_xinference.md index 638509a3b..d26fc09f3 100644 --- a/docs/user_docs/cli/kbcli_cluster_create_xinference.md +++ b/docs/user_docs/cli/kbcli_cluster_create_xinference.md @@ -24,17 +24,16 @@ kbcli cluster create xinference NAME [flags] --availability-policy string The availability policy of cluster. Legal values [none, node, zone]. (default "node") --cpu float CPU cores. Value range [0.5, 64]. (default 2) --cpu-mode Set to true if no GPU is available + --disable-exporter Enable or disable monitor. (default true) --gpu float GPU cores. Value range [0, 64]. (default 1) -h, --help help for xinference --host-network-accessible Specify whether the cluster can be accessed from within the VPC. --memory float Memory, the unit is Gi. Value range [0.5, 1000]. (default 6) - --monitoring-interval int The monitoring interval of cluster, 0 is disabled, the unit is second. Value range [0, 60]. --publicly-accessible Specify whether the cluster can be accessed from the public internet. --rbac-enabled Specify whether rbac resources will be created by client, otherwise KubeBlocks server will try to create rbac resources. --replicas int The number of replicas, for standalone mode, the replicas is 1, for replication mode, the default replicas is 2. Value range [1, 5]. (default 1) --tenancy string The tenancy of cluster. Legal values [SharedNode, DedicatedNode]. (default "SharedNode") --termination-policy string The termination policy of cluster. Legal values [DoNotTerminate, Halt, Delete, WipeOut]. (default "Delete") - --version string Cluster version. ``` ### Options inherited from parent commands diff --git a/docs/user_docs/cli/kbcli_cluster_edit-config.md b/docs/user_docs/cli/kbcli_cluster_edit-config.md index 3bcea146f..5a67195c5 100644 --- a/docs/user_docs/cli/kbcli_cluster_edit-config.md +++ b/docs/user_docs/cli/kbcli_cluster_edit-config.md @@ -5,7 +5,7 @@ title: kbcli cluster edit-config Edit the config file of the component. ``` -kbcli cluster edit-config NAME [--component=component-name] [--config-spec=config-spec-name] [--config-file=config-file] [flags] +kbcli cluster edit-config NAME [--components=component-name] [--config-spec=config-spec-name] [--config-file=config-file] [flags] ``` ### Examples diff --git a/docs/user_docs/cli/kbcli_cluster_expose.md b/docs/user_docs/cli/kbcli_cluster_expose.md index 2ec6d1065..27f94f087 100644 --- a/docs/user_docs/cli/kbcli_cluster_expose.md +++ b/docs/user_docs/cli/kbcli_cluster_expose.md @@ -32,6 +32,7 @@ kbcli cluster expose NAME --enable=[true|false] --type=[vpc|internet] [flags] -h, --help help for expose --name string OpsRequest name. if not specified, it will be randomly generated -o, --output format Prints the output in the specified format. Allowed values: JSON and YAML (default yaml) + --sub-type string Expose sub type, currently supported types are 'NodePort', 'LoadBalancer', only available if type is vpc (default "LoadBalancer") --ttlSecondsAfterSucceed int Time to live after the OpsRequest succeed --type string Expose type, currently supported types are 'vpc', 'internet' ``` diff --git a/docs/user_docs/cli/kbcli_fault_node_stop.md b/docs/user_docs/cli/kbcli_cluster_rebuild-instance.md similarity index 60% rename from docs/user_docs/cli/kbcli_fault_node_stop.md rename to docs/user_docs/cli/kbcli_cluster_rebuild-instance.md index 5c538dc52..2c5d6f612 100644 --- a/docs/user_docs/cli/kbcli_fault_node_stop.md +++ b/docs/user_docs/cli/kbcli_cluster_rebuild-instance.md @@ -1,50 +1,37 @@ --- -title: kbcli fault node stop +title: kbcli cluster rebuild-instance --- -Stop instance +Rebuild the specified instances in the cluster. ``` -kbcli fault node stop [flags] +kbcli cluster rebuild-instance NAME [flags] ``` ### Examples ``` - # Stop a specified EC2 instance. - kbcli fault node stop node1 -c=aws --region=cn-northwest-1 --duration=3m + # rebuild instance without backup + kbcli cluster rebuild-instance mycluster --instances pod1,pod2 - # Stop two specified EC2 instances. - kbcli fault node stop node1 node2 -c=aws --region=cn-northwest-1 --duration=3m - - # Restart two specified EC2 instances. - kbcli fault node restart node1 node2 -c=aws --region=cn-northwest-1 --duration=3m - - # Detach two specified volume from two specified EC2 instances. - kbcli fault node detach-volume node1 node2 -c=aws --region=cn-northwest-1 --duration=1m --volume-id=v1,v2 --device-name=/d1,/d2 - - # Stop two specified GCK instances. - kbcli fault node stop node1 node2 -c=gcp --region=us-central1-c --project=apecloud-platform-engineering - - # Restart two specified GCK instances. - kbcli fault node restart node1 node2 -c=gcp --region=us-central1-c --project=apecloud-platform-engineering - - # Detach two specified volume from two specified GCK instances. - kbcli fault node detach-volume node1 node2 -c=gcp --region=us-central1-c --project=apecloud-platform-engineering --device-name=/d1,/d2 + # rebuild instance from backup + kbcli cluster rebuild-instance mycluster --instances pod1,pod2 --backupName ``` ### Options ``` - --auto-approve Skip interactive approval before create secret. - -c, --cloud-provider string Cloud provider type, one of [aws gcp] + --auto-approve Skip interactive approval before rebuilding the instances.gi + --backup string instances will be rebuild by the specified backup. --dry-run string[="unchanged"] Must be "client", or "server". If with client strategy, only print the object that would be sent, and no data is actually sent. If with server strategy, submit the server-side request, but no data is persistent. (default "none") - --duration string Supported formats of the duration are: ms / s / m / h. (default "30s") - -h, --help help for stop + --env stringArray provide the necessary env for the 'Restore' operation from the backup. format: key1=value, key2=value + --force skip the pre-checks of the opsRequest to run the opsRequest forcibly + -h, --help help for rebuild-instance + --instance strings instance which need to rebuild. + --name string OpsRequest name. if not specified, it will be randomly generated + --node strings specified the target node which rebuilds the instance on the node otherwise will rebuild on a randon node. format: insName1=nodeName,insName2=nodeName -o, --output format Prints the output in the specified format. Allowed values: JSON and YAML (default yaml) - --project string The name of the GCP project. Only available when cloud-provider=gcp. - --region string The region of the node. - --secret string The name of the secret containing cloud provider specific credentials. + --ttlSecondsAfterSucceed int Time to live after the OpsRequest succeed ``` ### Options inherited from parent commands @@ -73,7 +60,7 @@ kbcli fault node stop [flags] ### SEE ALSO -* [kbcli fault node](kbcli_fault_node.md) - Node chaos. +* [kbcli cluster](kbcli_cluster.md) - Cluster command. #### Go Back to [CLI Overview](cli.md) Homepage. diff --git a/docs/user_docs/cli/kbcli_cluster_update.md b/docs/user_docs/cli/kbcli_cluster_update.md index a4d7b83bd..9612fb7da 100644 --- a/docs/user_docs/cli/kbcli_cluster_update.md +++ b/docs/user_docs/cli/kbcli_cluster_update.md @@ -64,11 +64,11 @@ kbcli cluster update NAME [flags] --backup-repo-name string the backup repository name --backup-retention-period string a time string ending with the 'd'|'D'|'h'|'H' character to describe how long the Backup should be retained (default "1d") --backup-starting-deadline-minutes int the deadline in minutes for starting the backup job if it misses its scheduled time for any reason + --disable-exporter Enable or disable monitoring (default true) --dry-run string[="unchanged"] Must be "none", "server", or "client". If client strategy, only print the object that would be sent, without sending it. If server strategy, submit server-side request without persisting the resource. (default "none") --edit Edit the API resource --enable-all-logs Enable advanced application all log extraction, set to true will ignore enabledLogs of component level, default is false -h, --help help for update - --monitoring-interval uint8 The monitoring interval of cluster, 0 is disabled, the unit is second, any non-zero value means enabling monitoring. --node-labels stringToString Node label selector (default []) -o, --output string Output format. One of: (json, yaml, name, go-template, go-template-file, template, templatefile, jsonpath, jsonpath-as-json, jsonpath-file). --pitr-enabled Specify whether enabled point in time recovery diff --git a/docs/user_docs/cli/kbcli_cluster_upgrade.md b/docs/user_docs/cli/kbcli_cluster_upgrade.md index 6ec9fb77d..5ffdcf3d5 100644 --- a/docs/user_docs/cli/kbcli_cluster_upgrade.md +++ b/docs/user_docs/cli/kbcli_cluster_upgrade.md @@ -19,12 +19,15 @@ kbcli cluster upgrade NAME [flags] ``` --auto-approve Skip interactive approval before upgrading the cluster - --cluster-version string Reference cluster version (required) + --cluster-version string Referring to the ClusterVersion CR(deprecated) + --component-definition string Referring to the ComponentDefinition (default "nil") + --components strings Component names to this operations --dry-run string[="unchanged"] Must be "client", or "server". If with client strategy, only print the object that would be sent, and no data is actually sent. If with server strategy, submit the server-side request, but no data is persistent. (default "none") --force skip the pre-checks of the opsRequest to run the opsRequest forcibly -h, --help help for upgrade --name string OpsRequest name. if not specified, it will be randomly generated -o, --output format Prints the output in the specified format. Allowed values: JSON and YAML (default yaml) + --service-version string Referring to the serviceVersion that is provided by ComponentDefinition and ComponentVersion (default "nil") --ttlSecondsAfterSucceed int Time to live after the OpsRequest succeed ``` diff --git a/docs/user_docs/cli/kbcli_cluster_vscale.md b/docs/user_docs/cli/kbcli_cluster_vscale.md index 96cbb0453..c254d9af7 100644 --- a/docs/user_docs/cli/kbcli_cluster_vscale.md +++ b/docs/user_docs/cli/kbcli_cluster_vscale.md @@ -13,16 +13,12 @@ kbcli cluster vscale NAME [flags] ``` # scale the computing resources of specified components, separate with commas for multiple components kbcli cluster vscale mycluster --components=mysql --cpu=500m --memory=500Mi - - # scale the computing resources of specified components by class, run command 'kbcli class list --cluster-definition cluster-definition-name' to get available classes - kbcli cluster vscale mycluster --components=mysql --class=general-2c4g ``` ### Options ``` --auto-approve Skip interactive approval before vertically scaling the cluster - --class string Component class --components strings Component names to this operations --cpu string Request and limit size of component cpu --dry-run string[="unchanged"] Must be "client", or "server". If with client strategy, only print the object that would be sent, and no data is actually sent. If with server strategy, submit the server-side request, but no data is persistent. (default "none") diff --git a/docs/user_docs/cli/kbcli_context.md b/docs/user_docs/cli/kbcli_context.md deleted file mode 100644 index 0cf3b9800..000000000 --- a/docs/user_docs/cli/kbcli_context.md +++ /dev/null @@ -1,59 +0,0 @@ ---- -title: kbcli context ---- - -kbcli context allows you to manage cloud context. This command is currently only applicable to cloud, and currently does not support switching the context of the local k8s cluster. - -### Examples - -``` - // Get the context name currently used by the user. - kbcli context current - // List all contexts created by the current user. - kbcli context list - // Get the description information of context context1. - kbcli context describe context1 - // Switch to context context2. - kbcli context use context2 -``` - -### Options - -``` - -h, --help help for context -``` - -### Options inherited from parent commands - -``` - --as string Username to impersonate for the operation. User could be a regular user or a service account in a namespace. - --as-group stringArray Group to impersonate for the operation, this flag can be repeated to specify multiple groups. - --as-uid string UID to impersonate for the operation. - --cache-dir string Default cache directory (default "$HOME/.kube/cache") - --certificate-authority string Path to a cert file for the certificate authority - --client-certificate string Path to a client certificate file for TLS - --client-key string Path to a client key file for TLS - --cluster string The name of the kubeconfig cluster to use - --context string The name of the kubeconfig context to use - --disable-compression If true, opt-out of response compression for all requests to the server - --insecure-skip-tls-verify If true, the server's certificate will not be checked for validity. This will make your HTTPS connections insecure - --kubeconfig string Path to the kubeconfig file to use for CLI requests. - --match-server-version Require server version to match client version - -n, --namespace string If present, the namespace scope for this CLI request - --request-timeout string The length of time to wait before giving up on a single server request. Non-zero values should contain a corresponding time unit (e.g. 1s, 2m, 3h). A value of zero means don't timeout requests. (default "0") - -s, --server string The address and port of the Kubernetes API server - --tls-server-name string Server name to use for server certificate validation. If it is not provided, the hostname used to contact the server is used - --token string Bearer token for authentication to the API server - --user string The name of the kubeconfig user to use -``` - -### SEE ALSO - - -* [kbcli context current](kbcli_context_current.md) - Get the currently used context. -* [kbcli context describe](kbcli_context_describe.md) - Get the description information of a context. -* [kbcli context list](kbcli_context_list.md) - List all created contexts. -* [kbcli context use](kbcli_context_use.md) - Use another context that you have already created. - -#### Go Back to [CLI Overview](cli.md) Homepage. - diff --git a/docs/user_docs/cli/kbcli_context_current.md b/docs/user_docs/cli/kbcli_context_current.md deleted file mode 100644 index 4240f7dfd..000000000 --- a/docs/user_docs/cli/kbcli_context_current.md +++ /dev/null @@ -1,46 +0,0 @@ ---- -title: kbcli context current ---- - -Get the currently used context. - -``` -kbcli context current [flags] -``` - -### Options - -``` - -h, --help help for current -``` - -### Options inherited from parent commands - -``` - --as string Username to impersonate for the operation. User could be a regular user or a service account in a namespace. - --as-group stringArray Group to impersonate for the operation, this flag can be repeated to specify multiple groups. - --as-uid string UID to impersonate for the operation. - --cache-dir string Default cache directory (default "$HOME/.kube/cache") - --certificate-authority string Path to a cert file for the certificate authority - --client-certificate string Path to a client certificate file for TLS - --client-key string Path to a client key file for TLS - --cluster string The name of the kubeconfig cluster to use - --context string The name of the kubeconfig context to use - --disable-compression If true, opt-out of response compression for all requests to the server - --insecure-skip-tls-verify If true, the server's certificate will not be checked for validity. This will make your HTTPS connections insecure - --kubeconfig string Path to the kubeconfig file to use for CLI requests. - --match-server-version Require server version to match client version - -n, --namespace string If present, the namespace scope for this CLI request - --request-timeout string The length of time to wait before giving up on a single server request. Non-zero values should contain a corresponding time unit (e.g. 1s, 2m, 3h). A value of zero means don't timeout requests. (default "0") - -s, --server string The address and port of the Kubernetes API server - --tls-server-name string Server name to use for server certificate validation. If it is not provided, the hostname used to contact the server is used - --token string Bearer token for authentication to the API server - --user string The name of the kubeconfig user to use -``` - -### SEE ALSO - -* [kbcli context](kbcli_context.md) - kbcli context allows you to manage cloud context. This command is currently only applicable to cloud, and currently does not support switching the context of the local k8s cluster. - -#### Go Back to [CLI Overview](cli.md) Homepage. - diff --git a/docs/user_docs/cli/kbcli_context_describe.md b/docs/user_docs/cli/kbcli_context_describe.md deleted file mode 100644 index 7a4476f28..000000000 --- a/docs/user_docs/cli/kbcli_context_describe.md +++ /dev/null @@ -1,47 +0,0 @@ ---- -title: kbcli context describe ---- - -Get the description information of a context. - -``` -kbcli context describe [flags] -``` - -### Options - -``` - -h, --help help for describe - -o, --output string Output format (table|yaml|json) (default "human") -``` - -### Options inherited from parent commands - -``` - --as string Username to impersonate for the operation. User could be a regular user or a service account in a namespace. - --as-group stringArray Group to impersonate for the operation, this flag can be repeated to specify multiple groups. - --as-uid string UID to impersonate for the operation. - --cache-dir string Default cache directory (default "$HOME/.kube/cache") - --certificate-authority string Path to a cert file for the certificate authority - --client-certificate string Path to a client certificate file for TLS - --client-key string Path to a client key file for TLS - --cluster string The name of the kubeconfig cluster to use - --context string The name of the kubeconfig context to use - --disable-compression If true, opt-out of response compression for all requests to the server - --insecure-skip-tls-verify If true, the server's certificate will not be checked for validity. This will make your HTTPS connections insecure - --kubeconfig string Path to the kubeconfig file to use for CLI requests. - --match-server-version Require server version to match client version - -n, --namespace string If present, the namespace scope for this CLI request - --request-timeout string The length of time to wait before giving up on a single server request. Non-zero values should contain a corresponding time unit (e.g. 1s, 2m, 3h). A value of zero means don't timeout requests. (default "0") - -s, --server string The address and port of the Kubernetes API server - --tls-server-name string Server name to use for server certificate validation. If it is not provided, the hostname used to contact the server is used - --token string Bearer token for authentication to the API server - --user string The name of the kubeconfig user to use -``` - -### SEE ALSO - -* [kbcli context](kbcli_context.md) - kbcli context allows you to manage cloud context. This command is currently only applicable to cloud, and currently does not support switching the context of the local k8s cluster. - -#### Go Back to [CLI Overview](cli.md) Homepage. - diff --git a/docs/user_docs/cli/kbcli_context_list.md b/docs/user_docs/cli/kbcli_context_list.md deleted file mode 100644 index f8bd19eb6..000000000 --- a/docs/user_docs/cli/kbcli_context_list.md +++ /dev/null @@ -1,46 +0,0 @@ ---- -title: kbcli context list ---- - -List all created contexts. - -``` -kbcli context list [flags] -``` - -### Options - -``` - -h, --help help for list -``` - -### Options inherited from parent commands - -``` - --as string Username to impersonate for the operation. User could be a regular user or a service account in a namespace. - --as-group stringArray Group to impersonate for the operation, this flag can be repeated to specify multiple groups. - --as-uid string UID to impersonate for the operation. - --cache-dir string Default cache directory (default "$HOME/.kube/cache") - --certificate-authority string Path to a cert file for the certificate authority - --client-certificate string Path to a client certificate file for TLS - --client-key string Path to a client key file for TLS - --cluster string The name of the kubeconfig cluster to use - --context string The name of the kubeconfig context to use - --disable-compression If true, opt-out of response compression for all requests to the server - --insecure-skip-tls-verify If true, the server's certificate will not be checked for validity. This will make your HTTPS connections insecure - --kubeconfig string Path to the kubeconfig file to use for CLI requests. - --match-server-version Require server version to match client version - -n, --namespace string If present, the namespace scope for this CLI request - --request-timeout string The length of time to wait before giving up on a single server request. Non-zero values should contain a corresponding time unit (e.g. 1s, 2m, 3h). A value of zero means don't timeout requests. (default "0") - -s, --server string The address and port of the Kubernetes API server - --tls-server-name string Server name to use for server certificate validation. If it is not provided, the hostname used to contact the server is used - --token string Bearer token for authentication to the API server - --user string The name of the kubeconfig user to use -``` - -### SEE ALSO - -* [kbcli context](kbcli_context.md) - kbcli context allows you to manage cloud context. This command is currently only applicable to cloud, and currently does not support switching the context of the local k8s cluster. - -#### Go Back to [CLI Overview](cli.md) Homepage. - diff --git a/docs/user_docs/cli/kbcli_context_use.md b/docs/user_docs/cli/kbcli_context_use.md deleted file mode 100644 index 998f7b026..000000000 --- a/docs/user_docs/cli/kbcli_context_use.md +++ /dev/null @@ -1,46 +0,0 @@ ---- -title: kbcli context use ---- - -Use another context that you have already created. - -``` -kbcli context use [flags] -``` - -### Options - -``` - -h, --help help for use -``` - -### Options inherited from parent commands - -``` - --as string Username to impersonate for the operation. User could be a regular user or a service account in a namespace. - --as-group stringArray Group to impersonate for the operation, this flag can be repeated to specify multiple groups. - --as-uid string UID to impersonate for the operation. - --cache-dir string Default cache directory (default "$HOME/.kube/cache") - --certificate-authority string Path to a cert file for the certificate authority - --client-certificate string Path to a client certificate file for TLS - --client-key string Path to a client key file for TLS - --cluster string The name of the kubeconfig cluster to use - --context string The name of the kubeconfig context to use - --disable-compression If true, opt-out of response compression for all requests to the server - --insecure-skip-tls-verify If true, the server's certificate will not be checked for validity. This will make your HTTPS connections insecure - --kubeconfig string Path to the kubeconfig file to use for CLI requests. - --match-server-version Require server version to match client version - -n, --namespace string If present, the namespace scope for this CLI request - --request-timeout string The length of time to wait before giving up on a single server request. Non-zero values should contain a corresponding time unit (e.g. 1s, 2m, 3h). A value of zero means don't timeout requests. (default "0") - -s, --server string The address and port of the Kubernetes API server - --tls-server-name string Server name to use for server certificate validation. If it is not provided, the hostname used to contact the server is used - --token string Bearer token for authentication to the API server - --user string The name of the kubeconfig user to use -``` - -### SEE ALSO - -* [kbcli context](kbcli_context.md) - kbcli context allows you to manage cloud context. This command is currently only applicable to cloud, and currently does not support switching the context of the local k8s cluster. - -#### Go Back to [CLI Overview](cli.md) Homepage. - diff --git a/docs/user_docs/cli/kbcli_dataprotection_describe-backup-policy.md b/docs/user_docs/cli/kbcli_dataprotection_describe-backup-policy.md index 2cc19413c..655a786cd 100644 --- a/docs/user_docs/cli/kbcli_dataprotection_describe-backup-policy.md +++ b/docs/user_docs/cli/kbcli_dataprotection_describe-backup-policy.md @@ -11,11 +11,11 @@ kbcli dataprotection describe-backup-policy [flags] ### Examples ``` - # describe a backup policy - kbcli cluster describe-backup-policy mypolicy + # describe the default backup policy of the cluster + kbcli cluster describe-backup-policy cluster-name - # describe the default backup policy of the specified cluster - kbcli cluster describe-backup-policy --cluster mycluster + # describe the backup policy of the cluster with specified name + kbcli cluster describe-backup-policy cluster-name --name backup-policy-name ``` ### Options diff --git a/docs/user_docs/cli/kbcli_dataprotection_list-backup-policy.md b/docs/user_docs/cli/kbcli_dataprotection_list-backup-policy.md index d1674cea5..2592291cc 100644 --- a/docs/user_docs/cli/kbcli_dataprotection_list-backup-policy.md +++ b/docs/user_docs/cli/kbcli_dataprotection_list-backup-policy.md @@ -14,11 +14,8 @@ kbcli dataprotection list-backup-policy [flags] # list all backup policies kbcli cluster list-backup-policy - # list backup policies with specified name - kbcli cluster list-backup-policy mypolicy - - # list backup policies of the specified cluster - kbcli cluster list-backup-policy --cluster mycluster + # using short cmd to list backup policy of the specified cluster + kbcli cluster list-bp mycluster ``` ### Options diff --git a/docs/user_docs/cli/kbcli_dataprotection_restore.md b/docs/user_docs/cli/kbcli_dataprotection_restore.md index e843f7150..7c4f852c5 100644 --- a/docs/user_docs/cli/kbcli_dataprotection_restore.md +++ b/docs/user_docs/cli/kbcli_dataprotection_restore.md @@ -18,11 +18,10 @@ kbcli dataprotection restore [flags] ### Options ``` - --cluster string The cluster to restore - --effective-common-component-def this backup will be restored for all components which refer to common ComponentDefinition. - -h, --help help for restore - --restore-to-time string point in time recovery(PITR) - --volume-restore-policy string the volume claim restore policy, supported values: [Serial, Parallel] (default "Parallel") + --cluster string The cluster to restore + -h, --help help for restore + --restore-to-time string point in time recovery(PITR) + --volume-restore-policy string the volume claim restore policy, supported values: [Serial, Parallel] (default "Parallel") ``` ### Options inherited from parent commands diff --git a/docs/user_docs/cli/kbcli_environment.md b/docs/user_docs/cli/kbcli_environment.md deleted file mode 100644 index 92ff46e62..000000000 --- a/docs/user_docs/cli/kbcli_environment.md +++ /dev/null @@ -1,59 +0,0 @@ ---- -title: kbcli environment ---- - -kbcli environment allows you to manage cloud environment. This command is currently only applicable to cloud, and currently does not support switching the environment of the local k8s cluster. - -### Examples - -``` - // Get the environment name currently used by the user. - kbcli environment current - // List all environments created by the current user. - kbcli environment list - // Get the description information of environment environment1. - kbcli environment describe environment1 - // Switch to environment environment2. - kbcli environment use environment2 -``` - -### Options - -``` - -h, --help help for environment -``` - -### Options inherited from parent commands - -``` - --as string Username to impersonate for the operation. User could be a regular user or a service account in a namespace. - --as-group stringArray Group to impersonate for the operation, this flag can be repeated to specify multiple groups. - --as-uid string UID to impersonate for the operation. - --cache-dir string Default cache directory (default "$HOME/.kube/cache") - --certificate-authority string Path to a cert file for the certificate authority - --client-certificate string Path to a client certificate file for TLS - --client-key string Path to a client key file for TLS - --cluster string The name of the kubeconfig cluster to use - --context string The name of the kubeconfig context to use - --disable-compression If true, opt-out of response compression for all requests to the server - --insecure-skip-tls-verify If true, the server's certificate will not be checked for validity. This will make your HTTPS connections insecure - --kubeconfig string Path to the kubeconfig file to use for CLI requests. - --match-server-version Require server version to match client version - -n, --namespace string If present, the namespace scope for this CLI request - --request-timeout string The length of time to wait before giving up on a single server request. Non-zero values should contain a corresponding time unit (e.g. 1s, 2m, 3h). A value of zero means don't timeout requests. (default "0") - -s, --server string The address and port of the Kubernetes API server - --tls-server-name string Server name to use for server certificate validation. If it is not provided, the hostname used to contact the server is used - --token string Bearer token for authentication to the API server - --user string The name of the kubeconfig user to use -``` - -### SEE ALSO - - -* [kbcli environment current](kbcli_environment_current.md) - Get the currently used environment. -* [kbcli environment describe](kbcli_environment_describe.md) - Get the description information of a environment. -* [kbcli environment list](kbcli_environment_list.md) - List all created environments. -* [kbcli environment use](kbcli_environment_use.md) - Use another environment that you have already created. - -#### Go Back to [CLI Overview](cli.md) Homepage. - diff --git a/docs/user_docs/cli/kbcli_environment_current.md b/docs/user_docs/cli/kbcli_environment_current.md deleted file mode 100644 index 814572777..000000000 --- a/docs/user_docs/cli/kbcli_environment_current.md +++ /dev/null @@ -1,46 +0,0 @@ ---- -title: kbcli environment current ---- - -Get the currently used environment. - -``` -kbcli environment current [flags] -``` - -### Options - -``` - -h, --help help for current -``` - -### Options inherited from parent commands - -``` - --as string Username to impersonate for the operation. User could be a regular user or a service account in a namespace. - --as-group stringArray Group to impersonate for the operation, this flag can be repeated to specify multiple groups. - --as-uid string UID to impersonate for the operation. - --cache-dir string Default cache directory (default "$HOME/.kube/cache") - --certificate-authority string Path to a cert file for the certificate authority - --client-certificate string Path to a client certificate file for TLS - --client-key string Path to a client key file for TLS - --cluster string The name of the kubeconfig cluster to use - --context string The name of the kubeconfig context to use - --disable-compression If true, opt-out of response compression for all requests to the server - --insecure-skip-tls-verify If true, the server's certificate will not be checked for validity. This will make your HTTPS connections insecure - --kubeconfig string Path to the kubeconfig file to use for CLI requests. - --match-server-version Require server version to match client version - -n, --namespace string If present, the namespace scope for this CLI request - --request-timeout string The length of time to wait before giving up on a single server request. Non-zero values should contain a corresponding time unit (e.g. 1s, 2m, 3h). A value of zero means don't timeout requests. (default "0") - -s, --server string The address and port of the Kubernetes API server - --tls-server-name string Server name to use for server certificate validation. If it is not provided, the hostname used to contact the server is used - --token string Bearer token for authentication to the API server - --user string The name of the kubeconfig user to use -``` - -### SEE ALSO - -* [kbcli environment](kbcli_environment.md) - kbcli environment allows you to manage cloud environment. This command is currently only applicable to cloud, and currently does not support switching the environment of the local k8s cluster. - -#### Go Back to [CLI Overview](cli.md) Homepage. - diff --git a/docs/user_docs/cli/kbcli_environment_describe.md b/docs/user_docs/cli/kbcli_environment_describe.md deleted file mode 100644 index 4a7e556a8..000000000 --- a/docs/user_docs/cli/kbcli_environment_describe.md +++ /dev/null @@ -1,47 +0,0 @@ ---- -title: kbcli environment describe ---- - -Get the description information of a environment. - -``` -kbcli environment describe [flags] -``` - -### Options - -``` - -h, --help help for describe - -o, --output string Output format (table|yaml|json) (default "human") -``` - -### Options inherited from parent commands - -``` - --as string Username to impersonate for the operation. User could be a regular user or a service account in a namespace. - --as-group stringArray Group to impersonate for the operation, this flag can be repeated to specify multiple groups. - --as-uid string UID to impersonate for the operation. - --cache-dir string Default cache directory (default "$HOME/.kube/cache") - --certificate-authority string Path to a cert file for the certificate authority - --client-certificate string Path to a client certificate file for TLS - --client-key string Path to a client key file for TLS - --cluster string The name of the kubeconfig cluster to use - --context string The name of the kubeconfig context to use - --disable-compression If true, opt-out of response compression for all requests to the server - --insecure-skip-tls-verify If true, the server's certificate will not be checked for validity. This will make your HTTPS connections insecure - --kubeconfig string Path to the kubeconfig file to use for CLI requests. - --match-server-version Require server version to match client version - -n, --namespace string If present, the namespace scope for this CLI request - --request-timeout string The length of time to wait before giving up on a single server request. Non-zero values should contain a corresponding time unit (e.g. 1s, 2m, 3h). A value of zero means don't timeout requests. (default "0") - -s, --server string The address and port of the Kubernetes API server - --tls-server-name string Server name to use for server certificate validation. If it is not provided, the hostname used to contact the server is used - --token string Bearer token for authentication to the API server - --user string The name of the kubeconfig user to use -``` - -### SEE ALSO - -* [kbcli environment](kbcli_environment.md) - kbcli environment allows you to manage cloud environment. This command is currently only applicable to cloud, and currently does not support switching the environment of the local k8s cluster. - -#### Go Back to [CLI Overview](cli.md) Homepage. - diff --git a/docs/user_docs/cli/kbcli_environment_list.md b/docs/user_docs/cli/kbcli_environment_list.md deleted file mode 100644 index ab9e3a756..000000000 --- a/docs/user_docs/cli/kbcli_environment_list.md +++ /dev/null @@ -1,46 +0,0 @@ ---- -title: kbcli environment list ---- - -List all created environments. - -``` -kbcli environment list [flags] -``` - -### Options - -``` - -h, --help help for list -``` - -### Options inherited from parent commands - -``` - --as string Username to impersonate for the operation. User could be a regular user or a service account in a namespace. - --as-group stringArray Group to impersonate for the operation, this flag can be repeated to specify multiple groups. - --as-uid string UID to impersonate for the operation. - --cache-dir string Default cache directory (default "$HOME/.kube/cache") - --certificate-authority string Path to a cert file for the certificate authority - --client-certificate string Path to a client certificate file for TLS - --client-key string Path to a client key file for TLS - --cluster string The name of the kubeconfig cluster to use - --context string The name of the kubeconfig context to use - --disable-compression If true, opt-out of response compression for all requests to the server - --insecure-skip-tls-verify If true, the server's certificate will not be checked for validity. This will make your HTTPS connections insecure - --kubeconfig string Path to the kubeconfig file to use for CLI requests. - --match-server-version Require server version to match client version - -n, --namespace string If present, the namespace scope for this CLI request - --request-timeout string The length of time to wait before giving up on a single server request. Non-zero values should contain a corresponding time unit (e.g. 1s, 2m, 3h). A value of zero means don't timeout requests. (default "0") - -s, --server string The address and port of the Kubernetes API server - --tls-server-name string Server name to use for server certificate validation. If it is not provided, the hostname used to contact the server is used - --token string Bearer token for authentication to the API server - --user string The name of the kubeconfig user to use -``` - -### SEE ALSO - -* [kbcli environment](kbcli_environment.md) - kbcli environment allows you to manage cloud environment. This command is currently only applicable to cloud, and currently does not support switching the environment of the local k8s cluster. - -#### Go Back to [CLI Overview](cli.md) Homepage. - diff --git a/docs/user_docs/cli/kbcli_environment_use.md b/docs/user_docs/cli/kbcli_environment_use.md deleted file mode 100644 index e221fa45f..000000000 --- a/docs/user_docs/cli/kbcli_environment_use.md +++ /dev/null @@ -1,46 +0,0 @@ ---- -title: kbcli environment use ---- - -Use another environment that you have already created. - -``` -kbcli environment use [flags] -``` - -### Options - -``` - -h, --help help for use -``` - -### Options inherited from parent commands - -``` - --as string Username to impersonate for the operation. User could be a regular user or a service account in a namespace. - --as-group stringArray Group to impersonate for the operation, this flag can be repeated to specify multiple groups. - --as-uid string UID to impersonate for the operation. - --cache-dir string Default cache directory (default "$HOME/.kube/cache") - --certificate-authority string Path to a cert file for the certificate authority - --client-certificate string Path to a client certificate file for TLS - --client-key string Path to a client key file for TLS - --cluster string The name of the kubeconfig cluster to use - --context string The name of the kubeconfig context to use - --disable-compression If true, opt-out of response compression for all requests to the server - --insecure-skip-tls-verify If true, the server's certificate will not be checked for validity. This will make your HTTPS connections insecure - --kubeconfig string Path to the kubeconfig file to use for CLI requests. - --match-server-version Require server version to match client version - -n, --namespace string If present, the namespace scope for this CLI request - --request-timeout string The length of time to wait before giving up on a single server request. Non-zero values should contain a corresponding time unit (e.g. 1s, 2m, 3h). A value of zero means don't timeout requests. (default "0") - -s, --server string The address and port of the Kubernetes API server - --tls-server-name string Server name to use for server certificate validation. If it is not provided, the hostname used to contact the server is used - --token string Bearer token for authentication to the API server - --user string The name of the kubeconfig user to use -``` - -### SEE ALSO - -* [kbcli environment](kbcli_environment.md) - kbcli environment allows you to manage cloud environment. This command is currently only applicable to cloud, and currently does not support switching the environment of the local k8s cluster. - -#### Go Back to [CLI Overview](cli.md) Homepage. - diff --git a/docs/user_docs/cli/kbcli_fault.md b/docs/user_docs/cli/kbcli_fault.md deleted file mode 100644 index c16772756..000000000 --- a/docs/user_docs/cli/kbcli_fault.md +++ /dev/null @@ -1,50 +0,0 @@ ---- -title: kbcli fault ---- - -Inject faults to pod. - -### Options - -``` - -h, --help help for fault -``` - -### Options inherited from parent commands - -``` - --as string Username to impersonate for the operation. User could be a regular user or a service account in a namespace. - --as-group stringArray Group to impersonate for the operation, this flag can be repeated to specify multiple groups. - --as-uid string UID to impersonate for the operation. - --cache-dir string Default cache directory (default "$HOME/.kube/cache") - --certificate-authority string Path to a cert file for the certificate authority - --client-certificate string Path to a client certificate file for TLS - --client-key string Path to a client key file for TLS - --cluster string The name of the kubeconfig cluster to use - --context string The name of the kubeconfig context to use - --disable-compression If true, opt-out of response compression for all requests to the server - --insecure-skip-tls-verify If true, the server's certificate will not be checked for validity. This will make your HTTPS connections insecure - --kubeconfig string Path to the kubeconfig file to use for CLI requests. - --match-server-version Require server version to match client version - -n, --namespace string If present, the namespace scope for this CLI request - --request-timeout string The length of time to wait before giving up on a single server request. Non-zero values should contain a corresponding time unit (e.g. 1s, 2m, 3h). A value of zero means don't timeout requests. (default "0") - -s, --server string The address and port of the Kubernetes API server - --tls-server-name string Server name to use for server certificate validation. If it is not provided, the hostname used to contact the server is used - --token string Bearer token for authentication to the API server - --user string The name of the kubeconfig user to use -``` - -### SEE ALSO - - -* [kbcli fault delete](kbcli_fault_delete.md) - Delete chaos resources. -* [kbcli fault io](kbcli_fault_io.md) - IO chaos. -* [kbcli fault list](kbcli_fault_list.md) - List chaos resources. -* [kbcli fault network](kbcli_fault_network.md) - Network chaos. -* [kbcli fault node](kbcli_fault_node.md) - Node chaos. -* [kbcli fault pod](kbcli_fault_pod.md) - Pod chaos. -* [kbcli fault stress](kbcli_fault_stress.md) - Add memory pressure or CPU load to the system. -* [kbcli fault time](kbcli_fault_time.md) - Clock skew failure. - -#### Go Back to [CLI Overview](cli.md) Homepage. - diff --git a/docs/user_docs/cli/kbcli_fault_delete.md b/docs/user_docs/cli/kbcli_fault_delete.md deleted file mode 100644 index 70837bee6..000000000 --- a/docs/user_docs/cli/kbcli_fault_delete.md +++ /dev/null @@ -1,56 +0,0 @@ ---- -title: kbcli fault delete ---- - -Delete chaos resources. - -``` -kbcli fault delete [flags] -``` - -### Examples - -``` - # Delete all chaos resources - kbcli fault delete - - # Delete specific chaos resources - kbcli fault delete podchaos -``` - -### Options - -``` - -h, --help help for delete -``` - -### Options inherited from parent commands - -``` - --as string Username to impersonate for the operation. User could be a regular user or a service account in a namespace. - --as-group stringArray Group to impersonate for the operation, this flag can be repeated to specify multiple groups. - --as-uid string UID to impersonate for the operation. - --cache-dir string Default cache directory (default "$HOME/.kube/cache") - --certificate-authority string Path to a cert file for the certificate authority - --client-certificate string Path to a client certificate file for TLS - --client-key string Path to a client key file for TLS - --cluster string The name of the kubeconfig cluster to use - --context string The name of the kubeconfig context to use - --disable-compression If true, opt-out of response compression for all requests to the server - --insecure-skip-tls-verify If true, the server's certificate will not be checked for validity. This will make your HTTPS connections insecure - --kubeconfig string Path to the kubeconfig file to use for CLI requests. - --match-server-version Require server version to match client version - -n, --namespace string If present, the namespace scope for this CLI request - --request-timeout string The length of time to wait before giving up on a single server request. Non-zero values should contain a corresponding time unit (e.g. 1s, 2m, 3h). A value of zero means don't timeout requests. (default "0") - -s, --server string The address and port of the Kubernetes API server - --tls-server-name string Server name to use for server certificate validation. If it is not provided, the hostname used to contact the server is used - --token string Bearer token for authentication to the API server - --user string The name of the kubeconfig user to use -``` - -### SEE ALSO - -* [kbcli fault](kbcli_fault.md) - Inject faults to pod. - -#### Go Back to [CLI Overview](cli.md) Homepage. - diff --git a/docs/user_docs/cli/kbcli_fault_io.md b/docs/user_docs/cli/kbcli_fault_io.md deleted file mode 100644 index 80f1f2ced..000000000 --- a/docs/user_docs/cli/kbcli_fault_io.md +++ /dev/null @@ -1,46 +0,0 @@ ---- -title: kbcli fault io ---- - -IO chaos. - -### Options - -``` - -h, --help help for io -``` - -### Options inherited from parent commands - -``` - --as string Username to impersonate for the operation. User could be a regular user or a service account in a namespace. - --as-group stringArray Group to impersonate for the operation, this flag can be repeated to specify multiple groups. - --as-uid string UID to impersonate for the operation. - --cache-dir string Default cache directory (default "$HOME/.kube/cache") - --certificate-authority string Path to a cert file for the certificate authority - --client-certificate string Path to a client certificate file for TLS - --client-key string Path to a client key file for TLS - --cluster string The name of the kubeconfig cluster to use - --context string The name of the kubeconfig context to use - --disable-compression If true, opt-out of response compression for all requests to the server - --insecure-skip-tls-verify If true, the server's certificate will not be checked for validity. This will make your HTTPS connections insecure - --kubeconfig string Path to the kubeconfig file to use for CLI requests. - --match-server-version Require server version to match client version - -n, --namespace string If present, the namespace scope for this CLI request - --request-timeout string The length of time to wait before giving up on a single server request. Non-zero values should contain a corresponding time unit (e.g. 1s, 2m, 3h). A value of zero means don't timeout requests. (default "0") - -s, --server string The address and port of the Kubernetes API server - --tls-server-name string Server name to use for server certificate validation. If it is not provided, the hostname used to contact the server is used - --token string Bearer token for authentication to the API server - --user string The name of the kubeconfig user to use -``` - -### SEE ALSO - -* [kbcli fault](kbcli_fault.md) - Inject faults to pod. -* [kbcli fault io attribute](kbcli_fault_io_attribute.md) - Override the attributes of the file. -* [kbcli fault io errno](kbcli_fault_io_errno.md) - Causes IO operations to return specific errors. -* [kbcli fault io latency](kbcli_fault_io_latency.md) - Delayed IO operations. -* [kbcli fault io mistake](kbcli_fault_io_mistake.md) - Alters the contents of the file, distorting the contents of the file. - -#### Go Back to [CLI Overview](cli.md) Homepage. - diff --git a/docs/user_docs/cli/kbcli_fault_io_attribute.md b/docs/user_docs/cli/kbcli_fault_io_attribute.md deleted file mode 100644 index b9cab95f6..000000000 --- a/docs/user_docs/cli/kbcli_fault_io_attribute.md +++ /dev/null @@ -1,94 +0,0 @@ ---- -title: kbcli fault io attribute ---- - -Override the attributes of the file. - -``` -kbcli fault io attribute [flags] -``` - -### Examples - -``` - # Affects the first container in default namespace's all pods. Delay all IO operations under the /data path by 10s. - kbcli fault io latency --delay=10s --volume-path=/data - - # Affects the first container in mycluster-mysql-0 pod. - kbcli fault io latency mycluster-mysql-0 --delay=10s --volume-path=/data - - # Affects the mysql container in mycluster-mysql-0 pod. - kbcli fault io latency mycluster-mysql-0 --delay=10s --volume-path=/data -c=mysql - - # There is a 50% probability of affecting the read IO operation of the test.txt file under the /data path. - kbcli fault io latency mycluster-mysql-0 --delay=10s --volume-path=/data --path=test.txt --percent=50 --method=READ -c=mysql - - # Same as above.Make all IO operations under the /data path return the specified error number 22 (Invalid argument). - kbcli fault io errno --volume-path=/data --errno=22 - - # Same as above.Modify the IO operation permission attribute of the files under the /data path to 72.(110 in octal). - kbcli fault io attribute --volume-path=/data --perm=72 - - # Modify all files so that random positions of 1's with a maximum length of 10 bytes will be replaced with 0's. - kbcli fault io mistake --volume-path=/data --filling=zero --max-occurrences=10 --max-length=1 -``` - -### Options - -``` - --annotation stringToString Select the pod to inject the fault according to Annotation. (default []) - --blocks uint The number of blocks the file occupies. - -c, --container stringArray The name of the container, such as mysql, prometheus.If it's empty, the first container will be injected. - --dry-run string[="unchanged"] Must be "client", or "server". If with client strategy, only print the object that would be sent, and no data is actually sent. If with server strategy, submit the server-side request, but no data is persistent. (default "none") - --duration string Supported formats of the duration are: ms / s / m / h. (default "10s") - --gid uint32 The owner's group ID. - -h, --help help for attribute - --ino uint ino number. - --label stringToString label for pod, such as '"app.kubernetes.io/component=mysql, statefulset.kubernetes.io/pod-name=mycluster-mysql-0. (default []) - --method stringArray The file system calls that need to inject faults. For example: WRITE READ - --mode string You can select "one", "all", "fixed", "fixed-percent", "random-max-percent", Specify the experimental mode, that is, which Pods to experiment with. (default "all") - --nlink uint32 The number of hard links. - --node stringArray Inject faults into pods in the specified node. - --node-label stringToString label for node, such as '"kubernetes.io/arch=arm64,kubernetes.io/hostname=minikube-m03,kubernetes.io/os=linux. (default []) - --ns-fault stringArray Specifies the namespace into which you want to inject faults. (default [default]) - -o, --output format Prints the output in the specified format. Allowed values: JSON and YAML (default yaml) - --path string The effective scope of the injection error can be a wildcard or a single file. - --percent int Probability of failure per operation, in %. (default 100) - --perm uint16 Decimal representation of file permissions. - --phase stringArray Specify the pod that injects the fault by the state of the pod. - --size uint File size. - --uid uint32 Owner's user ID. - --value string If you choose mode=fixed or fixed-percent or random-max-percent, you can enter a value to specify the number or percentage of pods you want to inject. - --volume-path string The mount point of the volume in the target container must be the root directory of the mount. -``` - -### Options inherited from parent commands - -``` - --as string Username to impersonate for the operation. User could be a regular user or a service account in a namespace. - --as-group stringArray Group to impersonate for the operation, this flag can be repeated to specify multiple groups. - --as-uid string UID to impersonate for the operation. - --cache-dir string Default cache directory (default "$HOME/.kube/cache") - --certificate-authority string Path to a cert file for the certificate authority - --client-certificate string Path to a client certificate file for TLS - --client-key string Path to a client key file for TLS - --cluster string The name of the kubeconfig cluster to use - --context string The name of the kubeconfig context to use - --disable-compression If true, opt-out of response compression for all requests to the server - --insecure-skip-tls-verify If true, the server's certificate will not be checked for validity. This will make your HTTPS connections insecure - --kubeconfig string Path to the kubeconfig file to use for CLI requests. - --match-server-version Require server version to match client version - -n, --namespace string If present, the namespace scope for this CLI request - --request-timeout string The length of time to wait before giving up on a single server request. Non-zero values should contain a corresponding time unit (e.g. 1s, 2m, 3h). A value of zero means don't timeout requests. (default "0") - -s, --server string The address and port of the Kubernetes API server - --tls-server-name string Server name to use for server certificate validation. If it is not provided, the hostname used to contact the server is used - --token string Bearer token for authentication to the API server - --user string The name of the kubeconfig user to use -``` - -### SEE ALSO - -* [kbcli fault io](kbcli_fault_io.md) - IO chaos. - -#### Go Back to [CLI Overview](cli.md) Homepage. - diff --git a/docs/user_docs/cli/kbcli_fault_io_errno.md b/docs/user_docs/cli/kbcli_fault_io_errno.md deleted file mode 100644 index 5e9bcb8c5..000000000 --- a/docs/user_docs/cli/kbcli_fault_io_errno.md +++ /dev/null @@ -1,88 +0,0 @@ ---- -title: kbcli fault io errno ---- - -Causes IO operations to return specific errors. - -``` -kbcli fault io errno [flags] -``` - -### Examples - -``` - # Affects the first container in default namespace's all pods. Delay all IO operations under the /data path by 10s. - kbcli fault io latency --delay=10s --volume-path=/data - - # Affects the first container in mycluster-mysql-0 pod. - kbcli fault io latency mycluster-mysql-0 --delay=10s --volume-path=/data - - # Affects the mysql container in mycluster-mysql-0 pod. - kbcli fault io latency mycluster-mysql-0 --delay=10s --volume-path=/data -c=mysql - - # There is a 50% probability of affecting the read IO operation of the test.txt file under the /data path. - kbcli fault io latency mycluster-mysql-0 --delay=10s --volume-path=/data --path=test.txt --percent=50 --method=READ -c=mysql - - # Same as above.Make all IO operations under the /data path return the specified error number 22 (Invalid argument). - kbcli fault io errno --volume-path=/data --errno=22 - - # Same as above.Modify the IO operation permission attribute of the files under the /data path to 72.(110 in octal). - kbcli fault io attribute --volume-path=/data --perm=72 - - # Modify all files so that random positions of 1's with a maximum length of 10 bytes will be replaced with 0's. - kbcli fault io mistake --volume-path=/data --filling=zero --max-occurrences=10 --max-length=1 -``` - -### Options - -``` - --annotation stringToString Select the pod to inject the fault according to Annotation. (default []) - -c, --container stringArray The name of the container, such as mysql, prometheus.If it's empty, the first container will be injected. - --dry-run string[="unchanged"] Must be "client", or "server". If with client strategy, only print the object that would be sent, and no data is actually sent. If with server strategy, submit the server-side request, but no data is persistent. (default "none") - --duration string Supported formats of the duration are: ms / s / m / h. (default "10s") - --errno int The returned error number. - -h, --help help for errno - --label stringToString label for pod, such as '"app.kubernetes.io/component=mysql, statefulset.kubernetes.io/pod-name=mycluster-mysql-0. (default []) - --method stringArray The file system calls that need to inject faults. For example: WRITE READ - --mode string You can select "one", "all", "fixed", "fixed-percent", "random-max-percent", Specify the experimental mode, that is, which Pods to experiment with. (default "all") - --node stringArray Inject faults into pods in the specified node. - --node-label stringToString label for node, such as '"kubernetes.io/arch=arm64,kubernetes.io/hostname=minikube-m03,kubernetes.io/os=linux. (default []) - --ns-fault stringArray Specifies the namespace into which you want to inject faults. (default [default]) - -o, --output format Prints the output in the specified format. Allowed values: JSON and YAML (default yaml) - --path string The effective scope of the injection error can be a wildcard or a single file. - --percent int Probability of failure per operation, in %. (default 100) - --phase stringArray Specify the pod that injects the fault by the state of the pod. - --value string If you choose mode=fixed or fixed-percent or random-max-percent, you can enter a value to specify the number or percentage of pods you want to inject. - --volume-path string The mount point of the volume in the target container must be the root directory of the mount. -``` - -### Options inherited from parent commands - -``` - --as string Username to impersonate for the operation. User could be a regular user or a service account in a namespace. - --as-group stringArray Group to impersonate for the operation, this flag can be repeated to specify multiple groups. - --as-uid string UID to impersonate for the operation. - --cache-dir string Default cache directory (default "$HOME/.kube/cache") - --certificate-authority string Path to a cert file for the certificate authority - --client-certificate string Path to a client certificate file for TLS - --client-key string Path to a client key file for TLS - --cluster string The name of the kubeconfig cluster to use - --context string The name of the kubeconfig context to use - --disable-compression If true, opt-out of response compression for all requests to the server - --insecure-skip-tls-verify If true, the server's certificate will not be checked for validity. This will make your HTTPS connections insecure - --kubeconfig string Path to the kubeconfig file to use for CLI requests. - --match-server-version Require server version to match client version - -n, --namespace string If present, the namespace scope for this CLI request - --request-timeout string The length of time to wait before giving up on a single server request. Non-zero values should contain a corresponding time unit (e.g. 1s, 2m, 3h). A value of zero means don't timeout requests. (default "0") - -s, --server string The address and port of the Kubernetes API server - --tls-server-name string Server name to use for server certificate validation. If it is not provided, the hostname used to contact the server is used - --token string Bearer token for authentication to the API server - --user string The name of the kubeconfig user to use -``` - -### SEE ALSO - -* [kbcli fault io](kbcli_fault_io.md) - IO chaos. - -#### Go Back to [CLI Overview](cli.md) Homepage. - diff --git a/docs/user_docs/cli/kbcli_fault_io_latency.md b/docs/user_docs/cli/kbcli_fault_io_latency.md deleted file mode 100644 index 34dedaf53..000000000 --- a/docs/user_docs/cli/kbcli_fault_io_latency.md +++ /dev/null @@ -1,88 +0,0 @@ ---- -title: kbcli fault io latency ---- - -Delayed IO operations. - -``` -kbcli fault io latency [flags] -``` - -### Examples - -``` - # Affects the first container in default namespace's all pods. Delay all IO operations under the /data path by 10s. - kbcli fault io latency --delay=10s --volume-path=/data - - # Affects the first container in mycluster-mysql-0 pod. - kbcli fault io latency mycluster-mysql-0 --delay=10s --volume-path=/data - - # Affects the mysql container in mycluster-mysql-0 pod. - kbcli fault io latency mycluster-mysql-0 --delay=10s --volume-path=/data -c=mysql - - # There is a 50% probability of affecting the read IO operation of the test.txt file under the /data path. - kbcli fault io latency mycluster-mysql-0 --delay=10s --volume-path=/data --path=test.txt --percent=50 --method=READ -c=mysql - - # Same as above.Make all IO operations under the /data path return the specified error number 22 (Invalid argument). - kbcli fault io errno --volume-path=/data --errno=22 - - # Same as above.Modify the IO operation permission attribute of the files under the /data path to 72.(110 in octal). - kbcli fault io attribute --volume-path=/data --perm=72 - - # Modify all files so that random positions of 1's with a maximum length of 10 bytes will be replaced with 0's. - kbcli fault io mistake --volume-path=/data --filling=zero --max-occurrences=10 --max-length=1 -``` - -### Options - -``` - --annotation stringToString Select the pod to inject the fault according to Annotation. (default []) - -c, --container stringArray The name of the container, such as mysql, prometheus.If it's empty, the first container will be injected. - --delay string Specific delay time. - --dry-run string[="unchanged"] Must be "client", or "server". If with client strategy, only print the object that would be sent, and no data is actually sent. If with server strategy, submit the server-side request, but no data is persistent. (default "none") - --duration string Supported formats of the duration are: ms / s / m / h. (default "10s") - -h, --help help for latency - --label stringToString label for pod, such as '"app.kubernetes.io/component=mysql, statefulset.kubernetes.io/pod-name=mycluster-mysql-0. (default []) - --method stringArray The file system calls that need to inject faults. For example: WRITE READ - --mode string You can select "one", "all", "fixed", "fixed-percent", "random-max-percent", Specify the experimental mode, that is, which Pods to experiment with. (default "all") - --node stringArray Inject faults into pods in the specified node. - --node-label stringToString label for node, such as '"kubernetes.io/arch=arm64,kubernetes.io/hostname=minikube-m03,kubernetes.io/os=linux. (default []) - --ns-fault stringArray Specifies the namespace into which you want to inject faults. (default [default]) - -o, --output format Prints the output in the specified format. Allowed values: JSON and YAML (default yaml) - --path string The effective scope of the injection error can be a wildcard or a single file. - --percent int Probability of failure per operation, in %. (default 100) - --phase stringArray Specify the pod that injects the fault by the state of the pod. - --value string If you choose mode=fixed or fixed-percent or random-max-percent, you can enter a value to specify the number or percentage of pods you want to inject. - --volume-path string The mount point of the volume in the target container must be the root directory of the mount. -``` - -### Options inherited from parent commands - -``` - --as string Username to impersonate for the operation. User could be a regular user or a service account in a namespace. - --as-group stringArray Group to impersonate for the operation, this flag can be repeated to specify multiple groups. - --as-uid string UID to impersonate for the operation. - --cache-dir string Default cache directory (default "$HOME/.kube/cache") - --certificate-authority string Path to a cert file for the certificate authority - --client-certificate string Path to a client certificate file for TLS - --client-key string Path to a client key file for TLS - --cluster string The name of the kubeconfig cluster to use - --context string The name of the kubeconfig context to use - --disable-compression If true, opt-out of response compression for all requests to the server - --insecure-skip-tls-verify If true, the server's certificate will not be checked for validity. This will make your HTTPS connections insecure - --kubeconfig string Path to the kubeconfig file to use for CLI requests. - --match-server-version Require server version to match client version - -n, --namespace string If present, the namespace scope for this CLI request - --request-timeout string The length of time to wait before giving up on a single server request. Non-zero values should contain a corresponding time unit (e.g. 1s, 2m, 3h). A value of zero means don't timeout requests. (default "0") - -s, --server string The address and port of the Kubernetes API server - --tls-server-name string Server name to use for server certificate validation. If it is not provided, the hostname used to contact the server is used - --token string Bearer token for authentication to the API server - --user string The name of the kubeconfig user to use -``` - -### SEE ALSO - -* [kbcli fault io](kbcli_fault_io.md) - IO chaos. - -#### Go Back to [CLI Overview](cli.md) Homepage. - diff --git a/docs/user_docs/cli/kbcli_fault_io_mistake.md b/docs/user_docs/cli/kbcli_fault_io_mistake.md deleted file mode 100644 index 60d8bdee4..000000000 --- a/docs/user_docs/cli/kbcli_fault_io_mistake.md +++ /dev/null @@ -1,90 +0,0 @@ ---- -title: kbcli fault io mistake ---- - -Alters the contents of the file, distorting the contents of the file. - -``` -kbcli fault io mistake [flags] -``` - -### Examples - -``` - # Affects the first container in default namespace's all pods. Delay all IO operations under the /data path by 10s. - kbcli fault io latency --delay=10s --volume-path=/data - - # Affects the first container in mycluster-mysql-0 pod. - kbcli fault io latency mycluster-mysql-0 --delay=10s --volume-path=/data - - # Affects the mysql container in mycluster-mysql-0 pod. - kbcli fault io latency mycluster-mysql-0 --delay=10s --volume-path=/data -c=mysql - - # There is a 50% probability of affecting the read IO operation of the test.txt file under the /data path. - kbcli fault io latency mycluster-mysql-0 --delay=10s --volume-path=/data --path=test.txt --percent=50 --method=READ -c=mysql - - # Same as above.Make all IO operations under the /data path return the specified error number 22 (Invalid argument). - kbcli fault io errno --volume-path=/data --errno=22 - - # Same as above.Modify the IO operation permission attribute of the files under the /data path to 72.(110 in octal). - kbcli fault io attribute --volume-path=/data --perm=72 - - # Modify all files so that random positions of 1's with a maximum length of 10 bytes will be replaced with 0's. - kbcli fault io mistake --volume-path=/data --filling=zero --max-occurrences=10 --max-length=1 -``` - -### Options - -``` - --annotation stringToString Select the pod to inject the fault according to Annotation. (default []) - -c, --container stringArray The name of the container, such as mysql, prometheus.If it's empty, the first container will be injected. - --dry-run string[="unchanged"] Must be "client", or "server". If with client strategy, only print the object that would be sent, and no data is actually sent. If with server strategy, submit the server-side request, but no data is persistent. (default "none") - --duration string Supported formats of the duration are: ms / s / m / h. (default "10s") - --filling string The filling content of the error data can only be zero (filling with 0) or random (filling with random bytes). - -h, --help help for mistake - --label stringToString label for pod, such as '"app.kubernetes.io/component=mysql, statefulset.kubernetes.io/pod-name=mycluster-mysql-0. (default []) - --max-length int The maximum length (in bytes) of each error. (default 1) - --max-occurrences int The maximum number of times an error can occur per operation. (default 1) - --method stringArray The file system calls that need to inject faults. For example: WRITE READ - --mode string You can select "one", "all", "fixed", "fixed-percent", "random-max-percent", Specify the experimental mode, that is, which Pods to experiment with. (default "all") - --node stringArray Inject faults into pods in the specified node. - --node-label stringToString label for node, such as '"kubernetes.io/arch=arm64,kubernetes.io/hostname=minikube-m03,kubernetes.io/os=linux. (default []) - --ns-fault stringArray Specifies the namespace into which you want to inject faults. (default [default]) - -o, --output format Prints the output in the specified format. Allowed values: JSON and YAML (default yaml) - --path string The effective scope of the injection error can be a wildcard or a single file. - --percent int Probability of failure per operation, in %. (default 100) - --phase stringArray Specify the pod that injects the fault by the state of the pod. - --value string If you choose mode=fixed or fixed-percent or random-max-percent, you can enter a value to specify the number or percentage of pods you want to inject. - --volume-path string The mount point of the volume in the target container must be the root directory of the mount. -``` - -### Options inherited from parent commands - -``` - --as string Username to impersonate for the operation. User could be a regular user or a service account in a namespace. - --as-group stringArray Group to impersonate for the operation, this flag can be repeated to specify multiple groups. - --as-uid string UID to impersonate for the operation. - --cache-dir string Default cache directory (default "$HOME/.kube/cache") - --certificate-authority string Path to a cert file for the certificate authority - --client-certificate string Path to a client certificate file for TLS - --client-key string Path to a client key file for TLS - --cluster string The name of the kubeconfig cluster to use - --context string The name of the kubeconfig context to use - --disable-compression If true, opt-out of response compression for all requests to the server - --insecure-skip-tls-verify If true, the server's certificate will not be checked for validity. This will make your HTTPS connections insecure - --kubeconfig string Path to the kubeconfig file to use for CLI requests. - --match-server-version Require server version to match client version - -n, --namespace string If present, the namespace scope for this CLI request - --request-timeout string The length of time to wait before giving up on a single server request. Non-zero values should contain a corresponding time unit (e.g. 1s, 2m, 3h). A value of zero means don't timeout requests. (default "0") - -s, --server string The address and port of the Kubernetes API server - --tls-server-name string Server name to use for server certificate validation. If it is not provided, the hostname used to contact the server is used - --token string Bearer token for authentication to the API server - --user string The name of the kubeconfig user to use -``` - -### SEE ALSO - -* [kbcli fault io](kbcli_fault_io.md) - IO chaos. - -#### Go Back to [CLI Overview](cli.md) Homepage. - diff --git a/docs/user_docs/cli/kbcli_fault_network.md b/docs/user_docs/cli/kbcli_fault_network.md deleted file mode 100644 index 414204069..000000000 --- a/docs/user_docs/cli/kbcli_fault_network.md +++ /dev/null @@ -1,50 +0,0 @@ ---- -title: kbcli fault network ---- - -Network chaos. - -### Options - -``` - -h, --help help for network -``` - -### Options inherited from parent commands - -``` - --as string Username to impersonate for the operation. User could be a regular user or a service account in a namespace. - --as-group stringArray Group to impersonate for the operation, this flag can be repeated to specify multiple groups. - --as-uid string UID to impersonate for the operation. - --cache-dir string Default cache directory (default "$HOME/.kube/cache") - --certificate-authority string Path to a cert file for the certificate authority - --client-certificate string Path to a client certificate file for TLS - --client-key string Path to a client key file for TLS - --cluster string The name of the kubeconfig cluster to use - --context string The name of the kubeconfig context to use - --disable-compression If true, opt-out of response compression for all requests to the server - --insecure-skip-tls-verify If true, the server's certificate will not be checked for validity. This will make your HTTPS connections insecure - --kubeconfig string Path to the kubeconfig file to use for CLI requests. - --match-server-version Require server version to match client version - -n, --namespace string If present, the namespace scope for this CLI request - --request-timeout string The length of time to wait before giving up on a single server request. Non-zero values should contain a corresponding time unit (e.g. 1s, 2m, 3h). A value of zero means don't timeout requests. (default "0") - -s, --server string The address and port of the Kubernetes API server - --tls-server-name string Server name to use for server certificate validation. If it is not provided, the hostname used to contact the server is used - --token string Bearer token for authentication to the API server - --user string The name of the kubeconfig user to use -``` - -### SEE ALSO - -* [kbcli fault](kbcli_fault.md) - Inject faults to pod. -* [kbcli fault network bandwidth](kbcli_fault_network_bandwidth.md) - Limit the bandwidth that pods use to communicate with other objects. -* [kbcli fault network corrupt](kbcli_fault_network_corrupt.md) - Distorts the messages a pod communicates with other objects. -* [kbcli fault network delay](kbcli_fault_network_delay.md) - Make pods communicate with other objects lazily. -* [kbcli fault network dns](kbcli_fault_network_dns.md) - Inject faults into DNS server. -* [kbcli fault network duplicate](kbcli_fault_network_duplicate.md) - Make pods communicate with other objects to pick up duplicate packets. -* [kbcli fault network http](kbcli_fault_network_http.md) - Intercept HTTP requests and responses. -* [kbcli fault network loss](kbcli_fault_network_loss.md) - Cause pods to communicate with other objects to drop packets. -* [kbcli fault network partition](kbcli_fault_network_partition.md) - Make a pod network partitioned from other objects. - -#### Go Back to [CLI Overview](cli.md) Homepage. - diff --git a/docs/user_docs/cli/kbcli_fault_network_bandwidth.md b/docs/user_docs/cli/kbcli_fault_network_bandwidth.md deleted file mode 100644 index c36c3e6d3..000000000 --- a/docs/user_docs/cli/kbcli_fault_network_bandwidth.md +++ /dev/null @@ -1,107 +0,0 @@ ---- -title: kbcli fault network bandwidth ---- - -Limit the bandwidth that pods use to communicate with other objects. - -``` -kbcli fault network bandwidth [flags] -``` - -### Examples - -``` - # Isolate all pods network under the default namespace from the outside world, including the k8s internal network. - kbcli fault network partition - - # The specified pod is isolated from the k8s external network "kubeblocks.io". - kbcli fault network partition mycluster-mysql-1 --external-targets=kubeblocks.io - - # Isolate the network between two pods. - kbcli fault network partition mycluster-mysql-1 --target-label=statefulset.kubernetes.io/pod-name=mycluster-mysql-2 - - // Like the partition command, the target can be specified through --target-label or --external-targets. The pod only has obstacles in communicating with this target. If the target is not specified, all communication will be blocked. - # Block all pod communication under the default namespace, resulting in a 50% packet loss rate. - kbcli fault network loss --loss=50 - - # Block the specified pod communication, so that the packet loss rate is 50%. - kbcli fault network loss mysql-cluster-mysql-2 --loss=50 - - kbcli fault network corrupt --corrupt=50 - - # Blocks specified pod communication with a 50% packet corruption rate. - kbcli fault network corrupt mysql-cluster-mysql-2 --corrupt=50 - - kbcli fault network duplicate --duplicate=50 - - # Block specified pod communication so that the packet repetition rate is 50%. - kbcli fault network duplicate mysql-cluster-mysql-2 --duplicate=50 - - kbcli fault network delay --latency=10s - - # Block the communication of the specified pod, causing its network delay for 10s. - kbcli fault network delay mysql-cluster-mysql-2 --latency=10s - - # Limit the communication bandwidth between mysql-cluster-mysql-2 and the outside. - kbcli fault network bandwidth mysql-cluster-mysql-2 --rate=1kbps --duration=1m -``` - -### Options - -``` - --annotation stringToString Select the pod to inject the fault according to Annotation. (default []) - --buffer uint32 the maximum number of bytes that can be sent instantaneously. (default 1) - --direction string You can select "to"" or "from"" or "both"". (default "to") - --dry-run string[="unchanged"] Must be "client", or "server". If with client strategy, only print the object that would be sent, and no data is actually sent. If with server strategy, submit the server-side request, but no data is persistent. (default "none") - --duration string Supported formats of the duration are: ms / s / m / h. (default "10s") - -e, --external-target stringArray a network target outside of Kubernetes, which can be an IPv4 address or a domain name, - such as "www.baidu.com". Only works with direction: to. - -h, --help help for bandwidth - --label stringToString label for pod, such as '"app.kubernetes.io/component=mysql, statefulset.kubernetes.io/pod-name=mycluster-mysql-0. (default []) - --limit uint32 the number of bytes waiting in the queue. (default 1) - --minburst uint32 the size of the peakrate bucket. - --mode string You can select "one", "all", "fixed", "fixed-percent", "random-max-percent", Specify the experimental mode, that is, which Pods to experiment with. (default "all") - --node stringArray Inject faults into pods in the specified node. - --node-label stringToString label for node, such as '"kubernetes.io/arch=arm64,kubernetes.io/hostname=minikube-m03,kubernetes.io/os=linux. (default []) - --ns-fault stringArray Specifies the namespace into which you want to inject faults. (default [default]) - -o, --output format Prints the output in the specified format. Allowed values: JSON and YAML (default yaml) - --peakrate uint the maximum consumption rate of the bucket. - --phase stringArray Specify the pod that injects the fault by the state of the pod. - --rate string the rate at which the bandwidth is limited. For example : 10 bps/kbps/mbps/gbps. - --target-label stringToString label for pod, such as '"app.kubernetes.io/component=mysql, statefulset.kubernetes.io/pod-name=mycluster-mysql-0"' (default []) - --target-mode string You can select "one", "all", "fixed", "fixed-percent", "random-max-percent", Specify the experimental mode, that is, which Pods to experiment with. - --target-ns-fault stringArray Specifies the namespace into which you want to inject faults. - --target-value string If you choose mode=fixed or fixed-percent or random-max-percent, you can enter a value to specify the number or percentage of pods you want to inject. - --value string If you choose mode=fixed or fixed-percent or random-max-percent, you can enter a value to specify the number or percentage of pods you want to inject. -``` - -### Options inherited from parent commands - -``` - --as string Username to impersonate for the operation. User could be a regular user or a service account in a namespace. - --as-group stringArray Group to impersonate for the operation, this flag can be repeated to specify multiple groups. - --as-uid string UID to impersonate for the operation. - --cache-dir string Default cache directory (default "$HOME/.kube/cache") - --certificate-authority string Path to a cert file for the certificate authority - --client-certificate string Path to a client certificate file for TLS - --client-key string Path to a client key file for TLS - --cluster string The name of the kubeconfig cluster to use - --context string The name of the kubeconfig context to use - --disable-compression If true, opt-out of response compression for all requests to the server - --insecure-skip-tls-verify If true, the server's certificate will not be checked for validity. This will make your HTTPS connections insecure - --kubeconfig string Path to the kubeconfig file to use for CLI requests. - --match-server-version Require server version to match client version - -n, --namespace string If present, the namespace scope for this CLI request - --request-timeout string The length of time to wait before giving up on a single server request. Non-zero values should contain a corresponding time unit (e.g. 1s, 2m, 3h). A value of zero means don't timeout requests. (default "0") - -s, --server string The address and port of the Kubernetes API server - --tls-server-name string Server name to use for server certificate validation. If it is not provided, the hostname used to contact the server is used - --token string Bearer token for authentication to the API server - --user string The name of the kubeconfig user to use -``` - -### SEE ALSO - -* [kbcli fault network](kbcli_fault_network.md) - Network chaos. - -#### Go Back to [CLI Overview](cli.md) Homepage. - diff --git a/docs/user_docs/cli/kbcli_fault_network_corrupt.md b/docs/user_docs/cli/kbcli_fault_network_corrupt.md deleted file mode 100644 index 2f8ad7bbb..000000000 --- a/docs/user_docs/cli/kbcli_fault_network_corrupt.md +++ /dev/null @@ -1,104 +0,0 @@ ---- -title: kbcli fault network corrupt ---- - -Distorts the messages a pod communicates with other objects. - -``` -kbcli fault network corrupt [flags] -``` - -### Examples - -``` - # Isolate all pods network under the default namespace from the outside world, including the k8s internal network. - kbcli fault network partition - - # The specified pod is isolated from the k8s external network "kubeblocks.io". - kbcli fault network partition mycluster-mysql-1 --external-targets=kubeblocks.io - - # Isolate the network between two pods. - kbcli fault network partition mycluster-mysql-1 --target-label=statefulset.kubernetes.io/pod-name=mycluster-mysql-2 - - // Like the partition command, the target can be specified through --target-label or --external-targets. The pod only has obstacles in communicating with this target. If the target is not specified, all communication will be blocked. - # Block all pod communication under the default namespace, resulting in a 50% packet loss rate. - kbcli fault network loss --loss=50 - - # Block the specified pod communication, so that the packet loss rate is 50%. - kbcli fault network loss mysql-cluster-mysql-2 --loss=50 - - kbcli fault network corrupt --corrupt=50 - - # Blocks specified pod communication with a 50% packet corruption rate. - kbcli fault network corrupt mysql-cluster-mysql-2 --corrupt=50 - - kbcli fault network duplicate --duplicate=50 - - # Block specified pod communication so that the packet repetition rate is 50%. - kbcli fault network duplicate mysql-cluster-mysql-2 --duplicate=50 - - kbcli fault network delay --latency=10s - - # Block the communication of the specified pod, causing its network delay for 10s. - kbcli fault network delay mysql-cluster-mysql-2 --latency=10s - - # Limit the communication bandwidth between mysql-cluster-mysql-2 and the outside. - kbcli fault network bandwidth mysql-cluster-mysql-2 --rate=1kbps --duration=1m -``` - -### Options - -``` - --annotation stringToString Select the pod to inject the fault according to Annotation. (default []) - -c, --correlation string Indicates the correlation between the probability of a packet error occurring and whether it occurred the previous time. Value range: [0, 100]. - --corrupt string Indicates the probability of a packet error occurring. Value range: [0, 100]. - --direction string You can select "to"" or "from"" or "both"". (default "to") - --dry-run string[="unchanged"] Must be "client", or "server". If with client strategy, only print the object that would be sent, and no data is actually sent. If with server strategy, submit the server-side request, but no data is persistent. (default "none") - --duration string Supported formats of the duration are: ms / s / m / h. (default "10s") - -e, --external-target stringArray a network target outside of Kubernetes, which can be an IPv4 address or a domain name, - such as "www.baidu.com". Only works with direction: to. - -h, --help help for corrupt - --label stringToString label for pod, such as '"app.kubernetes.io/component=mysql, statefulset.kubernetes.io/pod-name=mycluster-mysql-0. (default []) - --mode string You can select "one", "all", "fixed", "fixed-percent", "random-max-percent", Specify the experimental mode, that is, which Pods to experiment with. (default "all") - --node stringArray Inject faults into pods in the specified node. - --node-label stringToString label for node, such as '"kubernetes.io/arch=arm64,kubernetes.io/hostname=minikube-m03,kubernetes.io/os=linux. (default []) - --ns-fault stringArray Specifies the namespace into which you want to inject faults. (default [default]) - -o, --output format Prints the output in the specified format. Allowed values: JSON and YAML (default yaml) - --phase stringArray Specify the pod that injects the fault by the state of the pod. - --target-label stringToString label for pod, such as '"app.kubernetes.io/component=mysql, statefulset.kubernetes.io/pod-name=mycluster-mysql-0"' (default []) - --target-mode string You can select "one", "all", "fixed", "fixed-percent", "random-max-percent", Specify the experimental mode, that is, which Pods to experiment with. - --target-ns-fault stringArray Specifies the namespace into which you want to inject faults. - --target-value string If you choose mode=fixed or fixed-percent or random-max-percent, you can enter a value to specify the number or percentage of pods you want to inject. - --value string If you choose mode=fixed or fixed-percent or random-max-percent, you can enter a value to specify the number or percentage of pods you want to inject. -``` - -### Options inherited from parent commands - -``` - --as string Username to impersonate for the operation. User could be a regular user or a service account in a namespace. - --as-group stringArray Group to impersonate for the operation, this flag can be repeated to specify multiple groups. - --as-uid string UID to impersonate for the operation. - --cache-dir string Default cache directory (default "$HOME/.kube/cache") - --certificate-authority string Path to a cert file for the certificate authority - --client-certificate string Path to a client certificate file for TLS - --client-key string Path to a client key file for TLS - --cluster string The name of the kubeconfig cluster to use - --context string The name of the kubeconfig context to use - --disable-compression If true, opt-out of response compression for all requests to the server - --insecure-skip-tls-verify If true, the server's certificate will not be checked for validity. This will make your HTTPS connections insecure - --kubeconfig string Path to the kubeconfig file to use for CLI requests. - --match-server-version Require server version to match client version - -n, --namespace string If present, the namespace scope for this CLI request - --request-timeout string The length of time to wait before giving up on a single server request. Non-zero values should contain a corresponding time unit (e.g. 1s, 2m, 3h). A value of zero means don't timeout requests. (default "0") - -s, --server string The address and port of the Kubernetes API server - --tls-server-name string Server name to use for server certificate validation. If it is not provided, the hostname used to contact the server is used - --token string Bearer token for authentication to the API server - --user string The name of the kubeconfig user to use -``` - -### SEE ALSO - -* [kbcli fault network](kbcli_fault_network.md) - Network chaos. - -#### Go Back to [CLI Overview](cli.md) Homepage. - diff --git a/docs/user_docs/cli/kbcli_fault_network_delay.md b/docs/user_docs/cli/kbcli_fault_network_delay.md deleted file mode 100644 index fcaba1dcb..000000000 --- a/docs/user_docs/cli/kbcli_fault_network_delay.md +++ /dev/null @@ -1,105 +0,0 @@ ---- -title: kbcli fault network delay ---- - -Make pods communicate with other objects lazily. - -``` -kbcli fault network delay [flags] -``` - -### Examples - -``` - # Isolate all pods network under the default namespace from the outside world, including the k8s internal network. - kbcli fault network partition - - # The specified pod is isolated from the k8s external network "kubeblocks.io". - kbcli fault network partition mycluster-mysql-1 --external-targets=kubeblocks.io - - # Isolate the network between two pods. - kbcli fault network partition mycluster-mysql-1 --target-label=statefulset.kubernetes.io/pod-name=mycluster-mysql-2 - - // Like the partition command, the target can be specified through --target-label or --external-targets. The pod only has obstacles in communicating with this target. If the target is not specified, all communication will be blocked. - # Block all pod communication under the default namespace, resulting in a 50% packet loss rate. - kbcli fault network loss --loss=50 - - # Block the specified pod communication, so that the packet loss rate is 50%. - kbcli fault network loss mysql-cluster-mysql-2 --loss=50 - - kbcli fault network corrupt --corrupt=50 - - # Blocks specified pod communication with a 50% packet corruption rate. - kbcli fault network corrupt mysql-cluster-mysql-2 --corrupt=50 - - kbcli fault network duplicate --duplicate=50 - - # Block specified pod communication so that the packet repetition rate is 50%. - kbcli fault network duplicate mysql-cluster-mysql-2 --duplicate=50 - - kbcli fault network delay --latency=10s - - # Block the communication of the specified pod, causing its network delay for 10s. - kbcli fault network delay mysql-cluster-mysql-2 --latency=10s - - # Limit the communication bandwidth between mysql-cluster-mysql-2 and the outside. - kbcli fault network bandwidth mysql-cluster-mysql-2 --rate=1kbps --duration=1m -``` - -### Options - -``` - --annotation stringToString Select the pod to inject the fault according to Annotation. (default []) - -c, --correlation string Indicates the probability of a packet error occurring. Value range: [0, 100]. - --direction string You can select "to"" or "from"" or "both"". (default "to") - --dry-run string[="unchanged"] Must be "client", or "server". If with client strategy, only print the object that would be sent, and no data is actually sent. If with server strategy, submit the server-side request, but no data is persistent. (default "none") - --duration string Supported formats of the duration are: ms / s / m / h. (default "10s") - -e, --external-target stringArray a network target outside of Kubernetes, which can be an IPv4 address or a domain name, - such as "www.baidu.com". Only works with direction: to. - -h, --help help for delay - --jitter string the variation range of the delay time. - --label stringToString label for pod, such as '"app.kubernetes.io/component=mysql, statefulset.kubernetes.io/pod-name=mycluster-mysql-0. (default []) - --latency string the length of time to delay. - --mode string You can select "one", "all", "fixed", "fixed-percent", "random-max-percent", Specify the experimental mode, that is, which Pods to experiment with. (default "all") - --node stringArray Inject faults into pods in the specified node. - --node-label stringToString label for node, such as '"kubernetes.io/arch=arm64,kubernetes.io/hostname=minikube-m03,kubernetes.io/os=linux. (default []) - --ns-fault stringArray Specifies the namespace into which you want to inject faults. (default [default]) - -o, --output format Prints the output in the specified format. Allowed values: JSON and YAML (default yaml) - --phase stringArray Specify the pod that injects the fault by the state of the pod. - --target-label stringToString label for pod, such as '"app.kubernetes.io/component=mysql, statefulset.kubernetes.io/pod-name=mycluster-mysql-0"' (default []) - --target-mode string You can select "one", "all", "fixed", "fixed-percent", "random-max-percent", Specify the experimental mode, that is, which Pods to experiment with. - --target-ns-fault stringArray Specifies the namespace into which you want to inject faults. - --target-value string If you choose mode=fixed or fixed-percent or random-max-percent, you can enter a value to specify the number or percentage of pods you want to inject. - --value string If you choose mode=fixed or fixed-percent or random-max-percent, you can enter a value to specify the number or percentage of pods you want to inject. -``` - -### Options inherited from parent commands - -``` - --as string Username to impersonate for the operation. User could be a regular user or a service account in a namespace. - --as-group stringArray Group to impersonate for the operation, this flag can be repeated to specify multiple groups. - --as-uid string UID to impersonate for the operation. - --cache-dir string Default cache directory (default "$HOME/.kube/cache") - --certificate-authority string Path to a cert file for the certificate authority - --client-certificate string Path to a client certificate file for TLS - --client-key string Path to a client key file for TLS - --cluster string The name of the kubeconfig cluster to use - --context string The name of the kubeconfig context to use - --disable-compression If true, opt-out of response compression for all requests to the server - --insecure-skip-tls-verify If true, the server's certificate will not be checked for validity. This will make your HTTPS connections insecure - --kubeconfig string Path to the kubeconfig file to use for CLI requests. - --match-server-version Require server version to match client version - -n, --namespace string If present, the namespace scope for this CLI request - --request-timeout string The length of time to wait before giving up on a single server request. Non-zero values should contain a corresponding time unit (e.g. 1s, 2m, 3h). A value of zero means don't timeout requests. (default "0") - -s, --server string The address and port of the Kubernetes API server - --tls-server-name string Server name to use for server certificate validation. If it is not provided, the hostname used to contact the server is used - --token string Bearer token for authentication to the API server - --user string The name of the kubeconfig user to use -``` - -### SEE ALSO - -* [kbcli fault network](kbcli_fault_network.md) - Network chaos. - -#### Go Back to [CLI Overview](cli.md) Homepage. - diff --git a/docs/user_docs/cli/kbcli_fault_network_dns.md b/docs/user_docs/cli/kbcli_fault_network_dns.md deleted file mode 100644 index e049edbbf..000000000 --- a/docs/user_docs/cli/kbcli_fault_network_dns.md +++ /dev/null @@ -1,44 +0,0 @@ ---- -title: kbcli fault network dns ---- - -Inject faults into DNS server. - -### Options - -``` - -h, --help help for dns -``` - -### Options inherited from parent commands - -``` - --as string Username to impersonate for the operation. User could be a regular user or a service account in a namespace. - --as-group stringArray Group to impersonate for the operation, this flag can be repeated to specify multiple groups. - --as-uid string UID to impersonate for the operation. - --cache-dir string Default cache directory (default "$HOME/.kube/cache") - --certificate-authority string Path to a cert file for the certificate authority - --client-certificate string Path to a client certificate file for TLS - --client-key string Path to a client key file for TLS - --cluster string The name of the kubeconfig cluster to use - --context string The name of the kubeconfig context to use - --disable-compression If true, opt-out of response compression for all requests to the server - --insecure-skip-tls-verify If true, the server's certificate will not be checked for validity. This will make your HTTPS connections insecure - --kubeconfig string Path to the kubeconfig file to use for CLI requests. - --match-server-version Require server version to match client version - -n, --namespace string If present, the namespace scope for this CLI request - --request-timeout string The length of time to wait before giving up on a single server request. Non-zero values should contain a corresponding time unit (e.g. 1s, 2m, 3h). A value of zero means don't timeout requests. (default "0") - -s, --server string The address and port of the Kubernetes API server - --tls-server-name string Server name to use for server certificate validation. If it is not provided, the hostname used to contact the server is used - --token string Bearer token for authentication to the API server - --user string The name of the kubeconfig user to use -``` - -### SEE ALSO - -* [kbcli fault network](kbcli_fault_network.md) - Network chaos. -* [kbcli fault network dns error](kbcli_fault_network_dns_error.md) - Make DNS return an error when resolving external domain names. -* [kbcli fault network dns random](kbcli_fault_network_dns_random.md) - Make DNS return any IP when resolving external domain names. - -#### Go Back to [CLI Overview](cli.md) Homepage. - diff --git a/docs/user_docs/cli/kbcli_fault_network_dns_random.md b/docs/user_docs/cli/kbcli_fault_network_dns_random.md deleted file mode 100644 index 5a53ed5c7..000000000 --- a/docs/user_docs/cli/kbcli_fault_network_dns_random.md +++ /dev/null @@ -1,68 +0,0 @@ ---- -title: kbcli fault network dns random ---- - -Make DNS return any IP when resolving external domain names. - -``` -kbcli fault network dns random [flags] -``` - -### Examples - -``` - // Inject DNS faults into all pods under the default namespace, so that any IP is returned when accessing the bing.com domain name. - kbcli fault dns random --patterns=bing.com --duration=1m - - // Inject DNS faults into all pods under the default namespace, so that error is returned when accessing the bing.com domain name. - kbcli fault dns error --patterns=bing.com --duration=1m -``` - -### Options - -``` - --annotation stringToString Select the pod to inject the fault according to Annotation. (default []) - --dry-run string[="unchanged"] Must be "client", or "server". If with client strategy, only print the object that would be sent, and no data is actually sent. If with server strategy, submit the server-side request, but no data is persistent. (default "none") - --duration string Supported formats of the duration are: ms / s / m / h. (default "10s") - -h, --help help for random - --label stringToString label for pod, such as '"app.kubernetes.io/component=mysql, statefulset.kubernetes.io/pod-name=mycluster-mysql-0. (default []) - --mode string You can select "one", "all", "fixed", "fixed-percent", "random-max-percent", Specify the experimental mode, that is, which Pods to experiment with. (default "all") - --node stringArray Inject faults into pods in the specified node. - --node-label stringToString label for node, such as '"kubernetes.io/arch=arm64,kubernetes.io/hostname=minikube-m03,kubernetes.io/os=linux. (default []) - --ns-fault stringArray Specifies the namespace into which you want to inject faults. (default [default]) - -o, --output format Prints the output in the specified format. Allowed values: JSON and YAML (default yaml) - --patterns stringArray Select the domain name template that matching the failure behavior & supporting placeholders ? and wildcards *. - --phase stringArray Specify the pod that injects the fault by the state of the pod. - --value string If you choose mode=fixed or fixed-percent or random-max-percent, you can enter a value to specify the number or percentage of pods you want to inject. -``` - -### Options inherited from parent commands - -``` - --as string Username to impersonate for the operation. User could be a regular user or a service account in a namespace. - --as-group stringArray Group to impersonate for the operation, this flag can be repeated to specify multiple groups. - --as-uid string UID to impersonate for the operation. - --cache-dir string Default cache directory (default "$HOME/.kube/cache") - --certificate-authority string Path to a cert file for the certificate authority - --client-certificate string Path to a client certificate file for TLS - --client-key string Path to a client key file for TLS - --cluster string The name of the kubeconfig cluster to use - --context string The name of the kubeconfig context to use - --disable-compression If true, opt-out of response compression for all requests to the server - --insecure-skip-tls-verify If true, the server's certificate will not be checked for validity. This will make your HTTPS connections insecure - --kubeconfig string Path to the kubeconfig file to use for CLI requests. - --match-server-version Require server version to match client version - -n, --namespace string If present, the namespace scope for this CLI request - --request-timeout string The length of time to wait before giving up on a single server request. Non-zero values should contain a corresponding time unit (e.g. 1s, 2m, 3h). A value of zero means don't timeout requests. (default "0") - -s, --server string The address and port of the Kubernetes API server - --tls-server-name string Server name to use for server certificate validation. If it is not provided, the hostname used to contact the server is used - --token string Bearer token for authentication to the API server - --user string The name of the kubeconfig user to use -``` - -### SEE ALSO - -* [kbcli fault network dns](kbcli_fault_network_dns.md) - Inject faults into DNS server. - -#### Go Back to [CLI Overview](cli.md) Homepage. - diff --git a/docs/user_docs/cli/kbcli_fault_network_duplicate.md b/docs/user_docs/cli/kbcli_fault_network_duplicate.md deleted file mode 100644 index 15196d2e1..000000000 --- a/docs/user_docs/cli/kbcli_fault_network_duplicate.md +++ /dev/null @@ -1,104 +0,0 @@ ---- -title: kbcli fault network duplicate ---- - -Make pods communicate with other objects to pick up duplicate packets. - -``` -kbcli fault network duplicate [flags] -``` - -### Examples - -``` - # Isolate all pods network under the default namespace from the outside world, including the k8s internal network. - kbcli fault network partition - - # The specified pod is isolated from the k8s external network "kubeblocks.io". - kbcli fault network partition mycluster-mysql-1 --external-targets=kubeblocks.io - - # Isolate the network between two pods. - kbcli fault network partition mycluster-mysql-1 --target-label=statefulset.kubernetes.io/pod-name=mycluster-mysql-2 - - // Like the partition command, the target can be specified through --target-label or --external-targets. The pod only has obstacles in communicating with this target. If the target is not specified, all communication will be blocked. - # Block all pod communication under the default namespace, resulting in a 50% packet loss rate. - kbcli fault network loss --loss=50 - - # Block the specified pod communication, so that the packet loss rate is 50%. - kbcli fault network loss mysql-cluster-mysql-2 --loss=50 - - kbcli fault network corrupt --corrupt=50 - - # Blocks specified pod communication with a 50% packet corruption rate. - kbcli fault network corrupt mysql-cluster-mysql-2 --corrupt=50 - - kbcli fault network duplicate --duplicate=50 - - # Block specified pod communication so that the packet repetition rate is 50%. - kbcli fault network duplicate mysql-cluster-mysql-2 --duplicate=50 - - kbcli fault network delay --latency=10s - - # Block the communication of the specified pod, causing its network delay for 10s. - kbcli fault network delay mysql-cluster-mysql-2 --latency=10s - - # Limit the communication bandwidth between mysql-cluster-mysql-2 and the outside. - kbcli fault network bandwidth mysql-cluster-mysql-2 --rate=1kbps --duration=1m -``` - -### Options - -``` - --annotation stringToString Select the pod to inject the fault according to Annotation. (default []) - -c, --correlation string Indicates the correlation between the probability of a packet error occurring and whether it occurred the previous time. Value range: [0, 100]. - --direction string You can select "to"" or "from"" or "both"". (default "to") - --dry-run string[="unchanged"] Must be "client", or "server". If with client strategy, only print the object that would be sent, and no data is actually sent. If with server strategy, submit the server-side request, but no data is persistent. (default "none") - --duplicate string the probability of a packet being repeated. Value range: [0, 100]. - --duration string Supported formats of the duration are: ms / s / m / h. (default "10s") - -e, --external-target stringArray a network target outside of Kubernetes, which can be an IPv4 address or a domain name, - such as "www.baidu.com". Only works with direction: to. - -h, --help help for duplicate - --label stringToString label for pod, such as '"app.kubernetes.io/component=mysql, statefulset.kubernetes.io/pod-name=mycluster-mysql-0. (default []) - --mode string You can select "one", "all", "fixed", "fixed-percent", "random-max-percent", Specify the experimental mode, that is, which Pods to experiment with. (default "all") - --node stringArray Inject faults into pods in the specified node. - --node-label stringToString label for node, such as '"kubernetes.io/arch=arm64,kubernetes.io/hostname=minikube-m03,kubernetes.io/os=linux. (default []) - --ns-fault stringArray Specifies the namespace into which you want to inject faults. (default [default]) - -o, --output format Prints the output in the specified format. Allowed values: JSON and YAML (default yaml) - --phase stringArray Specify the pod that injects the fault by the state of the pod. - --target-label stringToString label for pod, such as '"app.kubernetes.io/component=mysql, statefulset.kubernetes.io/pod-name=mycluster-mysql-0"' (default []) - --target-mode string You can select "one", "all", "fixed", "fixed-percent", "random-max-percent", Specify the experimental mode, that is, which Pods to experiment with. - --target-ns-fault stringArray Specifies the namespace into which you want to inject faults. - --target-value string If you choose mode=fixed or fixed-percent or random-max-percent, you can enter a value to specify the number or percentage of pods you want to inject. - --value string If you choose mode=fixed or fixed-percent or random-max-percent, you can enter a value to specify the number or percentage of pods you want to inject. -``` - -### Options inherited from parent commands - -``` - --as string Username to impersonate for the operation. User could be a regular user or a service account in a namespace. - --as-group stringArray Group to impersonate for the operation, this flag can be repeated to specify multiple groups. - --as-uid string UID to impersonate for the operation. - --cache-dir string Default cache directory (default "$HOME/.kube/cache") - --certificate-authority string Path to a cert file for the certificate authority - --client-certificate string Path to a client certificate file for TLS - --client-key string Path to a client key file for TLS - --cluster string The name of the kubeconfig cluster to use - --context string The name of the kubeconfig context to use - --disable-compression If true, opt-out of response compression for all requests to the server - --insecure-skip-tls-verify If true, the server's certificate will not be checked for validity. This will make your HTTPS connections insecure - --kubeconfig string Path to the kubeconfig file to use for CLI requests. - --match-server-version Require server version to match client version - -n, --namespace string If present, the namespace scope for this CLI request - --request-timeout string The length of time to wait before giving up on a single server request. Non-zero values should contain a corresponding time unit (e.g. 1s, 2m, 3h). A value of zero means don't timeout requests. (default "0") - -s, --server string The address and port of the Kubernetes API server - --tls-server-name string Server name to use for server certificate validation. If it is not provided, the hostname used to contact the server is used - --token string Bearer token for authentication to the API server - --user string The name of the kubeconfig user to use -``` - -### SEE ALSO - -* [kbcli fault network](kbcli_fault_network.md) - Network chaos. - -#### Go Back to [CLI Overview](cli.md) Homepage. - diff --git a/docs/user_docs/cli/kbcli_fault_network_http.md b/docs/user_docs/cli/kbcli_fault_network_http.md deleted file mode 100644 index 294cf3082..000000000 --- a/docs/user_docs/cli/kbcli_fault_network_http.md +++ /dev/null @@ -1,46 +0,0 @@ ---- -title: kbcli fault network http ---- - -Intercept HTTP requests and responses. - -### Options - -``` - -h, --help help for http -``` - -### Options inherited from parent commands - -``` - --as string Username to impersonate for the operation. User could be a regular user or a service account in a namespace. - --as-group stringArray Group to impersonate for the operation, this flag can be repeated to specify multiple groups. - --as-uid string UID to impersonate for the operation. - --cache-dir string Default cache directory (default "$HOME/.kube/cache") - --certificate-authority string Path to a cert file for the certificate authority - --client-certificate string Path to a client certificate file for TLS - --client-key string Path to a client key file for TLS - --cluster string The name of the kubeconfig cluster to use - --context string The name of the kubeconfig context to use - --disable-compression If true, opt-out of response compression for all requests to the server - --insecure-skip-tls-verify If true, the server's certificate will not be checked for validity. This will make your HTTPS connections insecure - --kubeconfig string Path to the kubeconfig file to use for CLI requests. - --match-server-version Require server version to match client version - -n, --namespace string If present, the namespace scope for this CLI request - --request-timeout string The length of time to wait before giving up on a single server request. Non-zero values should contain a corresponding time unit (e.g. 1s, 2m, 3h). A value of zero means don't timeout requests. (default "0") - -s, --server string The address and port of the Kubernetes API server - --tls-server-name string Server name to use for server certificate validation. If it is not provided, the hostname used to contact the server is used - --token string Bearer token for authentication to the API server - --user string The name of the kubeconfig user to use -``` - -### SEE ALSO - -* [kbcli fault network](kbcli_fault_network.md) - Network chaos. -* [kbcli fault network http abort](kbcli_fault_network_http_abort.md) - Abort the HTTP request and response. -* [kbcli fault network http delay](kbcli_fault_network_http_delay.md) - Delay the HTTP request and response. -* [kbcli fault network http patch](kbcli_fault_network_http_patch.md) - Patch the HTTP request and response. -* [kbcli fault network http replace](kbcli_fault_network_http_replace.md) - Replace the HTTP request and response. - -#### Go Back to [CLI Overview](cli.md) Homepage. - diff --git a/docs/user_docs/cli/kbcli_fault_network_http_abort.md b/docs/user_docs/cli/kbcli_fault_network_http_abort.md deleted file mode 100644 index 0be4dc89b..000000000 --- a/docs/user_docs/cli/kbcli_fault_network_http_abort.md +++ /dev/null @@ -1,91 +0,0 @@ ---- -title: kbcli fault network http abort ---- - -Abort the HTTP request and response. - -``` -kbcli fault network http abort [flags] -``` - -### Examples - -``` - # By default, the method of GET from port 80 is blocked. - kbcli fault network http abort --duration=1m - - # Block the method of GET from port 4399. - kbcli fault network http abort --port=4399 --duration=1m - - # Block the method of POST from port 4399. - kbcli fault network http abort --port=4399 --method=POST --duration=1m - - # Delays post requests from port 4399. - kbcli fault network http delay --port=4399 --method=POST --delay=15s - - # Replace the GET method sent from port 80 with the PUT method. - kbcli fault network http replace --replace-method=PUT --duration=1m - - # Replace the GET method sent from port 80 with the PUT method, and replace the request body. - kbcli fault network http replace --body="you are good luck" --replace-method=PUT --duration=2m - - # Replace the response content "you" from port 80. - kbcli fault network http replace --target=Response --body=you --duration=30s - - # Append content to the body of the post request sent from port 4399, in JSON format. - kbcli fault network http patch --method=POST --port=4399 --body="you are good luck" --type=JSON --duration=30s -``` - -### Options - -``` - --abort Indicates whether to inject the fault that interrupts the connection. (default true) - --annotation stringToString Select the pod to inject the fault according to Annotation. (default []) - --code int32 The status code responded by target. - --dry-run string[="unchanged"] Must be "client", or "server". If with client strategy, only print the object that would be sent, and no data is actually sent. If with server strategy, submit the server-side request, but no data is persistent. (default "none") - --duration string Supported formats of the duration are: ms / s / m / h. (default "10s") - -h, --help help for abort - --label stringToString label for pod, such as '"app.kubernetes.io/component=mysql, statefulset.kubernetes.io/pod-name=mycluster-mysql-0. (default []) - --method string The HTTP method of the target request method. For example: GET, POST, PUT, DELETE, HEAD, OPTIONS, PATCH. (default "GET") - --mode string You can select "one", "all", "fixed", "fixed-percent", "random-max-percent", Specify the experimental mode, that is, which Pods to experiment with. (default "all") - --node stringArray Inject faults into pods in the specified node. - --node-label stringToString label for node, such as '"kubernetes.io/arch=arm64,kubernetes.io/hostname=minikube-m03,kubernetes.io/os=linux. (default []) - --ns-fault stringArray Specifies the namespace into which you want to inject faults. (default [default]) - -o, --output format Prints the output in the specified format. Allowed values: JSON and YAML (default yaml) - --path string The URI path of the target request. Supports Matching wildcards. (default "*") - --phase stringArray Specify the pod that injects the fault by the state of the pod. - --port int32 The TCP port that the target service listens on. (default 80) - --target string Specifies whether the target of fault injection is Request or Response. The target-related fields should be configured at the same time. (default "Request") - --value string If you choose mode=fixed or fixed-percent or random-max-percent, you can enter a value to specify the number or percentage of pods you want to inject. -``` - -### Options inherited from parent commands - -``` - --as string Username to impersonate for the operation. User could be a regular user or a service account in a namespace. - --as-group stringArray Group to impersonate for the operation, this flag can be repeated to specify multiple groups. - --as-uid string UID to impersonate for the operation. - --cache-dir string Default cache directory (default "$HOME/.kube/cache") - --certificate-authority string Path to a cert file for the certificate authority - --client-certificate string Path to a client certificate file for TLS - --client-key string Path to a client key file for TLS - --cluster string The name of the kubeconfig cluster to use - --context string The name of the kubeconfig context to use - --disable-compression If true, opt-out of response compression for all requests to the server - --insecure-skip-tls-verify If true, the server's certificate will not be checked for validity. This will make your HTTPS connections insecure - --kubeconfig string Path to the kubeconfig file to use for CLI requests. - --match-server-version Require server version to match client version - -n, --namespace string If present, the namespace scope for this CLI request - --request-timeout string The length of time to wait before giving up on a single server request. Non-zero values should contain a corresponding time unit (e.g. 1s, 2m, 3h). A value of zero means don't timeout requests. (default "0") - -s, --server string The address and port of the Kubernetes API server - --tls-server-name string Server name to use for server certificate validation. If it is not provided, the hostname used to contact the server is used - --token string Bearer token for authentication to the API server - --user string The name of the kubeconfig user to use -``` - -### SEE ALSO - -* [kbcli fault network http](kbcli_fault_network_http.md) - Intercept HTTP requests and responses. - -#### Go Back to [CLI Overview](cli.md) Homepage. - diff --git a/docs/user_docs/cli/kbcli_fault_network_http_delay.md b/docs/user_docs/cli/kbcli_fault_network_http_delay.md deleted file mode 100644 index 04ec969fb..000000000 --- a/docs/user_docs/cli/kbcli_fault_network_http_delay.md +++ /dev/null @@ -1,91 +0,0 @@ ---- -title: kbcli fault network http delay ---- - -Delay the HTTP request and response. - -``` -kbcli fault network http delay [flags] -``` - -### Examples - -``` - # By default, the method of GET from port 80 is blocked. - kbcli fault network http abort --duration=1m - - # Block the method of GET from port 4399. - kbcli fault network http abort --port=4399 --duration=1m - - # Block the method of POST from port 4399. - kbcli fault network http abort --port=4399 --method=POST --duration=1m - - # Delays post requests from port 4399. - kbcli fault network http delay --port=4399 --method=POST --delay=15s - - # Replace the GET method sent from port 80 with the PUT method. - kbcli fault network http replace --replace-method=PUT --duration=1m - - # Replace the GET method sent from port 80 with the PUT method, and replace the request body. - kbcli fault network http replace --body="you are good luck" --replace-method=PUT --duration=2m - - # Replace the response content "you" from port 80. - kbcli fault network http replace --target=Response --body=you --duration=30s - - # Append content to the body of the post request sent from port 4399, in JSON format. - kbcli fault network http patch --method=POST --port=4399 --body="you are good luck" --type=JSON --duration=30s -``` - -### Options - -``` - --annotation stringToString Select the pod to inject the fault according to Annotation. (default []) - --code int32 The status code responded by target. - --delay string The time for delay. (default "10s") - --dry-run string[="unchanged"] Must be "client", or "server". If with client strategy, only print the object that would be sent, and no data is actually sent. If with server strategy, submit the server-side request, but no data is persistent. (default "none") - --duration string Supported formats of the duration are: ms / s / m / h. (default "10s") - -h, --help help for delay - --label stringToString label for pod, such as '"app.kubernetes.io/component=mysql, statefulset.kubernetes.io/pod-name=mycluster-mysql-0. (default []) - --method string The HTTP method of the target request method. For example: GET, POST, PUT, DELETE, HEAD, OPTIONS, PATCH. (default "GET") - --mode string You can select "one", "all", "fixed", "fixed-percent", "random-max-percent", Specify the experimental mode, that is, which Pods to experiment with. (default "all") - --node stringArray Inject faults into pods in the specified node. - --node-label stringToString label for node, such as '"kubernetes.io/arch=arm64,kubernetes.io/hostname=minikube-m03,kubernetes.io/os=linux. (default []) - --ns-fault stringArray Specifies the namespace into which you want to inject faults. (default [default]) - -o, --output format Prints the output in the specified format. Allowed values: JSON and YAML (default yaml) - --path string The URI path of the target request. Supports Matching wildcards. (default "*") - --phase stringArray Specify the pod that injects the fault by the state of the pod. - --port int32 The TCP port that the target service listens on. (default 80) - --target string Specifies whether the target of fault injection is Request or Response. The target-related fields should be configured at the same time. (default "Request") - --value string If you choose mode=fixed or fixed-percent or random-max-percent, you can enter a value to specify the number or percentage of pods you want to inject. -``` - -### Options inherited from parent commands - -``` - --as string Username to impersonate for the operation. User could be a regular user or a service account in a namespace. - --as-group stringArray Group to impersonate for the operation, this flag can be repeated to specify multiple groups. - --as-uid string UID to impersonate for the operation. - --cache-dir string Default cache directory (default "$HOME/.kube/cache") - --certificate-authority string Path to a cert file for the certificate authority - --client-certificate string Path to a client certificate file for TLS - --client-key string Path to a client key file for TLS - --cluster string The name of the kubeconfig cluster to use - --context string The name of the kubeconfig context to use - --disable-compression If true, opt-out of response compression for all requests to the server - --insecure-skip-tls-verify If true, the server's certificate will not be checked for validity. This will make your HTTPS connections insecure - --kubeconfig string Path to the kubeconfig file to use for CLI requests. - --match-server-version Require server version to match client version - -n, --namespace string If present, the namespace scope for this CLI request - --request-timeout string The length of time to wait before giving up on a single server request. Non-zero values should contain a corresponding time unit (e.g. 1s, 2m, 3h). A value of zero means don't timeout requests. (default "0") - -s, --server string The address and port of the Kubernetes API server - --tls-server-name string Server name to use for server certificate validation. If it is not provided, the hostname used to contact the server is used - --token string Bearer token for authentication to the API server - --user string The name of the kubeconfig user to use -``` - -### SEE ALSO - -* [kbcli fault network http](kbcli_fault_network_http.md) - Intercept HTTP requests and responses. - -#### Go Back to [CLI Overview](cli.md) Homepage. - diff --git a/docs/user_docs/cli/kbcli_fault_network_http_patch.md b/docs/user_docs/cli/kbcli_fault_network_http_patch.md deleted file mode 100644 index 31182bdf0..000000000 --- a/docs/user_docs/cli/kbcli_fault_network_http_patch.md +++ /dev/null @@ -1,92 +0,0 @@ ---- -title: kbcli fault network http patch ---- - -Patch the HTTP request and response. - -``` -kbcli fault network http patch [flags] -``` - -### Examples - -``` - # By default, the method of GET from port 80 is blocked. - kbcli fault network http abort --duration=1m - - # Block the method of GET from port 4399. - kbcli fault network http abort --port=4399 --duration=1m - - # Block the method of POST from port 4399. - kbcli fault network http abort --port=4399 --method=POST --duration=1m - - # Delays post requests from port 4399. - kbcli fault network http delay --port=4399 --method=POST --delay=15s - - # Replace the GET method sent from port 80 with the PUT method. - kbcli fault network http replace --replace-method=PUT --duration=1m - - # Replace the GET method sent from port 80 with the PUT method, and replace the request body. - kbcli fault network http replace --body="you are good luck" --replace-method=PUT --duration=2m - - # Replace the response content "you" from port 80. - kbcli fault network http replace --target=Response --body=you --duration=30s - - # Append content to the body of the post request sent from port 4399, in JSON format. - kbcli fault network http patch --method=POST --port=4399 --body="you are good luck" --type=JSON --duration=30s -``` - -### Options - -``` - --annotation stringToString Select the pod to inject the fault according to Annotation. (default []) - --body string The fault of the request body or response body with patch faults. - --code int32 The status code responded by target. - --dry-run string[="unchanged"] Must be "client", or "server". If with client strategy, only print the object that would be sent, and no data is actually sent. If with server strategy, submit the server-side request, but no data is persistent. (default "none") - --duration string Supported formats of the duration are: ms / s / m / h. (default "10s") - -h, --help help for patch - --label stringToString label for pod, such as '"app.kubernetes.io/component=mysql, statefulset.kubernetes.io/pod-name=mycluster-mysql-0. (default []) - --method string The HTTP method of the target request method. For example: GET, POST, PUT, DELETE, HEAD, OPTIONS, PATCH. (default "GET") - --mode string You can select "one", "all", "fixed", "fixed-percent", "random-max-percent", Specify the experimental mode, that is, which Pods to experiment with. (default "all") - --node stringArray Inject faults into pods in the specified node. - --node-label stringToString label for node, such as '"kubernetes.io/arch=arm64,kubernetes.io/hostname=minikube-m03,kubernetes.io/os=linux. (default []) - --ns-fault stringArray Specifies the namespace into which you want to inject faults. (default [default]) - -o, --output format Prints the output in the specified format. Allowed values: JSON and YAML (default yaml) - --path string The URI path of the target request. Supports Matching wildcards. (default "*") - --phase stringArray Specify the pod that injects the fault by the state of the pod. - --port int32 The TCP port that the target service listens on. (default 80) - --target string Specifies whether the target of fault injection is Request or Response. The target-related fields should be configured at the same time. (default "Request") - --type string The type of patch faults of the request body or response body. Currently, it only supports JSON. - --value string If you choose mode=fixed or fixed-percent or random-max-percent, you can enter a value to specify the number or percentage of pods you want to inject. -``` - -### Options inherited from parent commands - -``` - --as string Username to impersonate for the operation. User could be a regular user or a service account in a namespace. - --as-group stringArray Group to impersonate for the operation, this flag can be repeated to specify multiple groups. - --as-uid string UID to impersonate for the operation. - --cache-dir string Default cache directory (default "$HOME/.kube/cache") - --certificate-authority string Path to a cert file for the certificate authority - --client-certificate string Path to a client certificate file for TLS - --client-key string Path to a client key file for TLS - --cluster string The name of the kubeconfig cluster to use - --context string The name of the kubeconfig context to use - --disable-compression If true, opt-out of response compression for all requests to the server - --insecure-skip-tls-verify If true, the server's certificate will not be checked for validity. This will make your HTTPS connections insecure - --kubeconfig string Path to the kubeconfig file to use for CLI requests. - --match-server-version Require server version to match client version - -n, --namespace string If present, the namespace scope for this CLI request - --request-timeout string The length of time to wait before giving up on a single server request. Non-zero values should contain a corresponding time unit (e.g. 1s, 2m, 3h). A value of zero means don't timeout requests. (default "0") - -s, --server string The address and port of the Kubernetes API server - --tls-server-name string Server name to use for server certificate validation. If it is not provided, the hostname used to contact the server is used - --token string Bearer token for authentication to the API server - --user string The name of the kubeconfig user to use -``` - -### SEE ALSO - -* [kbcli fault network http](kbcli_fault_network_http.md) - Intercept HTTP requests and responses. - -#### Go Back to [CLI Overview](cli.md) Homepage. - diff --git a/docs/user_docs/cli/kbcli_fault_network_http_replace.md b/docs/user_docs/cli/kbcli_fault_network_http_replace.md deleted file mode 100644 index 4a1f02ccf..000000000 --- a/docs/user_docs/cli/kbcli_fault_network_http_replace.md +++ /dev/null @@ -1,93 +0,0 @@ ---- -title: kbcli fault network http replace ---- - -Replace the HTTP request and response. - -``` -kbcli fault network http replace [flags] -``` - -### Examples - -``` - # By default, the method of GET from port 80 is blocked. - kbcli fault network http abort --duration=1m - - # Block the method of GET from port 4399. - kbcli fault network http abort --port=4399 --duration=1m - - # Block the method of POST from port 4399. - kbcli fault network http abort --port=4399 --method=POST --duration=1m - - # Delays post requests from port 4399. - kbcli fault network http delay --port=4399 --method=POST --delay=15s - - # Replace the GET method sent from port 80 with the PUT method. - kbcli fault network http replace --replace-method=PUT --duration=1m - - # Replace the GET method sent from port 80 with the PUT method, and replace the request body. - kbcli fault network http replace --body="you are good luck" --replace-method=PUT --duration=2m - - # Replace the response content "you" from port 80. - kbcli fault network http replace --target=Response --body=you --duration=30s - - # Append content to the body of the post request sent from port 4399, in JSON format. - kbcli fault network http patch --method=POST --port=4399 --body="you are good luck" --type=JSON --duration=30s -``` - -### Options - -``` - --annotation stringToString Select the pod to inject the fault according to Annotation. (default []) - --body string The content of the request body or response body to replace the failure. - --code int32 The status code responded by target. - --dry-run string[="unchanged"] Must be "client", or "server". If with client strategy, only print the object that would be sent, and no data is actually sent. If with server strategy, submit the server-side request, but no data is persistent. (default "none") - --duration string Supported formats of the duration are: ms / s / m / h. (default "10s") - -h, --help help for replace - --label stringToString label for pod, such as '"app.kubernetes.io/component=mysql, statefulset.kubernetes.io/pod-name=mycluster-mysql-0. (default []) - --method string The HTTP method of the target request method. For example: GET, POST, PUT, DELETE, HEAD, OPTIONS, PATCH. (default "GET") - --mode string You can select "one", "all", "fixed", "fixed-percent", "random-max-percent", Specify the experimental mode, that is, which Pods to experiment with. (default "all") - --node stringArray Inject faults into pods in the specified node. - --node-label stringToString label for node, such as '"kubernetes.io/arch=arm64,kubernetes.io/hostname=minikube-m03,kubernetes.io/os=linux. (default []) - --ns-fault stringArray Specifies the namespace into which you want to inject faults. (default [default]) - -o, --output format Prints the output in the specified format. Allowed values: JSON and YAML (default yaml) - --path string The URI path of the target request. Supports Matching wildcards. (default "*") - --phase stringArray Specify the pod that injects the fault by the state of the pod. - --port int32 The TCP port that the target service listens on. (default 80) - --replace-method string The replaced content of the HTTP request method. - --replace-path string The URI path used to replace content. - --target string Specifies whether the target of fault injection is Request or Response. The target-related fields should be configured at the same time. (default "Request") - --value string If you choose mode=fixed or fixed-percent or random-max-percent, you can enter a value to specify the number or percentage of pods you want to inject. -``` - -### Options inherited from parent commands - -``` - --as string Username to impersonate for the operation. User could be a regular user or a service account in a namespace. - --as-group stringArray Group to impersonate for the operation, this flag can be repeated to specify multiple groups. - --as-uid string UID to impersonate for the operation. - --cache-dir string Default cache directory (default "$HOME/.kube/cache") - --certificate-authority string Path to a cert file for the certificate authority - --client-certificate string Path to a client certificate file for TLS - --client-key string Path to a client key file for TLS - --cluster string The name of the kubeconfig cluster to use - --context string The name of the kubeconfig context to use - --disable-compression If true, opt-out of response compression for all requests to the server - --insecure-skip-tls-verify If true, the server's certificate will not be checked for validity. This will make your HTTPS connections insecure - --kubeconfig string Path to the kubeconfig file to use for CLI requests. - --match-server-version Require server version to match client version - -n, --namespace string If present, the namespace scope for this CLI request - --request-timeout string The length of time to wait before giving up on a single server request. Non-zero values should contain a corresponding time unit (e.g. 1s, 2m, 3h). A value of zero means don't timeout requests. (default "0") - -s, --server string The address and port of the Kubernetes API server - --tls-server-name string Server name to use for server certificate validation. If it is not provided, the hostname used to contact the server is used - --token string Bearer token for authentication to the API server - --user string The name of the kubeconfig user to use -``` - -### SEE ALSO - -* [kbcli fault network http](kbcli_fault_network_http.md) - Intercept HTTP requests and responses. - -#### Go Back to [CLI Overview](cli.md) Homepage. - diff --git a/docs/user_docs/cli/kbcli_fault_network_loss.md b/docs/user_docs/cli/kbcli_fault_network_loss.md deleted file mode 100644 index c6d0d401e..000000000 --- a/docs/user_docs/cli/kbcli_fault_network_loss.md +++ /dev/null @@ -1,104 +0,0 @@ ---- -title: kbcli fault network loss ---- - -Cause pods to communicate with other objects to drop packets. - -``` -kbcli fault network loss [flags] -``` - -### Examples - -``` - # Isolate all pods network under the default namespace from the outside world, including the k8s internal network. - kbcli fault network partition - - # The specified pod is isolated from the k8s external network "kubeblocks.io". - kbcli fault network partition mycluster-mysql-1 --external-targets=kubeblocks.io - - # Isolate the network between two pods. - kbcli fault network partition mycluster-mysql-1 --target-label=statefulset.kubernetes.io/pod-name=mycluster-mysql-2 - - // Like the partition command, the target can be specified through --target-label or --external-targets. The pod only has obstacles in communicating with this target. If the target is not specified, all communication will be blocked. - # Block all pod communication under the default namespace, resulting in a 50% packet loss rate. - kbcli fault network loss --loss=50 - - # Block the specified pod communication, so that the packet loss rate is 50%. - kbcli fault network loss mysql-cluster-mysql-2 --loss=50 - - kbcli fault network corrupt --corrupt=50 - - # Blocks specified pod communication with a 50% packet corruption rate. - kbcli fault network corrupt mysql-cluster-mysql-2 --corrupt=50 - - kbcli fault network duplicate --duplicate=50 - - # Block specified pod communication so that the packet repetition rate is 50%. - kbcli fault network duplicate mysql-cluster-mysql-2 --duplicate=50 - - kbcli fault network delay --latency=10s - - # Block the communication of the specified pod, causing its network delay for 10s. - kbcli fault network delay mysql-cluster-mysql-2 --latency=10s - - # Limit the communication bandwidth between mysql-cluster-mysql-2 and the outside. - kbcli fault network bandwidth mysql-cluster-mysql-2 --rate=1kbps --duration=1m -``` - -### Options - -``` - --annotation stringToString Select the pod to inject the fault according to Annotation. (default []) - -c, --correlation string Indicates the correlation between the probability of a packet error occurring and whether it occurred the previous time. Value range: [0, 100]. - --direction string You can select "to"" or "from"" or "both"". (default "to") - --dry-run string[="unchanged"] Must be "client", or "server". If with client strategy, only print the object that would be sent, and no data is actually sent. If with server strategy, submit the server-side request, but no data is persistent. (default "none") - --duration string Supported formats of the duration are: ms / s / m / h. (default "10s") - -e, --external-target stringArray a network target outside of Kubernetes, which can be an IPv4 address or a domain name, - such as "www.baidu.com". Only works with direction: to. - -h, --help help for loss - --label stringToString label for pod, such as '"app.kubernetes.io/component=mysql, statefulset.kubernetes.io/pod-name=mycluster-mysql-0. (default []) - --loss string Indicates the probability of a packet error occurring. Value range: [0, 100]. - --mode string You can select "one", "all", "fixed", "fixed-percent", "random-max-percent", Specify the experimental mode, that is, which Pods to experiment with. (default "all") - --node stringArray Inject faults into pods in the specified node. - --node-label stringToString label for node, such as '"kubernetes.io/arch=arm64,kubernetes.io/hostname=minikube-m03,kubernetes.io/os=linux. (default []) - --ns-fault stringArray Specifies the namespace into which you want to inject faults. (default [default]) - -o, --output format Prints the output in the specified format. Allowed values: JSON and YAML (default yaml) - --phase stringArray Specify the pod that injects the fault by the state of the pod. - --target-label stringToString label for pod, such as '"app.kubernetes.io/component=mysql, statefulset.kubernetes.io/pod-name=mycluster-mysql-0"' (default []) - --target-mode string You can select "one", "all", "fixed", "fixed-percent", "random-max-percent", Specify the experimental mode, that is, which Pods to experiment with. - --target-ns-fault stringArray Specifies the namespace into which you want to inject faults. - --target-value string If you choose mode=fixed or fixed-percent or random-max-percent, you can enter a value to specify the number or percentage of pods you want to inject. - --value string If you choose mode=fixed or fixed-percent or random-max-percent, you can enter a value to specify the number or percentage of pods you want to inject. -``` - -### Options inherited from parent commands - -``` - --as string Username to impersonate for the operation. User could be a regular user or a service account in a namespace. - --as-group stringArray Group to impersonate for the operation, this flag can be repeated to specify multiple groups. - --as-uid string UID to impersonate for the operation. - --cache-dir string Default cache directory (default "$HOME/.kube/cache") - --certificate-authority string Path to a cert file for the certificate authority - --client-certificate string Path to a client certificate file for TLS - --client-key string Path to a client key file for TLS - --cluster string The name of the kubeconfig cluster to use - --context string The name of the kubeconfig context to use - --disable-compression If true, opt-out of response compression for all requests to the server - --insecure-skip-tls-verify If true, the server's certificate will not be checked for validity. This will make your HTTPS connections insecure - --kubeconfig string Path to the kubeconfig file to use for CLI requests. - --match-server-version Require server version to match client version - -n, --namespace string If present, the namespace scope for this CLI request - --request-timeout string The length of time to wait before giving up on a single server request. Non-zero values should contain a corresponding time unit (e.g. 1s, 2m, 3h). A value of zero means don't timeout requests. (default "0") - -s, --server string The address and port of the Kubernetes API server - --tls-server-name string Server name to use for server certificate validation. If it is not provided, the hostname used to contact the server is used - --token string Bearer token for authentication to the API server - --user string The name of the kubeconfig user to use -``` - -### SEE ALSO - -* [kbcli fault network](kbcli_fault_network.md) - Network chaos. - -#### Go Back to [CLI Overview](cli.md) Homepage. - diff --git a/docs/user_docs/cli/kbcli_fault_network_partition.md b/docs/user_docs/cli/kbcli_fault_network_partition.md deleted file mode 100644 index 3d80f6362..000000000 --- a/docs/user_docs/cli/kbcli_fault_network_partition.md +++ /dev/null @@ -1,102 +0,0 @@ ---- -title: kbcli fault network partition ---- - -Make a pod network partitioned from other objects. - -``` -kbcli fault network partition [flags] -``` - -### Examples - -``` - # Isolate all pods network under the default namespace from the outside world, including the k8s internal network. - kbcli fault network partition - - # The specified pod is isolated from the k8s external network "kubeblocks.io". - kbcli fault network partition mycluster-mysql-1 --external-targets=kubeblocks.io - - # Isolate the network between two pods. - kbcli fault network partition mycluster-mysql-1 --target-label=statefulset.kubernetes.io/pod-name=mycluster-mysql-2 - - // Like the partition command, the target can be specified through --target-label or --external-targets. The pod only has obstacles in communicating with this target. If the target is not specified, all communication will be blocked. - # Block all pod communication under the default namespace, resulting in a 50% packet loss rate. - kbcli fault network loss --loss=50 - - # Block the specified pod communication, so that the packet loss rate is 50%. - kbcli fault network loss mysql-cluster-mysql-2 --loss=50 - - kbcli fault network corrupt --corrupt=50 - - # Blocks specified pod communication with a 50% packet corruption rate. - kbcli fault network corrupt mysql-cluster-mysql-2 --corrupt=50 - - kbcli fault network duplicate --duplicate=50 - - # Block specified pod communication so that the packet repetition rate is 50%. - kbcli fault network duplicate mysql-cluster-mysql-2 --duplicate=50 - - kbcli fault network delay --latency=10s - - # Block the communication of the specified pod, causing its network delay for 10s. - kbcli fault network delay mysql-cluster-mysql-2 --latency=10s - - # Limit the communication bandwidth between mysql-cluster-mysql-2 and the outside. - kbcli fault network bandwidth mysql-cluster-mysql-2 --rate=1kbps --duration=1m -``` - -### Options - -``` - --annotation stringToString Select the pod to inject the fault according to Annotation. (default []) - --direction string You can select "to"" or "from"" or "both"". (default "to") - --dry-run string[="unchanged"] Must be "client", or "server". If with client strategy, only print the object that would be sent, and no data is actually sent. If with server strategy, submit the server-side request, but no data is persistent. (default "none") - --duration string Supported formats of the duration are: ms / s / m / h. (default "10s") - -e, --external-target stringArray a network target outside of Kubernetes, which can be an IPv4 address or a domain name, - such as "www.baidu.com". Only works with direction: to. - -h, --help help for partition - --label stringToString label for pod, such as '"app.kubernetes.io/component=mysql, statefulset.kubernetes.io/pod-name=mycluster-mysql-0. (default []) - --mode string You can select "one", "all", "fixed", "fixed-percent", "random-max-percent", Specify the experimental mode, that is, which Pods to experiment with. (default "all") - --node stringArray Inject faults into pods in the specified node. - --node-label stringToString label for node, such as '"kubernetes.io/arch=arm64,kubernetes.io/hostname=minikube-m03,kubernetes.io/os=linux. (default []) - --ns-fault stringArray Specifies the namespace into which you want to inject faults. (default [default]) - -o, --output format Prints the output in the specified format. Allowed values: JSON and YAML (default yaml) - --phase stringArray Specify the pod that injects the fault by the state of the pod. - --target-label stringToString label for pod, such as '"app.kubernetes.io/component=mysql, statefulset.kubernetes.io/pod-name=mycluster-mysql-0"' (default []) - --target-mode string You can select "one", "all", "fixed", "fixed-percent", "random-max-percent", Specify the experimental mode, that is, which Pods to experiment with. - --target-ns-fault stringArray Specifies the namespace into which you want to inject faults. - --target-value string If you choose mode=fixed or fixed-percent or random-max-percent, you can enter a value to specify the number or percentage of pods you want to inject. - --value string If you choose mode=fixed or fixed-percent or random-max-percent, you can enter a value to specify the number or percentage of pods you want to inject. -``` - -### Options inherited from parent commands - -``` - --as string Username to impersonate for the operation. User could be a regular user or a service account in a namespace. - --as-group stringArray Group to impersonate for the operation, this flag can be repeated to specify multiple groups. - --as-uid string UID to impersonate for the operation. - --cache-dir string Default cache directory (default "$HOME/.kube/cache") - --certificate-authority string Path to a cert file for the certificate authority - --client-certificate string Path to a client certificate file for TLS - --client-key string Path to a client key file for TLS - --cluster string The name of the kubeconfig cluster to use - --context string The name of the kubeconfig context to use - --disable-compression If true, opt-out of response compression for all requests to the server - --insecure-skip-tls-verify If true, the server's certificate will not be checked for validity. This will make your HTTPS connections insecure - --kubeconfig string Path to the kubeconfig file to use for CLI requests. - --match-server-version Require server version to match client version - -n, --namespace string If present, the namespace scope for this CLI request - --request-timeout string The length of time to wait before giving up on a single server request. Non-zero values should contain a corresponding time unit (e.g. 1s, 2m, 3h). A value of zero means don't timeout requests. (default "0") - -s, --server string The address and port of the Kubernetes API server - --tls-server-name string Server name to use for server certificate validation. If it is not provided, the hostname used to contact the server is used - --token string Bearer token for authentication to the API server - --user string The name of the kubeconfig user to use -``` - -### SEE ALSO - -* [kbcli fault network](kbcli_fault_network.md) - Network chaos. - -#### Go Back to [CLI Overview](cli.md) Homepage. - diff --git a/docs/user_docs/cli/kbcli_fault_node.md b/docs/user_docs/cli/kbcli_fault_node.md deleted file mode 100644 index e89be737b..000000000 --- a/docs/user_docs/cli/kbcli_fault_node.md +++ /dev/null @@ -1,45 +0,0 @@ ---- -title: kbcli fault node ---- - -Node chaos. - -### Options - -``` - -h, --help help for node -``` - -### Options inherited from parent commands - -``` - --as string Username to impersonate for the operation. User could be a regular user or a service account in a namespace. - --as-group stringArray Group to impersonate for the operation, this flag can be repeated to specify multiple groups. - --as-uid string UID to impersonate for the operation. - --cache-dir string Default cache directory (default "$HOME/.kube/cache") - --certificate-authority string Path to a cert file for the certificate authority - --client-certificate string Path to a client certificate file for TLS - --client-key string Path to a client key file for TLS - --cluster string The name of the kubeconfig cluster to use - --context string The name of the kubeconfig context to use - --disable-compression If true, opt-out of response compression for all requests to the server - --insecure-skip-tls-verify If true, the server's certificate will not be checked for validity. This will make your HTTPS connections insecure - --kubeconfig string Path to the kubeconfig file to use for CLI requests. - --match-server-version Require server version to match client version - -n, --namespace string If present, the namespace scope for this CLI request - --request-timeout string The length of time to wait before giving up on a single server request. Non-zero values should contain a corresponding time unit (e.g. 1s, 2m, 3h). A value of zero means don't timeout requests. (default "0") - -s, --server string The address and port of the Kubernetes API server - --tls-server-name string Server name to use for server certificate validation. If it is not provided, the hostname used to contact the server is used - --token string Bearer token for authentication to the API server - --user string The name of the kubeconfig user to use -``` - -### SEE ALSO - -* [kbcli fault](kbcli_fault.md) - Inject faults to pod. -* [kbcli fault node detach-volume](kbcli_fault_node_detach-volume.md) - Detach volume -* [kbcli fault node restart](kbcli_fault_node_restart.md) - Restart instance -* [kbcli fault node stop](kbcli_fault_node_stop.md) - Stop instance - -#### Go Back to [CLI Overview](cli.md) Homepage. - diff --git a/docs/user_docs/cli/kbcli_fault_pod.md b/docs/user_docs/cli/kbcli_fault_pod.md deleted file mode 100644 index 144789ad5..000000000 --- a/docs/user_docs/cli/kbcli_fault_pod.md +++ /dev/null @@ -1,45 +0,0 @@ ---- -title: kbcli fault pod ---- - -Pod chaos. - -### Options - -``` - -h, --help help for pod -``` - -### Options inherited from parent commands - -``` - --as string Username to impersonate for the operation. User could be a regular user or a service account in a namespace. - --as-group stringArray Group to impersonate for the operation, this flag can be repeated to specify multiple groups. - --as-uid string UID to impersonate for the operation. - --cache-dir string Default cache directory (default "$HOME/.kube/cache") - --certificate-authority string Path to a cert file for the certificate authority - --client-certificate string Path to a client certificate file for TLS - --client-key string Path to a client key file for TLS - --cluster string The name of the kubeconfig cluster to use - --context string The name of the kubeconfig context to use - --disable-compression If true, opt-out of response compression for all requests to the server - --insecure-skip-tls-verify If true, the server's certificate will not be checked for validity. This will make your HTTPS connections insecure - --kubeconfig string Path to the kubeconfig file to use for CLI requests. - --match-server-version Require server version to match client version - -n, --namespace string If present, the namespace scope for this CLI request - --request-timeout string The length of time to wait before giving up on a single server request. Non-zero values should contain a corresponding time unit (e.g. 1s, 2m, 3h). A value of zero means don't timeout requests. (default "0") - -s, --server string The address and port of the Kubernetes API server - --tls-server-name string Server name to use for server certificate validation. If it is not provided, the hostname used to contact the server is used - --token string Bearer token for authentication to the API server - --user string The name of the kubeconfig user to use -``` - -### SEE ALSO - -* [kbcli fault](kbcli_fault.md) - Inject faults to pod. -* [kbcli fault pod failure](kbcli_fault_pod_failure.md) - failure pod -* [kbcli fault pod kill](kbcli_fault_pod_kill.md) - kill pod -* [kbcli fault pod kill-container](kbcli_fault_pod_kill-container.md) - kill containers - -#### Go Back to [CLI Overview](cli.md) Homepage. - diff --git a/docs/user_docs/cli/kbcli_fault_pod_failure.md b/docs/user_docs/cli/kbcli_fault_pod_failure.md deleted file mode 100644 index 407862761..000000000 --- a/docs/user_docs/cli/kbcli_fault_pod_failure.md +++ /dev/null @@ -1,94 +0,0 @@ ---- -title: kbcli fault pod failure ---- - -failure pod - -``` -kbcli fault pod failure [flags] -``` - -### Examples - -``` - # kill all pods in default namespace - kbcli fault pod kill - - # kill any pod in default namespace - kbcli fault pod kill --mode=one - - # kill two pods in default namespace - kbcli fault pod kill --mode=fixed --value=2 - - # kill 50% pods in default namespace - kbcli fault pod kill --mode=percentage --value=50 - - # kill mysql-cluster-mysql-0 pod in default namespace - kbcli fault pod kill mysql-cluster-mysql-0 - - # kill all pods in default namespace - kbcli fault pod kill --ns-fault="default" - - # --label is required to specify the pods that need to be killed. - kbcli fault pod kill --label statefulset.kubernetes.io/pod-name=mysql-cluster-mysql-2 - - # kill pod under the specified node. - kbcli fault pod kill --node=minikube-m02 - - # kill pod under the specified node-label. - kbcli fault pod kill --node-label=kubernetes.io/arch=arm64 - - # Allow the experiment to last for one minute. - kbcli fault pod failure --duration=1m - - # kill container in pod - kbcli fault pod kill-container mysql-cluster-mysql-0 --container=mysql -``` - -### Options - -``` - --annotation stringToString Select the pod to inject the fault according to Annotation. (default []) - --dry-run string[="unchanged"] Must be "client", or "server". If with client strategy, only print the object that would be sent, and no data is actually sent. If with server strategy, submit the server-side request, but no data is persistent. (default "none") - --duration string Supported formats of the duration are: ms / s / m / h. (default "10s") - -h, --help help for failure - --label stringToString label for pod, such as '"app.kubernetes.io/component=mysql, statefulset.kubernetes.io/pod-name=mycluster-mysql-0. (default []) - --mode string You can select "one", "all", "fixed", "fixed-percent", "random-max-percent", Specify the experimental mode, that is, which Pods to experiment with. (default "all") - --node stringArray Inject faults into pods in the specified node. - --node-label stringToString label for node, such as '"kubernetes.io/arch=arm64,kubernetes.io/hostname=minikube-m03,kubernetes.io/os=linux. (default []) - --ns-fault stringArray Specifies the namespace into which you want to inject faults. (default [default]) - -o, --output format Prints the output in the specified format. Allowed values: JSON and YAML (default yaml) - --phase stringArray Specify the pod that injects the fault by the state of the pod. - --value string If you choose mode=fixed or fixed-percent or random-max-percent, you can enter a value to specify the number or percentage of pods you want to inject. -``` - -### Options inherited from parent commands - -``` - --as string Username to impersonate for the operation. User could be a regular user or a service account in a namespace. - --as-group stringArray Group to impersonate for the operation, this flag can be repeated to specify multiple groups. - --as-uid string UID to impersonate for the operation. - --cache-dir string Default cache directory (default "$HOME/.kube/cache") - --certificate-authority string Path to a cert file for the certificate authority - --client-certificate string Path to a client certificate file for TLS - --client-key string Path to a client key file for TLS - --cluster string The name of the kubeconfig cluster to use - --context string The name of the kubeconfig context to use - --disable-compression If true, opt-out of response compression for all requests to the server - --insecure-skip-tls-verify If true, the server's certificate will not be checked for validity. This will make your HTTPS connections insecure - --kubeconfig string Path to the kubeconfig file to use for CLI requests. - --match-server-version Require server version to match client version - -n, --namespace string If present, the namespace scope for this CLI request - --request-timeout string The length of time to wait before giving up on a single server request. Non-zero values should contain a corresponding time unit (e.g. 1s, 2m, 3h). A value of zero means don't timeout requests. (default "0") - -s, --server string The address and port of the Kubernetes API server - --tls-server-name string Server name to use for server certificate validation. If it is not provided, the hostname used to contact the server is used - --token string Bearer token for authentication to the API server - --user string The name of the kubeconfig user to use -``` - -### SEE ALSO - -* [kbcli fault pod](kbcli_fault_pod.md) - Pod chaos. - -#### Go Back to [CLI Overview](cli.md) Homepage. - diff --git a/docs/user_docs/cli/kbcli_fault_pod_kill-container.md b/docs/user_docs/cli/kbcli_fault_pod_kill-container.md deleted file mode 100644 index dc02b6bf9..000000000 --- a/docs/user_docs/cli/kbcli_fault_pod_kill-container.md +++ /dev/null @@ -1,95 +0,0 @@ ---- -title: kbcli fault pod kill-container ---- - -kill containers - -``` -kbcli fault pod kill-container [flags] -``` - -### Examples - -``` - # kill all pods in default namespace - kbcli fault pod kill - - # kill any pod in default namespace - kbcli fault pod kill --mode=one - - # kill two pods in default namespace - kbcli fault pod kill --mode=fixed --value=2 - - # kill 50% pods in default namespace - kbcli fault pod kill --mode=percentage --value=50 - - # kill mysql-cluster-mysql-0 pod in default namespace - kbcli fault pod kill mysql-cluster-mysql-0 - - # kill all pods in default namespace - kbcli fault pod kill --ns-fault="default" - - # --label is required to specify the pods that need to be killed. - kbcli fault pod kill --label statefulset.kubernetes.io/pod-name=mysql-cluster-mysql-2 - - # kill pod under the specified node. - kbcli fault pod kill --node=minikube-m02 - - # kill pod under the specified node-label. - kbcli fault pod kill --node-label=kubernetes.io/arch=arm64 - - # Allow the experiment to last for one minute. - kbcli fault pod failure --duration=1m - - # kill container in pod - kbcli fault pod kill-container mysql-cluster-mysql-0 --container=mysql -``` - -### Options - -``` - --annotation stringToString Select the pod to inject the fault according to Annotation. (default []) - -c, --container stringArray the name of the container you want to kill, such as mysql, prometheus. - --dry-run string[="unchanged"] Must be "client", or "server". If with client strategy, only print the object that would be sent, and no data is actually sent. If with server strategy, submit the server-side request, but no data is persistent. (default "none") - --duration string Supported formats of the duration are: ms / s / m / h. (default "10s") - -h, --help help for kill-container - --label stringToString label for pod, such as '"app.kubernetes.io/component=mysql, statefulset.kubernetes.io/pod-name=mycluster-mysql-0. (default []) - --mode string You can select "one", "all", "fixed", "fixed-percent", "random-max-percent", Specify the experimental mode, that is, which Pods to experiment with. (default "all") - --node stringArray Inject faults into pods in the specified node. - --node-label stringToString label for node, such as '"kubernetes.io/arch=arm64,kubernetes.io/hostname=minikube-m03,kubernetes.io/os=linux. (default []) - --ns-fault stringArray Specifies the namespace into which you want to inject faults. (default [default]) - -o, --output format Prints the output in the specified format. Allowed values: JSON and YAML (default yaml) - --phase stringArray Specify the pod that injects the fault by the state of the pod. - --value string If you choose mode=fixed or fixed-percent or random-max-percent, you can enter a value to specify the number or percentage of pods you want to inject. -``` - -### Options inherited from parent commands - -``` - --as string Username to impersonate for the operation. User could be a regular user or a service account in a namespace. - --as-group stringArray Group to impersonate for the operation, this flag can be repeated to specify multiple groups. - --as-uid string UID to impersonate for the operation. - --cache-dir string Default cache directory (default "$HOME/.kube/cache") - --certificate-authority string Path to a cert file for the certificate authority - --client-certificate string Path to a client certificate file for TLS - --client-key string Path to a client key file for TLS - --cluster string The name of the kubeconfig cluster to use - --context string The name of the kubeconfig context to use - --disable-compression If true, opt-out of response compression for all requests to the server - --insecure-skip-tls-verify If true, the server's certificate will not be checked for validity. This will make your HTTPS connections insecure - --kubeconfig string Path to the kubeconfig file to use for CLI requests. - --match-server-version Require server version to match client version - -n, --namespace string If present, the namespace scope for this CLI request - --request-timeout string The length of time to wait before giving up on a single server request. Non-zero values should contain a corresponding time unit (e.g. 1s, 2m, 3h). A value of zero means don't timeout requests. (default "0") - -s, --server string The address and port of the Kubernetes API server - --tls-server-name string Server name to use for server certificate validation. If it is not provided, the hostname used to contact the server is used - --token string Bearer token for authentication to the API server - --user string The name of the kubeconfig user to use -``` - -### SEE ALSO - -* [kbcli fault pod](kbcli_fault_pod.md) - Pod chaos. - -#### Go Back to [CLI Overview](cli.md) Homepage. - diff --git a/docs/user_docs/cli/kbcli_fault_pod_kill.md b/docs/user_docs/cli/kbcli_fault_pod_kill.md deleted file mode 100644 index 28addb53a..000000000 --- a/docs/user_docs/cli/kbcli_fault_pod_kill.md +++ /dev/null @@ -1,95 +0,0 @@ ---- -title: kbcli fault pod kill ---- - -kill pod - -``` -kbcli fault pod kill [flags] -``` - -### Examples - -``` - # kill all pods in default namespace - kbcli fault pod kill - - # kill any pod in default namespace - kbcli fault pod kill --mode=one - - # kill two pods in default namespace - kbcli fault pod kill --mode=fixed --value=2 - - # kill 50% pods in default namespace - kbcli fault pod kill --mode=percentage --value=50 - - # kill mysql-cluster-mysql-0 pod in default namespace - kbcli fault pod kill mysql-cluster-mysql-0 - - # kill all pods in default namespace - kbcli fault pod kill --ns-fault="default" - - # --label is required to specify the pods that need to be killed. - kbcli fault pod kill --label statefulset.kubernetes.io/pod-name=mysql-cluster-mysql-2 - - # kill pod under the specified node. - kbcli fault pod kill --node=minikube-m02 - - # kill pod under the specified node-label. - kbcli fault pod kill --node-label=kubernetes.io/arch=arm64 - - # Allow the experiment to last for one minute. - kbcli fault pod failure --duration=1m - - # kill container in pod - kbcli fault pod kill-container mysql-cluster-mysql-0 --container=mysql -``` - -### Options - -``` - --annotation stringToString Select the pod to inject the fault according to Annotation. (default []) - --dry-run string[="unchanged"] Must be "client", or "server". If with client strategy, only print the object that would be sent, and no data is actually sent. If with server strategy, submit the server-side request, but no data is persistent. (default "none") - --duration string Supported formats of the duration are: ms / s / m / h. (default "10s") - -g, --grace-period int Grace period represents the duration in seconds before the pod should be killed - -h, --help help for kill - --label stringToString label for pod, such as '"app.kubernetes.io/component=mysql, statefulset.kubernetes.io/pod-name=mycluster-mysql-0. (default []) - --mode string You can select "one", "all", "fixed", "fixed-percent", "random-max-percent", Specify the experimental mode, that is, which Pods to experiment with. (default "all") - --node stringArray Inject faults into pods in the specified node. - --node-label stringToString label for node, such as '"kubernetes.io/arch=arm64,kubernetes.io/hostname=minikube-m03,kubernetes.io/os=linux. (default []) - --ns-fault stringArray Specifies the namespace into which you want to inject faults. (default [default]) - -o, --output format Prints the output in the specified format. Allowed values: JSON and YAML (default yaml) - --phase stringArray Specify the pod that injects the fault by the state of the pod. - --value string If you choose mode=fixed or fixed-percent or random-max-percent, you can enter a value to specify the number or percentage of pods you want to inject. -``` - -### Options inherited from parent commands - -``` - --as string Username to impersonate for the operation. User could be a regular user or a service account in a namespace. - --as-group stringArray Group to impersonate for the operation, this flag can be repeated to specify multiple groups. - --as-uid string UID to impersonate for the operation. - --cache-dir string Default cache directory (default "$HOME/.kube/cache") - --certificate-authority string Path to a cert file for the certificate authority - --client-certificate string Path to a client certificate file for TLS - --client-key string Path to a client key file for TLS - --cluster string The name of the kubeconfig cluster to use - --context string The name of the kubeconfig context to use - --disable-compression If true, opt-out of response compression for all requests to the server - --insecure-skip-tls-verify If true, the server's certificate will not be checked for validity. This will make your HTTPS connections insecure - --kubeconfig string Path to the kubeconfig file to use for CLI requests. - --match-server-version Require server version to match client version - -n, --namespace string If present, the namespace scope for this CLI request - --request-timeout string The length of time to wait before giving up on a single server request. Non-zero values should contain a corresponding time unit (e.g. 1s, 2m, 3h). A value of zero means don't timeout requests. (default "0") - -s, --server string The address and port of the Kubernetes API server - --tls-server-name string Server name to use for server certificate validation. If it is not provided, the hostname used to contact the server is used - --token string Bearer token for authentication to the API server - --user string The name of the kubeconfig user to use -``` - -### SEE ALSO - -* [kbcli fault pod](kbcli_fault_pod.md) - Pod chaos. - -#### Go Back to [CLI Overview](cli.md) Homepage. - diff --git a/docs/user_docs/cli/kbcli_fault_stress.md b/docs/user_docs/cli/kbcli_fault_stress.md deleted file mode 100644 index 74029b57c..000000000 --- a/docs/user_docs/cli/kbcli_fault_stress.md +++ /dev/null @@ -1,75 +0,0 @@ ---- -title: kbcli fault stress ---- - -Add memory pressure or CPU load to the system. - -``` -kbcli fault stress [flags] -``` - -### Examples - -``` - # Affects the first container in default namespace's all pods.Making CPU load up to 50%, and the memory up to 100MB. - kbcli fault stress --cpu-worker=2 --cpu-load=50 --memory-worker=1 --memory-size=100Mi - - # Affects the first container in mycluster-mysql-0 pod. Making the CPU load up to 50%, and the memory up to 500MB. - kbcli fault stress mycluster-mysql-0 --cpu-worker=2 --cpu-load=50 - - # Affects the mysql container in mycluster-mysql-0 pod. Making the memory up to 500MB. - kbcli fault stress mycluster-mysql-0 --memory-worker=2 --memory-size=500Mi -c=mysql -``` - -### Options - -``` - --annotation stringToString Select the pod to inject the fault according to Annotation. (default []) - -c, --container stringArray The name of the container, such as mysql, prometheus.If it's empty, the first container will be injected. - --cpu-load int Specifies the percentage of CPU occupied. 0 means no extra load added, 100 means full load. The total load is workers * load. - --cpu-worker int Specifies the number of threads that exert CPU pressure. - --dry-run string[="unchanged"] Must be "client", or "server". If with client strategy, only print the object that would be sent, and no data is actually sent. If with server strategy, submit the server-side request, but no data is persistent. (default "none") - --duration string Supported formats of the duration are: ms / s / m / h. (default "10s") - -h, --help help for stress - --label stringToString label for pod, such as '"app.kubernetes.io/component=mysql, statefulset.kubernetes.io/pod-name=mycluster-mysql-0. (default []) - --memory-size string Specify the size of the allocated memory or the percentage of the total memory, and the sum of the allocated memory is size. For example:256MB or 25% - --memory-worker int Specifies the number of threads that apply memory pressure. - --mode string You can select "one", "all", "fixed", "fixed-percent", "random-max-percent", Specify the experimental mode, that is, which Pods to experiment with. (default "all") - --node stringArray Inject faults into pods in the specified node. - --node-label stringToString label for node, such as '"kubernetes.io/arch=arm64,kubernetes.io/hostname=minikube-m03,kubernetes.io/os=linux. (default []) - --ns-fault stringArray Specifies the namespace into which you want to inject faults. (default [default]) - -o, --output format Prints the output in the specified format. Allowed values: JSON and YAML (default yaml) - --phase stringArray Specify the pod that injects the fault by the state of the pod. - --value string If you choose mode=fixed or fixed-percent or random-max-percent, you can enter a value to specify the number or percentage of pods you want to inject. -``` - -### Options inherited from parent commands - -``` - --as string Username to impersonate for the operation. User could be a regular user or a service account in a namespace. - --as-group stringArray Group to impersonate for the operation, this flag can be repeated to specify multiple groups. - --as-uid string UID to impersonate for the operation. - --cache-dir string Default cache directory (default "$HOME/.kube/cache") - --certificate-authority string Path to a cert file for the certificate authority - --client-certificate string Path to a client certificate file for TLS - --client-key string Path to a client key file for TLS - --cluster string The name of the kubeconfig cluster to use - --context string The name of the kubeconfig context to use - --disable-compression If true, opt-out of response compression for all requests to the server - --insecure-skip-tls-verify If true, the server's certificate will not be checked for validity. This will make your HTTPS connections insecure - --kubeconfig string Path to the kubeconfig file to use for CLI requests. - --match-server-version Require server version to match client version - -n, --namespace string If present, the namespace scope for this CLI request - --request-timeout string The length of time to wait before giving up on a single server request. Non-zero values should contain a corresponding time unit (e.g. 1s, 2m, 3h). A value of zero means don't timeout requests. (default "0") - -s, --server string The address and port of the Kubernetes API server - --tls-server-name string Server name to use for server certificate validation. If it is not provided, the hostname used to contact the server is used - --token string Bearer token for authentication to the API server - --user string The name of the kubeconfig user to use -``` - -### SEE ALSO - -* [kbcli fault](kbcli_fault.md) - Inject faults to pod. - -#### Go Back to [CLI Overview](cli.md) Homepage. - diff --git a/docs/user_docs/cli/kbcli_fault_time.md b/docs/user_docs/cli/kbcli_fault_time.md deleted file mode 100644 index ec2271ed0..000000000 --- a/docs/user_docs/cli/kbcli_fault_time.md +++ /dev/null @@ -1,79 +0,0 @@ ---- -title: kbcli fault time ---- - -Clock skew failure. - -``` -kbcli fault time [flags] -``` - -### Examples - -``` - # Affects the first container in default namespace's all pods.Shifts the clock back five seconds. - kbcli fault time --time-offset=-5s - - # Affects the first container in default namespace's all pods. - kbcli fault time --time-offset=-5m5s - - # Affects the first container in mycluster-mysql-0 pod. Shifts the clock forward five seconds. - kbcli fault time mycluster-mysql-0 --time-offset=+5s50ms - - # Affects the mysql container in mycluster-mysql-0 pod. Shifts the clock forward five seconds. - kbcli fault time mycluster-mysql-0 --time-offset=+5s -c=mysql - - # The clock that specifies the effect of time offset is CLOCK_REALTIME. - kbcli fault time mycluster-mysql-0 --time-offset=+5s --clock-id=CLOCK_REALTIME -c=mysql -``` - -### Options - -``` - --annotation stringToString Select the pod to inject the fault according to Annotation. (default []) - --clock-id stringArray Specifies the clock on which the time offset acts.If it's empty, it will be set to ['CLOCK_REALTIME'].See clock_gettime [https://man7.org/linux/man-pages/man2/clock_gettime.2.html] document for details. - -c, --container stringArray Specifies the injected container name. For example: mysql. If it's empty, the first container will be injected. - --dry-run string[="unchanged"] Must be "client", or "server". If with client strategy, only print the object that would be sent, and no data is actually sent. If with server strategy, submit the server-side request, but no data is persistent. (default "none") - --duration string Supported formats of the duration are: ms / s / m / h. (default "10s") - -h, --help help for time - --label stringToString label for pod, such as '"app.kubernetes.io/component=mysql, statefulset.kubernetes.io/pod-name=mycluster-mysql-0. (default []) - --mode string You can select "one", "all", "fixed", "fixed-percent", "random-max-percent", Specify the experimental mode, that is, which Pods to experiment with. (default "all") - --node stringArray Inject faults into pods in the specified node. - --node-label stringToString label for node, such as '"kubernetes.io/arch=arm64,kubernetes.io/hostname=minikube-m03,kubernetes.io/os=linux. (default []) - --ns-fault stringArray Specifies the namespace into which you want to inject faults. (default [default]) - -o, --output format Prints the output in the specified format. Allowed values: JSON and YAML (default yaml) - --phase stringArray Specify the pod that injects the fault by the state of the pod. - --time-offset string Specifies the length of the time offset. For example: -5s, -10m100ns. - --value string If you choose mode=fixed or fixed-percent or random-max-percent, you can enter a value to specify the number or percentage of pods you want to inject. -``` - -### Options inherited from parent commands - -``` - --as string Username to impersonate for the operation. User could be a regular user or a service account in a namespace. - --as-group stringArray Group to impersonate for the operation, this flag can be repeated to specify multiple groups. - --as-uid string UID to impersonate for the operation. - --cache-dir string Default cache directory (default "$HOME/.kube/cache") - --certificate-authority string Path to a cert file for the certificate authority - --client-certificate string Path to a client certificate file for TLS - --client-key string Path to a client key file for TLS - --cluster string The name of the kubeconfig cluster to use - --context string The name of the kubeconfig context to use - --disable-compression If true, opt-out of response compression for all requests to the server - --insecure-skip-tls-verify If true, the server's certificate will not be checked for validity. This will make your HTTPS connections insecure - --kubeconfig string Path to the kubeconfig file to use for CLI requests. - --match-server-version Require server version to match client version - -n, --namespace string If present, the namespace scope for this CLI request - --request-timeout string The length of time to wait before giving up on a single server request. Non-zero values should contain a corresponding time unit (e.g. 1s, 2m, 3h). A value of zero means don't timeout requests. (default "0") - -s, --server string The address and port of the Kubernetes API server - --tls-server-name string Server name to use for server certificate validation. If it is not provided, the hostname used to contact the server is used - --token string Bearer token for authentication to the API server - --user string The name of the kubeconfig user to use -``` - -### SEE ALSO - -* [kbcli fault](kbcli_fault.md) - Inject faults to pod. - -#### Go Back to [CLI Overview](cli.md) Homepage. - diff --git a/docs/user_docs/cli/kbcli_infra.md b/docs/user_docs/cli/kbcli_infra.md deleted file mode 100644 index a7934026e..000000000 --- a/docs/user_docs/cli/kbcli_infra.md +++ /dev/null @@ -1,44 +0,0 @@ ---- -title: kbcli infra ---- - -infra command - -### Options - -``` - -h, --help help for infra -``` - -### Options inherited from parent commands - -``` - --as string Username to impersonate for the operation. User could be a regular user or a service account in a namespace. - --as-group stringArray Group to impersonate for the operation, this flag can be repeated to specify multiple groups. - --as-uid string UID to impersonate for the operation. - --cache-dir string Default cache directory (default "$HOME/.kube/cache") - --certificate-authority string Path to a cert file for the certificate authority - --client-certificate string Path to a client certificate file for TLS - --client-key string Path to a client key file for TLS - --cluster string The name of the kubeconfig cluster to use - --context string The name of the kubeconfig context to use - --disable-compression If true, opt-out of response compression for all requests to the server - --insecure-skip-tls-verify If true, the server's certificate will not be checked for validity. This will make your HTTPS connections insecure - --kubeconfig string Path to the kubeconfig file to use for CLI requests. - --match-server-version Require server version to match client version - -n, --namespace string If present, the namespace scope for this CLI request - --request-timeout string The length of time to wait before giving up on a single server request. Non-zero values should contain a corresponding time unit (e.g. 1s, 2m, 3h). A value of zero means don't timeout requests. (default "0") - -s, --server string The address and port of the Kubernetes API server - --tls-server-name string Server name to use for server certificate validation. If it is not provided, the hostname used to contact the server is used - --token string Bearer token for authentication to the API server - --user string The name of the kubeconfig user to use -``` - -### SEE ALSO - - -* [kbcli infra create](kbcli_infra_create.md) - create kubernetes cluster. -* [kbcli infra delete](kbcli_infra_delete.md) - delete kubernetes cluster. - -#### Go Back to [CLI Overview](cli.md) Homepage. - diff --git a/docs/user_docs/cli/kbcli_infra_create.md b/docs/user_docs/cli/kbcli_infra_create.md deleted file mode 100644 index ea38d46ab..000000000 --- a/docs/user_docs/cli/kbcli_infra_create.md +++ /dev/null @@ -1,127 +0,0 @@ ---- -title: kbcli infra create ---- - -create kubernetes cluster. - -``` -kbcli infra create [flags] -``` - -### Examples - -``` - # Create kubernetes cluster with specified config yaml - kbcli infra create -c cluster.yaml - - # example cluster.yaml - cat cluster.yaml - metadata: - name: kb-k8s-test-cluster - user: - name: user1 - privateKeyPath: ~/.ssh/test.pem - nodes: - - name: kb-infra-node-0 - address: 1.1.1.1 - internalAddress: 10.128.0.19 - - name: kb-infra-node-1 - address: 1.1.1.2 - internalAddress: 10.128.0.20 - - name: kb-infra-node-2 - address: 1.1.1.3 - internalAddress: 10.128.0.21 - options: - hugePageFeature: - hugePageSize: 10GB - roleGroup: - etcd: - - kb-infra-node-0 - - kb-infra-node-1 - - kb-infra-node-2 - master: - - kb-infra-node-0 - worker: - - kb-infra-node-1 - - kb-infra-node-2 - - kubernetes: - containerManager: containerd - # apis/kubeadm/types.Networking - networking: - plugin: cilium - dnsDomain: cluster.local - podSubnet: 10.233.64.0/18 - serviceSubnet: 10.233.0.0/18 - controlPlaneEndpoint: - domain: lb.kubeblocks.local - port: 6443 - cri: - containerRuntimeType: "containerd" - containerRuntimeEndpoint: "unix:///run/containerd/containerd.sock" - sandBoxImage: "k8s.gcr.io/pause:3.8" - addons: - - name: openebs - namespace: kube-blocks - sources: - chart: - name: openebs - version: 3.7.0 - repo: https://openebs.github.io/charts - options: - values: - - "localprovisioner.basePath=/mnt/disks" - - "localprovisioner.hostpathClass.isDefaultClass=true" -``` - -### Options - -``` - -c, --config string Specify infra cluster config file. [option] - --container-runtime string Specify kubernetes container runtime. default is containerd (default "containerd") - --debug set debug mode - --etcd strings Specify etcd nodes - -h, --help help for create - --master strings Specify master nodes - --name string Specify kubernetes cluster name - --nodes strings List of machines on which kubernetes is installed. [require] - --output-kubeconfig string Specified output kubeconfig. [option] (default "$HOME/.kube/config") - -p, --password string Specify the password for the account to execute sudo. [option] - --private-key string The PrimaryKey for ssh to the remote machine. [option] - --private-key-path string Specify the file PrimaryKeyPath of ssh to the remote machine. default ~/.ssh/id_rsa. - --sandbox-image string Specified sandbox-image will not be used by the cri. [option] (default "k8s.gcr.io/pause:3.8") - -t, --timeout int Specify the ssh timeout.[option] (default 30) - -u, --user string Specify the account to access the remote server. [require] - --version string Specify install kubernetes version. default version is v1.26.5 (default "v1.26.5") - --worker strings Specify worker nodes -``` - -### Options inherited from parent commands - -``` - --as string Username to impersonate for the operation. User could be a regular user or a service account in a namespace. - --as-group stringArray Group to impersonate for the operation, this flag can be repeated to specify multiple groups. - --as-uid string UID to impersonate for the operation. - --cache-dir string Default cache directory (default "$HOME/.kube/cache") - --certificate-authority string Path to a cert file for the certificate authority - --client-certificate string Path to a client certificate file for TLS - --client-key string Path to a client key file for TLS - --cluster string The name of the kubeconfig cluster to use - --context string The name of the kubeconfig context to use - --disable-compression If true, opt-out of response compression for all requests to the server - --insecure-skip-tls-verify If true, the server's certificate will not be checked for validity. This will make your HTTPS connections insecure - --kubeconfig string Path to the kubeconfig file to use for CLI requests. - --match-server-version Require server version to match client version - -n, --namespace string If present, the namespace scope for this CLI request - --request-timeout string The length of time to wait before giving up on a single server request. Non-zero values should contain a corresponding time unit (e.g. 1s, 2m, 3h). A value of zero means don't timeout requests. (default "0") - -s, --server string The address and port of the Kubernetes API server - --tls-server-name string Server name to use for server certificate validation. If it is not provided, the hostname used to contact the server is used - --token string Bearer token for authentication to the API server -``` - -### SEE ALSO - -* [kbcli infra](kbcli_infra.md) - infra command - -#### Go Back to [CLI Overview](cli.md) Homepage. - diff --git a/docs/user_docs/cli/kbcli_infra_delete.md b/docs/user_docs/cli/kbcli_infra_delete.md deleted file mode 100644 index df0df7a78..000000000 --- a/docs/user_docs/cli/kbcli_infra_delete.md +++ /dev/null @@ -1,65 +0,0 @@ ---- -title: kbcli infra delete ---- - -delete kubernetes cluster. - -``` -kbcli infra delete [flags] -``` - -### Examples - -``` - # delete kubernetes cluster with specified config yaml - kbcli infra delete -c cluster.yaml -``` - -### Options - -``` - -c, --config string Specify infra cluster config file. [option] - --debug set debug mode - --delete-cri delete cri - --etcd strings Specify etcd nodes - -h, --help help for delete - --master strings Specify master nodes - --name string Specify kubernetes cluster name - --nodes strings List of machines on which kubernetes is installed. [require] - -p, --password string Specify the password for the account to execute sudo. [option] - --private-key string The PrimaryKey for ssh to the remote machine. [option] - --private-key-path string Specify the file PrimaryKeyPath of ssh to the remote machine. default ~/.ssh/id_rsa. - -t, --timeout int Specify the ssh timeout.[option] (default 30) - -u, --user string Specify the account to access the remote server. [require] - --worker strings Specify worker nodes -``` - -### Options inherited from parent commands - -``` - --as string Username to impersonate for the operation. User could be a regular user or a service account in a namespace. - --as-group stringArray Group to impersonate for the operation, this flag can be repeated to specify multiple groups. - --as-uid string UID to impersonate for the operation. - --cache-dir string Default cache directory (default "$HOME/.kube/cache") - --certificate-authority string Path to a cert file for the certificate authority - --client-certificate string Path to a client certificate file for TLS - --client-key string Path to a client key file for TLS - --cluster string The name of the kubeconfig cluster to use - --context string The name of the kubeconfig context to use - --disable-compression If true, opt-out of response compression for all requests to the server - --insecure-skip-tls-verify If true, the server's certificate will not be checked for validity. This will make your HTTPS connections insecure - --kubeconfig string Path to the kubeconfig file to use for CLI requests. - --match-server-version Require server version to match client version - -n, --namespace string If present, the namespace scope for this CLI request - --request-timeout string The length of time to wait before giving up on a single server request. Non-zero values should contain a corresponding time unit (e.g. 1s, 2m, 3h). A value of zero means don't timeout requests. (default "0") - -s, --server string The address and port of the Kubernetes API server - --tls-server-name string Server name to use for server certificate validation. If it is not provided, the hostname used to contact the server is used - --token string Bearer token for authentication to the API server -``` - -### SEE ALSO - -* [kbcli infra](kbcli_infra.md) - infra command - -#### Go Back to [CLI Overview](cli.md) Homepage. - diff --git a/docs/user_docs/cli/kbcli_kubeblocks_install.md b/docs/user_docs/cli/kbcli_kubeblocks_install.md index 7002d7c4b..704c34a0f 100644 --- a/docs/user_docs/cli/kbcli_kubeblocks_install.md +++ b/docs/user_docs/cli/kbcli_kubeblocks_install.md @@ -40,12 +40,13 @@ kbcli kubeblocks install [flags] --set-file stringArray Set values from respective files specified via the command line (can specify multiple or separate values with commas: key1=path1,key2=path2) --set-json stringArray Set JSON values on the command line (can specify multiple or separate values with commas: key1=jsonval1,key2=jsonval2) --set-string stringArray Set STRING values on the command line (can specify multiple or separate values with commas: key1=val1,key2=val2) - --timeout duration Time to wait for installing KubeBlocks, such as --timeout=10m (default 5m0s) + --timeout duration Time to wait for installing KubeBlocks, such as --timeout=10m (default 10m0s) --tolerations strings Tolerations for Kubeblocks, such as '"dev=true:NoSchedule,large=true:NoSchedule"' --topology-keys stringArray Topology keys for affinity -f, --values strings Specify values in a YAML file or a URL (can specify multiple) --version string KubeBlocks version --wait Wait for KubeBlocks to be ready, including all the auto installed add-ons. It will wait for a --timeout period (default true) + --wait-addons Wait for auto installed add-ons. It will wait for a --timeout period (default true) ``` ### Options inherited from parent commands diff --git a/docs/user_docs/cli/kbcli_kubeblocks_uninstall.md b/docs/user_docs/cli/kbcli_kubeblocks_uninstall.md index 737c267b7..b4e26c292 100644 --- a/docs/user_docs/cli/kbcli_kubeblocks_uninstall.md +++ b/docs/user_docs/cli/kbcli_kubeblocks_uninstall.md @@ -23,7 +23,7 @@ kbcli kubeblocks uninstall [flags] --remove-namespace Remove default created "kb-system" namespace or not --remove-pvcs Remove PersistentVolumeClaim or not --remove-pvs Remove PersistentVolume or not - --timeout duration Time to wait for uninstalling KubeBlocks, such as --timeout=5m (default 5m0s) + --timeout duration Time to wait for uninstalling KubeBlocks, such as --timeout=5m (default 10m0s) --wait Wait for KubeBlocks to be uninstalled, including all the add-ons. It will wait for a --timeout period (default true) ``` diff --git a/docs/user_docs/cli/kbcli_kubeblocks_upgrade.md b/docs/user_docs/cli/kbcli_kubeblocks_upgrade.md index ee9989f91..870ca1eb9 100644 --- a/docs/user_docs/cli/kbcli_kubeblocks_upgrade.md +++ b/docs/user_docs/cli/kbcli_kubeblocks_upgrade.md @@ -28,7 +28,7 @@ kbcli kubeblocks upgrade [flags] --set-file stringArray Set values from respective files specified via the command line (can specify multiple or separate values with commas: key1=path1,key2=path2) --set-json stringArray Set JSON values on the command line (can specify multiple or separate values with commas: key1=jsonval1,key2=jsonval2) --set-string stringArray Set STRING values on the command line (can specify multiple or separate values with commas: key1=val1,key2=val2) - --timeout duration Time to wait for upgrading KubeBlocks, such as --timeout=10m (default 5m0s) + --timeout duration Time to wait for upgrading KubeBlocks, such as --timeout=10m (default 10m0s) -f, --values strings Specify values in a YAML file or a URL (can specify multiple) --version string Set KubeBlocks version --wait Wait for KubeBlocks to be ready. It will wait for a --timeout period (default true) diff --git a/docs/user_docs/cli/kbcli_login.md b/docs/user_docs/cli/kbcli_login.md deleted file mode 100644 index 407acf5f7..000000000 --- a/docs/user_docs/cli/kbcli_login.md +++ /dev/null @@ -1,49 +0,0 @@ ---- -title: kbcli login ---- - -Authenticate with the KubeBlocks Cloud - -``` -kbcli login [flags] -``` - -### Options - -``` - -c, --context string Context name. - -h, --help help for login - --no-browser Do not open the browser for authentication. - -o, --org string Organization name. - -r, --region string Specify the region [jp] to log in. (default "jp") -``` - -### Options inherited from parent commands - -``` - --as string Username to impersonate for the operation. User could be a regular user or a service account in a namespace. - --as-group stringArray Group to impersonate for the operation, this flag can be repeated to specify multiple groups. - --as-uid string UID to impersonate for the operation. - --cache-dir string Default cache directory (default "$HOME/.kube/cache") - --certificate-authority string Path to a cert file for the certificate authority - --client-certificate string Path to a client certificate file for TLS - --client-key string Path to a client key file for TLS - --cluster string The name of the kubeconfig cluster to use - --disable-compression If true, opt-out of response compression for all requests to the server - --insecure-skip-tls-verify If true, the server's certificate will not be checked for validity. This will make your HTTPS connections insecure - --kubeconfig string Path to the kubeconfig file to use for CLI requests. - --match-server-version Require server version to match client version - -n, --namespace string If present, the namespace scope for this CLI request - --request-timeout string The length of time to wait before giving up on a single server request. Non-zero values should contain a corresponding time unit (e.g. 1s, 2m, 3h). A value of zero means don't timeout requests. (default "0") - -s, --server string The address and port of the Kubernetes API server - --tls-server-name string Server name to use for server certificate validation. If it is not provided, the hostname used to contact the server is used - --token string Bearer token for authentication to the API server - --user string The name of the kubeconfig user to use -``` - -### SEE ALSO - - - -#### Go Back to [CLI Overview](cli.md) Homepage. - diff --git a/docs/user_docs/cli/kbcli_logout.md b/docs/user_docs/cli/kbcli_logout.md deleted file mode 100644 index 416c15948..000000000 --- a/docs/user_docs/cli/kbcli_logout.md +++ /dev/null @@ -1,47 +0,0 @@ ---- -title: kbcli logout ---- - -Log out of the KubeBlocks Cloud - -``` -kbcli logout [flags] -``` - -### Options - -``` - -h, --help help for logout - -r, --region string Specify the region [jp] to log in. (default "jp") -``` - -### Options inherited from parent commands - -``` - --as string Username to impersonate for the operation. User could be a regular user or a service account in a namespace. - --as-group stringArray Group to impersonate for the operation, this flag can be repeated to specify multiple groups. - --as-uid string UID to impersonate for the operation. - --cache-dir string Default cache directory (default "$HOME/.kube/cache") - --certificate-authority string Path to a cert file for the certificate authority - --client-certificate string Path to a client certificate file for TLS - --client-key string Path to a client key file for TLS - --cluster string The name of the kubeconfig cluster to use - --context string The name of the kubeconfig context to use - --disable-compression If true, opt-out of response compression for all requests to the server - --insecure-skip-tls-verify If true, the server's certificate will not be checked for validity. This will make your HTTPS connections insecure - --kubeconfig string Path to the kubeconfig file to use for CLI requests. - --match-server-version Require server version to match client version - -n, --namespace string If present, the namespace scope for this CLI request - --request-timeout string The length of time to wait before giving up on a single server request. Non-zero values should contain a corresponding time unit (e.g. 1s, 2m, 3h). A value of zero means don't timeout requests. (default "0") - -s, --server string The address and port of the Kubernetes API server - --tls-server-name string Server name to use for server certificate validation. If it is not provided, the hostname used to contact the server is used - --token string Bearer token for authentication to the API server - --user string The name of the kubeconfig user to use -``` - -### SEE ALSO - - - -#### Go Back to [CLI Overview](cli.md) Homepage. - diff --git a/docs/user_docs/cli/kbcli_migration.md b/docs/user_docs/cli/kbcli_migration.md deleted file mode 100644 index 3cf6987d9..000000000 --- a/docs/user_docs/cli/kbcli_migration.md +++ /dev/null @@ -1,48 +0,0 @@ ---- -title: kbcli migration ---- - -Data migration between two data sources. - -### Options - -``` - -h, --help help for migration -``` - -### Options inherited from parent commands - -``` - --as string Username to impersonate for the operation. User could be a regular user or a service account in a namespace. - --as-group stringArray Group to impersonate for the operation, this flag can be repeated to specify multiple groups. - --as-uid string UID to impersonate for the operation. - --cache-dir string Default cache directory (default "$HOME/.kube/cache") - --certificate-authority string Path to a cert file for the certificate authority - --client-certificate string Path to a client certificate file for TLS - --client-key string Path to a client key file for TLS - --cluster string The name of the kubeconfig cluster to use - --context string The name of the kubeconfig context to use - --disable-compression If true, opt-out of response compression for all requests to the server - --insecure-skip-tls-verify If true, the server's certificate will not be checked for validity. This will make your HTTPS connections insecure - --kubeconfig string Path to the kubeconfig file to use for CLI requests. - --match-server-version Require server version to match client version - -n, --namespace string If present, the namespace scope for this CLI request - --request-timeout string The length of time to wait before giving up on a single server request. Non-zero values should contain a corresponding time unit (e.g. 1s, 2m, 3h). A value of zero means don't timeout requests. (default "0") - -s, --server string The address and port of the Kubernetes API server - --tls-server-name string Server name to use for server certificate validation. If it is not provided, the hostname used to contact the server is used - --token string Bearer token for authentication to the API server - --user string The name of the kubeconfig user to use -``` - -### SEE ALSO - - -* [kbcli migration create](kbcli_migration_create.md) - Create a migration task. -* [kbcli migration describe](kbcli_migration_describe.md) - Show details of a specific migration task. -* [kbcli migration list](kbcli_migration_list.md) - List migration tasks. -* [kbcli migration logs](kbcli_migration_logs.md) - Access migration task log file. -* [kbcli migration templates](kbcli_migration_templates.md) - List migration templates. -* [kbcli migration terminate](kbcli_migration_terminate.md) - Delete migration task. - -#### Go Back to [CLI Overview](cli.md) Homepage. - diff --git a/docs/user_docs/cli/kbcli_migration_create.md b/docs/user_docs/cli/kbcli_migration_create.md deleted file mode 100644 index e06fc2197..000000000 --- a/docs/user_docs/cli/kbcli_migration_create.md +++ /dev/null @@ -1,90 +0,0 @@ ---- -title: kbcli migration create ---- - -Create a migration task. - -``` -kbcli migration create NAME [flags] -``` - -### Examples - -``` - # Create a migration task to migrate the entire database under mysql: mydb1 and mytable1 under database: mydb2 to the target mysql - kbcli migration create mytask --template apecloud-mysql2mysql - --source user:123456@127.0.0.1:3306 - --sink user:123456@127.0.0.1:3305 - --migration-object '"mydb1","mydb2.mytable1"' - - # Create a migration task to migrate the schema: myschema under database: mydb1 under PostgreSQL to the target PostgreSQL - kbcli migration create mytask --template apecloud-pg2pg - --source user:123456@127.0.0.1:3306/mydb1 - --sink user:123456@127.0.0.1:3305/mydb1 - --migration-object '"myschema"' - - # Use prechecks, data initialization, CDC, but do not perform structure initialization - kbcli migration create mytask --template apecloud-pg2pg - --source user:123456@127.0.0.1:3306/mydb1 - --sink user:123456@127.0.0.1:3305/mydb1 - --migration-object '"myschema"' - --steps precheck=true,init-struct=false,init-data=true,cdc=true - - # Create a migration task with two tolerations - kbcli migration create mytask --template apecloud-pg2pg - --source user:123456@127.0.0.1:3306/mydb1 - --sink user:123456@127.0.0.1:3305/mydb1 - --migration-object '"myschema"' - --tolerations '"step=global,key=engineType,value=pg,operator=Equal,effect=NoSchedule","step=init-data,key=diskType,value=ssd,operator=Equal,effect=NoSchedule"' - - # Limit resource usage when performing data initialization - kbcli migration create mytask --template apecloud-pg2pg - --source user:123456@127.0.0.1:3306/mydb1 - --sink user:123456@127.0.0.1:3305/mydb1 - --migration-object '"myschema"' - --resources '"step=init-data,cpu=1000m,memory=1Gi"' -``` - -### Options - -``` - -h, --help help for create - --migration-object strings Set the data objects that need to be migrated,such as '"db1.table1","db2"' - --resources strings Resources limit for migration, such as '"cpu=3000m,memory=3Gi"' - --sink string Set the sink database information for migration.such as '{username}:{password}@{connection_address}:{connection_port}/[{database}] - --source string Set the source database information for migration.such as '{username}:{password}@{connection_address}:{connection_port}/[{database}]' - --steps strings Set up migration steps,such as: precheck=true,init-struct=true,init-data=true,cdc=true - --template string Specify migration template, run "kbcli migration templates" to show all available migration templates - --tolerations strings Tolerations for migration, such as '"key=engineType,value=pg,operator=Equal,effect=NoSchedule"' -``` - -### Options inherited from parent commands - -``` - --as string Username to impersonate for the operation. User could be a regular user or a service account in a namespace. - --as-group stringArray Group to impersonate for the operation, this flag can be repeated to specify multiple groups. - --as-uid string UID to impersonate for the operation. - --cache-dir string Default cache directory (default "$HOME/.kube/cache") - --certificate-authority string Path to a cert file for the certificate authority - --client-certificate string Path to a client certificate file for TLS - --client-key string Path to a client key file for TLS - --cluster string The name of the kubeconfig cluster to use - --context string The name of the kubeconfig context to use - --disable-compression If true, opt-out of response compression for all requests to the server - --insecure-skip-tls-verify If true, the server's certificate will not be checked for validity. This will make your HTTPS connections insecure - --kubeconfig string Path to the kubeconfig file to use for CLI requests. - --match-server-version Require server version to match client version - -n, --namespace string If present, the namespace scope for this CLI request - --request-timeout string The length of time to wait before giving up on a single server request. Non-zero values should contain a corresponding time unit (e.g. 1s, 2m, 3h). A value of zero means don't timeout requests. (default "0") - -s, --server string The address and port of the Kubernetes API server - --tls-server-name string Server name to use for server certificate validation. If it is not provided, the hostname used to contact the server is used - --token string Bearer token for authentication to the API server - --user string The name of the kubeconfig user to use -``` - -### SEE ALSO - -* [kbcli migration](kbcli_migration.md) - Data migration between two data sources. - -#### Go Back to [CLI Overview](cli.md) Homepage. - diff --git a/docs/user_docs/cli/kbcli_migration_describe.md b/docs/user_docs/cli/kbcli_migration_describe.md deleted file mode 100644 index 73432c7c0..000000000 --- a/docs/user_docs/cli/kbcli_migration_describe.md +++ /dev/null @@ -1,53 +0,0 @@ ---- -title: kbcli migration describe ---- - -Show details of a specific migration task. - -``` -kbcli migration describe NAME [flags] -``` - -### Examples - -``` - # describe a specified migration task - kbcli migration describe mytask -``` - -### Options - -``` - -h, --help help for describe -``` - -### Options inherited from parent commands - -``` - --as string Username to impersonate for the operation. User could be a regular user or a service account in a namespace. - --as-group stringArray Group to impersonate for the operation, this flag can be repeated to specify multiple groups. - --as-uid string UID to impersonate for the operation. - --cache-dir string Default cache directory (default "$HOME/.kube/cache") - --certificate-authority string Path to a cert file for the certificate authority - --client-certificate string Path to a client certificate file for TLS - --client-key string Path to a client key file for TLS - --cluster string The name of the kubeconfig cluster to use - --context string The name of the kubeconfig context to use - --disable-compression If true, opt-out of response compression for all requests to the server - --insecure-skip-tls-verify If true, the server's certificate will not be checked for validity. This will make your HTTPS connections insecure - --kubeconfig string Path to the kubeconfig file to use for CLI requests. - --match-server-version Require server version to match client version - -n, --namespace string If present, the namespace scope for this CLI request - --request-timeout string The length of time to wait before giving up on a single server request. Non-zero values should contain a corresponding time unit (e.g. 1s, 2m, 3h). A value of zero means don't timeout requests. (default "0") - -s, --server string The address and port of the Kubernetes API server - --tls-server-name string Server name to use for server certificate validation. If it is not provided, the hostname used to contact the server is used - --token string Bearer token for authentication to the API server - --user string The name of the kubeconfig user to use -``` - -### SEE ALSO - -* [kbcli migration](kbcli_migration.md) - Data migration between two data sources. - -#### Go Back to [CLI Overview](cli.md) Homepage. - diff --git a/docs/user_docs/cli/kbcli_migration_list.md b/docs/user_docs/cli/kbcli_migration_list.md deleted file mode 100644 index 62347f476..000000000 --- a/docs/user_docs/cli/kbcli_migration_list.md +++ /dev/null @@ -1,69 +0,0 @@ ---- -title: kbcli migration list ---- - -List migration tasks. - -``` -kbcli migration list [NAME] [flags] -``` - -### Examples - -``` - # list all migration tasks - kbcli migration list - - # list a single migration task with specified NAME - kbcli migration list mytask - - # list a single migration task in YAML output format - kbcli migration list mytask -o yaml - - # list a single migration task in JSON output format - kbcli migration list mytask -o json - - # list a single migration task in wide output format - kbcli migration list mytask -o wide -``` - -### Options - -``` - -A, --all-namespaces If present, list the requested object(s) across all namespaces. Namespace in current context is ignored even if specified with --namespace. - -h, --help help for list - -o, --output format prints the output in the specified format. Allowed values: table, json, yaml, wide (default table) - -l, --selector string Selector (label query) to filter on, supports '=', '==', and '!='.(e.g. -l key1=value1,key2=value2). Matching objects must satisfy all of the specified label constraints. - --show-labels When printing, show all labels as the last column (default hide labels column) -``` - -### Options inherited from parent commands - -``` - --as string Username to impersonate for the operation. User could be a regular user or a service account in a namespace. - --as-group stringArray Group to impersonate for the operation, this flag can be repeated to specify multiple groups. - --as-uid string UID to impersonate for the operation. - --cache-dir string Default cache directory (default "$HOME/.kube/cache") - --certificate-authority string Path to a cert file for the certificate authority - --client-certificate string Path to a client certificate file for TLS - --client-key string Path to a client key file for TLS - --cluster string The name of the kubeconfig cluster to use - --context string The name of the kubeconfig context to use - --disable-compression If true, opt-out of response compression for all requests to the server - --insecure-skip-tls-verify If true, the server's certificate will not be checked for validity. This will make your HTTPS connections insecure - --kubeconfig string Path to the kubeconfig file to use for CLI requests. - --match-server-version Require server version to match client version - -n, --namespace string If present, the namespace scope for this CLI request - --request-timeout string The length of time to wait before giving up on a single server request. Non-zero values should contain a corresponding time unit (e.g. 1s, 2m, 3h). A value of zero means don't timeout requests. (default "0") - -s, --server string The address and port of the Kubernetes API server - --tls-server-name string Server name to use for server certificate validation. If it is not provided, the hostname used to contact the server is used - --token string Bearer token for authentication to the API server - --user string The name of the kubeconfig user to use -``` - -### SEE ALSO - -* [kbcli migration](kbcli_migration.md) - Data migration between two data sources. - -#### Go Back to [CLI Overview](cli.md) Homepage. - diff --git a/docs/user_docs/cli/kbcli_migration_logs.md b/docs/user_docs/cli/kbcli_migration_logs.md deleted file mode 100644 index 2048907c9..000000000 --- a/docs/user_docs/cli/kbcli_migration_logs.md +++ /dev/null @@ -1,72 +0,0 @@ ---- -title: kbcli migration logs ---- - -Access migration task log file. - -``` -kbcli migration logs NAME [flags] -``` - -### Examples - -``` - # Logs when returning to the "init-struct" step from the migration task mytask - kbcli migration logs mytask --step init-struct - - # Logs only the most recent 20 lines when returning to the "cdc" step from the migration task mytask - kbcli migration logs mytask --step cdc --tail=20 -``` - -### Options - -``` - --all-containers Get all containers' logs in the pod(s). - -c, --container string Print the logs of this container - -f, --follow Specify if the logs should be streamed. - -h, --help help for logs - --ignore-errors If watching / following pod logs, allow for any errors that occur to be non-fatal - --insecure-skip-tls-verify-backend Skip verifying the identity of the kubelet that logs are requested from. In theory, an attacker could provide invalid log content back. You might want to use this if your kubelet serving certificates have expired. - --limit-bytes int Maximum bytes of logs to return. Defaults to no limit. - --max-log-requests int Specify maximum number of concurrent logs to follow when using by a selector. Defaults to 5. - --pod-running-timeout duration The length of time (like 5s, 2m, or 3h, higher than zero) to wait until at least one pod is running (default 20s) - --prefix Prefix each log line with the log source (pod name and container name) - -p, --previous If true, print the logs for the previous instance of the container in a pod if it exists. - -l, --selector string Selector (label query) to filter on, supports '=', '==', and '!='.(e.g. -l key1=value1,key2=value2). Matching objects must satisfy all of the specified label constraints. - --since duration Only return logs newer than a relative duration like 5s, 2m, or 3h. Defaults to all logs. Only one of since-time / since may be used. - --since-time string Only return logs after a specific date (RFC3339). Defaults to all logs. Only one of since-time / since may be used. - --step string Specify the step. Allow values: precheck,init-struct,init-data,cdc - --tail int Lines of recent log file to display. Defaults to -1 with no selector, showing all log lines otherwise 10, if a selector is provided. (default -1) - --timestamps Include timestamps on each line in the log output -``` - -### Options inherited from parent commands - -``` - --as string Username to impersonate for the operation. User could be a regular user or a service account in a namespace. - --as-group stringArray Group to impersonate for the operation, this flag can be repeated to specify multiple groups. - --as-uid string UID to impersonate for the operation. - --cache-dir string Default cache directory (default "$HOME/.kube/cache") - --certificate-authority string Path to a cert file for the certificate authority - --client-certificate string Path to a client certificate file for TLS - --client-key string Path to a client key file for TLS - --cluster string The name of the kubeconfig cluster to use - --context string The name of the kubeconfig context to use - --disable-compression If true, opt-out of response compression for all requests to the server - --insecure-skip-tls-verify If true, the server's certificate will not be checked for validity. This will make your HTTPS connections insecure - --kubeconfig string Path to the kubeconfig file to use for CLI requests. - --match-server-version Require server version to match client version - -n, --namespace string If present, the namespace scope for this CLI request - --request-timeout string The length of time to wait before giving up on a single server request. Non-zero values should contain a corresponding time unit (e.g. 1s, 2m, 3h). A value of zero means don't timeout requests. (default "0") - -s, --server string The address and port of the Kubernetes API server - --tls-server-name string Server name to use for server certificate validation. If it is not provided, the hostname used to contact the server is used - --token string Bearer token for authentication to the API server - --user string The name of the kubeconfig user to use -``` - -### SEE ALSO - -* [kbcli migration](kbcli_migration.md) - Data migration between two data sources. - -#### Go Back to [CLI Overview](cli.md) Homepage. - diff --git a/docs/user_docs/cli/kbcli_migration_templates.md b/docs/user_docs/cli/kbcli_migration_templates.md deleted file mode 100644 index cd25b2ee5..000000000 --- a/docs/user_docs/cli/kbcli_migration_templates.md +++ /dev/null @@ -1,69 +0,0 @@ ---- -title: kbcli migration templates ---- - -List migration templates. - -``` -kbcli migration templates [NAME] [flags] -``` - -### Examples - -``` - # list all migration templates - kbcli migration templates - - # list a single migration template with specified NAME - kbcli migration templates mytemplate - - # list a single migration template in YAML output format - kbcli migration templates mytemplate -o yaml - - # list a single migration template in JSON output format - kbcli migration templates mytemplate -o json - - # list a single migration template in wide output format - kbcli migration templates mytemplate -o wide -``` - -### Options - -``` - -A, --all-namespaces If present, list the requested object(s) across all namespaces. Namespace in current context is ignored even if specified with --namespace. - -h, --help help for templates - -o, --output format prints the output in the specified format. Allowed values: table, json, yaml, wide (default table) - -l, --selector string Selector (label query) to filter on, supports '=', '==', and '!='.(e.g. -l key1=value1,key2=value2). Matching objects must satisfy all of the specified label constraints. - --show-labels When printing, show all labels as the last column (default hide labels column) -``` - -### Options inherited from parent commands - -``` - --as string Username to impersonate for the operation. User could be a regular user or a service account in a namespace. - --as-group stringArray Group to impersonate for the operation, this flag can be repeated to specify multiple groups. - --as-uid string UID to impersonate for the operation. - --cache-dir string Default cache directory (default "$HOME/.kube/cache") - --certificate-authority string Path to a cert file for the certificate authority - --client-certificate string Path to a client certificate file for TLS - --client-key string Path to a client key file for TLS - --cluster string The name of the kubeconfig cluster to use - --context string The name of the kubeconfig context to use - --disable-compression If true, opt-out of response compression for all requests to the server - --insecure-skip-tls-verify If true, the server's certificate will not be checked for validity. This will make your HTTPS connections insecure - --kubeconfig string Path to the kubeconfig file to use for CLI requests. - --match-server-version Require server version to match client version - -n, --namespace string If present, the namespace scope for this CLI request - --request-timeout string The length of time to wait before giving up on a single server request. Non-zero values should contain a corresponding time unit (e.g. 1s, 2m, 3h). A value of zero means don't timeout requests. (default "0") - -s, --server string The address and port of the Kubernetes API server - --tls-server-name string Server name to use for server certificate validation. If it is not provided, the hostname used to contact the server is used - --token string Bearer token for authentication to the API server - --user string The name of the kubeconfig user to use -``` - -### SEE ALSO - -* [kbcli migration](kbcli_migration.md) - Data migration between two data sources. - -#### Go Back to [CLI Overview](cli.md) Homepage. - diff --git a/docs/user_docs/cli/kbcli_migration_terminate.md b/docs/user_docs/cli/kbcli_migration_terminate.md deleted file mode 100644 index bcec9fa01..000000000 --- a/docs/user_docs/cli/kbcli_migration_terminate.md +++ /dev/null @@ -1,59 +0,0 @@ ---- -title: kbcli migration terminate ---- - -Delete migration task. - -``` -kbcli migration terminate NAME [flags] -``` - -### Examples - -``` - # terminate a migration task named mytask and delete resources in k8s without affecting source and target data in database - kbcli migration terminate mytask -``` - -### Options - -``` - -A, --all-namespaces If present, list the requested object(s) across all namespaces. Namespace in current context is ignored even if specified with --namespace. - --auto-approve Skip interactive approval before deleting - --force If true, immediately remove resources from API and bypass graceful deletion. Note that immediate deletion of some resources may result in inconsistency or data loss and requires confirmation. - --grace-period int Period of time in seconds given to the resource to terminate gracefully. Ignored if negative. Set to 1 for immediate shutdown. Can only be set to 0 when --force is true (force deletion). (default -1) - -h, --help help for terminate - --now If true, resources are signaled for immediate shutdown (same as --grace-period=1). - -l, --selector string Selector (label query) to filter on, supports '=', '==', and '!='.(e.g. -l key1=value1,key2=value2). Matching objects must satisfy all of the specified label constraints. -``` - -### Options inherited from parent commands - -``` - --as string Username to impersonate for the operation. User could be a regular user or a service account in a namespace. - --as-group stringArray Group to impersonate for the operation, this flag can be repeated to specify multiple groups. - --as-uid string UID to impersonate for the operation. - --cache-dir string Default cache directory (default "$HOME/.kube/cache") - --certificate-authority string Path to a cert file for the certificate authority - --client-certificate string Path to a client certificate file for TLS - --client-key string Path to a client key file for TLS - --cluster string The name of the kubeconfig cluster to use - --context string The name of the kubeconfig context to use - --disable-compression If true, opt-out of response compression for all requests to the server - --insecure-skip-tls-verify If true, the server's certificate will not be checked for validity. This will make your HTTPS connections insecure - --kubeconfig string Path to the kubeconfig file to use for CLI requests. - --match-server-version Require server version to match client version - -n, --namespace string If present, the namespace scope for this CLI request - --request-timeout string The length of time to wait before giving up on a single server request. Non-zero values should contain a corresponding time unit (e.g. 1s, 2m, 3h). A value of zero means don't timeout requests. (default "0") - -s, --server string The address and port of the Kubernetes API server - --tls-server-name string Server name to use for server certificate validation. If it is not provided, the hostname used to contact the server is used - --token string Bearer token for authentication to the API server - --user string The name of the kubeconfig user to use -``` - -### SEE ALSO - -* [kbcli migration](kbcli_migration.md) - Data migration between two data sources. - -#### Go Back to [CLI Overview](cli.md) Homepage. - diff --git a/docs/user_docs/cli/kbcli_org.md b/docs/user_docs/cli/kbcli_org.md deleted file mode 100644 index 33f948d50..000000000 --- a/docs/user_docs/cli/kbcli_org.md +++ /dev/null @@ -1,59 +0,0 @@ ---- -title: kbcli org ---- - -kbcli org is used to manage cloud organizations and is only suitable for interacting with cloud. - -### Examples - -``` - // Get the organization name currently used by the user. - kbcli org current - // List all organizations the current user has joined. - kbcli org list - // Get the description information of organization org1. - kbcli org describe org1 - // Switch to organization org2. - kbcli org switch org2 -``` - -### Options - -``` - -h, --help help for org -``` - -### Options inherited from parent commands - -``` - --as string Username to impersonate for the operation. User could be a regular user or a service account in a namespace. - --as-group stringArray Group to impersonate for the operation, this flag can be repeated to specify multiple groups. - --as-uid string UID to impersonate for the operation. - --cache-dir string Default cache directory (default "$HOME/.kube/cache") - --certificate-authority string Path to a cert file for the certificate authority - --client-certificate string Path to a client certificate file for TLS - --client-key string Path to a client key file for TLS - --cluster string The name of the kubeconfig cluster to use - --context string The name of the kubeconfig context to use - --disable-compression If true, opt-out of response compression for all requests to the server - --insecure-skip-tls-verify If true, the server's certificate will not be checked for validity. This will make your HTTPS connections insecure - --kubeconfig string Path to the kubeconfig file to use for CLI requests. - --match-server-version Require server version to match client version - -n, --namespace string If present, the namespace scope for this CLI request - --request-timeout string The length of time to wait before giving up on a single server request. Non-zero values should contain a corresponding time unit (e.g. 1s, 2m, 3h). A value of zero means don't timeout requests. (default "0") - -s, --server string The address and port of the Kubernetes API server - --tls-server-name string Server name to use for server certificate validation. If it is not provided, the hostname used to contact the server is used - --token string Bearer token for authentication to the API server - --user string The name of the kubeconfig user to use -``` - -### SEE ALSO - - -* [kbcli org current](kbcli_org_current.md) - Get current organization. -* [kbcli org describe](kbcli_org_describe.md) - Get the description information of an organization. -* [kbcli org list](kbcli_org_list.md) - List all organizations you have joined. -* [kbcli org switch](kbcli_org_switch.md) - Switch to another organization you are already a member of. - -#### Go Back to [CLI Overview](cli.md) Homepage. - diff --git a/docs/user_docs/cli/kbcli_org_current.md b/docs/user_docs/cli/kbcli_org_current.md deleted file mode 100644 index e1ea6ab62..000000000 --- a/docs/user_docs/cli/kbcli_org_current.md +++ /dev/null @@ -1,46 +0,0 @@ ---- -title: kbcli org current ---- - -Get current organization. - -``` -kbcli org current [flags] -``` - -### Options - -``` - -h, --help help for current -``` - -### Options inherited from parent commands - -``` - --as string Username to impersonate for the operation. User could be a regular user or a service account in a namespace. - --as-group stringArray Group to impersonate for the operation, this flag can be repeated to specify multiple groups. - --as-uid string UID to impersonate for the operation. - --cache-dir string Default cache directory (default "$HOME/.kube/cache") - --certificate-authority string Path to a cert file for the certificate authority - --client-certificate string Path to a client certificate file for TLS - --client-key string Path to a client key file for TLS - --cluster string The name of the kubeconfig cluster to use - --context string The name of the kubeconfig context to use - --disable-compression If true, opt-out of response compression for all requests to the server - --insecure-skip-tls-verify If true, the server's certificate will not be checked for validity. This will make your HTTPS connections insecure - --kubeconfig string Path to the kubeconfig file to use for CLI requests. - --match-server-version Require server version to match client version - -n, --namespace string If present, the namespace scope for this CLI request - --request-timeout string The length of time to wait before giving up on a single server request. Non-zero values should contain a corresponding time unit (e.g. 1s, 2m, 3h). A value of zero means don't timeout requests. (default "0") - -s, --server string The address and port of the Kubernetes API server - --tls-server-name string Server name to use for server certificate validation. If it is not provided, the hostname used to contact the server is used - --token string Bearer token for authentication to the API server - --user string The name of the kubeconfig user to use -``` - -### SEE ALSO - -* [kbcli org](kbcli_org.md) - kbcli org is used to manage cloud organizations and is only suitable for interacting with cloud. - -#### Go Back to [CLI Overview](cli.md) Homepage. - diff --git a/docs/user_docs/cli/kbcli_org_describe.md b/docs/user_docs/cli/kbcli_org_describe.md deleted file mode 100644 index ceb90c561..000000000 --- a/docs/user_docs/cli/kbcli_org_describe.md +++ /dev/null @@ -1,47 +0,0 @@ ---- -title: kbcli org describe ---- - -Get the description information of an organization. - -``` -kbcli org describe [flags] -``` - -### Options - -``` - -h, --help help for describe - -o, --output string Output format (human|yaml|json) (default "human") -``` - -### Options inherited from parent commands - -``` - --as string Username to impersonate for the operation. User could be a regular user or a service account in a namespace. - --as-group stringArray Group to impersonate for the operation, this flag can be repeated to specify multiple groups. - --as-uid string UID to impersonate for the operation. - --cache-dir string Default cache directory (default "$HOME/.kube/cache") - --certificate-authority string Path to a cert file for the certificate authority - --client-certificate string Path to a client certificate file for TLS - --client-key string Path to a client key file for TLS - --cluster string The name of the kubeconfig cluster to use - --context string The name of the kubeconfig context to use - --disable-compression If true, opt-out of response compression for all requests to the server - --insecure-skip-tls-verify If true, the server's certificate will not be checked for validity. This will make your HTTPS connections insecure - --kubeconfig string Path to the kubeconfig file to use for CLI requests. - --match-server-version Require server version to match client version - -n, --namespace string If present, the namespace scope for this CLI request - --request-timeout string The length of time to wait before giving up on a single server request. Non-zero values should contain a corresponding time unit (e.g. 1s, 2m, 3h). A value of zero means don't timeout requests. (default "0") - -s, --server string The address and port of the Kubernetes API server - --tls-server-name string Server name to use for server certificate validation. If it is not provided, the hostname used to contact the server is used - --token string Bearer token for authentication to the API server - --user string The name of the kubeconfig user to use -``` - -### SEE ALSO - -* [kbcli org](kbcli_org.md) - kbcli org is used to manage cloud organizations and is only suitable for interacting with cloud. - -#### Go Back to [CLI Overview](cli.md) Homepage. - diff --git a/docs/user_docs/cli/kbcli_org_list.md b/docs/user_docs/cli/kbcli_org_list.md deleted file mode 100644 index b946e0996..000000000 --- a/docs/user_docs/cli/kbcli_org_list.md +++ /dev/null @@ -1,46 +0,0 @@ ---- -title: kbcli org list ---- - -List all organizations you have joined. - -``` -kbcli org list [flags] -``` - -### Options - -``` - -h, --help help for list -``` - -### Options inherited from parent commands - -``` - --as string Username to impersonate for the operation. User could be a regular user or a service account in a namespace. - --as-group stringArray Group to impersonate for the operation, this flag can be repeated to specify multiple groups. - --as-uid string UID to impersonate for the operation. - --cache-dir string Default cache directory (default "$HOME/.kube/cache") - --certificate-authority string Path to a cert file for the certificate authority - --client-certificate string Path to a client certificate file for TLS - --client-key string Path to a client key file for TLS - --cluster string The name of the kubeconfig cluster to use - --context string The name of the kubeconfig context to use - --disable-compression If true, opt-out of response compression for all requests to the server - --insecure-skip-tls-verify If true, the server's certificate will not be checked for validity. This will make your HTTPS connections insecure - --kubeconfig string Path to the kubeconfig file to use for CLI requests. - --match-server-version Require server version to match client version - -n, --namespace string If present, the namespace scope for this CLI request - --request-timeout string The length of time to wait before giving up on a single server request. Non-zero values should contain a corresponding time unit (e.g. 1s, 2m, 3h). A value of zero means don't timeout requests. (default "0") - -s, --server string The address and port of the Kubernetes API server - --tls-server-name string Server name to use for server certificate validation. If it is not provided, the hostname used to contact the server is used - --token string Bearer token for authentication to the API server - --user string The name of the kubeconfig user to use -``` - -### SEE ALSO - -* [kbcli org](kbcli_org.md) - kbcli org is used to manage cloud organizations and is only suitable for interacting with cloud. - -#### Go Back to [CLI Overview](cli.md) Homepage. - diff --git a/docs/user_docs/cli/kbcli_org_switch.md b/docs/user_docs/cli/kbcli_org_switch.md deleted file mode 100644 index 7827bdaf2..000000000 --- a/docs/user_docs/cli/kbcli_org_switch.md +++ /dev/null @@ -1,46 +0,0 @@ ---- -title: kbcli org switch ---- - -Switch to another organization you are already a member of. - -``` -kbcli org switch [flags] -``` - -### Options - -``` - -h, --help help for switch -``` - -### Options inherited from parent commands - -``` - --as string Username to impersonate for the operation. User could be a regular user or a service account in a namespace. - --as-group stringArray Group to impersonate for the operation, this flag can be repeated to specify multiple groups. - --as-uid string UID to impersonate for the operation. - --cache-dir string Default cache directory (default "$HOME/.kube/cache") - --certificate-authority string Path to a cert file for the certificate authority - --client-certificate string Path to a client certificate file for TLS - --client-key string Path to a client key file for TLS - --cluster string The name of the kubeconfig cluster to use - --context string The name of the kubeconfig context to use - --disable-compression If true, opt-out of response compression for all requests to the server - --insecure-skip-tls-verify If true, the server's certificate will not be checked for validity. This will make your HTTPS connections insecure - --kubeconfig string Path to the kubeconfig file to use for CLI requests. - --match-server-version Require server version to match client version - -n, --namespace string If present, the namespace scope for this CLI request - --request-timeout string The length of time to wait before giving up on a single server request. Non-zero values should contain a corresponding time unit (e.g. 1s, 2m, 3h). A value of zero means don't timeout requests. (default "0") - -s, --server string The address and port of the Kubernetes API server - --tls-server-name string Server name to use for server certificate validation. If it is not provided, the hostname used to contact the server is used - --token string Bearer token for authentication to the API server - --user string The name of the kubeconfig user to use -``` - -### SEE ALSO - -* [kbcli org](kbcli_org.md) - kbcli org is used to manage cloud organizations and is only suitable for interacting with cloud. - -#### Go Back to [CLI Overview](cli.md) Homepage. - diff --git a/docs/user_docs/cli/kbcli_playground_destroy.md b/docs/user_docs/cli/kbcli_playground_destroy.md index 99376396d..9f9f78d1b 100644 --- a/docs/user_docs/cli/kbcli_playground_destroy.md +++ b/docs/user_docs/cli/kbcli_playground_destroy.md @@ -21,7 +21,7 @@ kbcli playground destroy [flags] --auto-approve Skip interactive approval before destroying the playground -h, --help help for destroy --purge Purge all resources before destroying kubernetes cluster, delete all clusters created by KubeBlocks and uninstall KubeBlocks. (default true) - --timeout duration Time to wait for destroying KubeBlocks, such as --timeout=10m (default 5m0s) + --timeout duration Time to wait for destroying KubeBlocks, such as --timeout=10m (default 10m0s) ``` ### Options inherited from parent commands diff --git a/docs/user_docs/cli/kbcli_playground_init.md b/docs/user_docs/cli/kbcli_playground_init.md index cbd8664bf..fa1cad4e5 100644 --- a/docs/user_docs/cli/kbcli_playground_init.md +++ b/docs/user_docs/cli/kbcli_playground_init.md @@ -58,7 +58,7 @@ kbcli playground init [flags] --cluster-version string Specify the cluster version, run "kbcli cv list" to get the available cluster versions -h, --help help for init --region string The region to create kubernetes cluster - --timeout duration Time to wait for init playground, such as --timeout=10m (default 5m0s) + --timeout duration Time to wait for init playground, such as --timeout=10m (default 10m0s) --version string KubeBlocks version ``` diff --git a/docs/user_docs/cli/kbcli_report.md b/docs/user_docs/cli/kbcli_report.md index 9d669f60d..ca61eab7f 100644 --- a/docs/user_docs/cli/kbcli_report.md +++ b/docs/user_docs/cli/kbcli_report.md @@ -2,7 +2,7 @@ title: kbcli report --- -report kubeblocks or cluster info. +Report kubeblocks or cluster info. ### Options diff --git a/docs/user_docs/cli/kbcli_report_cluster.md b/docs/user_docs/cli/kbcli_report_cluster.md index a4ce972dd..2194d47b8 100644 --- a/docs/user_docs/cli/kbcli_report_cluster.md +++ b/docs/user_docs/cli/kbcli_report_cluster.md @@ -72,7 +72,7 @@ kbcli report cluster NAME [-f file] [-with-logs] [-mask] [flags] ### SEE ALSO -* [kbcli report](kbcli_report.md) - report kubeblocks or cluster info. +* [kbcli report](kbcli_report.md) - Report kubeblocks or cluster info. #### Go Back to [CLI Overview](cli.md) Homepage. diff --git a/docs/user_docs/cli/kbcli_report_kubeblocks.md b/docs/user_docs/cli/kbcli_report_kubeblocks.md index e78e30b17..14094b0c4 100644 --- a/docs/user_docs/cli/kbcli_report_kubeblocks.md +++ b/docs/user_docs/cli/kbcli_report_kubeblocks.md @@ -63,7 +63,7 @@ kbcli report kubeblocks [-f file] [--with-logs] [--mask] [flags] ### SEE ALSO -* [kbcli report](kbcli_report.md) - report kubeblocks or cluster info. +* [kbcli report](kbcli_report.md) - Report kubeblocks or cluster info. #### Go Back to [CLI Overview](cli.md) Homepage. diff --git a/go.mod b/go.mod index 1f263be7b..b30e4e219 100644 --- a/go.mod +++ b/go.mod @@ -3,13 +3,11 @@ module github.com/apecloud/kbcli go 1.21 require ( - cuelang.org/go v0.6.0 - github.com/99designs/keyring v1.2.2 + cuelang.org/go v0.8.0 github.com/Masterminds/semver/v3 v3.2.1 - github.com/apecloud/kubebench v0.0.0-20240313105909-ba8654f654fc - github.com/apecloud/kubeblocks v0.0.0-20240328092917-34c21903b27b + github.com/apecloud/kubebench v0.0.0-20240327101848-6a031d3f4ebe + github.com/apecloud/kubeblocks v0.9.0 github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 - github.com/benbjohnson/clock v1.3.5 github.com/briandowns/spinner v1.23.0 github.com/chaos-mesh/chaos-mesh/api v0.0.0-20230912020346-a5d89c1c90ad github.com/containerd/stargz-snapshotter/estargz v0.14.3 @@ -17,13 +15,11 @@ require ( github.com/docker/go-connections v0.4.1-0.20190612165340-fd1b1942c4d5 github.com/dustin/go-humanize v1.0.1 github.com/evanphx/json-patch v5.6.0+incompatible - github.com/fatih/color v1.15.0 + github.com/fatih/color v1.16.0 github.com/ghodss/yaml v1.0.0 github.com/go-git/go-git/v5 v5.6.1 - github.com/go-logr/logr v1.3.0 - github.com/golang-jwt/jwt v3.2.2+incompatible - github.com/google/uuid v1.3.1 - github.com/hashicorp/go-cleanhttp v0.5.2 + github.com/go-logr/logr v1.4.1 + github.com/google/uuid v1.6.0 github.com/hashicorp/go-version v1.6.0 github.com/hashicorp/hc-install v0.5.2 github.com/hashicorp/terraform-exec v0.18.0 @@ -33,10 +29,9 @@ require ( github.com/kubernetes-csi/external-snapshotter/client/v6 v6.2.0 github.com/leaanthony/debme v1.2.1 github.com/manifoldco/promptui v0.9.0 - github.com/mattn/go-isatty v0.0.19 github.com/mitchellh/mapstructure v1.5.1-0.20220423185008-bf980b35cac4 - github.com/onsi/ginkgo/v2 v2.13.0 - github.com/onsi/gomega v1.27.10 + github.com/onsi/ginkgo/v2 v2.14.0 + github.com/onsi/gomega v1.30.0 github.com/pkg/errors v0.9.1 github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 github.com/prometheus/alertmanager v0.26.0 @@ -47,43 +42,43 @@ require ( github.com/sethvargo/go-password v0.2.0 github.com/sirupsen/logrus v1.9.3 github.com/spf13/cast v1.5.1 - github.com/spf13/cobra v1.7.0 + github.com/spf13/cobra v1.8.0 github.com/spf13/pflag v1.0.5 github.com/spf13/viper v1.16.0 github.com/stoewer/go-strcase v1.2.0 github.com/stretchr/testify v1.8.4 github.com/xeipuuv/gojsonschema v1.2.0 go.uber.org/zap v1.26.0 - golang.org/x/crypto v0.17.0 - golang.org/x/exp v0.0.0-20230711153332-06a737ee72cb - golang.org/x/sync v0.3.0 + golang.org/x/crypto v0.21.0 + golang.org/x/exp v0.0.0-20240119083558-1b970713d09a + golang.org/x/sync v0.6.0 gopkg.in/yaml.v2 v2.4.0 helm.sh/helm/v3 v3.12.3 - k8s.io/api v0.28.2 - k8s.io/apiextensions-apiserver v0.28.1 - k8s.io/apimachinery v0.28.2 - k8s.io/cli-runtime v0.28.2 - k8s.io/client-go v0.28.2 - k8s.io/component-base v0.28.2 + k8s.io/api v0.29.0 + k8s.io/apiextensions-apiserver v0.29.0 + k8s.io/apimachinery v0.29.0 + k8s.io/cli-runtime v0.28.3 + k8s.io/client-go v12.0.0+incompatible + k8s.io/component-base v0.29.0 k8s.io/klog v1.0.0 - k8s.io/klog/v2 v2.100.1 - k8s.io/kube-openapi v0.0.0-20230918164632-68afd615200d + k8s.io/klog/v2 v2.110.1 + k8s.io/kube-openapi v0.0.0-20231010175941-2dd684a91f00 k8s.io/kubectl v0.28.2 - k8s.io/metrics v0.28.2 - k8s.io/utils v0.0.0-20230726121419-3b25d923346b - sigs.k8s.io/controller-runtime v0.15.2 + k8s.io/metrics v0.28.3 + k8s.io/utils v0.0.0-20231127182322-b307cd553661 + sigs.k8s.io/controller-runtime v0.17.2 sigs.k8s.io/kustomize/kyaml v0.14.3 - sigs.k8s.io/yaml v1.3.0 + sigs.k8s.io/yaml v1.4.0 ) require ( - cloud.google.com/go v0.110.7 // indirect - cloud.google.com/go/compute v1.23.0 // indirect + cloud.google.com/go v0.112.0 // indirect + cloud.google.com/go/compute v1.23.3 // indirect cloud.google.com/go/compute/metadata v0.2.3 // indirect - cloud.google.com/go/iam v1.1.1 // indirect - cloud.google.com/go/storage v1.30.1 // indirect + cloud.google.com/go/iam v1.1.5 // indirect + cloud.google.com/go/storage v1.36.0 // indirect + cuelabs.dev/go/oci/ociregistry v0.0.0-20240314152124-224736b49f2e // indirect dario.cat/mergo v1.0.0 // indirect - github.com/99designs/go-keychain v0.0.0-20191008050251-8e49817e8af4 // indirect github.com/AdaLogics/go-fuzz-headers v0.0.0-20230811130428-ced1acdcaa24 // indirect github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 // indirect github.com/BurntSushi/toml v1.3.2 // indirect @@ -99,7 +94,7 @@ require ( github.com/ahmetalpbalkan/go-cursor v0.0.0-20131010032410-8136607ea412 // indirect github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137 // indirect github.com/antlr/antlr4/runtime/Go/antlr/v4 v4.0.0-20230305170008-8188dc5388df // indirect - github.com/aws/aws-sdk-go v1.44.317 // indirect + github.com/aws/aws-sdk-go v1.50.8 // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d // indirect github.com/bhmj/jsonslice v1.1.2 // indirect @@ -111,7 +106,7 @@ require ( github.com/chzyer/readline v1.5.1 // indirect github.com/clbanning/mxj/v2 v2.5.7 // indirect github.com/cloudflare/circl v1.3.3 // indirect - github.com/cockroachdb/apd/v3 v3.2.0 // indirect + github.com/cockroachdb/apd/v3 v3.2.1 // indirect github.com/containerd/cgroups v1.1.0 // indirect github.com/containerd/containerd v1.7.11 // indirect github.com/containerd/log v0.1.0 // indirect @@ -121,9 +116,8 @@ require ( github.com/containers/storage v1.48.1 // indirect github.com/coreos/go-semver v0.3.1 // indirect github.com/coreos/go-systemd/v22 v22.5.0 // indirect - github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect + github.com/cpuguy83/go-md2man/v2 v2.0.3 // indirect github.com/cyphar/filepath-securejoin v0.2.4 // indirect - github.com/danieljoos/wincred v1.2.0 // indirect github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect github.com/daviddengcn/go-colortext v1.0.0 // indirect github.com/deckarep/golang-set/v2 v2.3.1 // indirect @@ -133,20 +127,19 @@ require ( github.com/dlclark/regexp2 v1.10.0 // indirect github.com/docker/cli v24.0.7+incompatible // indirect github.com/docker/distribution v2.8.2+incompatible // indirect - github.com/docker/docker v24.0.7+incompatible // indirect + github.com/docker/docker v24.0.9+incompatible // indirect github.com/docker/docker-credential-helpers v0.8.0 // indirect github.com/docker/go v1.5.1-1.0.20160303222718-d30aec9fd63c // indirect github.com/docker/go-metrics v0.0.1 // indirect github.com/docker/go-units v0.5.0 // indirect - github.com/dvsekhvalnov/jose2go v1.5.0 // indirect - github.com/emicklei/go-restful/v3 v3.10.2 // indirect + github.com/emicklei/go-restful/v3 v3.11.0 // indirect github.com/emicklei/proto v1.10.0 // indirect github.com/emirpasic/gods v1.18.1 // indirect - github.com/evanphx/json-patch/v5 v5.6.0 // indirect + github.com/evanphx/json-patch/v5 v5.8.0 // indirect github.com/exponent-io/jsonpath v0.0.0-20151013193312-d6023ce2651d // indirect github.com/fatih/camelcase v1.0.0 // indirect - github.com/felixge/httpsnoop v1.0.3 // indirect - github.com/fsnotify/fsnotify v1.6.0 // indirect + github.com/felixge/httpsnoop v1.0.4 // indirect + github.com/fsnotify/fsnotify v1.7.0 // indirect github.com/fvbommel/sortorder v1.1.0 // indirect github.com/go-errors/errors v1.4.2 // indirect github.com/go-git/gcfg v1.5.0 // indirect @@ -155,7 +148,7 @@ require ( github.com/go-kit/log v0.2.1 // indirect github.com/go-logfmt/logfmt v0.5.1 // indirect github.com/go-logr/stdr v1.2.2 // indirect - github.com/go-logr/zapr v1.2.4 // indirect + github.com/go-logr/zapr v1.3.0 // indirect github.com/go-ole/go-ole v1.2.6 // indirect github.com/go-openapi/jsonpointer v0.19.6 // indirect github.com/go-openapi/jsonreference v0.20.2 // indirect @@ -165,16 +158,15 @@ require ( github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 // indirect github.com/go-test/deep v1.1.0 // indirect github.com/gobwas/glob v0.2.3 // indirect - github.com/godbus/dbus v0.0.0-20190726142602-4481cbc300e2 // indirect github.com/godbus/dbus/v5 v5.1.0 // indirect github.com/gogo/protobuf v1.3.2 // indirect github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect github.com/golang/mock v1.6.0 // indirect - github.com/golang/protobuf v1.5.3 // indirect + github.com/golang/protobuf v1.5.4 // indirect github.com/golang/snappy v0.0.4 // indirect github.com/goodhosts/hostsfile v0.1.1 // indirect github.com/google/btree v1.1.2 // indirect - github.com/google/cel-go v0.16.0 // indirect + github.com/google/cel-go v0.17.7 // indirect github.com/google/certificate-transparency-go v1.1.5 // indirect github.com/google/gnostic-models v0.6.8 // indirect github.com/google/go-cmp v0.6.0 // indirect @@ -182,16 +174,16 @@ require ( github.com/google/go-intervals v0.0.2 // indirect github.com/google/gofuzz v1.2.0 // indirect github.com/google/pprof v0.0.0-20230323073829-e72429f035bd // indirect - github.com/google/s2a-go v0.1.4 // indirect + github.com/google/s2a-go v0.1.7 // indirect github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect - github.com/googleapis/enterprise-certificate-proxy v0.2.3 // indirect - github.com/googleapis/gax-go/v2 v2.11.0 // indirect + github.com/googleapis/enterprise-certificate-proxy v0.3.2 // indirect + github.com/googleapis/gax-go/v2 v2.12.0 // indirect github.com/gorilla/handlers v1.5.1 // indirect github.com/gorilla/mux v1.8.0 // indirect github.com/gosuri/uitable v0.0.4 // indirect github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7 // indirect - github.com/gsterjov/go-libsecret v0.0.0-20161001094733-a6f4afe4910c // indirect github.com/hashicorp/errwrap v1.1.0 // indirect + github.com/hashicorp/go-cleanhttp v0.5.2 // indirect github.com/hashicorp/go-getter v1.7.0 // indirect github.com/hashicorp/go-multierror v1.1.1 // indirect github.com/hashicorp/go-safetemp v1.0.0 // indirect @@ -202,7 +194,7 @@ require ( github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/jackc/pgpassfile v1.0.0 // indirect github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a // indirect - github.com/jackc/pgx/v5 v5.4.3 // indirect + github.com/jackc/pgx/v5 v5.5.4 // indirect github.com/jackc/puddle/v2 v2.2.1 // indirect github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect github.com/jmespath/go-jmespath v0.4.0 // indirect @@ -212,7 +204,7 @@ require ( github.com/jpillora/backoff v1.0.0 // indirect github.com/json-iterator/go v1.1.12 // indirect github.com/kevinburke/ssh_config v1.2.0 // indirect - github.com/klauspost/compress v1.16.6 // indirect + github.com/klauspost/compress v1.17.6 // indirect github.com/klauspost/pgzip v1.2.6 // indirect github.com/lann/builder v0.0.0-20180802200727-47ae307949d0 // indirect github.com/lann/ps v0.0.0-20150810152359-62de8c46ede0 // indirect @@ -224,9 +216,9 @@ require ( github.com/magiconair/properties v1.8.7 // indirect github.com/mailru/easyjson v0.7.7 // indirect github.com/mattn/go-colorable v0.1.13 // indirect - github.com/mattn/go-runewidth v0.0.14 // indirect + github.com/mattn/go-isatty v0.0.20 // indirect + github.com/mattn/go-runewidth v0.0.15 // indirect github.com/mattn/go-shellwords v1.0.12 // indirect - github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0 // indirect github.com/miekg/pkcs11 v1.1.1 // indirect github.com/mistifyio/go-zfs/v3 v3.0.1 // indirect github.com/mitchellh/copystructure v1.2.0 // indirect @@ -245,14 +237,12 @@ require ( github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00 // indirect github.com/montanaflynn/stats v0.6.6 // indirect github.com/morikuni/aec v1.0.0 // indirect - github.com/mpvl/unique v0.0.0-20150818121801-cbe035fff7de // indirect - github.com/mtibben/percent v0.2.1 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f // indirect github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f // indirect github.com/nsf/termbox-go v0.0.0-20190121233118-02980233997d // indirect github.com/opencontainers/go-digest v1.0.0 // indirect - github.com/opencontainers/image-spec v1.1.0-rc5 // indirect + github.com/opencontainers/image-spec v1.1.0 // indirect github.com/opencontainers/runc v1.1.7 // indirect github.com/opencontainers/runtime-spec v1.1.0-rc.3 // indirect github.com/opencontainers/selinux v1.11.0 // indirect @@ -261,16 +251,17 @@ require ( github.com/peterbourgon/diskv v2.0.1+incompatible // indirect github.com/pjbgf/sha1cd v0.3.0 // indirect github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c // indirect - github.com/prometheus/client_golang v1.18.0 // indirect + github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring v0.71.0 // indirect + github.com/prometheus/client_golang v1.19.0 // indirect github.com/prometheus/client_model v0.5.0 // indirect - github.com/prometheus/common v0.45.0 // indirect + github.com/prometheus/common v0.48.0 // indirect github.com/prometheus/common/sigv4 v0.1.0 // indirect github.com/prometheus/procfs v0.12.0 // indirect github.com/protocolbuffers/txtpbfmt v0.0.0-20230328191034-3462fbc510c0 // indirect github.com/rancher/wharfie v0.6.2 // indirect github.com/redis/go-redis/v9 v9.4.0 // indirect - github.com/rivo/uniseg v0.4.4 // indirect - github.com/rogpeppe/go-internal v1.10.0 // indirect + github.com/rivo/uniseg v0.4.6 // indirect + github.com/rogpeppe/go-internal v1.12.0 // indirect github.com/rubenv/sql-migrate v1.3.1 // indirect github.com/russross/blackfriday/v2 v2.1.0 // indirect github.com/segmentio/ksuid v1.0.4 // indirect @@ -302,47 +293,48 @@ require ( github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d // indirect github.com/yusufpapurcu/wmi v1.2.3 // indirect github.com/zclconf/go-cty v1.12.1 // indirect - go.etcd.io/etcd/api/v3 v3.5.9 // indirect - go.etcd.io/etcd/client/pkg/v3 v3.5.9 // indirect - go.etcd.io/etcd/client/v3 v3.5.9 // indirect + go.etcd.io/etcd/api/v3 v3.5.10 // indirect + go.etcd.io/etcd/client/pkg/v3 v3.5.10 // indirect + go.etcd.io/etcd/client/v3 v3.5.10 // indirect go.mongodb.org/mongo-driver v1.13.1 // indirect go.opencensus.io v0.24.0 // indirect - go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.45.0 // indirect - go.opentelemetry.io/otel v1.20.0 // indirect - go.opentelemetry.io/otel/metric v1.20.0 // indirect - go.opentelemetry.io/otel/trace v1.20.0 // indirect + go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.47.0 // indirect + go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.47.0 // indirect + go.opentelemetry.io/otel v1.22.0 // indirect + go.opentelemetry.io/otel/metric v1.22.0 // indirect + go.opentelemetry.io/otel/trace v1.22.0 // indirect go.starlark.net v0.0.0-20230525235612-a134d8f9ddca // indirect go.uber.org/multierr v1.11.0 // indirect go4.org/netipx v0.0.0-20230728184502-ec4c8b891b28 // indirect - golang.org/x/mod v0.12.0 // indirect - golang.org/x/net v0.17.0 // indirect - golang.org/x/oauth2 v0.12.0 // indirect - golang.org/x/sys v0.15.0 // indirect - golang.org/x/term v0.15.0 // indirect + golang.org/x/mod v0.16.0 // indirect + golang.org/x/net v0.23.0 // indirect + golang.org/x/oauth2 v0.18.0 // indirect + golang.org/x/sys v0.18.0 // indirect + golang.org/x/term v0.18.0 // indirect golang.org/x/text v0.14.0 // indirect - golang.org/x/time v0.3.0 // indirect - golang.org/x/tools v0.12.0 // indirect - golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect - gomodules.xyz/jsonpatch/v2 v2.3.0 // indirect - google.golang.org/api v0.126.0 // indirect - google.golang.org/appengine v1.6.7 // indirect - google.golang.org/genproto v0.0.0-20230822172742-b8732ec3820d // indirect - google.golang.org/genproto/googleapis/api v0.0.0-20230822172742-b8732ec3820d // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20230822172742-b8732ec3820d // indirect - google.golang.org/grpc v1.59.0 // indirect - google.golang.org/protobuf v1.31.0 // indirect + golang.org/x/time v0.5.0 // indirect + golang.org/x/tools v0.19.0 // indirect + gomodules.xyz/jsonpatch/v2 v2.4.0 // indirect + google.golang.org/api v0.161.0 // indirect + google.golang.org/appengine v1.6.8 // indirect + google.golang.org/genproto v0.0.0-20240125205218-1f4bbc51befe // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20240125205218-1f4bbc51befe // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20240125205218-1f4bbc51befe // indirect + google.golang.org/grpc v1.61.0 // indirect + google.golang.org/protobuf v1.33.0 // indirect gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/ini.v1 v1.67.0 // indirect gopkg.in/warnings.v0 v0.1.2 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect - k8s.io/apiserver v0.28.1 // indirect - k8s.io/component-helpers v0.28.2 // indirect + k8s.io/apiserver v0.29.0 // indirect + k8s.io/component-helpers v0.28.3 // indirect + k8s.io/kubernetes v1.28.3 // indirect oras.land/oras-go v1.2.4 // indirect periph.io/x/host/v3 v3.8.0 // indirect sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect sigs.k8s.io/kustomize/api v0.13.5-0.20230601165947-6ce0bf390ce3 // indirect sigs.k8s.io/kustomize/kustomize/v5 v5.0.4-0.20230601165947-6ce0bf390ce3 // indirect - sigs.k8s.io/structured-merge-diff/v4 v4.2.3 // indirect + sigs.k8s.io/structured-merge-diff/v4 v4.4.1 // indirect ) replace ( @@ -351,3 +343,37 @@ replace ( github.com/docker/docker => github.com/moby/moby v24.0.7+incompatible github.com/spf13/afero => github.com/spf13/afero v1.2.2 ) + +replace ( + golang.org/x/exp => golang.org/x/exp v0.0.0-20230711153332-06a737ee72cb + k8s.io/api => k8s.io/api v0.28.3 + k8s.io/apiextensions-apiserver => k8s.io/apiextensions-apiserver v0.28.3 + k8s.io/apimachinery => k8s.io/apimachinery v0.28.3 + k8s.io/apiserver => k8s.io/apiserver v0.28.3 + k8s.io/cli-runtime => k8s.io/cli-runtime v0.28.3 + k8s.io/client-go => k8s.io/client-go v0.28.3 + k8s.io/cloud-provider => k8s.io/cloud-provider v0.28.3 + k8s.io/cluster-bootstrap => k8s.io/cluster-bootstrap v0.28.3 + k8s.io/code-generator => k8s.io/code-generator v0.28.3 + k8s.io/component-base => k8s.io/component-base v0.29.0 + k8s.io/component-helpers => k8s.io/component-helpers v0.28.3 + k8s.io/controller-manager => k8s.io/controller-manager v0.28.3 + k8s.io/cri-api => k8s.io/cri-api v0.28.3 + k8s.io/csi-translation-lib => k8s.io/csi-translation-lib v0.28.3 + k8s.io/dynamic-resource-allocation => k8s.io/dynamic-resource-allocation v0.28.3 + k8s.io/endpointslice => k8s.io/endpointslice v0.28.3 + k8s.io/kms => k8s.io/kms v0.28.3 + k8s.io/kube-aggregator => k8s.io/kube-aggregator v0.28.3 + k8s.io/kube-controller-manager => k8s.io/kube-controller-manager v0.28.3 + k8s.io/kube-proxy => k8s.io/kube-proxy v0.28.3 + k8s.io/kube-scheduler => k8s.io/kube-scheduler v0.28.3 + k8s.io/kubectl => k8s.io/kubectl v0.28.3 + k8s.io/kubelet => k8s.io/kubelet v0.28.3 + k8s.io/legacy-cloud-providers => k8s.io/legacy-cloud-providers v0.28.3 + k8s.io/metrics => k8s.io/metrics v0.28.3 + k8s.io/mount-utils => k8s.io/mount-utils v0.28.3 + k8s.io/pod-security-admission => k8s.io/pod-security-admission v0.28.3 + k8s.io/sample-apiserver => k8s.io/sample-apiserver v0.28.3 + k8s.io/sample-cli-plugin => k8s.io/sample-cli-plugin v0.28.3 + k8s.io/sample-controller => k8s.io/sample-controller v0.28.3 +) diff --git a/go.sum b/go.sum index 57a37c6be..0e4ba50df 100644 --- a/go.sum +++ b/go.sum @@ -6,7 +6,6 @@ cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxK 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 v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To= -cloud.google.com/go v0.51.0/go.mod h1:hWtGJ6gnXH+KgDv+V0zFGDvpi07n3z8ZNj3T1RW0Gcw= cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4= cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M= cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc= @@ -31,8 +30,8 @@ cloud.google.com/go v0.100.2/go.mod h1:4Xra9TjzAeYHrl5+oeLlzbM2k3mjVhZh4UqTZ//w9 cloud.google.com/go v0.102.0/go.mod h1:oWcCzKlqJ5zgHQt9YsaeTY9KzIvjyy0ArmiBUgpQ+nc= cloud.google.com/go v0.102.1/go.mod h1:XZ77E9qnTEnrgEOvr4xzfdX5TRo7fB4T2F4O6+34hIU= cloud.google.com/go v0.104.0/go.mod h1:OO6xxXdJyvuJPcEPBLN9BJPD+jep5G1+2U5B5gkRYtA= -cloud.google.com/go v0.110.7 h1:rJyC7nWRg2jWGZ4wSJ5nY65GTdYJkg0cd/uXb+ACI6o= -cloud.google.com/go v0.110.7/go.mod h1:+EYjdK8e5RME/VY/qLCAtuyALQ9q67dvuum8i+H5xsI= +cloud.google.com/go v0.112.0 h1:tpFCD7hpHFlQ8yPwT3x+QeXqc2T6+n6T+hmABHfDUSM= +cloud.google.com/go v0.112.0/go.mod h1:3jEEVwZ/MHU4djK5t5RHuKOA/GbLddgTdVubX1qnPD4= cloud.google.com/go/aiplatform v1.22.0/go.mod h1:ig5Nct50bZlzV6NvKaTwmplLLddFx0YReh9WfTO5jKw= cloud.google.com/go/aiplatform v1.24.0/go.mod h1:67UUvRBKG6GTayHKV8DBv2RtR1t93YRu5B1P3x99mYY= cloud.google.com/go/analytics v0.11.0/go.mod h1:DjEWCu41bVbYcKyvlws9Er60YE4a//bK6mnhWvQeFNI= @@ -69,8 +68,9 @@ cloud.google.com/go/compute v1.6.0/go.mod h1:T29tfhtVbq1wvAPo0E3+7vhgmkOYeXjhFvz cloud.google.com/go/compute v1.6.1/go.mod h1:g85FgpzFvNULZ+S8AYq87axRKuf2Kh7deLqV/jJ3thU= cloud.google.com/go/compute v1.7.0/go.mod h1:435lt8av5oL9P3fv1OEzSbSUe+ybHXGMPQHHZWZxy9U= cloud.google.com/go/compute v1.10.0/go.mod h1:ER5CLbMxl90o2jtNbGSbtfOpQKR0t15FOtRsugnLrlU= -cloud.google.com/go/compute v1.23.0 h1:tP41Zoavr8ptEqaW6j+LQOnyBBhO7OkOMAGrgLopTwY= -cloud.google.com/go/compute v1.23.0/go.mod h1:4tCnrn48xsqlwSAiLf1HXMQk8CONslYbdiEZc9FEIbM= +cloud.google.com/go/compute v1.23.3 h1:6sVlXXBmbd7jNX0Ipq0trII3e4n1/MsADLK6a+aiVlk= +cloud.google.com/go/compute v1.23.3/go.mod h1:VCgBUoMnIVIR0CscqQiPJLAG25E3ZRZMzcFZeQ+h8CI= +cloud.google.com/go/compute/metadata v0.2.0/go.mod h1:zFmK7XCadkQkj6TtorcaGlCW1hT1fIilQDwofLpJ20k= cloud.google.com/go/compute/metadata v0.2.3 h1:mg4jlk7mCAj6xXp9UJ4fjI9VUI5rubuGBW5aJ7UnBMY= cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA= cloud.google.com/go/containeranalysis v0.5.1/go.mod h1:1D92jd8gRR/c0fGMlymRgxWD3Qw9C1ff6/T7mLgVL8I= @@ -111,8 +111,8 @@ cloud.google.com/go/gkehub v0.10.0/go.mod h1:UIPwxI0DsrpsVoWpLB0stwKCP+WFVG9+y97 cloud.google.com/go/grafeas v0.2.0/go.mod h1:KhxgtF2hb0P191HlY5besjYm6MqTSTj3LSI+M+ByZHc= cloud.google.com/go/iam v0.3.0/go.mod h1:XzJPvDayI+9zsASAFO68Hk07u3z+f+JrT2xXNdp4bnY= cloud.google.com/go/iam v0.5.0/go.mod h1:wPU9Vt0P4UmCux7mqtRu6jcpPAb74cP1fh50J3QpkUc= -cloud.google.com/go/iam v1.1.1 h1:lW7fzj15aVIXYHREOqjRBV9PsH0Z6u8Y46a1YGvQP4Y= -cloud.google.com/go/iam v1.1.1/go.mod h1:A5avdyVL2tCppe4unb0951eI9jreack+RJ0/d+KUZOU= +cloud.google.com/go/iam v1.1.5 h1:1jTsCu4bcsNsE4iiqNT5SHwrDRCfRmIaaaVFhRveTJI= +cloud.google.com/go/iam v1.1.5/go.mod h1:rB6P/Ic3mykPbFio+vo7403drjlgvoWfYpJhMXEbzv8= cloud.google.com/go/language v1.4.0/go.mod h1:F9dRpNFQmJbkaop6g0JhSBXCNlO90e1KWx5iDdxbWic= cloud.google.com/go/language v1.6.0/go.mod h1:6dJ8t3B+lUYfStgls25GusK04NLh3eDLQnWM3mdEbhI= cloud.google.com/go/lifesciences v0.5.0/go.mod h1:3oIKy8ycWGPUyZDR/8RNnTOYevhaMLqh5vLUXs9zvT8= @@ -173,8 +173,8 @@ cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9 cloud.google.com/go/storage v1.22.1/go.mod h1:S8N1cAStu7BOeFfE8KAQzmyyLkK8p/vmRq6kuBTW58Y= cloud.google.com/go/storage v1.23.0/go.mod h1:vOEEDNFnciUMhBeT6hsJIn3ieU5cFRmzeLgDvXzfIXc= cloud.google.com/go/storage v1.27.0/go.mod h1:x9DOL8TK/ygDUMieqwfhdpQryTeEkhGKMi80i/iqR2s= -cloud.google.com/go/storage v1.30.1 h1:uOdMxAs8HExqBlnLtnQyP0YkvbiDpdGShGKtx6U/oNM= -cloud.google.com/go/storage v1.30.1/go.mod h1:NfxhC0UJE1aXSx7CIIbCf7y9HKT7BiccwkR7+P7gN8E= +cloud.google.com/go/storage v1.36.0 h1:P0mOkAcaJxhCTvAkMhxMfrTKiNcub4YmmPBtlhAyTr8= +cloud.google.com/go/storage v1.36.0/go.mod h1:M6M/3V/D3KpzMTJyPOR/HU6n2Si5QdaXYEsng2xgOs8= cloud.google.com/go/talent v1.1.0/go.mod h1:Vl4pt9jiHKvOgF9KoZo6Kob9oV4lwd/ZD5Cto54zDRw= cloud.google.com/go/talent v1.2.0/go.mod h1:MoNF9bhFQbiJ6eFD3uSsg0uBALw4n4gaCaEjBw9zo8g= cloud.google.com/go/videointelligence v1.6.0/go.mod h1:w0DIDlVRKtwPCn/C4iwZIJdvC69yInhW0cfi+p546uU= @@ -186,37 +186,22 @@ cloud.google.com/go/webrisk v1.4.0/go.mod h1:Hn8X6Zr+ziE2aNd8SliSDWpEnSS1u4R9+xX cloud.google.com/go/webrisk v1.5.0/go.mod h1:iPG6fr52Tv7sGk0H6qUFzmL3HHZev1htXuWDEEsqMTg= cloud.google.com/go/workflows v1.6.0/go.mod h1:6t9F5h/unJz41YqfBmqSASJSXccBLtD1Vwf+KmJENM0= cloud.google.com/go/workflows v1.7.0/go.mod h1:JhSrZuVZWuiDfKEFxU0/F1PQjmpnpcoISEXH2bcHC3M= -cuelang.org/go v0.6.0 h1:dJhgKCog+FEZt7OwAYV1R+o/RZPmE8aqFoptmxSWyr8= -cuelang.org/go v0.6.0/go.mod h1:9CxOX8aawrr3BgSdqPj7V0RYoXo7XIb+yDFC6uESrOQ= +cuelabs.dev/go/oci/ociregistry v0.0.0-20240314152124-224736b49f2e h1:GwCVItFUPxwdsEYnlUcJ6PJxOjTeFFCKOh6QWg4oAzQ= +cuelabs.dev/go/oci/ociregistry v0.0.0-20240314152124-224736b49f2e/go.mod h1:ApHceQLLwcOkCEXM1+DyCXTHEJhNGDpJ2kmV6axsx24= +cuelang.org/go v0.8.0 h1:fO1XPe/SUGtc7dhnGnTPbpIDoQm/XxhDtoSF7jzO01c= +cuelang.org/go v0.8.0/go.mod h1:CoDbYolfMms4BhWUlhD+t5ORnihR7wvjcfgyO9lL5FI= dario.cat/mergo v1.0.0 h1:AGCNq9Evsj31mOgNPcLyXc+4PNABt905YmuqPYYpBWk= dario.cat/mergo v1.0.0/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk= -dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= github.com/14rcole/gopopulate v0.0.0-20180821133914-b175b219e774 h1:SCbEWT58NSt7d2mcFdvxC9uyrdcTfvBbPLThhkDmXzg= github.com/14rcole/gopopulate v0.0.0-20180821133914-b175b219e774/go.mod h1:6/0dYRLLXyJjbkIPeeGyoJ/eKOSI0eU6eTlCBYibgd0= -github.com/99designs/go-keychain v0.0.0-20191008050251-8e49817e8af4 h1:/vQbFIOMbk2FiG/kXiLl8BRyzTWDw7gX/Hz7Dd5eDMs= -github.com/99designs/go-keychain v0.0.0-20191008050251-8e49817e8af4/go.mod h1:hN7oaIRCjzsZ2dE+yG5k+rsdt3qcwykqK6HVGcKwsw4= -github.com/99designs/keyring v1.2.2 h1:pZd3neh/EmUzWONb35LxQfvuY7kiSXAq3HQd97+XBn0= -github.com/99designs/keyring v1.2.2/go.mod h1:wes/FrByc8j7lFOAGLGSNEg8f/PaI3cgTBqhFkHUrPk= github.com/AdaLogics/go-fuzz-headers v0.0.0-20230811130428-ced1acdcaa24 h1:bvDV9vkmnHYOMsOr4WLk+Vo07yKIzd94sVoIqshQ4bU= github.com/AdaLogics/go-fuzz-headers v0.0.0-20230811130428-ced1acdcaa24/go.mod h1:8o94RPi1/7XTJvwPpRSzSUedZrtlirdB3r9Z20bi2f8= github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 h1:L/gRVlceqvL25UVaW/CKtUDjefjrs0SPonmDGUVOYP0= github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= -github.com/Azure/go-autorest/autorest v0.9.0/go.mod h1:xyHB1BMZT0cuDHU7I0+g046+BFDTQ8rEZB0s4Yfa6bI= -github.com/Azure/go-autorest/autorest v0.9.6/go.mod h1:/FALq9T/kS7b5J5qsQ+RSTUdAmGFqi0vUdVNNx8q630= -github.com/Azure/go-autorest/autorest/adal v0.5.0/go.mod h1:8Z9fGy2MpX0PvDjB1pEgQTmVqjGhiHBW7RJJEciWzS0= -github.com/Azure/go-autorest/autorest/adal v0.8.2/go.mod h1:ZjhuQClTqx435SRJ2iMlOxPYt3d2C/T/7TiQCVZSn3Q= -github.com/Azure/go-autorest/autorest/date v0.1.0/go.mod h1:plvfp3oPSKwf2DNjlBjWF/7vwR+cUD/ELuzDCXwHUVA= -github.com/Azure/go-autorest/autorest/date v0.2.0/go.mod h1:vcORJHLJEh643/Ioh9+vPmf1Ij9AEBM5FuBIXLmIy0g= -github.com/Azure/go-autorest/autorest/mocks v0.1.0/go.mod h1:OTyCOPRA2IgIlWxVYxBee2F5Gr4kF2zd2J5cFRaIDN0= -github.com/Azure/go-autorest/autorest/mocks v0.2.0/go.mod h1:OTyCOPRA2IgIlWxVYxBee2F5Gr4kF2zd2J5cFRaIDN0= -github.com/Azure/go-autorest/autorest/mocks v0.3.0/go.mod h1:a8FDP3DYzQ4RYfVAxAN3SVSiiO77gL2j2ronKKP0syM= -github.com/Azure/go-autorest/logger v0.1.0/go.mod h1:oExouG+K6PryycPJfVSxi/koC6LSNgds39diKLz7Vrc= -github.com/Azure/go-autorest/tracing v0.5.0/go.mod h1:r/s2XiOKccPW3HrqB+W0TQzfbtp2fGCgRFtBroKn4Dk= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/toml v1.2.1/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= github.com/BurntSushi/toml v1.3.2 h1:o7IhLm0Msx3BaB+n3Ag7L8EVlByGnpq14C4YWiu/gL8= github.com/BurntSushi/toml v1.3.2/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= -github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/DATA-DOG/go-sqlmock v1.5.0 h1:Shsta01QNfFxHCfpW6YH2STWB0MudeXXEWMr20OEh60= github.com/DATA-DOG/go-sqlmock v1.5.0/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM= github.com/MakeNowJust/heredoc v1.0.0 h1:cXCdzVdstXyiTqTvfqk9SDHpKNjxuom+DOlyEeQ4pzQ= @@ -242,10 +227,6 @@ github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAE github.com/ProtonMail/go-crypto v0.0.0-20230217124315-7d5c6f04bbb8/go.mod h1:I0gYDMZ6Z5GRU7l58bNFSkPTFN6Yl12dsUlAZ8xy98g= github.com/ProtonMail/go-crypto v0.0.0-20230528122434-6f98819771a1 h1:JMDGhoQvXNTqH6Y3MC0IUw6tcZvaUdujNqzK2HYWZc8= github.com/ProtonMail/go-crypto v0.0.0-20230528122434-6f98819771a1/go.mod h1:EjAoLdwvbIOoOQr3ihjnSoLZRtE8azugULFRteWMNc0= -github.com/PuerkitoBio/purell v1.0.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= -github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= -github.com/PuerkitoBio/urlesc v0.0.0-20160726150825-5bd2802263f2/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= -github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= github.com/Shopify/logrus-bugsnag v0.0.0-20170309145241-6dbc35f2c30d/go.mod h1:HI8ITrYtUY+O+ZhtlqUnD8+KwNPOyugEhfP9fdUIaEQ= github.com/Shopify/logrus-bugsnag v0.0.0-20171204204709-577dee27f20d h1:UrqY+r/OJnIp5u0s1SbQ8dVfLCZJsnvazdBP5hS4iRs= github.com/Shopify/logrus-bugsnag v0.0.0-20171204204709-577dee27f20d/go.mod h1:HI8ITrYtUY+O+ZhtlqUnD8+KwNPOyugEhfP9fdUIaEQ= @@ -270,10 +251,10 @@ github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be/go.mod h1:ySMOLuW github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= github.com/antlr/antlr4/runtime/Go/antlr/v4 v4.0.0-20230305170008-8188dc5388df h1:7RFfzj4SSt6nnvCPbCqijJi1nWCd+TqAT3bYCStRC18= github.com/antlr/antlr4/runtime/Go/antlr/v4 v4.0.0-20230305170008-8188dc5388df/go.mod h1:pSwJ0fSY5KhvocuWSx4fz3BA8OrA1bQn+K1Eli3BRwM= -github.com/apecloud/kubebench v0.0.0-20240313105909-ba8654f654fc h1:BkFyEBEmDMdDhkWNAs9yg6zAj7xZjWON2u8b265T2a8= -github.com/apecloud/kubebench v0.0.0-20240313105909-ba8654f654fc/go.mod h1:5IZiDkFdgiZRGLsL+FOlvPsiF9LbyU55DVj4/5vT7+4= -github.com/apecloud/kubeblocks v0.0.0-20240328092917-34c21903b27b h1:nLcuqUQDxtD685CqLnnl+4m8YkogJ5p2J20aqofdv3o= -github.com/apecloud/kubeblocks v0.0.0-20240328092917-34c21903b27b/go.mod h1:scOC+CrVliHgn7ZwfKXkoXcTOIynXQhy97dHJLiQF8g= +github.com/apecloud/kubebench v0.0.0-20240327101848-6a031d3f4ebe h1:OFkCAToRcNt0VqgCndw0mw1Ke3P2XgRJLrXsNOyc3sQ= +github.com/apecloud/kubebench v0.0.0-20240327101848-6a031d3f4ebe/go.mod h1:5IZiDkFdgiZRGLsL+FOlvPsiF9LbyU55DVj4/5vT7+4= +github.com/apecloud/kubeblocks v0.9.0 h1:9AFKumqy/JLIwgfPLgRdCuPfMoipYEHm/zUQ9OFbQoM= +github.com/apecloud/kubeblocks v0.9.0/go.mod h1:kp9nenBgXsO03SbxN7a5S2HdNTsIQlpTcSgY8Mf2KS0= github.com/apparentlymart/go-textseg v1.0.0/go.mod h1:z96Txxhf3xSFMPmb5X/1W05FF/Nj9VFpLOpjS5yuumk= github.com/apparentlymart/go-textseg/v13 v13.0.0/go.mod h1:ZK2fH7c4NqDTLtiYLvIkEghdlcqw7yxLeM89kiTRPUo= github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= @@ -283,15 +264,13 @@ github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio= github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs= +github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY= github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 h1:DklsrG3dyBCFEj5IhUbnKptjxatkF07cF2ak3yi77so= github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw= github.com/aws/aws-sdk-go v1.38.35/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro= github.com/aws/aws-sdk-go v1.44.122/go.mod h1:y4AeaBuwd2Lk+GepC1E9v0qOiTws0MIWAX4oIKwKHZo= -github.com/aws/aws-sdk-go v1.44.317 h1:+8XWrLmGMwPPXSRSLPzhgcGnzJ2mYkgkrcB9C/GnSOU= -github.com/aws/aws-sdk-go v1.44.317/go.mod h1:aVsgQcEevwlmQ7qHE9I3h+dtQgpqhFB+i8Phjh7fkwI= -github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= -github.com/benbjohnson/clock v1.3.5 h1:VvXlSJBzZpA/zum6Sj74hxwYI2DIxRWuNIoXAzHZz5o= -github.com/benbjohnson/clock v1.3.5/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= +github.com/aws/aws-sdk-go v1.50.8 h1:gY0WoOW+/Wz6XmYSgDH9ge3wnAevYDSQWPxxJvqAkP4= +github.com/aws/aws-sdk-go v1.50.8/go.mod h1:LF8svs817+Nz+DmiMQKTO3ubZ/6IaTpq3TjupRn3Eqk= github.com/beorn7/perks v0.0.0-20150223135152-b965b613227f/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= 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= @@ -369,8 +348,10 @@ github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWH github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cncf/xds/go v0.0.0-20211001041855-01bcc9b48dfe/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= -github.com/cockroachdb/apd/v3 v3.2.0 h1:79kHCn4tO0VGu3W0WujYrMjBDk8a2H4KEUYcXf7whcg= -github.com/cockroachdb/apd/v3 v3.2.0/go.mod h1:klXJcjp+FffLTHlhIG69tezTDvdP065naDsHzKhYSqc= +github.com/cncf/xds/go v0.0.0-20231109132714-523115ebc101 h1:7To3pQ+pZo0i3dsWEbinPNFs5gPSBOsJtx3wTT94VBY= +github.com/cncf/xds/go v0.0.0-20231109132714-523115ebc101/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cockroachdb/apd/v3 v3.2.1 h1:U+8j7t0axsIgvQUqthuNm82HIrYXodOV2iWLWtEaIwg= +github.com/cockroachdb/apd/v3 v3.2.1/go.mod h1:klXJcjp+FffLTHlhIG69tezTDvdP065naDsHzKhYSqc= github.com/containerd/cgroups v1.1.0 h1:v8rEWFl6EoqHB+swVNjVoCJE8o3jX7e8nqBGPLaDFBM= github.com/containerd/cgroups v1.1.0/go.mod h1:6ppBcbh/NOOUU+dMKrykgaBnK9lCIBxHqJDGwsa1mIw= github.com/containerd/containerd v1.7.11 h1:lfGKw3eU35sjV0aG2eYZTiwFEY1pCzxdzicHP3SZILw= @@ -405,15 +386,14 @@ github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfc github.com/corpix/uarand v0.1.1 h1:RMr1TWc9F4n5jiPDzFHtmaUXLKLNUFK0SgCLo4BhX/U= github.com/corpix/uarand v0.1.1/go.mod h1:SFKZvkcRoLqVRFZ4u25xPmp6m9ktANfbpXZ7SJ0/FNU= github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= -github.com/cpuguy83/go-md2man/v2 v2.0.2 h1:p1EgwI/C7NhT0JmVkwCD2ZBK8j4aeHQX2pMHHBfMQ6w= github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= +github.com/cpuguy83/go-md2man/v2 v2.0.3 h1:qMCsGGgs+MAzDFyp9LpAe1Lqy/fY/qCovCm0qnXZOBM= +github.com/cpuguy83/go-md2man/v2 v2.0.3/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/creack/pty v1.1.18 h1:n56/Zwd5o6whRC5PMGretI4IdRLlmBXYNjScPaBgsbY= github.com/creack/pty v1.1.18/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4= github.com/cyphar/filepath-securejoin v0.2.4 h1:Ugdm7cg7i6ZK6x3xDF1oEu1nfkyfH53EtKeQYTC3kyg= github.com/cyphar/filepath-securejoin v0.2.4/go.mod h1:aPGpWjXOXUn2NCNjFvBE6aRxGGx79pTxQpKOJNYHHl4= -github.com/danieljoos/wincred v1.2.0 h1:ozqKHaLK0W/ii4KVbbvluM91W2H3Sh0BncbUNPS7jLE= -github.com/danieljoos/wincred v1.2.0/go.mod h1:FzQLLMKBFdvu+osBrnFODiv32YGwCfx0SkRa/eYHgec= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= @@ -454,18 +434,13 @@ github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4 github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= github.com/docker/libtrust v0.0.0-20160708172513-aabc10ec26b7 h1:UhxFibDNY/bfvqU5CAUmr9zpesgbU6SWc8/B4mflAE4= github.com/docker/libtrust v0.0.0-20160708172513-aabc10ec26b7/go.mod h1:cyGadeNEkKy96OOhEzfZl+yxihPEzKnqJwvfuSUqbZE= -github.com/docker/spdystream v0.0.0-20160310174837-449fdfce4d96/go.mod h1:Qh8CwZgvJUkLughtfhJv5dyTYa91l1fOUCrgjqmcifM= -github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE= github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= github.com/dvsekhvalnov/jose2go v0.0.0-20170216131308-f21a8cedbbae/go.mod h1:7BvyPhdbLxMXIYTFPLsyJRFMsKmOZnQmzh6Gb+uquuM= -github.com/dvsekhvalnov/jose2go v1.5.0 h1:3j8ya4Z4kMCwT5nXIKFSV84YS+HdqSSO0VsTQxaLAeM= -github.com/dvsekhvalnov/jose2go v1.5.0/go.mod h1:QsHjhyTlD/lAVqn/NSbVZmSCGeDehTB/mPZadG+mhXU= -github.com/elazarl/goproxy v0.0.0-20180725130230-947c36da3153/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc= -github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= -github.com/emicklei/go-restful v2.9.5+incompatible/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= -github.com/emicklei/go-restful/v3 v3.10.2 h1:hIovbnmBTLjHXkqEBUz3HGpXZdM7ZrE9fJIZIqlJLqE= -github.com/emicklei/go-restful/v3 v3.10.2/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= +github.com/emicklei/go-restful/v3 v3.8.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= +github.com/emicklei/go-restful/v3 v3.9.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= +github.com/emicklei/go-restful/v3 v3.11.0 h1:rAQeMHw1c7zTmncogyy8VvRZwtkmkZ4FxERmMY4rD+g= +github.com/emicklei/go-restful/v3 v3.11.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= github.com/emicklei/proto v1.10.0 h1:pDGyFRVV5RvV+nkBK9iy3q67FBy9Xa7vwrOTE+g5aGw= github.com/emicklei/proto v1.10.0/go.mod h1:rn1FgRS/FANiZdD2djyH7TMA9jdRDcYQ9IEN9yvjX0A= github.com/emirpasic/gods v1.18.1 h1:FXtiHYKDGKCW2KzwZKx0iC0PQmdlorYgdFG9jPXJ1Bc= @@ -480,12 +455,14 @@ github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.m github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0= github.com/envoyproxy/go-control-plane v0.10.2-0.20220325020618-49ff273808a1/go.mod h1:KJwIaB5Mv44NWtYuAOFCVOjcI94vtpEz2JU/D2v6IjE= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= +github.com/envoyproxy/protoc-gen-validate v1.0.2 h1:QkIBuU5k+x7/QXPvPPnWXWlCdaBFApVqftFV6k087DA= +github.com/envoyproxy/protoc-gen-validate v1.0.2/go.mod h1:GpiZQP3dDbg4JouG/NNS7QWXpgx6x8QiMKdmN72jogE= github.com/erikstmartin/go-testdb v0.0.0-20160219214506-8d10e4a1bae5/go.mod h1:a2zkGnVExMxdzMo3M0Hi/3sEU+cWnZpSni0O6/Yb/P0= -github.com/evanphx/json-patch v4.9.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= +github.com/evanphx/json-patch v4.12.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= github.com/evanphx/json-patch v5.6.0+incompatible h1:jBYDEEiFBPxA0v50tFdvOzQQTCvpL6mnFh5mB2/l16U= github.com/evanphx/json-patch v5.6.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= -github.com/evanphx/json-patch/v5 v5.6.0 h1:b91NhWfaz02IuVxO9faSllyAtNXHMPkC5J8sJCLunww= -github.com/evanphx/json-patch/v5 v5.6.0/go.mod h1:G79N1coSVB93tBe7j6PhzjmR3/2VvlbKOFpnXhI9Bw4= +github.com/evanphx/json-patch/v5 v5.8.0 h1:lRj6N9Nci7MvzrXuX6HFzU8XjmhPiXPlsKEy1u0KQro= +github.com/evanphx/json-patch/v5 v5.8.0/go.mod h1:VNkHZ/282BpEyt/tObQO8s5CMPmYYq14uClGH4abBuQ= github.com/exponent-io/jsonpath v0.0.0-20151013193312-d6023ce2651d h1:105gxyaGwCFad8crR9dcMQWvV9Hvulu6hwUh4tWPJnM= github.com/exponent-io/jsonpath v0.0.0-20151013193312-d6023ce2651d/go.mod h1:ZZMPRZwes7CROmyNKgQzC3XPs6L/G2EJLHddWejkmf4= github.com/fasthttp/router v1.4.20 h1:yPeNxz5WxZGojzolKqiP15DTXnxZce9Drv577GBrDgU= @@ -495,11 +472,11 @@ github.com/fatih/camelcase v1.0.0/go.mod h1:yN2Sb0lFhZJUdVvtELVWefmrXpuZESvPmqwo github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU= github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= -github.com/fatih/color v1.15.0 h1:kOqh6YHBtK8aywxGerMG2Eq3H6Qgoqeo13Bk2Mv/nBs= -github.com/fatih/color v1.15.0/go.mod h1:0h5ZqXfHYED7Bhv2ZJamyIOUej9KtShiJESRwBDUSsw= +github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM= +github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE= github.com/felixge/httpsnoop v1.0.1/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= -github.com/felixge/httpsnoop v1.0.3 h1:s/nj+GCswXYzN5v2DpNMuMQYe+0DDwt5WVCU6CWBdXk= -github.com/felixge/httpsnoop v1.0.3/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= +github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= +github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= github.com/foxcpp/go-mockdns v1.0.0 h1:7jBqxd3WDWwi/6WhDvacvH1XsN3rOLXyHM1uhvIx6FI= github.com/foxcpp/go-mockdns v1.0.0/go.mod h1:lgRN6+KxQBawyIghpnl5CezHFGS9VLzvtVlwxvzXTQ4= github.com/frankban/quicktest v1.14.3/go.mod h1:mgiwOwqx65TmIk1wJ6Q7wvnVMocbUorkibMOrVTHZps= @@ -507,11 +484,10 @@ github.com/frankban/quicktest v1.14.4 h1:g2rn0vABPOOXmZUj+vbmUp0lPoXEMuhTpIluN0X github.com/frankban/quicktest v1.14.4/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= -github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY= -github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= +github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA= +github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM= github.com/fvbommel/sortorder v1.1.0 h1:fUmoe+HLsBTctBDoaBwpQo5N+nrCp8g/BjKb/6ZQmYw= github.com/fvbommel/sortorder v1.1.0/go.mod h1:uk88iVf1ovNn1iLfgUVU2F9o5eO30ui720w+kxuqRs0= -github.com/ghodss/yaml v0.0.0-20150909031657-73d445a93680/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/gliderlabs/ssh v0.3.5 h1:OcaySEmAQJgyYcArR+gGGTHCyE7nvhEMTlYY+Dp8CpY= @@ -527,9 +503,6 @@ github.com/go-git/go-git-fixtures/v4 v4.3.1 h1:y5z6dd3qi8Hl+stezc8p3JxDkoTRqMAlK github.com/go-git/go-git-fixtures/v4 v4.3.1/go.mod h1:8LHG1a3SRW71ettAD/jW13h8c6AqjVSeL11RAdgaqpo= github.com/go-git/go-git/v5 v5.6.1 h1:q4ZRqQl4pR/ZJHc1L5CFjGA1a10u76aV1iC+nh+bHsk= github.com/go-git/go-git/v5 v5.6.1/go.mod h1:mvyoL6Unz0PiTQrGQfSfiLFhBH1c1e84ylC2MDs4ee8= -github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= -github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= -github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-gorp/gorp/v3 v3.0.5 h1:PUjzYdYu3HBOh8LE+UUmRG2P0IRDak9XMeGNvaeq4Ow= github.com/go-gorp/gorp/v3 v3.0.5/go.mod h1:dLEjIyyRNiXvNZ8PSmzpt1GsWAUK8kjVhEpjH8TixEw= github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= @@ -546,35 +519,27 @@ github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7 github.com/go-logr/logr v0.2.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU= github.com/go-logr/logr v1.2.0/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-logr/logr v1.2.3/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= -github.com/go-logr/logr v1.3.0 h1:2y3SDp0ZXuc6/cjLSZ+Q3ir+QB9T/iG5yYRXqsagWSY= github.com/go-logr/logr v1.3.0/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= +github.com/go-logr/logr v1.4.1 h1:pKouT5E8xu9zeFC39JXRDukb6JFQPXM5p5I91188VAQ= +github.com/go-logr/logr v1.4.1/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= -github.com/go-logr/zapr v1.2.4 h1:QHVo+6stLbfJmYGkQ7uGHUCu5hnAFAj6mDe6Ea0SeOo= -github.com/go-logr/zapr v1.2.4/go.mod h1:FyHWQIzQORZ0QVE1BtVHv3cKtNLuXsbNLtpuhNapBOA= +github.com/go-logr/zapr v1.3.0 h1:XGdV8XW8zdwFiwOA2Dryh1gj2KRQyOOoNmBy4EplIcQ= +github.com/go-logr/zapr v1.3.0/go.mod h1:YKepepNBd1u/oyhd/yQmtjVXmm9uML4IXUgMOwR8/Gg= github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY= github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= -github.com/go-openapi/jsonpointer v0.0.0-20160704185906-46af16f9f7b1/go.mod h1:+35s3my2LFTysnkMfxsJBAMHj/DoqoB9knIWoYG/Vk0= -github.com/go-openapi/jsonpointer v0.19.2/go.mod h1:3akKfEdA7DF1sugOqz1dVQHBcuDBPKZGEoHC/NkiQRg= -github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= github.com/go-openapi/jsonpointer v0.19.6 h1:eCs3fxoIi3Wh6vtgmLTOjdhSpiqphQ+DaPn38N2ZdrE= github.com/go-openapi/jsonpointer v0.19.6/go.mod h1:osyAmYz/mB/C3I+WsTTSgw1ONzaLJoLCyoi6/zppojs= -github.com/go-openapi/jsonreference v0.0.0-20160704190145-13c6e3589ad9/go.mod h1:W3Z9FmVs9qj+KR4zFKmDPGiLdk1D9Rlm7cyMvf57TTg= -github.com/go-openapi/jsonreference v0.19.2/go.mod h1:jMjeRr2HHw6nAVajTXJ4eiUwohSTlpa0o73RUL1owJc= -github.com/go-openapi/jsonreference v0.19.3/go.mod h1:rjx6GuL8TTa9VaixXglHmQmIL98+wF9xc8zWvFonSJ8= +github.com/go-openapi/jsonreference v0.20.1/go.mod h1:Bl1zwGIM8/wsvqjsOQLJ/SH+En5Ap4rVB5KVcIDZG2k= github.com/go-openapi/jsonreference v0.20.2 h1:3sVjiK66+uXK/6oQ8xgcRKcFgQ5KXa2KvnJRumpMGbE= github.com/go-openapi/jsonreference v0.20.2/go.mod h1:Bl1zwGIM8/wsvqjsOQLJ/SH+En5Ap4rVB5KVcIDZG2k= -github.com/go-openapi/spec v0.0.0-20160808142527-6aced65f8501/go.mod h1:J8+jY1nAiCcj+friV/PDoE1/3eeccG9LYBs0tYvLOWc= -github.com/go-openapi/spec v0.19.3/go.mod h1:FpwSN1ksY1eteniUU7X0N/BgJ7a4WvBFVA8Lj9mJglo= -github.com/go-openapi/swag v0.0.0-20160704191624-1d0bd113de87/go.mod h1:DXUve3Dpr1UfpPtxFw+EFuQ41HhCWZfha5jSVRG7C7I= -github.com/go-openapi/swag v0.19.2/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= -github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= github.com/go-openapi/swag v0.22.3/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14= github.com/go-openapi/swag v0.22.4 h1:QLMzNJnMGPRNDCbySlcj1x01tzU8/9LTTL9hZZZogBU= github.com/go-openapi/swag v0.22.4/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14= -github.com/go-quicktest/qt v1.100.0 h1:I7iSLgIwNp0E0UnSvKJzs7ig0jg/Iq83zsZjtQNW7jY= -github.com/go-quicktest/qt v1.100.0/go.mod h1:leyLsQ4jksGmF1KaQEyabnqGIiJTbOU5S46QegToEj4= +github.com/go-quicktest/qt v1.101.0 h1:O1K29Txy5P2OK0dGo59b7b0LR6wKfIhttaAhHUyn7eI= +github.com/go-quicktest/qt v1.101.0/go.mod h1:14Bz/f7NwaXPtdYEgzsx46kqSxVwTbzVZsDC26tQJow= github.com/go-redis/redis/v7 v7.4.1 h1:PASvf36gyUpr2zdOUS/9Zqc80GbM+9BDyiJSJDDOrTI= github.com/go-redis/redis/v7 v7.4.1/go.mod h1:JDNMw23GTyLNC4GZu9njt15ctBQVn7xjRfnwdHj/Dcg= github.com/go-sql-driver/mysql v1.3.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= @@ -582,6 +547,7 @@ github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LB github.com/go-sql-driver/mysql v1.7.1 h1:lUIinVbN1DY0xBg0eMOzmmtGoHwWBbvnWubQUrtU8EI= github.com/go-sql-driver/mysql v1.7.1/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI= github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls= github.com/go-test/deep v1.1.0 h1:WOcxcdHcvdgThNXjw0t76K42FXTU7HpNQWHpA2HHNlg= @@ -594,8 +560,6 @@ github.com/gobuffalo/packr/v2 v2.8.3 h1:xE1yzvnO56cUC0sTpKR3DIbxZgB54AftTFMhB2XE github.com/gobuffalo/packr/v2 v2.8.3/go.mod h1:0SahksCVcx4IMnigTjiFuyldmTrdTctXsOdiU5KwbKc= github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y= github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8= -github.com/godbus/dbus v0.0.0-20190726142602-4481cbc300e2 h1:ZpnhV/YsD2/4cESfV5+Hoeu/iUR3ruzNvZ+yQfO03a0= -github.com/godbus/dbus v0.0.0-20190726142602-4481cbc300e2/go.mod h1:bBOAhwG1umN6/6ZUMtDFBMQR8jRg9O75tm9K00oMsK4= github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/godbus/dbus/v5 v5.1.0 h1:4KLkAxT3aOY8Li4FRJe/KvhoNFFxo0m6fNuFUO8QJUk= github.com/godbus/dbus/v5 v5.1.0/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= @@ -605,11 +569,8 @@ github.com/gofrs/uuid v4.4.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRx github.com/gogo/protobuf v1.0.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= 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/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= -github.com/golang-jwt/jwt v3.2.2+incompatible h1:IfV12K8xAKAnZqdXVzCZ+TOjboZ2keLg81eXfW3O+oY= -github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I= github.com/golang-jwt/jwt/v4 v4.5.0 h1:7cYmW1XlMY7h7ii7UhUyChSgS5wUJEnm9uZVTGqOWzg= github.com/golang-jwt/jwt/v4 v4.5.0/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0= @@ -648,8 +609,9 @@ github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= github.com/golang/protobuf v1.5.1/go.mod h1:DopwsBzvsk0Fs44TXzsVbJyPhcCPeIwnvohx4u74HPM= github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= -github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= +github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= @@ -665,10 +627,11 @@ github.com/goodhosts/hostsfile v0.1.1 h1:SqRUTFOshOCon0ZSXDrW1bkKZvs4+5pRgYFWySd github.com/goodhosts/hostsfile v0.1.1/go.mod h1:lXcUP8xO4WR5vvuQ3F/N0bMQoclOtYKEEUnyY2jTusY= 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/btree v1.0.1/go.mod h1:xXMiIv4Fb/0kKde4SpL7qlzvu5cMJDRkFDxJfI9uaxA= github.com/google/btree v1.1.2 h1:xf4v41cLI2Z6FxbKm+8Bu+m8ifhj15JuZ9sa0jZCMUU= github.com/google/btree v1.1.2/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4= -github.com/google/cel-go v0.16.0 h1:DG9YQ8nFCFXAs/FDDwBxmL1tpKNrdlGUM9U3537bX/Y= -github.com/google/cel-go v0.16.0/go.mod h1:HXZKzB0LXqer5lHHgfWAnlYwJaQBDKMjxjulNQzhwhY= +github.com/google/cel-go v0.17.7 h1:6ebJFzu1xO2n7TLtN+UBqShGBhlD85bhvglh5DpcfqQ= +github.com/google/cel-go v0.17.7/go.mod h1:HXZKzB0LXqer5lHHgfWAnlYwJaQBDKMjxjulNQzhwhY= github.com/google/certificate-transparency-go v1.0.10-0.20180222191210-5ab67e519c93/go.mod h1:QeJfpSbVSfYc7RgB3gJFj9cbuQMMchQxrWXz8Ruopmg= github.com/google/certificate-transparency-go v1.1.5 h1:EVfYyOiMSdwwXd6FJxnh0jYgYj/Dh5n9sXtgIr5+Vj0= github.com/google/certificate-transparency-go v1.1.5/go.mod h1:CnNCSPt9ptZQ8jDSrqyTmh2dT2MQLKymfGYwXqjQ7YY= @@ -717,27 +680,28 @@ github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLe github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20210122040257-d980be63207e/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20210601050228-01bbb1931b22/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20210609004039-a478d1d731e9/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20230323073829-e72429f035bd h1:r8yyd+DJDmsUhGrRBxH5Pj7KeFK5l+Y3FsgT8keqKtk= github.com/google/pprof v0.0.0-20230323073829-e72429f035bd/go.mod h1:79YE0hCXdHag9sBkw2o+N/YnZtTkXi0UT9Nnixa5eYk= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= -github.com/google/s2a-go v0.1.4 h1:1kZ/sQM3srePvKs3tXAvQzo66XfcReoqFpIpIccE7Oc= -github.com/google/s2a-go v0.1.4/go.mod h1:Ej+mSEMGRnqRzjc7VtF+jdBwYG5fuJfiZ8ELkjEwM0A= +github.com/google/s2a-go v0.1.7 h1:60BLSyTrOV4/haCDW4zb1guZItoSq8foHCXrAnjBo/o= +github.com/google/s2a-go v0.1.7/go.mod h1:50CgR4k1jNlWBu4UfS4AcfhVe1r6pdZPygJ3R8F0Qdw= github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4= github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ= github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.2.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/google/uuid v1.3.1 h1:KjJaJ9iWZ3jOFZIf1Lqf4laDRCasjl0BCmnEGxkdLb4= -github.com/google/uuid v1.3.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= +github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/googleapis/enterprise-certificate-proxy v0.0.0-20220520183353-fd19c99a87aa/go.mod h1:17drOmN3MwGY7t0e+Ei9b45FFGA3fBs3x36SsCg1hq8= github.com/googleapis/enterprise-certificate-proxy v0.1.0/go.mod h1:17drOmN3MwGY7t0e+Ei9b45FFGA3fBs3x36SsCg1hq8= github.com/googleapis/enterprise-certificate-proxy v0.2.0/go.mod h1:8C0jb7/mgJe/9KK8Lm7X9ctZC2t60YyIpYEI16jx0Qg= -github.com/googleapis/enterprise-certificate-proxy v0.2.3 h1:yk9/cqRKtT9wXZSsRH9aurXEpJX+U6FLtpYTdC3R06k= -github.com/googleapis/enterprise-certificate-proxy v0.2.3/go.mod h1:AwSRAtLfXpU5Nm3pW+v7rGDHp09LsPtGY9MduiEsR9k= +github.com/googleapis/enterprise-certificate-proxy v0.3.2 h1:Vie5ybvEvT75RniqhfFxPRy3Bf7vr3h0cechB90XaQs= +github.com/googleapis/enterprise-certificate-proxy v0.3.2/go.mod h1:VLSiSSBs/ksPL8kq3OBOQ6WRI2QnaFynd1DCjZ62+V0= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= github.com/googleapis/gax-go/v2 v2.1.0/go.mod h1:Q3nei7sK6ybPYH7twZdmQpAd1MKb7pfu6SK+H1/DsU0= @@ -747,9 +711,8 @@ github.com/googleapis/gax-go/v2 v2.3.0/go.mod h1:b8LNqSzNabLiUpXKkY7HAR5jr6bIT99 github.com/googleapis/gax-go/v2 v2.4.0/go.mod h1:XOTVJ59hdnfJLIP/dh8n5CGryZR2LxK9wbMD5+iXC6c= github.com/googleapis/gax-go/v2 v2.5.1/go.mod h1:h6B0KMMFNtI2ddbGJn3T3ZbwkeT6yqEF02fYlzkUCyo= github.com/googleapis/gax-go/v2 v2.6.0/go.mod h1:1mjbznJAPHFpesgE5ucqfYEscaz5kMdcIDwU/6+DDoY= -github.com/googleapis/gax-go/v2 v2.11.0 h1:9V9PWXEsWnPpQhu/PeQIkS4eGzMlTLGgt80cUUI8Ki4= -github.com/googleapis/gax-go/v2 v2.11.0/go.mod h1:DxmR61SGKkGLa2xigwuZIQpkCI2S5iydzRfb3peWZJI= -github.com/googleapis/gnostic v0.4.1/go.mod h1:LRhVm6pbyptWbWbuZ38d1eyptfvIytN3ir6b65WBswg= +github.com/googleapis/gax-go/v2 v2.12.0 h1:A+gCJKdRfqXkr+BIRGtZLibNXf0m1f9E4HG56etFpas= +github.com/googleapis/gax-go/v2 v2.12.0/go.mod h1:y+aIqrI5eb1YGMVJfuV3185Ts/D7qKpsEkdD5+I6QGU= github.com/googleapis/go-type-adapters v1.0.0/go.mod h1:zHW75FOG2aur7gAO2B+MLby+cLsWGBF62rFAi7WjWO4= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/gorilla/handlers v1.5.1 h1:9lRY6j8DEeeBT10CvO9hGW0gmky0BprnvDI5vfhUHH4= @@ -776,8 +739,6 @@ github.com/grpc-ecosystem/grpc-gateway v1.16.0 h1:gmcG1KaJ57LophUzW0Hy8NmPhnMZb4 github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.0 h1:YBftPWNWd4WwGqtY2yeZL2ef8rHAxPBD8KFhJpmcqms= github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.0/go.mod h1:YN5jB8ie0yfIUg6VvR9Kz84aCaG7AsGZnLjhHbUqwPg= -github.com/gsterjov/go-libsecret v0.0.0-20161001094733-a6f4afe4910c h1:6rhixN/i8ZofjG1Y75iExal34USq5p+wiN1tpie8IrU= -github.com/gsterjov/go-libsecret v0.0.0-20161001094733-a6f4afe4910c/go.mod h1:NMPJylDgVpX0MLRlPy15sqSwOFv/U1GZ2m21JhFfek0= github.com/hailocab/go-hostpool v0.0.0-20160125115350-e80d13ce29ed h1:5upAirOpQc1Q53c0bnx2ufif5kANL7bfZWcc6VJWJd8= github.com/hailocab/go-hostpool v0.0.0-20160125115350-e80d13ce29ed/go.mod h1:tMWxXQ9wFIaZeTI9F+hmhFiGpFmhOHzyShyFUhRm0H4= github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q= @@ -832,7 +793,7 @@ github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1: github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/icrowley/fake v0.0.0-20180203215853-4178557ae428 h1:Mo9W14pwbO9VfRe+ygqZ8dFbPpoIK1HFrG/zjTuQ+nc= github.com/icrowley/fake v0.0.0-20180203215853-4178557ae428/go.mod h1:uhpZMVGznybq1itEKXj6RYw9I71qK4kH+OGMjRC4KEo= -github.com/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= +github.com/imdario/mergo v0.3.6/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= github.com/imdario/mergo v0.3.11/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= github.com/imdario/mergo v0.3.13/go.mod h1:4lJ1jqUDcsbIECGy0RUJAXNIhg+6ocWgb1ALK2O4oXg= github.com/imdario/mergo v0.3.14 h1:fOqeC1+nCuuk6PKQdg9YmosXX7Y7mHX6R/0ZldI9iHo= @@ -844,15 +805,14 @@ github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsI github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg= github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a h1:bbPeKD0xmW/Y25WS6cokEszi5g+S0QxI/d45PkRi7Nk= github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM= -github.com/jackc/pgx/v5 v5.4.3 h1:cxFyXhxlvAifxnkKKdlxv8XqUf59tDlYjnV5YYfsJJY= -github.com/jackc/pgx/v5 v5.4.3/go.mod h1:Ig06C2Vu0t5qXC60W8sqIthScaEnFvojjj9dSljmHRA= +github.com/jackc/pgx/v5 v5.5.4 h1:Xp2aQS8uXButQdnCMWNmvx6UysWQQC+u1EoizjguY+8= +github.com/jackc/pgx/v5 v5.5.4/go.mod h1:ez9gk+OAat140fv9ErkZDYFWmXLfV+++K0uAOiwgm1A= github.com/jackc/puddle/v2 v2.2.1 h1:RhxXJtFG022u4ibrCSMSiu5aOq1i77R3OHKNJj77OAk= github.com/jackc/puddle/v2 v2.2.1/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4= github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A= github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo= github.com/jedib0t/go-pretty/v6 v6.4.6 h1:v6aG9h6Uby3IusSSEjHaZNXpHFhzqMmjXcPq1Rjl9Jw= github.com/jedib0t/go-pretty/v6 v6.4.6/go.mod h1:Ndk3ase2CkQbXLLNf5QDHoYb6J9WtVfmHZu9n8rk2xs= -github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= github.com/jessevdk/go-flags v1.5.0/go.mod h1:Fw0T6WPc1dYxT4mKEZRfG5kJhaTDP9pj1c2EWnYs/m4= github.com/jinzhu/gorm v0.0.0-20170222002820-5409931a1bb8 h1:CZkYfurY6KGhVtlalI4QwQ6T0Cu6iuY3e0x5RLu96WE= github.com/jinzhu/gorm v0.0.0-20170222002820-5409931a1bb8/go.mod h1:Vla75njaFJ8clLU1W44h34PjIkijhjHIYnZxMqCdxqo= @@ -894,13 +854,12 @@ github.com/karrick/godirwalk v1.17.0/go.mod h1:j4mkqPuvaLI8mp1DroR3P6ad7cyYd4c1q github.com/kevinburke/ssh_config v1.2.0 h1:x584FjTGwHzMwvHx18PXxbBVzfnxogHaAReU4gf13a4= github.com/kevinburke/ssh_config v1.2.0/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM= 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/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= github.com/klauspost/compress v1.15.11/go.mod h1:QPwzmACJjUTFsnSHH934V6woptycfrDDJnH7hvFVbGM= -github.com/klauspost/compress v1.16.6 h1:91SKEy4K37vkp255cJ8QesJhjyRO0hn9i9G0GoUwLsk= -github.com/klauspost/compress v1.16.6/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= +github.com/klauspost/compress v1.17.6 h1:60eq2E/jlfwQXtvZEeBUYADs+BwKBWURIY+Gj2eRGjI= +github.com/klauspost/compress v1.17.6/go.mod h1:/dCuZOvVtNoHsyb+cuJD3itjs3NbnF6KH9zAO4BDxPM= github.com/klauspost/pgzip v1.2.6 h1:8RXeL5crjEUFnR2/Sn6GJNWtSQ3Dk8pq4CL3jvdDyjU= github.com/klauspost/pgzip v1.2.6/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= @@ -917,7 +876,6 @@ github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NB github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= -github.com/kr/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= @@ -957,10 +915,6 @@ github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czP github.com/magiconair/properties v1.8.5/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60= github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY= github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= -github.com/mailru/easyjson v0.0.0-20160728113105-d5b7844b561a/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.0/go.mod h1:KAzv3t3aY1NaHWoQz1+4F1ccyAH66Jk7yos7ldAVICs= github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= github.com/manifoldco/promptui v0.9.0 h1:3V4HzJk1TtXW1MTZMP7mdlwbBpIinw3HztaIlYthEiA= @@ -987,15 +941,15 @@ github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Ky github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= -github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA= -github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= +github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/mattn/go-oci8 v0.1.1/go.mod h1:wjDx6Xm9q7dFtHJvIlrI99JytznLw5wQ4R+9mNXJwGI= github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= github.com/mattn/go-runewidth v0.0.13/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= -github.com/mattn/go-runewidth v0.0.14 h1:+xnbZSEeDbOIg5/mE6JF0w6n9duR1l3/WmbinWVwUuU= -github.com/mattn/go-runewidth v0.0.14/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= +github.com/mattn/go-runewidth v0.0.15 h1:UNAjwbU9l54TA3KzvqLGxwWjHmMgBUVhBiTjelZgg3U= +github.com/mattn/go-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= github.com/mattn/go-shellwords v1.0.12 h1:M2zGm7EW6UQJvDeQxo4T51eKPurbeFbe8WtebGE2xrk= github.com/mattn/go-shellwords v1.0.12/go.mod h1:EZzvwXDESEeg03EKmM+RmDnNOPKG4lLtQsUlTZDWQ8Y= github.com/mattn/go-sqlite3 v1.6.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= @@ -1004,8 +958,6 @@ github.com/mattn/go-sqlite3 v1.14.15/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S github.com/mattn/go-sqlite3 v2.0.3+incompatible h1:gXHsfypPkaMZrKbD5209QV9jbUTJKjyR5WD3HYQSd+U= github.com/mattn/go-sqlite3 v2.0.3+incompatible/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= -github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0 h1:jWpvCLoY8Z/e3VKvlsiIGKtc+UG6U5vzxaoagmhXfyg= -github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0/go.mod h1:QUyp042oQthUoa9bqDv0ER0wrtXnBruoNd7aNjkbP+k= github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= github.com/miekg/dns v1.1.50 h1:DQUfb9uc6smULcREF09Uc+/Gd46YWqJd5DbpPE9xkcA= github.com/miekg/dns v1.1.50/go.mod h1:e3IlAVfNqAllflbibAZEWOXOQ+Ynzk/dDozDxY7XnME= @@ -1068,10 +1020,6 @@ github.com/montanaflynn/stats v0.6.6 h1:Duep6KMIDpY4Yo11iFsvyqJDyfzLF9+sndUKT+v6 github.com/montanaflynn/stats v0.6.6/go.mod h1:etXPPgVO6n31NxCd9KQUMvCM+ve0ruNzt6R8Bnaayow= github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A= github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc= -github.com/mpvl/unique v0.0.0-20150818121801-cbe035fff7de h1:D5x39vF5KCwKQaw+OC9ZPiLVHXz3UFw2+psEX+gYcto= -github.com/mpvl/unique v0.0.0-20150818121801-cbe035fff7de/go.mod h1:kJun4WP5gFuHZgRjZUWWuH1DTxCtxbHDOIJsudS8jzY= -github.com/mtibben/percent v0.2.1 h1:5gssi8Nqo8QU/r2pynCm+hBQHpkB/uNK7BJCFogWdzs= -github.com/mtibben/percent v0.2.1/go.mod h1:KG9uO+SZkUp+VkRHsCdYQV3XSZrrSpR3O9ibNBTZrns= github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= @@ -1085,32 +1033,57 @@ github.com/nelsam/hel/v2 v2.3.3/go.mod h1:1ZTGfU2PFTOd5mx22i5O0Lc2GY933lQ2wb/ggy github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= github.com/nsf/termbox-go v0.0.0-20190121233118-02980233997d h1:x3S6kxmy49zXVVyhcnrFqxvNVCBPb2KZ9hV2RBdS840= github.com/nsf/termbox-go v0.0.0-20190121233118-02980233997d/go.mod h1:IuKpRQcYE1Tfu+oAQqaLisqDeXgjyyltCfsaoYN18NQ= +github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY= -github.com/onsi/ginkgo v0.0.0-20170829012221-11459a886d9c/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.10.1/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/ginkgo v1.11.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.12.0/go.mod h1:oUhWkIvk5aDxtKvDDuw8gItl8pKl42LzjC9KZE0HfGg= +github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= +github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0= github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE= github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU= -github.com/onsi/ginkgo/v2 v2.13.0 h1:0jY9lJquiL8fcf3M4LAXN5aMlS/b2BV86HFFPCPMgE4= -github.com/onsi/ginkgo/v2 v2.13.0/go.mod h1:TE309ZR8s5FsKKpuB1YAQYBzCaAfUgatB/xlT/ETL/o= -github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= +github.com/onsi/ginkgo/v2 v2.1.3/go.mod h1:vw5CSIxN1JObi/U8gcbwft7ZxR2dgaR70JSE3/PpL4c= +github.com/onsi/ginkgo/v2 v2.1.4/go.mod h1:um6tUpWM/cxCK3/FK8BXqEiUMUwRgSM4JXG47RKZmLU= +github.com/onsi/ginkgo/v2 v2.1.6/go.mod h1:MEH45j8TBi6u9BMogfbp0stKC5cdGjumZj5Y7AG4VIk= +github.com/onsi/ginkgo/v2 v2.3.0/go.mod h1:Eew0uilEqZmIEZr8JrvYlvOM7Rr6xzTmMV8AyFNU9d0= +github.com/onsi/ginkgo/v2 v2.4.0/go.mod h1:iHkDK1fKGcBoEHT5W7YBq4RFWaQulw+caOMkAt4OrFo= +github.com/onsi/ginkgo/v2 v2.5.0/go.mod h1:Luc4sArBICYCS8THh8v3i3i5CuSZO+RaQRaJoeNwomw= +github.com/onsi/ginkgo/v2 v2.7.0/go.mod h1:yjiuMwPokqY1XauOgju45q3sJt6VzQ/Fict1LFVcsAo= +github.com/onsi/ginkgo/v2 v2.8.1/go.mod h1:N1/NbDngAFcSLdyZ+/aYTYGSlq9qMCS/cNKGJjy+csc= +github.com/onsi/ginkgo/v2 v2.9.0/go.mod h1:4xkjoL/tZv4SMWeww56BU5kAt19mVB47gTWxmrTcxyk= +github.com/onsi/ginkgo/v2 v2.9.1/go.mod h1:FEcmzVcCHl+4o9bQZVab+4dC9+j+91t2FHSzmGAPfuo= +github.com/onsi/ginkgo/v2 v2.9.2/go.mod h1:WHcJJG2dIlcCqVfBAwUCrJxSPFb6v4azBwgxeMeDuts= +github.com/onsi/ginkgo/v2 v2.9.4/go.mod h1:gCQYp2Q+kSoIj7ykSVb9nskRSsR6PUj4AiLywzIhbKM= +github.com/onsi/ginkgo/v2 v2.14.0 h1:vSmGj2Z5YPb9JwCWT6z6ihcUvDhuXLc3sJiqd3jMKAY= +github.com/onsi/ginkgo/v2 v2.14.0/go.mod h1:JkUdW7JkN0V6rFvsHcJ478egV3XH9NxpD27Hal/PhZw= github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= github.com/onsi/gomega v1.9.0/go.mod h1:Ho0h+IUsWyvy1OpqCwxlQ/21gkhVunqlU8fDGcoTdcA= -github.com/onsi/gomega v1.27.10 h1:naR28SdDFlqrG6kScpT8VWpu1xWY5nJRCF3XaYyBjhI= -github.com/onsi/gomega v1.27.10/go.mod h1:RsS8tutOdbdgzbPtzzATp12yT7kM5I5aElG3evPbQ0M= +github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= +github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY= +github.com/onsi/gomega v1.19.0/go.mod h1:LY+I3pBVzYsTBU1AnDwOSxaYi9WoWiqgwooUqq9yPro= +github.com/onsi/gomega v1.20.1/go.mod h1:DtrZpjmvpn2mPm4YWQa0/ALMDj9v4YxLgojwPeREyVo= +github.com/onsi/gomega v1.21.1/go.mod h1:iYAIXgPSaDHak0LCMA+AWBpIKBr8WZicMxnE8luStNc= +github.com/onsi/gomega v1.22.1/go.mod h1:x6n7VNe4hw0vkyYUM4mjIXx3JbLiPaBPNgB7PRQ1tuM= +github.com/onsi/gomega v1.24.0/go.mod h1:Z/NWtiqwBrwUt4/2loMmHL63EDLnYHmVbuBpDr2vQAg= +github.com/onsi/gomega v1.24.1/go.mod h1:3AOiACssS3/MajrniINInwbfOOtfZvplPzuRSmvt1jM= +github.com/onsi/gomega v1.26.0/go.mod h1:r+zV744Re+DiYCIPRlYOTxn0YkOLcAnW8k1xXdMPGhM= +github.com/onsi/gomega v1.27.1/go.mod h1:aHX5xOykVYzWOV4WqQy0sy8BQptgukenXpCXfadcIAw= +github.com/onsi/gomega v1.27.3/go.mod h1:5vG284IBtfDAmDyrK+eGyZmUgUlmi+Wngqo557cZ6Gw= +github.com/onsi/gomega v1.27.4/go.mod h1:riYq/GJKh8hhoM01HN6Vmuy93AarCXCBGpvFDK3q3fQ= +github.com/onsi/gomega v1.27.6/go.mod h1:PIQNjfQwkP3aQAH7lf7j87O/5FiNr+ZR8+ipb+qQlhg= +github.com/onsi/gomega v1.30.0 h1:hvMK7xYz4D3HapigLTeGdId/NcfQx1VHMJc60ew99+8= +github.com/onsi/gomega v1.30.0/go.mod h1:9sxs+SwGrKI0+PWe4Fxa9tFQQBG5xSsSbMXOI8PPpoQ= github.com/opencontainers/go-digest v0.0.0-20170106003457-a6d0ee40d420/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= github.com/opencontainers/image-spec v1.0.1/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= github.com/opencontainers/image-spec v1.0.2/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= -github.com/opencontainers/image-spec v1.1.0-rc5 h1:Ygwkfw9bpDvs+c9E34SdgGOj41dX/cbdlwvlWt0pnFI= -github.com/opencontainers/image-spec v1.1.0-rc5/go.mod h1:X4pATf0uXsnn3g5aiGIsVnJBR4mxhKzfwmvK/B2NTm8= +github.com/opencontainers/image-spec v1.1.0 h1:8SG7/vwALn54lVB/0yZ/MMwhFrPYtpEHQb2IpWsCzug= +github.com/opencontainers/image-spec v1.1.0/go.mod h1:W4s4sFTMaBeK1BQLXbG4AdM2szdn85PY75RI83NrTrM= github.com/opencontainers/runc v1.1.7 h1:y2EZDS8sNng4Ksf0GUYNhKbTShZJPJg1FiXJNH/uoCk= github.com/opencontainers/runc v1.1.7/go.mod h1:CbUumNnWCuTGFukNXahoo/RFBZvDAgRh/smNYNOhA50= github.com/opencontainers/runtime-spec v1.1.0-rc.3 h1:l04uafi6kxByhbxev7OWiuUv0LZxEsYUfDWZ6bztAuU= @@ -1151,6 +1124,8 @@ github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c/go.mod h1:Om github.com/poy/onpar v0.0.0-20200406201722-06f95a1c68e8/go.mod h1:nSbFQvMj97ZyhFRSJYtut+msi4sOY6zJDGCdSc+/rZU= github.com/poy/onpar v1.1.2 h1:QaNrNiZx0+Nar5dLgTVp5mXkyoVFIbepjyEoGSnhbAY= github.com/poy/onpar v1.1.2/go.mod h1:6X8FLNoxyr9kkmnlqpK6LSoiOtrO6MICtWwEuWkLjzg= +github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring v0.71.0 h1:et+XkusxWLz+XNqZiyMom9tv9ACvNAUyLXti2LTiV7o= +github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring v0.71.0/go.mod h1:3RiUkFmR9kmPZi9r/8a5jw0a9yg+LMmr7qa0wjqvSiI= github.com/prometheus/alertmanager v0.26.0 h1:uOMJWfIwJguc3NaM3appWNbbrh6G/OjvaHMk22aBBYc= github.com/prometheus/alertmanager v0.26.0/go.mod h1:rVcnARltVjavgVaNnmevxK7kOn7IZavyf0KNgHkbEpU= github.com/prometheus/client_golang v0.9.0-pre1.0.20180209125602-c332b6f63c06/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= @@ -1160,8 +1135,8 @@ github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5Fsn github.com/prometheus/client_golang v1.1.0/go.mod h1:I1FGZT9+L76gKKOs5djB6ezCbFQP1xR9D75/vuwEF3g= github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0= -github.com/prometheus/client_golang v1.18.0 h1:HzFfmkOzH5Q8L8G+kSJKUx5dtG87sewO+FoDDqP5Tbk= -github.com/prometheus/client_golang v1.18.0/go.mod h1:T+GXkCk5wSJyOqMIzVgvvjFDlkOQntgjkJWKrN5txjA= +github.com/prometheus/client_golang v1.19.0 h1:ygXvpU1AoN1MhdzckN+PyD9QJOSD4x7kmXYlnfbA6JU= +github.com/prometheus/client_golang v1.19.0/go.mod h1:ZRM9uEAypZakd+q/x7+gmsvXdURP+DABIEIjnmDdp+k= github.com/prometheus/client_model v0.0.0-20171117100541-99fa1f4be8e5/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= 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= @@ -1177,8 +1152,8 @@ github.com/prometheus/common v0.6.0/go.mod h1:eBmuwkDJBwy6iBfxCBob6t6dR6ENT/y+J+ github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc= github.com/prometheus/common v0.29.0/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls= -github.com/prometheus/common v0.45.0 h1:2BGz0eBc2hdMDLnO/8n0jeB3oPrt2D08CekT0lneoxM= -github.com/prometheus/common v0.45.0/go.mod h1:YJmSTw9BoKxJplESWWxlbyttQR4uaEcGyv9MZjVOJsY= +github.com/prometheus/common v0.48.0 h1:QO8U2CdOzSn1BBsmXJXduaaW+dY/5QLjfB8svtSzKKE= +github.com/prometheus/common v0.48.0/go.mod h1:0/KsvlIEfPQCQ5I2iNSAWKPZziNCvRs5EC6ILDTlAPc= github.com/prometheus/common/sigv4 v0.1.0 h1:qoVebwtwwEhS85Czm2dSROY5fTo2PAPEVdDeppTwGX4= github.com/prometheus/common/sigv4 v0.1.0/go.mod h1:2Jkxxk9yYvCkE5G1sQT7GuEXm57JrvHu9k5YwTjsNtI= github.com/prometheus/procfs v0.0.0-20180125133057-cb4147076ac7/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= @@ -1204,8 +1179,8 @@ github.com/replicatedhq/termui/v3 v3.1.1-0.20200811145416-f40076d26851/go.mod h1 github.com/replicatedhq/troubleshoot v0.57.0 h1:m9B31Mhgiz4Lwz+W4RvFkqhfYZLCwAqRPUwiwmSAAps= github.com/replicatedhq/troubleshoot v0.57.0/go.mod h1:R5VdixzaBXfWLbP9mcLuZKs/bDCyGGS4+vFtKGWs9xE= github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= -github.com/rivo/uniseg v0.4.4 h1:8TfxU8dW6PdqD27gjM8MVNuicgxIjxpm4K7x4jp8sis= -github.com/rivo/uniseg v0.4.4/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= +github.com/rivo/uniseg v0.4.6 h1:Sovz9sDSwbOz9tgUy8JpT+KgCkPYJEN/oYzlJiYTNLg= +github.com/rivo/uniseg v0.4.6/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= github.com/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs= github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro= github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= @@ -1214,8 +1189,9 @@ github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFR github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE= github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= -github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog= +github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8= +github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4= github.com/rubenv/sql-migrate v1.3.1 h1:Vx+n4Du8X8VTYuXbhNxdEUoh6wiJERA0GlWocR5FrbA= github.com/rubenv/sql-migrate v1.3.1/go.mod h1:YzG/Vh82CwyhTFXy+Mf5ahAiiEOpAlHurg+23VEzcsk= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= @@ -1278,13 +1254,12 @@ github.com/spf13/cast v1.5.1/go.mod h1:b9PdjNptOpzXr7Rq1q9gJML/2cdGQAo69NKzQ10KN github.com/spf13/cobra v0.0.1/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= github.com/spf13/cobra v0.0.6/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE= github.com/spf13/cobra v1.2.1/go.mod h1:ExllRjgxM/piMAM+3tAZvg8fsklGAf3tPfi+i8t68Nk= -github.com/spf13/cobra v1.7.0 h1:hyqWnYt1ZQShIddO5kBpj3vu05/++x6tJ6dg8EC572I= -github.com/spf13/cobra v1.7.0/go.mod h1:uLxZILRyS/50WlhOIKD7W6V5bgeIt+4sICxh6uRMrb0= +github.com/spf13/cobra v1.8.0 h1:7aJaZx1B85qltLMc546zn58BxxfZdR/W22ej9CFoEf0= +github.com/spf13/cobra v1.8.0/go.mod h1:WXLWApfZ71AjXPya3WOlMsY9yMs7YeiHhFVlvLyhcho= github.com/spf13/jwalterweatherman v0.0.0-20141219030609-3d60171a6431/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= 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 v0.0.0-20170130214245-9ff6c6923cff/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/pflag v1.0.0/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= 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= @@ -1313,6 +1288,7 @@ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ github.com/stretchr/testify v1.7.4/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= @@ -1380,6 +1356,7 @@ github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9de github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/yuin/goldmark v1.4.0/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= +github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= github.com/yusufpapurcu/wmi v1.2.3 h1:E1ctvB7uKFMOJw3fdOW32DwGE9I7t++CRUEMKvFoFiw= github.com/yusufpapurcu/wmi v1.2.3/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0= @@ -1395,25 +1372,25 @@ github.com/zclconf/go-cty v1.12.1 h1:PcupnljUm9EIvbgSHQnHhUr3fO6oFmkOrvs2BAFNXXY github.com/zclconf/go-cty v1.12.1/go.mod h1:s9IfD1LK5ccNMSWCVFCE2rJfHiZgi7JijgeWIMfhLvA= github.com/zclconf/go-cty-debug v0.0.0-20191215020915-b22d67c1ba0b/go.mod h1:ZRKQfBXbGkpdV6QMzT3rU1kSTAnfu1dO8dPKjYprgj8= go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= -go.etcd.io/bbolt v1.3.7 h1:j+zJOnnEjF/kyHlDDgGnVL/AIqIJPq8UoB2GSNfkUfQ= -go.etcd.io/bbolt v1.3.7/go.mod h1:N9Mkw9X8x5fupy0IKsmuqVtoGDyxsaDlbk4Rd05IAQw= +go.etcd.io/bbolt v1.3.8 h1:xs88BrvEv273UsB79e0hcVrlUWmS0a8upikMFhSyAtA= +go.etcd.io/bbolt v1.3.8/go.mod h1:N9Mkw9X8x5fupy0IKsmuqVtoGDyxsaDlbk4Rd05IAQw= go.etcd.io/etcd/api/v3 v3.5.0/go.mod h1:cbVKeC6lCfl7j/8jBhAK6aIYO9XOjdptoxU/nLQcPvs= -go.etcd.io/etcd/api/v3 v3.5.9 h1:4wSsluwyTbGGmyjJktOf3wFQoTBIURXHnq9n/G/JQHs= -go.etcd.io/etcd/api/v3 v3.5.9/go.mod h1:uyAal843mC8uUVSLWz6eHa/d971iDGnCRpmKd2Z+X8k= +go.etcd.io/etcd/api/v3 v3.5.10 h1:szRajuUUbLyppkhs9K6BRtjY37l66XQQmw7oZRANE4k= +go.etcd.io/etcd/api/v3 v3.5.10/go.mod h1:TidfmT4Uycad3NM/o25fG3J07odo4GBB9hoxaodFCtI= go.etcd.io/etcd/client/pkg/v3 v3.5.0/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g= -go.etcd.io/etcd/client/pkg/v3 v3.5.9 h1:oidDC4+YEuSIQbsR94rY9gur91UPL6DnxDCIYd2IGsE= -go.etcd.io/etcd/client/pkg/v3 v3.5.9/go.mod h1:y+CzeSmkMpWN2Jyu1npecjB9BBnABxGM4pN8cGuJeL4= +go.etcd.io/etcd/client/pkg/v3 v3.5.10 h1:kfYIdQftBnbAq8pUWFXfpuuxFSKzlmM5cSn76JByiT0= +go.etcd.io/etcd/client/pkg/v3 v3.5.10/go.mod h1:DYivfIviIuQ8+/lCq4vcxuseg2P2XbHygkKwFo9fc8U= go.etcd.io/etcd/client/v2 v2.305.0/go.mod h1:h9puh54ZTgAKtEbut2oe9P4L/oqKCVB6xsXlzd7alYQ= -go.etcd.io/etcd/client/v2 v2.305.9 h1:YZ2OLi0OvR0H75AcgSUajjd5uqKDKocQUqROTG11jIo= -go.etcd.io/etcd/client/v2 v2.305.9/go.mod h1:0NBdNx9wbxtEQLwAQtrDHwx58m02vXpDcgSYI2seohQ= -go.etcd.io/etcd/client/v3 v3.5.9 h1:r5xghnU7CwbUxD/fbUtRyJGaYNfDun8sp/gTr1hew6E= -go.etcd.io/etcd/client/v3 v3.5.9/go.mod h1:i/Eo5LrZ5IKqpbtpPDuaUnDOUv471oDg8cjQaUr2MbA= -go.etcd.io/etcd/pkg/v3 v3.5.9 h1:6R2jg/aWd/zB9+9JxmijDKStGJAPFsX3e6BeJkMi6eQ= -go.etcd.io/etcd/pkg/v3 v3.5.9/go.mod h1:BZl0SAShQFk0IpLWR78T/+pyt8AruMHhTNNX73hkNVY= -go.etcd.io/etcd/raft/v3 v3.5.9 h1:ZZ1GIHoUlHsn0QVqiRysAm3/81Xx7+i2d7nSdWxlOiI= -go.etcd.io/etcd/raft/v3 v3.5.9/go.mod h1:WnFkqzFdZua4LVlVXQEGhmooLeyS7mqzS4Pf4BCVqXg= -go.etcd.io/etcd/server/v3 v3.5.9 h1:vomEmmxeztLtS5OEH7d0hBAg4cjVIu9wXuNzUZx2ZA0= -go.etcd.io/etcd/server/v3 v3.5.9/go.mod h1:GgI1fQClQCFIzuVjlvdbMxNbnISt90gdfYyqiAIt65g= +go.etcd.io/etcd/client/v2 v2.305.10 h1:MrmRktzv/XF8CvtQt+P6wLUlURaNpSDJHFZhe//2QE4= +go.etcd.io/etcd/client/v2 v2.305.10/go.mod h1:m3CKZi69HzilhVqtPDcjhSGp+kA1OmbNn0qamH80xjA= +go.etcd.io/etcd/client/v3 v3.5.10 h1:W9TXNZ+oB3MCd/8UjxHTWK5J9Nquw9fQBLJd5ne5/Ao= +go.etcd.io/etcd/client/v3 v3.5.10/go.mod h1:RVeBnDz2PUEZqTpgqwAtUd8nAPf5kjyFyND7P1VkOKc= +go.etcd.io/etcd/pkg/v3 v3.5.10 h1:WPR8K0e9kWl1gAhB5A7gEa5ZBTNkT9NdNWrR8Qpo1CM= +go.etcd.io/etcd/pkg/v3 v3.5.10/go.mod h1:TKTuCKKcF1zxmfKWDkfz5qqYaE3JncKKZPFf8c1nFUs= +go.etcd.io/etcd/raft/v3 v3.5.10 h1:cgNAYe7xrsrn/5kXMSaH8kM/Ky8mAdMqGOxyYwpP0LA= +go.etcd.io/etcd/raft/v3 v3.5.10/go.mod h1:odD6kr8XQXTy9oQnyMPBOr0TVe+gT0neQhElQ6jbGRc= +go.etcd.io/etcd/server/v3 v3.5.10 h1:4NOGyOwD5sUZ22PiWYKmfxqoeh72z6EhYjNosKGLmZg= +go.etcd.io/etcd/server/v3 v3.5.10/go.mod h1:gBplPHfs6YI0L+RpGkTQO7buDbHv5HJGG/Bst0/zIPo= go.mongodb.org/mongo-driver v1.13.1 h1:YIc7HTYsKndGK4RFzJ3covLz1byri52x0IoMB0Pt/vk= go.mongodb.org/mongo-driver v1.13.1/go.mod h1:wcDf1JBCXy2mOW0bWHwO/IOYqdca1MPCwDtFu/Z9+eo= go.mozilla.org/pkcs7 v0.0.0-20200128120323-432b2356ecb1/go.mod h1:SNgMg+EgDFwmvSmLRTNKC5fegJjB7v23qTQ0XLGUNHk= @@ -1426,22 +1403,22 @@ go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E= go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0= go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= -go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.46.0 h1:PzIubN4/sjByhDRHLviCjJuweBXWFZWhghjg7cS28+M= -go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.46.0/go.mod h1:Ct6zzQEuGK3WpJs2n4dn+wfJYzd/+hNnxMRTWjGn30M= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.45.0 h1:x8Z78aZx8cOF0+Kkazoc7lwUNMGy0LrzEMxTm4BbTxg= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.45.0/go.mod h1:62CPTSry9QZtOaSsE3tOzhx6LzDhHnXJ6xHeMNNiM6Q= -go.opentelemetry.io/otel v1.20.0 h1:vsb/ggIY+hUjD/zCAQHpzTmndPqv/ml2ArbsbfBYTAc= -go.opentelemetry.io/otel v1.20.0/go.mod h1:oUIGj3D77RwJdM6PPZImDpSZGDvkD9fhesHny69JFrs= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.47.0 h1:UNQQKPfTDe1J81ViolILjTKPr9WetKW6uei2hFgJmFs= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.47.0/go.mod h1:r9vWsPS/3AQItv3OSlEJ/E4mbrhUbbw18meOjArPtKQ= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.47.0 h1:sv9kVfal0MK0wBMCOGr+HeJm9v803BkJxGrk2au7j08= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.47.0/go.mod h1:SK2UL73Zy1quvRPonmOmRDiWk1KBV3LyIeeIxcEApWw= +go.opentelemetry.io/otel v1.22.0 h1:xS7Ku+7yTFvDfDraDIJVpw7XPyuHlB9MCiqqX5mcJ6Y= +go.opentelemetry.io/otel v1.22.0/go.mod h1:eoV4iAi3Ea8LkAEI9+GFT44O6T/D0GWAVFyZVCC6pMI= go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.20.0 h1:DeFD0VgTZ+Cj6hxravYYZE2W4GlneVH81iAOPjZkzk8= go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.20.0/go.mod h1:GijYcYmNpX1KazD5JmWGsi4P7dDTTTnfv1UbGn84MnU= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.20.0 h1:gvmNvqrPYovvyRmCSygkUDyL8lC5Tl845MLEwqpxhEU= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.20.0/go.mod h1:vNUq47TGFioo+ffTSnKNdob241vePmtNZnAODKapKd0= -go.opentelemetry.io/otel/metric v1.20.0 h1:ZlrO8Hu9+GAhnepmRGhSU7/VkpjrNowxRN9GyKR4wzA= -go.opentelemetry.io/otel/metric v1.20.0/go.mod h1:90DRw3nfK4D7Sm/75yQ00gTJxtkBxX+wu6YaNymbpVM= -go.opentelemetry.io/otel/sdk v1.20.0 h1:5Jf6imeFZlZtKv9Qbo6qt2ZkmWtdWx/wzcCbNUlAWGM= -go.opentelemetry.io/otel/sdk v1.20.0/go.mod h1:rmkSx1cZCm/tn16iWDn1GQbLtsW/LvsdEEFzCSRM6V0= -go.opentelemetry.io/otel/trace v1.20.0 h1:+yxVAPZPbQhbC3OfAkeIVTky6iTFpcr4SiY9om7mXSQ= -go.opentelemetry.io/otel/trace v1.20.0/go.mod h1:HJSK7F/hA5RlzpZ0zKDCHCDHm556LCDtKaAo6JmBFUU= +go.opentelemetry.io/otel/metric v1.22.0 h1:lypMQnGyJYeuYPhOM/bgjbFM6WE44W1/T45er4d8Hhg= +go.opentelemetry.io/otel/metric v1.22.0/go.mod h1:evJGjVpZv0mQ5QBRJoBF64yMuOf4xCWdXjK8pzFvliY= +go.opentelemetry.io/otel/sdk v1.21.0 h1:FTt8qirL1EysG6sTQRZ5TokkU8d0ugCj8htOgThZXQ8= +go.opentelemetry.io/otel/sdk v1.21.0/go.mod h1:Nna6Yv7PWTdgJHVRD9hIYywQBRx7pbox6nwBnZIxl/E= +go.opentelemetry.io/otel/trace v1.22.0 h1:Hg6pPujv0XG9QaVbGOBVHunyuLcCC3jN7WEhPx83XD0= +go.opentelemetry.io/otel/trace v1.22.0/go.mod h1:RbbHXVqKES9QhzZq/fE5UnOSILqRt40a21sPw2He1xo= go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= go.opentelemetry.io/proto/otlp v1.0.0 h1:T0TX0tmXU8a3CbNXzEKGeU5mIVOdf0oykP+u2lIVU/I= go.opentelemetry.io/proto/otlp v1.0.0/go.mod h1:Sy6pihPLfYHkr3NkUbEhGHFhINUSI/v80hjKIs5JXpM= @@ -1449,16 +1426,14 @@ go.starlark.net v0.0.0-20230525235612-a134d8f9ddca h1:VdD38733bfYv5tUZwEIskMM93V go.starlark.net v0.0.0-20230525235612-a134d8f9ddca/go.mod h1:jxU+3+j+71eXOW14274+SmmuW82qJzl6iZSeqEtTGds= go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= -go.uber.org/goleak v1.1.11/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= -go.uber.org/goleak v1.2.1 h1:NBol2c7O1ZokfZ0LEU9K6Whx/KnwvepVetCUhtKja4A= -go.uber.org/goleak v1.2.1/go.mod h1:qlT2yGI9QafXHhZZLxlSuNsMw3FFLxBr+tBRlmO1xH4= +go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= +go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= go.uber.org/zap v1.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo= -go.uber.org/zap v1.24.0/go.mod h1:2kMP+WWQ8aoFoedH3T2sq6iJ2yDWpHbP0f6MQbS9Gkg= go.uber.org/zap v1.26.0 h1:sI7k6L95XOKS281NhVKOFCUNIvv9e0w4BF8N3u+tCRo= go.uber.org/zap v1.26.0/go.mod h1:dtElttAiwGvoJ/vj4IwHBS/gXsEu/pZ50mUIRWuG0so= go4.org/netipx v0.0.0-20230728184502-ec4c8b891b28 h1:zLxFnORHDFTSkJPawMU7LzsuGQJ4MUFS653jJHpORow= @@ -1470,9 +1445,7 @@ golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACk golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/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-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20191206172530-e9b2fee46413/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200414173820-0848c9571904/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= @@ -1480,7 +1453,6 @@ golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a/go.mod h1:LzIPMQfyMNhhGPh golang.org/x/crypto v0.0.0-20201117144127-c1f2f97bffc9/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.0.0-20220314234659-1baeb1ce4c0b/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.0.0-20220525230936-793ad666bf5e/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.0.0-20220826181053-bd7e27e6170d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= @@ -1490,22 +1462,11 @@ golang.org/x/crypto v0.3.1-0.20221117191849-2c476679df9a/go.mod h1:hebNnKkNXi2Uz golang.org/x/crypto v0.5.0/go.mod h1:NK/OQwhpMQP3MwtdjgLlYHnH9ebylxKWv3e0fK+mkQU= golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU= -golang.org/x/crypto v0.17.0 h1:r8bRNjWL3GshPW3gkd+RpvzWrZAwPS49OmTGZ/uhM4k= -golang.org/x/crypto v0.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4= -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/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= -golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= -golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= -golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= -golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= +golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4= +golang.org/x/crypto v0.21.0 h1:X31++rzVUdKhX5sWmSOFZxx8UW/ldWx55cbf08iNAMA= +golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs= golang.org/x/exp v0.0.0-20230711153332-06a737ee72cb h1:xIApU0ow1zwMa2uL1VDNeQlNVFTWMQxZUZCMDy0Q4Us= golang.org/x/exp v0.0.0-20230711153332-06a737ee72cb/go.mod h1:FXUEEKJgO7OQYeo8N01OfiKP8RXMtf6e8aTskBGqWdc= -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= @@ -1518,22 +1479,23 @@ golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPI golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= -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/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= -golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3/go.mod h1:3p9vT2HGsQu2K1YbXdKPJLVgG5VJdoTa1poYQBtP1AY= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/mod v0.6.0/go.mod h1:4mET923SAdbXp2ki8ey+zGs1SLqsuM2Y0uvdZR/fUNI= +golang.org/x/mod v0.7.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= -golang.org/x/mod v0.12.0 h1:rmsUpXtvNzj340zd98LZ4KntptpfRHwpFOHG188oHXc= -golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/mod v0.9.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/mod v0.10.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/mod v0.11.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/mod v0.16.0 h1:QX4fJ0Rr5cPQCF7O9lh9Se4pmwfwskqZfq5moyldzic= +golang.org/x/mod v0.16.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180811021610-c39426892332/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -1554,7 +1516,6 @@ golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/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-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= @@ -1566,6 +1527,7 @@ golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/ golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= @@ -1578,9 +1540,11 @@ golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= +golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk= golang.org/x/net v0.0.0-20210503060351-7fd8e65b6420/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= @@ -1596,12 +1560,16 @@ golang.org/x/net v0.0.0-20220909164309-bea034e7d591/go.mod h1:YDH+HFinaLZZlnHAfS golang.org/x/net v0.0.0-20221014081412-f15817d10f9b/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco= golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY= +golang.org/x/net v0.3.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE= golang.org/x/net v0.5.0/go.mod h1:DivGGAXEgPSlEBzxGzZI+ZLohi+xUj054jfeKui00ws= golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= -golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM= +golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns= +golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= +golang.org/x/net v0.23.0 h1:7EYJ93RZ9vYSZAIb2x3lnuvqO5zneoD6IvWjuhfxjTs= +golang.org/x/net v0.23.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg= 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= @@ -1628,8 +1596,9 @@ golang.org/x/oauth2 v0.0.0-20220822191816-0ebed06d0094/go.mod h1:h4gKUeWbJ4rQPri golang.org/x/oauth2 v0.0.0-20220909003341-f21342109be1/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg= golang.org/x/oauth2 v0.0.0-20221014153046-6fdb5e3db783/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg= golang.org/x/oauth2 v0.1.0/go.mod h1:G9FE4dLTsbXUu90h/Pf85g4w1D+SSAgR+q46nJZ8M4A= -golang.org/x/oauth2 v0.12.0 h1:smVPGxink+n1ZI5pkQa8y6fZT0RW0MgCO5bFpepy4B4= -golang.org/x/oauth2 v0.12.0/go.mod h1:A74bZ3aGXgCY0qaIC9Ahg6Lglin4AMAco8cIv9baba4= +golang.org/x/oauth2 v0.8.0/go.mod h1:yr7u4HXZRm1R1kBWqr/xKNqewf0plRYoB7sla+BCIXE= +golang.org/x/oauth2 v0.18.0 h1:09qnuIAgzdx1XplqJvW6CQqMCtGZykZWcXzPMPUusvI= +golang.org/x/oauth2 v0.18.0/go.mod h1:Wf7knwG0MPoWIMMBgFlEaSUDaKskp0dCfrlJRJXbBi8= 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= @@ -1645,8 +1614,8 @@ golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220929204114-8fcdb60fdcc0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E= -golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= +golang.org/x/sync v0.6.0 h1:5BMeUDZ7vkXGfEr1x9B4bRcTH4lpkTkpdh0T/J+qjbQ= +golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= 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= @@ -1657,19 +1626,17 @@ golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5h golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b/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-20190222072716-a9d3bda3a223/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-20190412213103-97732733099d/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-20190524152521-dbbf3f1254d4/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-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190801041406-cbf593c0f2f3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191010194322-b09406accb47/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -1691,7 +1658,6 @@ golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200622214017-ed371f2e16b4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -1700,6 +1666,7 @@ golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201204225414-ed752295db88/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210220050731-9a76102bfb43/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -1721,6 +1688,7 @@ golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210908233432-aa78b53d3365/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211124211545-fe61309f8881/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211210111614-af8b64212486/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -1728,8 +1696,10 @@ golang.org/x/sys v0.0.0-20220128215802-99c3d69c2c27/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220209214540-3681064d5158/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220227234510-4e6760a101f9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220310020820-b874c991c1a5/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220319134239-a9b59b0215f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220328115105-d36c6a25d886/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220422013727-9388b58f7150/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220502124256-b6088ccd6cba/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -1742,7 +1712,6 @@ golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220825204002-c680a09ffe64/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220906165534-d0df966e6959/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20221013171732-95e765b1cc43/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -1750,9 +1719,12 @@ golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.4.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.9.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc= -golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4= +golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= @@ -1760,11 +1732,15 @@ golang.org/x/term v0.0.0-20220526004731-065cf7ba2467/go.mod h1:jbD1KX2456YbFQfuX golang.org/x/term v0.0.0-20220722155259-a9ba230a4035/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc= +golang.org/x/term v0.3.0/go.mod h1:q750SLmJuPmVoN1blW3UFBPREJfb1KmY3vwxfr+nFDA= golang.org/x/term v0.4.0/go.mod h1:9P2UbLfCdcvo3p/nzKvsmas4TnlujnuoV9hGgYzW1lQ= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U= -golang.org/x/term v0.15.0 h1:y/Oo/a/q3IXu26lQgl04j/gjuBDOBlx7X6Om1j2CPW4= -golang.org/x/term v0.15.0/go.mod h1:BDl952bC7+uMoWR75FIrCDx79TPU9oHkTZ9yRbYOrX0= +golang.org/x/term v0.7.0/go.mod h1:P32HKFT3hSsZrRxla30E9HqToFYAQPCMs/zFMBUFqPY= +golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= +golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U= +golang.org/x/term v0.18.0 h1:FcHjZXDMxI8mM3nwhX9HlKop4C0YQvCVCdwYl2wOtE8= +golang.org/x/term v0.18.0/go.mod h1:ILwASektA3OnRv7amZ1xhE/KTR+u50pbXfZ03+6Nx58= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -1776,37 +1752,35 @@ golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.5.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.6.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20200416051211-89c76fbcd5d1/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4= golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk= +golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= 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-20181011042414-1f849cf54d09/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-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-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-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= 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-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/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= @@ -1819,7 +1793,6 @@ golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapK golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= @@ -1828,9 +1801,9 @@ golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjs golang.org/x/tools v0.0.0-20200313205530-4303120df7d8/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200505023115-26f46d2f7ef8/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200616133436-c1934b75d054/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= @@ -1840,6 +1813,7 @@ golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82u golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= @@ -1849,11 +1823,15 @@ golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.4/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.7/go.mod h1:LGqMHiF4EqQNHR1JncWGqT5BVaXmza+X+BDGol+dOxo= +golang.org/x/tools v0.1.10/go.mod h1:Uh6Zz+xoGYZom868N8YTex3t7RhtHDBrE8Gzo9bV56E= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/tools v0.2.0/go.mod h1:y4OqIKeOV/fWJetJ8bXPU1sEVniLMIyDAZWeHdV+NTA= +golang.org/x/tools v0.4.0/go.mod h1:UE5sM2OK9E/d67R0ANs2xJizIymRP5gJU295PvKXxjQ= golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= -golang.org/x/tools v0.12.0 h1:YW6HUoUmYBpwSgyaGaZq1fHjrBjX1rlpZ54T6mu2kss= -golang.org/x/tools v0.12.0/go.mod h1:Sc0INKfu04TlqNoRA1hgpFZbhYXHPr4V5DzpSBTPqQM= +golang.org/x/tools v0.7.0/go.mod h1:4pg6aUX35JBAogB10C9AtvVL+qowtN4pT3CGSQex14s= +golang.org/x/tools v0.8.0/go.mod h1:JxBZ99ISMI5ViVkT1tr6tdNmXeTrcpVSD3vZ1RsRdN4= +golang.org/x/tools v0.19.0 h1:tfGCXNR1OsFG+sVdLAitlpjAvD/I6dHDKnYrpEZUHkw= +golang.org/x/tools v0.19.0/go.mod h1:qoJWxmGSIBmAeriMx19ogtrEPrGtDbPK634QFIcLAhc= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -1863,8 +1841,8 @@ golang.org/x/xerrors v0.0.0-20220517211312-f3a8303e98df/go.mod h1:K8+ghG5WaK9qNq golang.org/x/xerrors v0.0.0-20220609144429-65e65417b02f/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 h1:H2TDz8ibqkAF6YGhCdN3jS9O0/s90v0rJh3X/OLHEUk= golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= -gomodules.xyz/jsonpatch/v2 v2.3.0 h1:8NFhfS6gzxNqjLIYnZxg319wZ5Qjnx4m/CcX+Klzazc= -gomodules.xyz/jsonpatch/v2 v2.3.0/go.mod h1:AH3dM2RI6uoBZxn3LVrfvJ3E0/9dG4cSrbuBJT4moAY= +gomodules.xyz/jsonpatch/v2 v2.4.0 h1:Ci3iUJyx9UeRx7CeFN8ARgGbkESwJK+KB9lLcWxY/Zw= +gomodules.xyz/jsonpatch/v2 v2.4.0/go.mod h1:AH3dM2RI6uoBZxn3LVrfvJ3E0/9dG4cSrbuBJT4moAY= google.golang.org/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= @@ -1914,16 +1892,17 @@ google.golang.org/api v0.96.0/go.mod h1:w7wJQLTM+wvQpNf5JyEcBoxK0RH7EDrh/L4qfsuJ google.golang.org/api v0.97.0/go.mod h1:w7wJQLTM+wvQpNf5JyEcBoxK0RH7EDrh/L4qfsuJ13s= google.golang.org/api v0.98.0/go.mod h1:w7wJQLTM+wvQpNf5JyEcBoxK0RH7EDrh/L4qfsuJ13s= google.golang.org/api v0.100.0/go.mod h1:ZE3Z2+ZOr87Rx7dqFsdRQkRBk36kDtp/h+QpHbB7a70= -google.golang.org/api v0.126.0 h1:q4GJq+cAdMAC7XP7njvQ4tvohGLiSlytuL4BQxbIZ+o= -google.golang.org/api v0.126.0/go.mod h1:mBwVAtz+87bEN6CbA1GtZPDOqY2R5ONPqJeIlvyo4Aw= +google.golang.org/api v0.161.0 h1:oYzk/bs26WN10AV7iU7MVJVXBH8oCPS2hHyBiEeFoSU= +google.golang.org/api v0.161.0/go.mod h1:0mu0TpK33qnydLvWqbImq2b1eQ5FHRSDCBzAxX9ZHyw= 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/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= -google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c= google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/appengine v1.6.8 h1:IhEN5q69dyKagZPYMSdIjS2HqprW324FRQZJcGqPAsM= +google.golang.org/appengine v1.6.8/go.mod h1:1jJ3jBArFh5pcgW8gCtRJnepW8FzD1V44FJffLiz/Ds= 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= @@ -2025,12 +2004,12 @@ google.golang.org/genproto v0.0.0-20221010155953-15ba04fc1c0e/go.mod h1:3526vdqw google.golang.org/genproto v0.0.0-20221014173430-6e2ab493f96b/go.mod h1:1vXfmgAz9N9Jx0QA82PqRVauvCz1SGSz739p0f183jM= google.golang.org/genproto v0.0.0-20221014213838-99cd37c6964a/go.mod h1:1vXfmgAz9N9Jx0QA82PqRVauvCz1SGSz739p0f183jM= google.golang.org/genproto v0.0.0-20221025140454-527a21cfbd71/go.mod h1:9qHF0xnpdSfF6knlcsnpzUu5y+rpwgbvsyGAZPBMg4s= -google.golang.org/genproto v0.0.0-20230822172742-b8732ec3820d h1:VBu5YqKPv6XiJ199exd8Br+Aetz+o08F+PLMnwJQHAY= -google.golang.org/genproto v0.0.0-20230822172742-b8732ec3820d/go.mod h1:yZTlhN0tQnXo3h00fuXNCxJdLdIdnVFVBaRJ5LWBbw4= -google.golang.org/genproto/googleapis/api v0.0.0-20230822172742-b8732ec3820d h1:DoPTO70H+bcDXcd39vOqb2viZxgqeBeSGtZ55yZU4/Q= -google.golang.org/genproto/googleapis/api v0.0.0-20230822172742-b8732ec3820d/go.mod h1:KjSP20unUpOx5kyQUFa7k4OJg0qeJ7DEZflGDu2p6Bk= -google.golang.org/genproto/googleapis/rpc v0.0.0-20230822172742-b8732ec3820d h1:uvYuEyMHKNt+lT4K3bN6fGswmK8qSvcreM3BwjDh+y4= -google.golang.org/genproto/googleapis/rpc v0.0.0-20230822172742-b8732ec3820d/go.mod h1:+Bk1OCOj40wS2hwAMA+aCW9ypzm63QTBBHp6lQ3p+9M= +google.golang.org/genproto v0.0.0-20240125205218-1f4bbc51befe h1:USL2DhxfgRchafRvt/wYyyQNzwgL7ZiURcozOE/Pkvo= +google.golang.org/genproto v0.0.0-20240125205218-1f4bbc51befe/go.mod h1:cc8bqMqtv9gMOr0zHg2Vzff5ULhhL2IXP4sbcn32Dro= +google.golang.org/genproto/googleapis/api v0.0.0-20240125205218-1f4bbc51befe h1:0poefMBYvYbs7g5UkjS6HcxBPaTRAmznle9jnxYoAI8= +google.golang.org/genproto/googleapis/api v0.0.0-20240125205218-1f4bbc51befe/go.mod h1:4jWUdICTdgc3Ibxmr8nAJiiLHwQBY0UI0XZcEMaFKaA= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240125205218-1f4bbc51befe h1:bQnxqljG/wqi4NTXu2+DJ3n7APcEA882QZ1JvhQAq9o= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240125205218-1f4bbc51befe/go.mod h1:PAREbraiVEVGVdTZsVWjSbbTtSyGbAgIIvni8a8CD5s= google.golang.org/grpc v1.0.5/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= @@ -2068,8 +2047,8 @@ google.golang.org/grpc v1.48.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACu google.golang.org/grpc v1.49.0/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI= google.golang.org/grpc v1.50.0/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI= google.golang.org/grpc v1.50.1/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI= -google.golang.org/grpc v1.59.0 h1:Z5Iec2pjwb+LEOqzpB2MR12/eKFhDPhuqW91O+4bwUk= -google.golang.org/grpc v1.59.0/go.mod h1:aUPDwccQo6OTjy7Hct4AfBPD1GptF4fyUjIkQ9YtF98= +google.golang.org/grpc v1.61.0 h1:TOvOcuXn30kRao+gfcvsebNEa5iZIiLkisYEkf7R7o0= +google.golang.org/grpc v1.61.0/go.mod h1:VUbo7IFqmF1QtCAstipjG0GIoq49KvMe9+h1jFLBNJs= google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= @@ -2086,8 +2065,9 @@ google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQ google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= -google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8= -google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI= +google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= gopkg.in/airbrake/gobrake.v2 v2.0.9/go.mod h1:/h5ZAUhDkGaJfjzjKLSjv6zCL6O0LLBxU4K+aSYdM/U= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/cenkalti/backoff.v2 v2.2.1 h1:eJ9UAg01/HIHG987TwxvnzK2MgxXq97YY6rYDpY9aII= @@ -2097,7 +2077,6 @@ gopkg.in/check.v1 v1.0.0-20160105164936-4f90aeace3a2/go.mod h1:Co6ibVJAznAaIkqp8 gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/cheggaaa/pb.v1 v1.0.27/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw= @@ -2147,46 +2126,48 @@ honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWh honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= -k8s.io/api v0.19.0/go.mod h1:I1K45XlvTrDjmj5LoM5LuP/KYrhWbjUKT/SoPG0qTjw= -k8s.io/api v0.28.2 h1:9mpl5mOb6vXZvqbQmankOfPIGiudghwCoLl1EYfUZbw= -k8s.io/api v0.28.2/go.mod h1:RVnJBsjU8tcMq7C3iaRSGMeaKt2TWEUXcpIt/90fjEg= -k8s.io/apiextensions-apiserver v0.28.1 h1:l2ThkBRjrWpw4f24uq0Da2HaEgqJZ7pcgiEUTKSmQZw= -k8s.io/apiextensions-apiserver v0.28.1/go.mod h1:sVvrI+P4vxh2YBBcm8n2ThjNyzU4BQGilCQ/JAY5kGs= -k8s.io/apimachinery v0.19.0/go.mod h1:DnPGDnARWFvYa3pMHgSxtbZb7gpzzAZ1pTfaUNDVlmA= -k8s.io/apimachinery v0.28.2 h1:KCOJLrc6gu+wV1BYgwik4AF4vXOlVJPdiqn0yAWWwXQ= -k8s.io/apimachinery v0.28.2/go.mod h1:RdzF87y/ngqk9H4z3EL2Rppv5jj95vGS/HaFXrLDApU= -k8s.io/apiserver v0.28.1 h1:dw2/NKauDZCnOUAzIo2hFhtBRUo6gQK832NV8kuDbGM= -k8s.io/apiserver v0.28.1/go.mod h1:d8aizlSRB6yRgJ6PKfDkdwCy2DXt/d1FDR6iJN9kY1w= -k8s.io/cli-runtime v0.28.2 h1:64meB2fDj10/ThIMEJLO29a1oujSm0GQmKzh1RtA/uk= -k8s.io/cli-runtime v0.28.2/go.mod h1:bTpGOvpdsPtDKoyfG4EG041WIyFZLV9qq4rPlkyYfDA= -k8s.io/client-go v0.19.0/go.mod h1:H9E/VT95blcFQnlyShFgnFT9ZnJOAceiUHM3MlRC+mU= -k8s.io/client-go v0.28.2 h1:DNoYI1vGq0slMBN/SWKMZMw0Rq+0EQW6/AK4v9+3VeY= -k8s.io/client-go v0.28.2/go.mod h1:sMkApowspLuc7omj1FOSUxSoqjr+d5Q0Yc0LOFnYFJY= -k8s.io/code-generator v0.19.0/go.mod h1:moqLn7w0t9cMs4+5CQyxnfA/HV8MF6aAVENF+WZZhgk= -k8s.io/component-base v0.28.2 h1:Yc1yU+6AQSlpJZyvehm/NkJBII72rzlEsd6MkBQ+G0E= -k8s.io/component-base v0.28.2/go.mod h1:4IuQPQviQCg3du4si8GpMrhAIegxpsgPngPRR/zWpzc= -k8s.io/component-helpers v0.28.2 h1:r/XJ265PMirW9EcGXr/F+2yWrLPo2I69KdvcY/h9HAo= -k8s.io/component-helpers v0.28.2/go.mod h1:pF1R5YWQ+sgf0i6EbVm+MQCzkYuqutDUibdrkvAa6aI= -k8s.io/gengo v0.0.0-20200413195148-3a45101e95ac/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= -k8s.io/gengo v0.0.0-20200428234225-8167cfdcfc14/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= +k8s.io/api v0.28.3 h1:Gj1HtbSdB4P08C8rs9AR94MfSGpRhJgsS+GF9V26xMM= +k8s.io/api v0.28.3/go.mod h1:MRCV/jr1dW87/qJnZ57U5Pak65LGmQVkKTzf3AtKFHc= +k8s.io/apiextensions-apiserver v0.28.3 h1:Od7DEnhXHnHPZG+W9I97/fSQkVpVPQx2diy+2EtmY08= +k8s.io/apiextensions-apiserver v0.28.3/go.mod h1:NE1XJZ4On0hS11aWWJUTNkmVB03j9LM7gJSisbRt8Lc= +k8s.io/apimachinery v0.28.3 h1:B1wYx8txOaCQG0HmYF6nbpU8dg6HvA06x5tEffvOe7A= +k8s.io/apimachinery v0.28.3/go.mod h1:uQTKmIqs+rAYaq+DFaoD2X7pcjLOqbQX2AOiO0nIpb8= +k8s.io/apiserver v0.28.3 h1:8Ov47O1cMyeDzTXz0rwcfIIGAP/dP7L8rWbEljRcg5w= +k8s.io/apiserver v0.28.3/go.mod h1:YIpM+9wngNAv8Ctt0rHG4vQuX/I5rvkEMtZtsxW2rNM= +k8s.io/cli-runtime v0.28.3 h1:lvuJYVkwCqHEvpS6KuTZsUVwPePFjBfSGvuaLl2SxzA= +k8s.io/cli-runtime v0.28.3/go.mod h1:jeX37ZPjIcENVuXDDTskG3+FnVuZms5D9omDXS/2Jjc= +k8s.io/client-go v0.28.3 h1:2OqNb72ZuTZPKCl+4gTKvqao0AMOl9f3o2ijbAj3LI4= +k8s.io/client-go v0.28.3/go.mod h1:LTykbBp9gsA7SwqirlCXBWtK0guzfhpoW4qSm7i9dxo= +k8s.io/code-generator v0.28.3/go.mod h1:A2EAHTRYvCvBrb/MM2zZBNipeCk3f8NtpdNIKawC43M= +k8s.io/component-base v0.29.0 h1:T7rjd5wvLnPBV1vC4zWd/iWRbV8Mdxs+nGaoaFzGw3s= +k8s.io/component-base v0.29.0/go.mod h1:sADonFTQ9Zc9yFLghpDpmNXEdHyQmFIGbiuZbqAXQ1M= +k8s.io/component-helpers v0.28.3 h1:te9ieTGzcztVktUs92X53P6BamAoP73MK0qQP0WmDqc= +k8s.io/component-helpers v0.28.3/go.mod h1:oJR7I9ist5UAQ3y/CTdbw6CXxdMZ1Lw2Ua/EZEwnVLs= +k8s.io/gengo v0.0.0-20210813121822-485abfe95c7c/go.mod h1:FiNAH4ZV3gBg2Kwh89tzAEV2be7d5xI0vBa/VySYy3E= +k8s.io/gengo v0.0.0-20220902162205-c0856e24416d/go.mod h1:FiNAH4ZV3gBg2Kwh89tzAEV2be7d5xI0vBa/VySYy3E= k8s.io/klog v1.0.0 h1:Pt+yjF5aB1xDSVbau4VsWe+dQNzA0qv1LlXdC2dF6Q8= k8s.io/klog v1.0.0/go.mod h1:4Bi6QPql/J/LkTDqv7R/cd3hPo4k2DG6Ptcz060Ez5I= k8s.io/klog/v2 v2.0.0/go.mod h1:PBfzABfn139FHAV07az/IF9Wp1bkk3vpT2XSJ76fSDE= k8s.io/klog/v2 v2.2.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y= -k8s.io/klog/v2 v2.100.1 h1:7WCHKK6K8fNhTqfBhISHQ97KrnJNFZMcQvKp7gP/tmg= +k8s.io/klog/v2 v2.80.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0= k8s.io/klog/v2 v2.100.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0= -k8s.io/kube-openapi v0.0.0-20200805222855-6aeccd4b50c6/go.mod h1:UuqjUnNftUyPE5H64/qeyjQoUZhGpeFDVdxjTeEVN2o= -k8s.io/kube-openapi v0.0.0-20230918164632-68afd615200d h1:/CFeJBjBrZvHX09rObS2+2iEEDevMWYc1v3aIYAjIYI= -k8s.io/kube-openapi v0.0.0-20230918164632-68afd615200d/go.mod h1:AsvuZPBlUDVuCdzJ87iajxtXuR9oktsTctW/R9wwouA= -k8s.io/kubectl v0.28.2 h1:fOWOtU6S0smdNjG1PB9WFbqEIMlkzU5ahyHkc7ESHgM= -k8s.io/kubectl v0.28.2/go.mod h1:6EQWTPySF1fn7yKoQZHYf9TPwIl2AygHEcJoxFekr64= -k8s.io/kubelet v0.26.1 h1:wQyCQYmLW6GN3v7gVTxnc3jAE4zMYDlzdF3FZV4rKas= -k8s.io/kubelet v0.26.1/go.mod h1:gFVZ1Ab4XdjtnYdVRATwGwku7FhTxo6LVEZwYoQaDT8= -k8s.io/metrics v0.28.2 h1:Z/oMk5SmiT/Ji1SaWOPfW2l9W831BLO9/XxDq9iS3ak= -k8s.io/metrics v0.28.2/go.mod h1:QTIIdjMrq+KodO+rmp6R9Pr1LZO8kTArNtkWoQXw0sw= -k8s.io/utils v0.0.0-20200729134348-d5654de09c73/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= -k8s.io/utils v0.0.0-20230726121419-3b25d923346b h1:sgn3ZU783SCgtaSJjpcVVlRqd6GSnlTLKgpAAttJvpI= -k8s.io/utils v0.0.0-20230726121419-3b25d923346b/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= +k8s.io/klog/v2 v2.110.1 h1:U/Af64HJf7FcwMcXyKm2RPM22WZzyR7OSpYj5tg3cL0= +k8s.io/klog/v2 v2.110.1/go.mod h1:YGtd1984u+GgbuZ7e08/yBuAfKLSO0+uR1Fhi6ExXjo= +k8s.io/kube-openapi v0.0.0-20230717233707-2695361300d9/go.mod h1:wZK2AVp1uHCp4VamDVgBP2COHZjqD1T68Rf0CM3YjSM= +k8s.io/kube-openapi v0.0.0-20231010175941-2dd684a91f00 h1:aVUu9fTY98ivBPKR9Y5w/AuzbMm96cd3YHRTU83I780= +k8s.io/kube-openapi v0.0.0-20231010175941-2dd684a91f00/go.mod h1:AsvuZPBlUDVuCdzJ87iajxtXuR9oktsTctW/R9wwouA= +k8s.io/kubectl v0.28.3 h1:H1Peu1O3EbN9zHkJCcvhiJ4NUj6lb88sGPO5wrWIM6k= +k8s.io/kubectl v0.28.3/go.mod h1:RDAudrth/2wQ3Sg46fbKKl4/g+XImzvbsSRZdP2RiyE= +k8s.io/kubelet v0.28.3 h1:bp/uIf1R5F61BlFvFtzc4PDEiK7TtFcw3wFJlc0V0LM= +k8s.io/kubelet v0.28.3/go.mod h1:E3NHYbp/v45Ao6AD0EOZnqO3L0R6Haks6Nm0+bnFwtU= +k8s.io/kubernetes v1.28.3 h1:XTci6gzk+JR51UZuZQCFJ4CsyUkfivSjLI4O1P9z6LY= +k8s.io/kubernetes v1.28.3/go.mod h1:NhAysZWvHtNcJFFHic87ofxQN7loylCQwg3ZvXVDbag= +k8s.io/metrics v0.28.3 h1:w2s3kVi7HulXqCVDFkF4hN/OsL1tXTTb4Biif995h/g= +k8s.io/metrics v0.28.3/go.mod h1:OZZ23AHFojPzU6r3xoHGRUcV3I9pauLua+07sAUbwLc= +k8s.io/utils v0.0.0-20210802155522-efc7438f0176/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= +k8s.io/utils v0.0.0-20230406110748-d93618cff8a2/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= +k8s.io/utils v0.0.0-20231127182322-b307cd553661 h1:FepOBzJ0GXm8t0su67ln2wAZjbQ6RxQGZDnzuLcrUTI= +k8s.io/utils v0.0.0-20231127182322-b307cd553661/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= oras.land/oras-go v1.2.4 h1:djpBY2/2Cs1PV87GSJlxv4voajVOMZxqqtq9AB8YNvY= oras.land/oras-go v1.2.4/go.mod h1:DYcGfb3YF1nKjcezfX2SNlDAeQFKSXmf+qrFmrh4324= periph.io/x/host/v3 v3.8.0 h1:T5ojZ2wvnZHGPS4h95N2ZpcCyHnsvH3YRZ1UUUiv5CQ= @@ -2195,8 +2176,8 @@ rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8 rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= -sigs.k8s.io/controller-runtime v0.15.2 h1:9V7b7SDQSJ08IIsJ6CY1CE85Okhp87dyTMNDG0FS7f4= -sigs.k8s.io/controller-runtime v0.15.2/go.mod h1:7ngYvp1MLT+9GeZ+6lH3LOlcHkp/+tzA/fmHa4iq9kk= +sigs.k8s.io/controller-runtime v0.17.2 h1:FwHwD1CTUemg0pW2otk7/U5/i5m2ymzvOXdbeGOUvw0= +sigs.k8s.io/controller-runtime v0.17.2/go.mod h1:+MngTvIQQQhfXtwfdGw/UOQ/aIaqsYywfCINOtwMO/s= sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd h1:EDPBXCAspyGV4jQlpZSudPeMmr1bNJefnuqLsRAsHZo= sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0= sigs.k8s.io/kustomize/api v0.13.5-0.20230601165947-6ce0bf390ce3 h1:XX3Ajgzov2RKUdc5jW3t5jwY7Bo7dcRm+tFxT+NfgY0= @@ -2205,10 +2186,10 @@ sigs.k8s.io/kustomize/kustomize/v5 v5.0.4-0.20230601165947-6ce0bf390ce3 h1:vq2Tt sigs.k8s.io/kustomize/kustomize/v5 v5.0.4-0.20230601165947-6ce0bf390ce3/go.mod h1:/d88dHCvoy7d0AKFT0yytezSGZKjsZBVs9YTkBHSGFk= sigs.k8s.io/kustomize/kyaml v0.14.3 h1:WpabVAKZe2YEp/irTSHwD6bfjwZnTtSDewd2BVJGMZs= sigs.k8s.io/kustomize/kyaml v0.14.3/go.mod h1:npvh9epWysfQ689Rtt/U+dpOJDTBn8kUnF1O6VzvmZA= -sigs.k8s.io/structured-merge-diff/v4 v4.0.1/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw= -sigs.k8s.io/structured-merge-diff/v4 v4.2.3 h1:PRbqxJClWWYMNV1dhaG4NsibJbArud9kFxnAMREiWFE= sigs.k8s.io/structured-merge-diff/v4 v4.2.3/go.mod h1:qjx8mGObPmV2aSZepjQjbmb2ihdVs8cGKBraizNC69E= -sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o= +sigs.k8s.io/structured-merge-diff/v4 v4.4.1 h1:150L+0vs/8DA78h1u02ooW1/fFq/Lwr+sGiqlzvrtq4= +sigs.k8s.io/structured-merge-diff/v4 v4.4.1/go.mod h1:N8hJocpFajUSSeSJ9bOZ77VzejKZaXsTtZo4/u7Io08= sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc= -sigs.k8s.io/yaml v1.3.0 h1:a2VclLzOGrwOHDiV8EfBGhvjHvP46CtW5j6POvhYGGo= sigs.k8s.io/yaml v1.3.0/go.mod h1:GeOyir5tyXNByN85N/dRIT9es5UQNerPYEKK56eTBm8= +sigs.k8s.io/yaml v1.4.0 h1:Mk1wCc2gy/F0THH0TAp1QYyJNzRm2KCLy3o5ASXVI5E= +sigs.k8s.io/yaml v1.4.0/go.mod h1:Ejl7/uTz7PSA4eKMyQCUTnhZYNmLIl+5c2lQPGR2BPY= diff --git a/hack/install_cli.sh b/hack/install_cli.sh index 013e452e3..712e214a6 100755 --- a/hack/install_cli.sh +++ b/hack/install_cli.sh @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Copyright (C) 2022-2024 ApeCloud Co., Ltd # @@ -14,6 +14,7 @@ # See the License for the specific language governing permissions and # limitations under the License. +# kbcli location : ${CLI_INSTALL_DIR:="/usr/local/bin"} : ${CLI_BREW_INSTALL_DIR:="/opt/homebrew/bin"} @@ -29,33 +30,29 @@ CLI_FILENAME=kbcli CLI_FILE="${CLI_INSTALL_DIR}/${CLI_FILENAME}" CLI_BREW_FILE="${CLI_BREW_INSTALL_DIR}/${CLI_FILENAME}" -TOKEN="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" -REPO="apecloud/kubeblocks" +REPO="apecloud/kbcli" GITHUB="https://api.github.com" -DOWNLOAD_BASE="https://github.com/${REPO}/releases/download" -FILE="kbcli-darwin-arm64-v0.3.0.tar.gz" # the name of your release asset file, e.g. build.tar.gz +GITLAB_REPO="85948" +GITLAB="https://jihulab.com/api/v4/projects" +COUNTRY_CODE="" -gh_curl() { - curl -H "Authorization: token $TOKEN" \ - -H "Accept: application/vnd.github.v3.raw" \ - $@ +getCountryCode() { + COUNTRY_CODE=`curl -m 20 --connect-timeout 10 -s https://ifconfig.io/country_code` } getSystemInfo() { ARCH=$(uname -m) case $ARCH in - armv7*) ARCH="arm";; - aarch64) ARCH="arm64";; - x86_64) ARCH="amd64";; + armv7*) ARCH="arm" ;; + aarch64) ARCH="arm64" ;; + x86_64) ARCH="amd64" ;; esac OS=$(echo $(uname) | tr '[:upper:]' '[:lower:]') # Most linux distro needs root permission to copy the file to /usr/local/bin - if [ "$OS" == "linux" ] || [ "$OS" == "darwin" ]; then - if [ "$CLI_INSTALL_DIR" == "/usr/local/bin" ]; then - USE_SUDO="true" - fi + if [[ "$OS" == "linux" || "$OS" == "darwin" ]] && [ "$CLI_INSTALL_DIR" == "/usr/local/bin" ]; then + USE_SUDO="true" fi } @@ -95,7 +92,7 @@ checkHttpRequestCLI() { fi } -checkExistingCli() { +checkExistingCLI() { if [ -f "$CLI_FILE" ]; then echo -e "\nkbcli is detected: $CLI_FILE" echo -e "\nPlease uninstall first" @@ -109,31 +106,51 @@ checkExistingCli() { fi } +getLatestRelease() { + latest_release="" + if [[ "$COUNTRY_CODE" == "CN" || "$COUNTRY_CODE" == "" ]]; then + releaseURL=$GITLAB/$GITLAB_REPO/repository/tags/latest + if [ "$HTTP_REQUEST_CLI" == "curl" ]; then + latest_release=`curl -s $releaseURL | grep 'message'|awk 'NR==1{print $1}'` + else + latest_release=`wget -q --header="Accept: application/json" -O - $releaseURL | grep 'tag_name'|awk 'NR==1{print $1}'` + fi + latest_release=${latest_release#*"message\":\""} + latest_release=${latest_release%%"\","*} + else + releaseURL=$GITHUB/repos/$REPO/releases/latest + if [ "$HTTP_REQUEST_CLI" == "curl" ]; then + latest_release=$(curl -s $releaseURL | grep \"tag_name\" | awk 'NR==1{print $2}' | sed -n 's/\"\(.*\)\",/\1/p') + else + latest_release=$(wget -q --header="Accept: application/json" -O - $releaseURL | grep \"tag_name\" | awk 'NR==1{print $2}' | sed -n 's/\"\(.*\)\",/\1/p') + fi + fi + ret_val=$latest_release +} + downloadFile() { LATEST_RELEASE_TAG=$1 - if [ "$LATEST_RELEASE_TAG" = "latest" ]; then - LATEST_RELEASE_TAG=$(gh_curl -s $GITHUB/repos/$REPO/releases/latest | grep '.tag_name' | awk -F: '{print $2}' | sed 's/,//g;s/\"//g;s/ //g') - fi - CLI_ARTIFACT="${CLI_FILENAME}-${OS}-${ARCH}-${LATEST_RELEASE_TAG}.tar.gz" - asset_id=$(gh_curl -s $GITHUB/repos/$REPO/releases/tags/$LATEST_RELEASE_TAG | grep -B 2 "\"name\": \"$CLI_ARTIFACT\"" | grep -w id | awk -F: '{print $2}' | sed 's/,//g;s/\"//g;s/ //g') - - if [ "$asset_id" = "null" ] || [ -z "$asset_id" ]; then - echo "ERROR: LATEST_RELEASE_TAG not found $LATEST_RELEASE_TAG" - exit 1 + DOWNLOAD_BASE="https://github.com/$REPO/releases/download" + if [[ "$COUNTRY_CODE" == "CN" || "$COUNTRY_CODE" == "" ]]; then + DOWNLOAD_BASE="$GITLAB/$GITLAB_REPO/packages/generic/kubeblocks" fi + DOWNLOAD_URL="${DOWNLOAD_BASE}/${LATEST_RELEASE_TAG}/${CLI_ARTIFACT}" # Create the temp directory CLI_TMP_ROOT=$(mktemp -dt kbcli-install-XXXXXX) ARTIFACT_TMP_FILE="$CLI_TMP_ROOT/$CLI_ARTIFACT" echo "Downloading ..." - DOWNLOAD_ASSET_URL="https://$TOKEN:@api.github.com/repos/$REPO/releases/assets/$asset_id" - httpstatus=$(curl -SL -q -w "%{http_code}" --header 'Accept:application/octet-stream' "$DOWNLOAD_ASSET_URL" -o "$ARTIFACT_TMP_FILE") + if [ "$HTTP_REQUEST_CLI" == "curl" ]; then + curl -SL --header 'Accept:application/octet-stream' "$DOWNLOAD_URL" -o "$ARTIFACT_TMP_FILE" + else + wget -q --show-progress -O "$ARTIFACT_TMP_FILE" "$DOWNLOAD_URL" + fi - if [[ "$httpstatus" != "200" || ! -f "$ARTIFACT_TMP_FILE" ]]; then - echo "Failed to download $CLI_ARTIFACT" + if [[ $? -ne 0 || ! -f "$ARTIFACT_TMP_FILE" ]]; then + echo "Failed to download $CLI_ARTIFACT." exit 1 fi } @@ -155,6 +172,7 @@ installFile() { kbcli version echo -e "Make sure your docker service is running and begin your journey with kbcli:\n" echo -e "\t$CLI_FILENAME playground init" + echo -e "" else echo "Failed to install $CLI_FILENAME" exit 1 @@ -189,12 +207,13 @@ trap "fail_trap" EXIT getSystemInfo verifySupported -checkExistingCli +checkExistingCLI checkHttpRequestCLI +getCountryCode if [ -z "$1" ]; then echo "Getting the latest kbcli ..." - ret_val="latest" + getLatestRelease elif [[ $1 == v* ]]; then ret_val=$1 else @@ -204,4 +223,4 @@ fi downloadFile $ret_val installFile cleanup -installCompleted +installCompleted \ No newline at end of file diff --git a/pkg/action/template/cluster_operations_template.cue b/pkg/action/template/cluster_operations_template.cue index 295c77df0..f8d5ea879 100644 --- a/pkg/action/template/cluster_operations_template.cue +++ b/pkg/action/template/cluster_operations_template.cue @@ -17,38 +17,38 @@ // required, command line input options for parameters and flags options: { - name: string - namespace: string - opsRequestName: string - type: string - typeLower: string - ttlSecondsAfterSucceed: int - clusterVersionRef: string - component: string - instance: string + name: string + namespace: string + opsRequestName: string + type: string + typeLower: string + ttlSecondsAfterSucceed: int + clusterVersionRef: string + componentDefinitionName: string + serviceVersion: string + component: string + instance: string componentNames: [...string] rebuildInstanceFrom: [ - ...{ - componentName: string - backupName?: string - instances: [ - ...{ - name: string - targetNodeName?: string - } - ] - envForRestore?: [ - ...{ - name: string - value: string - }, - ] - }, + ...{ + componentName: string + backupName?: string + instances: [ + ...{ + name: string + targetNodeName?: string + }, + ] + envForRestore?: [ + ...{ + name: string + value: string + }, + ] + }, ] - cpu: string - memory: string - class: string - classDefRef: {...} + cpu: string + memory: string replicas: int storage: string vctNames: [...string] @@ -58,17 +58,18 @@ options: { cfgTemplateName: string cfgFile: string forceRestart: bool - force: bool + force: bool services: [ ...{ name: string serviceType: string annotations: {...} + roleSelector?: string }, ] params: [ ...{ - name: string + name: string value: string }, ] @@ -78,6 +79,17 @@ options: { // define operation block, #upgrade: { clusterVersionRef: options.clusterVersionRef + if len(options.componentNames) > 0 { + components: [ for _, cName in options.componentNames { + componentName: cName + if options.componentDefinitionName != "nil" { + componentDefinitionName: options.componentDefinitionName + } + if options.serviceVersion != "nil" { + serviceVersion: options.serviceVersion + } + }] + } } // required, k8s api resource content @@ -98,10 +110,10 @@ content: { } } spec: { - clusterRef: options.name + clusterName: options.name type: options.type ttlSecondsAfterSucceed: options.ttlSecondsAfterSucceed - force: options.force + force: options.force if options.type == "Upgrade" { upgrade: #upgrade } @@ -128,9 +140,6 @@ content: { if options.type == "VerticalScaling" { verticalScaling: [ for _, cName in options.componentNames { componentName: cName - if options.class != "" { - classDefRef: options.classDefRef - } requests: { if options.memory != "" { memory: options.memory @@ -212,6 +221,7 @@ content: { if len(svc.annotations) > 0 { annotations: svc.annotations } + roleSelector: *svc.roleSelector | "" }] }] @@ -232,18 +242,18 @@ content: { } }] } - if options.type == "RebuildInstance" { - rebuildFrom: options.rebuildInstanceFrom - } + if options.type == "RebuildInstance" { + rebuildFrom: options.rebuildInstanceFrom + } if options.type == "Custom" { - customSpec: { - opsDefinitionRef: options.opsDefinitionName - components: [ - { - name: options.component - parameters: options.params - } - ] + custom: { + opsDefinitionName: options.opsDefinitionName + components: [ + { + componentName: options.component + parameters: options.params + }, + ] } } } diff --git a/pkg/action/template/opsrequest_template.cue b/pkg/action/template/opsrequest_template.cue index 4fd73109d..d7419fea7 100644 --- a/pkg/action/template/opsrequest_template.cue +++ b/pkg/action/template/opsrequest_template.cue @@ -19,7 +19,7 @@ options: { opsRequestName: string namespace: string - clusterRef: string + clusterName: string opsType: string backupSpec: {} restoreSpec: {} @@ -35,14 +35,14 @@ content: { namespace: options.namespace } spec: { - clusterRef: options.clusterRef + clusterName: options.clusterName type: options.opsType force: options.force if options.opsType == "Backup" { - backupSpec: options.backupSpec + backup: options.backupSpec } if options.opsType == "Restore" { - restoreSpec: options.restoreSpec + restore: options.restoreSpec } ttlSecondsAfterSucceed: 30 } diff --git a/pkg/cluster/builtin_charts.go b/pkg/cluster/builtin_charts.go index c8f1fffcf..8bbb638cf 100644 --- a/pkg/cluster/builtin_charts.go +++ b/pkg/cluster/builtin_charts.go @@ -72,6 +72,10 @@ var ( llmChart embed.FS //go:embed charts/xinference-cluster.tgz xinferenceChart embed.FS + //go:embed charts/elasticsearch-cluster.tgz + elasticsearchChart embed.FS + //go:embed charts/qdrant-cluster.tgz + qdrantChart embed.FS ) var builtinClusterTypes = map[ClusterType]bool{} @@ -125,6 +129,18 @@ func init() { name: "xinference-cluster.tgz", alias: "", }, + + "elasticsearch": { + chartFS: elasticsearchChart, + name: "elasticsearch-cluster.tgz", + alias: "", + }, + + "qdrant": { + chartFS: qdrantChart, + name: "qdrant-cluster.tgz", + alias: "", + }, } for k, v := range embedChartConfigs { diff --git a/pkg/cluster/charts/apecloud-mysql-cluster.tgz b/pkg/cluster/charts/apecloud-mysql-cluster.tgz index 52a4d1c43..d6bdc8239 100644 Binary files a/pkg/cluster/charts/apecloud-mysql-cluster.tgz and b/pkg/cluster/charts/apecloud-mysql-cluster.tgz differ diff --git a/pkg/cluster/charts/elasticsearch-cluster.tgz b/pkg/cluster/charts/elasticsearch-cluster.tgz new file mode 100644 index 000000000..a361de26a Binary files /dev/null and b/pkg/cluster/charts/elasticsearch-cluster.tgz differ diff --git a/pkg/cluster/charts/kafka-cluster.tgz b/pkg/cluster/charts/kafka-cluster.tgz index f303d970d..462ad9181 100644 Binary files a/pkg/cluster/charts/kafka-cluster.tgz and b/pkg/cluster/charts/kafka-cluster.tgz differ diff --git a/pkg/cluster/charts/llm-cluster.tgz b/pkg/cluster/charts/llm-cluster.tgz index 2fc5d32ea..81ead8bff 100644 Binary files a/pkg/cluster/charts/llm-cluster.tgz and b/pkg/cluster/charts/llm-cluster.tgz differ diff --git a/pkg/cluster/charts/mongodb-cluster.tgz b/pkg/cluster/charts/mongodb-cluster.tgz index af3d5027d..a94eb21e3 100644 Binary files a/pkg/cluster/charts/mongodb-cluster.tgz and b/pkg/cluster/charts/mongodb-cluster.tgz differ diff --git a/pkg/cluster/charts/postgresql-cluster.tgz b/pkg/cluster/charts/postgresql-cluster.tgz index b243b909b..fd2815603 100644 Binary files a/pkg/cluster/charts/postgresql-cluster.tgz and b/pkg/cluster/charts/postgresql-cluster.tgz differ diff --git a/pkg/cluster/charts/qdrant-cluster.tgz b/pkg/cluster/charts/qdrant-cluster.tgz new file mode 100644 index 000000000..6963e736b Binary files /dev/null and b/pkg/cluster/charts/qdrant-cluster.tgz differ diff --git a/pkg/cluster/charts/redis-cluster.tgz b/pkg/cluster/charts/redis-cluster.tgz index 25c480d13..8222168c2 100644 Binary files a/pkg/cluster/charts/redis-cluster.tgz and b/pkg/cluster/charts/redis-cluster.tgz differ diff --git a/pkg/cluster/charts/xinference-cluster.tgz b/pkg/cluster/charts/xinference-cluster.tgz index 63f1433c9..478f551aa 100644 Binary files a/pkg/cluster/charts/xinference-cluster.tgz and b/pkg/cluster/charts/xinference-cluster.tgz differ diff --git a/pkg/cluster/cluster.go b/pkg/cluster/cluster.go index d5d2c9cb4..971b74b7d 100644 --- a/pkg/cluster/cluster.go +++ b/pkg/cluster/cluster.go @@ -369,7 +369,7 @@ func (o *ClusterObjects) GetInstanceInfo() []*InstanceInfo { Namespace: pod.Namespace, Cluster: getLabelVal(pod.Labels, constant.AppInstanceLabelKey), Component: getLabelVal(pod.Labels, constant.KBAppComponentLabelKey), - Status: string(pod.Status.Phase), + Status: o.getPodPhase(&pod), Role: getLabelVal(pod.Labels, constant.RoleLabelKey), AccessMode: getLabelVal(pod.Labels, constant.ConsensusSetAccessModeLabelKey), CreatedTime: util.TimeFormat(&pod.CreationTimestamp), @@ -389,6 +389,92 @@ func (o *ClusterObjects) GetInstanceInfo() []*InstanceInfo { return instances } +// port from https://github.com/kubernetes/kubernetes/blob/master/pkg/printers/internalversion/printers.go#L860 +func (o *ClusterObjects) getPodPhase(pod *corev1.Pod) string { + reason := string(pod.Status.Phase) + if pod.Status.Reason != "" { + reason = pod.Status.Reason + } + + // If the Pod carries {type:PodScheduled, reason:WaitingForGates}, set reason to 'SchedulingGated'. + for _, condition := range pod.Status.Conditions { + if condition.Type == corev1.PodScheduled && condition.Reason == corev1.PodReasonSchedulingGated { + reason = corev1.PodReasonSchedulingGated + } + } + hasPodReadyCondition := func(conditions []corev1.PodCondition) bool { + for _, condition := range conditions { + if condition.Type == corev1.PodReady && condition.Status == corev1.ConditionTrue { + return true + } + } + return false + } + initializing := false + for i := range pod.Status.InitContainerStatuses { + container := pod.Status.InitContainerStatuses[i] + switch { + case container.State.Terminated != nil && container.State.Terminated.ExitCode == 0: + continue + case container.State.Terminated != nil: + // initialization is failed + if len(container.State.Terminated.Reason) == 0 { + if container.State.Terminated.Signal != 0 { + reason = fmt.Sprintf("Init:Signal:%d", container.State.Terminated.Signal) + } else { + reason = fmt.Sprintf("Init:ExitCode:%d", container.State.Terminated.ExitCode) + } + } else { + reason = "Init:" + container.State.Terminated.Reason + } + initializing = true + case container.State.Waiting != nil && len(container.State.Waiting.Reason) > 0 && container.State.Waiting.Reason != "PodInitializing": + reason = "Init:" + container.State.Waiting.Reason + initializing = true + default: + reason = fmt.Sprintf("Init:%d/%d", i, len(pod.Spec.InitContainers)) + initializing = true + } + break + } + if !initializing { + hasRunning := false + for i := len(pod.Status.ContainerStatuses) - 1; i >= 0; i-- { + container := pod.Status.ContainerStatuses[i] + switch { + case container.State.Waiting != nil && container.State.Waiting.Reason != "": + reason = container.State.Waiting.Reason + case container.State.Terminated != nil && container.State.Terminated.Reason != "": + reason = container.State.Terminated.Reason + case container.State.Terminated != nil && container.State.Terminated.Reason == "": + if container.State.Terminated.Signal != 0 { + reason = fmt.Sprintf("Signal:%d", container.State.Terminated.Signal) + } else { + reason = fmt.Sprintf("ExitCode:%d", container.State.Terminated.ExitCode) + } + case container.Ready && container.State.Running != nil: + hasRunning = true + } + } + + // change pod status back to "Running" if there is at least one container still reporting as "Running" status + if reason == "Completed" && hasRunning { + if hasPodReadyCondition(pod.Status.Conditions) { + reason = "Running" + } else { + reason = "NotReady" + } + } + } + + if pod.DeletionTimestamp != nil && pod.Status.Reason == "NodeLost" { + reason = "Unknown" + } else if pod.DeletionTimestamp != nil { + reason = "Terminating" + } + return reason +} + func (o *ClusterObjects) getStorageInfo(component *appsv1alpha1.ClusterComponentSpec) []StorageInfo { if component == nil { return nil diff --git a/pkg/cluster/helper.go b/pkg/cluster/helper.go index 8dc918628..3b17062a7 100644 --- a/pkg/cluster/helper.go +++ b/pkg/cluster/helper.go @@ -25,6 +25,7 @@ import ( "strings" appsv1alpha1 "github.com/apecloud/kubeblocks/apis/apps/v1alpha1" + appsv1beta1 "github.com/apecloud/kubeblocks/apis/apps/v1beta1" "github.com/apecloud/kubeblocks/pkg/constant" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -175,6 +176,14 @@ func GetClusterDefByName(dynamic dynamic.Interface, name string) (*appsv1alpha1. return clusterDef, nil } +func GetComponentDefByName(dynamic dynamic.Interface, name string) (*appsv1alpha1.ComponentDefinition, error) { + componentDef := &appsv1alpha1.ComponentDefinition{} + if err := util.GetK8SClientObject(dynamic, componentDef, types.CompDefGVR(), "", name); err != nil { + return nil, err + } + return componentDef, nil +} + func GetDefaultCompName(cd *appsv1alpha1.ClusterDefinition) (string, error) { if len(cd.Spec.ComponentDefs) >= 1 { return cd.Spec.ComponentDefs[0].Name, nil @@ -283,7 +292,7 @@ func GetDefaultVersion(dynamic dynamic.Interface, clusterDef string) (string, er defaultVersion := "" for _, item := range versionList.Items { - if k, ok := item.Annotations[constant.DefaultClusterVersionAnnotationKey]; !ok || k != "true" { + if k, ok := item.Annotations[types.KBDefaultClusterVersionAnnotationKey]; !ok || k != "true" { continue } if defaultVersion != "" { @@ -379,8 +388,8 @@ func GetConfigMapByName(dynamic dynamic.Interface, namespace, name string) (*cor return cmObj, nil } -func GetConfigConstraintByName(dynamic dynamic.Interface, name string) (*appsv1alpha1.ConfigConstraint, error) { - ccObj := &appsv1alpha1.ConfigConstraint{} +func GetConfigConstraintByName(dynamic dynamic.Interface, name string) (*appsv1beta1.ConfigConstraint, error) { + ccObj := &appsv1beta1.ConfigConstraint{} if err := util.GetK8SClientObject(dynamic, ccObj, types.ConfigConstraintGVR(), "", name); err != nil { return nil, err } diff --git a/pkg/cluster/helper_test.go b/pkg/cluster/helper_test.go index 1e0d13191..606201a01 100644 --- a/pkg/cluster/helper_test.go +++ b/pkg/cluster/helper_test.go @@ -27,6 +27,7 @@ import ( "github.com/apecloud/kubeblocks/pkg/constant" "github.com/apecloud/kbcli/pkg/testing" + "github.com/apecloud/kbcli/pkg/types" ) var _ = Describe("helper", func() { @@ -101,7 +102,7 @@ var _ = Describe("helper", func() { Expect(defaultVer).Should(BeEmpty()) By("set default version, should return default version") - cv1.Annotations = map[string]string{constant.DefaultClusterVersionAnnotationKey: "true"} + cv1.Annotations = map[string]string{types.KBDefaultClusterVersionAnnotationKey: "true"} dynamic = testing.FakeDynamicClient(testing.FakeClusterDef(), testing.FakeClusterVersion(), cv1, cv2) defaultVer, err = GetDefaultVersion(dynamic, clusterDefName) Expect(err).Should(Succeed()) diff --git a/pkg/cmd/alert/add_receiver.go b/pkg/cmd/alert/add_receiver.go deleted file mode 100644 index 5593c7363..000000000 --- a/pkg/cmd/alert/add_receiver.go +++ /dev/null @@ -1,573 +0,0 @@ -/* -Copyright (C) 2022-2024 ApeCloud Co., Ltd - -This file is part of KubeBlocks project - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU Affero General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU Affero General Public License for more details. - -You should have received a copy of the GNU Affero General Public License -along with this program. If not, see . -*/ - -package alert - -import ( - "context" - "fmt" - "strconv" - "strings" - - "github.com/pkg/errors" - "github.com/spf13/cobra" - "golang.org/x/exp/slices" - corev1 "k8s.io/api/core/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - apitypes "k8s.io/apimachinery/pkg/types" - "k8s.io/cli-runtime/pkg/genericiooptions" - "k8s.io/client-go/kubernetes" - cmdutil "k8s.io/kubectl/pkg/cmd/util" - "k8s.io/kubectl/pkg/util/templates" - "sigs.k8s.io/yaml" - - "github.com/prometheus/alertmanager/config" - "github.com/prometheus/alertmanager/timeinterval" - - "github.com/apecloud/kbcli/pkg/util" -) - -var ( - // alertConfigmapName is the name of alertmanager configmap - alertConfigmapName = getConfigMapName(alertManagerAddonName) - - // webhookAdaptorConfigmapName is the name of webhook adaptor - webhookAdaptorConfigmapName = getConfigMapName(webhookAdaptorAddonName) -) - -var ( - addReceiverExample = templates.Examples(` - # add webhook receiver without token, for example feishu - kbcli alert add-receiver --webhook='url=https://open.feishu.cn/open-apis/bot/v2/hook/foo' - - # add webhook receiver with token, for example feishu - kbcli alert add-receiver --webhook='url=https://open.feishu.cn/open-apis/bot/v2/hook/foo,token=XXX' - - # add email receiver - kbcli alert add-receiver --email='user1@kubeblocks.io,user2@kubeblocks.io' - - # add email receiver, and only receive alert from cluster mycluster - kbcli alert add-receiver --email='user1@kubeblocks.io,user2@kubeblocks.io' --cluster=mycluster - - # add email receiver, and only receive alert from cluster mycluster and alert severity is warning - kbcli alert add-receiver --email='user1@kubeblocks.io,user2@kubeblocks.io' --cluster=mycluster --severity=warning - - # add email receiver, and only receive alert from mysql clusters - kbcli alert add-receiver --email='user1@kubeblocks.io,user2@kubeblocks.io' --type=mysql - - # add email receiver, and only receive alert triggered by specified rule - kbcli alert add-receiver --email='user1@kubeblocks.io,user2@kubeblocks.io' --rule=MysqlDown - - # add slack receiver - kbcli alert add-receiver --slack api_url=https://hooks.slackConfig.com/services/foo,channel=monitor,username=kubeblocks-alert-bot`) -) - -type baseOptions struct { - genericiooptions.IOStreams - alertConfigMap *corev1.ConfigMap - webhookConfigMap *corev1.ConfigMap - client kubernetes.Interface - Factory cmdutil.Factory - AlertConfigMapKey apitypes.NamespacedName - AlertConfigFileName string - NoAdapter bool -} - -type Times struct { - StartTime string - EndTime string -} - -type TimeInterval struct { - Times Times - Weekdays []string -} - -type AddReceiverOptions struct { - baseOptions - - Emails []string - Webhooks []string - Slacks []string - Clusters []string - Severities []string - Types []string - Rules []string - Name string - InputName []string - SendResolved bool - RepeatInterval string - MuteTimeInterval *timeinterval.TimeInterval - CustomMatchers []string - - receiver *receiver - route *route - timeInterval *config.TimeInterval - webhookAdaptorReceivers []webhookAdaptorReceiver -} - -func NewAddReceiverOption(f cmdutil.Factory, streams genericiooptions.IOStreams) *AddReceiverOptions { - o := AddReceiverOptions{baseOptions: baseOptions{Factory: f, IOStreams: streams}} - return &o -} - -func newAddReceiverCmd(f cmdutil.Factory, streams genericiooptions.IOStreams) *cobra.Command { - o := NewAddReceiverOption(f, streams) - cmd := &cobra.Command{ - Use: "add-receiver", - Short: "Add alert receiver, such as email, slack, webhook and so on.", - Example: addReceiverExample, - Run: func(cmd *cobra.Command, args []string) { - o.InputName = args - util.CheckErr(o.Exec()) - }, - } - - cmd.Flags().StringArrayVar(&o.Emails, "email", []string{}, "Add email address, such as user@kubeblocks.io, more than one emailConfig can be specified separated by comma") - cmd.Flags().StringArrayVar(&o.Webhooks, "webhook", []string{}, "Add webhook receiver, such as url=https://open.feishu.cn/open-apis/bot/v2/hook/foo,token=xxxxx") - cmd.Flags().StringArrayVar(&o.Slacks, "slack", []string{}, "Add slack receiver, such as api_url=https://hooks.slackConfig.com/services/foo,channel=monitor,username=kubeblocks-alert-bot") - cmd.Flags().StringArrayVar(&o.Clusters, "cluster", []string{}, "Cluster name, such as mycluster, more than one cluster can be specified, such as mycluster1,mycluster2") - cmd.Flags().StringArrayVar(&o.Severities, "severity", []string{}, "Alert severity level, critical, warning or info, more than one severity level can be specified, such as critical,warning") - cmd.Flags().StringArrayVar(&o.Types, "type", []string{}, "Engine type, such as mysql, more than one types can be specified, such as mysql,postgresql,redis") - cmd.Flags().StringArrayVar(&o.Rules, "rule", []string{}, "Rule name, such as MysqlDown, more than one rule names can be specified, such as MysqlDown,MysqlRestarted") - cmd.Flags().StringVar(&o.RepeatInterval, "repeat-interval", "", "Repeat interval of current receiver") - - // register completions - util.CheckErr(cmd.RegisterFlagCompletionFunc("severity", - func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { - return severities(), cobra.ShellCompDirectiveNoFileComp - })) - - return cmd -} - -func (o *AddReceiverOptions) Exec() error { - if err := o.complete(); err != nil { - return err - } - if err := o.validate(); err != nil { - return err - } - if err := o.run(); err != nil { - return err - } - return nil -} - -func (o *baseOptions) complete() error { - var err error - ctx := context.Background() - - if o.Factory == nil { - return errors.Errorf("no factory") - } - o.client, err = o.Factory.KubernetesClientSet() - if err != nil { - return err - } - - namespace, err := util.GetKubeBlocksNamespace(o.client) - if err != nil { - return err - } - - if len(o.AlertConfigFileName) == 0 { - o.AlertConfigFileName = alertConfigFileName - } - if len(o.AlertConfigMapKey.Name) == 0 { - o.AlertConfigMapKey.Name = alertConfigmapName - } - if len(o.AlertConfigMapKey.Namespace) == 0 { - o.AlertConfigMapKey.Namespace = namespace - } - // get alertmanager configmap - o.alertConfigMap, err = o.client.CoreV1().ConfigMaps(o.AlertConfigMapKey.Namespace).Get(ctx, o.AlertConfigMapKey.Name, metav1.GetOptions{}) - if err != nil { - return err - } - - // get webhook adaptor configmap - o.webhookConfigMap, err = o.client.CoreV1().ConfigMaps(namespace).Get(ctx, webhookAdaptorConfigmapName, metav1.GetOptions{}) - return err -} - -func (o *AddReceiverOptions) validate() error { - if len(o.Emails) == 0 && len(o.Webhooks) == 0 && len(o.Slacks) == 0 { - return fmt.Errorf("must specify at least one receiver, such as --email, --webhook or --slack") - } - - // if name is not specified, generate a random one - if len(o.InputName) == 0 { - o.Name = generateReceiverName() - } else { - o.Name = o.InputName[0] - } - - if err := o.checkEmails(); err != nil { - return err - } - - if err := o.checkSeverities(); err != nil { - return err - } - return nil -} - -// checkSeverities checks if severity is valid -func (o *AddReceiverOptions) checkSeverities() error { - if len(o.Severities) == 0 { - return nil - } - checkSeverity := func(severity string) error { - ss := strings.Split(severity, ",") - for _, s := range ss { - if !slices.Contains(severities(), strings.ToLower(strings.TrimSpace(s))) { - return fmt.Errorf("invalid severity: %s, must be one of %v", s, severities()) - } - } - return nil - } - - for _, severity := range o.Severities { - if err := checkSeverity(severity); err != nil { - return err - } - } - return nil -} - -// checkEmails checks if email SMTP is configured, if not, do not allow to add email receiver -func (o *AddReceiverOptions) checkEmails() error { - if len(o.Emails) == 0 { - return nil - } - - errMsg := "SMTP %sis not configured, if you want to add email receiver, please use `kbcli alert config-smtpserver` configure it first" - data, err := getConfigData(o.alertConfigMap, o.AlertConfigFileName) - if err != nil { - return err - } - - if data["global"] == nil { - return fmt.Errorf(errMsg, "") - } - - // check smtp config in global - checkKeys := []string{"smtp_from", "smtp_smarthost", "smtp_auth_username", "smtp_auth_password"} - checkSMTP := func(key string) error { - val := data["global"].(map[string]interface{})[key] - if val == nil || fmt.Sprintf("%v", val) == "" { - return fmt.Errorf(errMsg, key+" ") - } - return nil - } - - for _, key := range checkKeys { - if err = checkSMTP(key); err != nil { - return err - } - } - return nil -} - -func (o *AddReceiverOptions) run() error { - // build time interval - o.buildTimeInterval() - - // build receiver - if err := o.buildReceiver(); err != nil { - return err - } - - // build route - o.buildRoute() - - // add alertmanager receiver and route - if err := o.addReceiver(); err != nil { - return err - } - - // add webhook receiver - if err := o.addWebhookReceivers(); err != nil { - return err - } - - fmt.Fprintf(o.Out, "Receiver %s added successfully.\n", o.receiver.Name) - return nil -} - -// buildReceiver builds receiver from receiver options -func (o *AddReceiverOptions) buildReceiver() error { - webhookConfigs, err := o.buildWebhook() - if err != nil { - return err - } - - slackConfigs, err := buildSlackConfigs(o.Slacks) - if err != nil { - return err - } - - o.receiver = &receiver{ - Name: o.Name, - EmailConfigs: buildEmailConfigs(o.Emails), - WebhookConfigs: webhookConfigs, - SlackConfigs: slackConfigs, - } - return nil -} - -func (o *AddReceiverOptions) buildRoute() { - r := &route{ - Receiver: o.Name, - Continue: true, - RepeatInterval: o.RepeatInterval, - } - - var clusterArray []string - var severityArray []string - var typesArray []string - var rulesArray []string - - if o.MuteTimeInterval != nil { - r.MuteTimeIntervals = []string{o.Name} - } - - splitStr := func(strArray []string, target *[]string) { - for _, s := range strArray { - ss := strings.Split(s, ",") - *target = append(*target, ss...) - } - } - - // parse clusters and severities - splitStr(o.Clusters, &clusterArray) - splitStr(o.Severities, &severityArray) - splitStr(o.Types, &typesArray) - splitStr(o.Rules, &rulesArray) - - // build matchers - buildMatchers := func(t string, values []string) string { - if len(values) == 0 { - return "" - } - deValues := removeDuplicateStr(values) - switch t { - case routeMatcherClusterType: - return routeMatcherClusterKey + routeMatcherOperator + strings.Join(deValues, "|") - case routeMatcherSeverityType: - return routeMatcherSeverityKey + routeMatcherOperator + strings.Join(deValues, "|") - case routeMatcherTypeType: - return routeMatcherTypeKey + routeMatcherOperator + strings.Join(deValues, "|") - case routeMatcherRuleType: - return routeMatcherRuleKey + routeMatcherOperator + strings.Join(deValues, "|") - default: - return "" - } - } - - r.Matchers = append(r.Matchers, buildMatchers(routeMatcherClusterType, clusterArray), - buildMatchers(routeMatcherSeverityType, severityArray), - buildMatchers(routeMatcherTypeType, typesArray), - buildMatchers(routeMatcherRuleType, rulesArray)) - // add custom matchers - if len(o.CustomMatchers) > 0 { - r.Matchers = append(r.Matchers, o.CustomMatchers...) - } - o.route = r -} - -func (o *AddReceiverOptions) buildTimeInterval() { - if o.MuteTimeInterval == nil { - return - } - o.timeInterval = &config.TimeInterval{ - Name: o.Name, - TimeIntervals: []timeinterval.TimeInterval{*o.MuteTimeInterval}, - } -} - -// addReceiver adds receiver to alertmanager config -func (o *AddReceiverOptions) addReceiver() error { - data, err := getConfigData(o.alertConfigMap, o.AlertConfigFileName) - if err != nil { - return err - } - - // add time interval - if o.timeInterval != nil { - timeIntervals := getTimeIntervalsFromData(data) - if timeIntervalExists(timeIntervals, o.Name) { - return fmt.Errorf("timeInterval %s already exists", o.timeInterval.Name) - } - timeIntervals = append(timeIntervals, o.timeInterval) - data["time_intervals"] = timeIntervals - } - - // add receiver - receivers := getReceiversFromData(data) - if receiverExists(receivers, o.Name) { - return fmt.Errorf("receiver %s already exists", o.receiver.Name) - } - receivers = append(receivers, o.receiver) - - // add route - routes := getRoutesFromData(data) - routes = append(routes, o.route) - - data["receivers"] = receivers - data["route"].(map[string]interface{})["routes"] = routes - - // update alertmanager configmap - return updateConfig(o.client, o.alertConfigMap, o.AlertConfigFileName, data) -} - -func (o *AddReceiverOptions) addWebhookReceivers() error { - data, err := getConfigData(o.webhookConfigMap, webhookAdaptorFileName) - if err != nil { - return err - } - - receivers := getReceiversFromData(data) - for _, r := range o.webhookAdaptorReceivers { - receivers = append(receivers, r) - } - data["receivers"] = receivers - - // update webhook configmap - return updateConfig(o.client, o.webhookConfigMap, webhookAdaptorFileName, data) -} - -// buildWebhook builds webhookConfig and webhookAdaptorReceiver from webhook options -func (o *AddReceiverOptions) buildWebhook() ([]*webhookConfig, error) { - var ws []*webhookConfig - var waReceivers []webhookAdaptorReceiver - for _, hook := range o.Webhooks { - m := strToMap(hook) - if len(m) == 0 { - return nil, fmt.Errorf("invalid webhook: %s, webhook should be in the format of url=my-url,token=my-token", hook) - } - w := webhookConfig{ - MaxAlerts: 10, - SendResolved: o.SendResolved, - } - waReceiver := webhookAdaptorReceiver{Name: o.Name} - for k, v := range m { - // check webhookConfig keys - switch webhookKey(k) { - case webhookURL: - if valid, err := urlIsValid(v); !valid { - return nil, fmt.Errorf("invalid webhook url: %s, %v", v, err) - } - if o.NoAdapter { - w.URL = v - } else { - w.URL = getWebhookAdaptorURL(o.Name, o.webhookConfigMap.Namespace) - } - webhookType := getWebhookType(v) - waReceiver.Type = string(webhookType) - waReceiver.Params.URL = v - case webhookToken: - waReceiver.Params.Secret = v - default: - return nil, fmt.Errorf("invalid webhook key: %s, webhook key should be one of url and token", k) - } - } - ws = append(ws, &w) - waReceivers = append(waReceivers, waReceiver) - } - o.webhookAdaptorReceivers = waReceivers - return ws, nil -} - -func timeIntervalExists(timeIntervals []interface{}, name string) bool { - for _, r := range timeIntervals { - if r == nil { - continue - } - n := r.(map[string]interface{})["name"] - if n != nil && n.(string) == name { - return true - } - } - return false -} - -func receiverExists(receivers []interface{}, name string) bool { - for _, r := range receivers { - n := r.(map[string]interface{})["name"] - if n != nil && n.(string) == name { - return true - } - } - return false -} - -// buildSlackConfigs builds slackConfig from slack options -func buildSlackConfigs(slacks []string) ([]*slackConfig, error) { - var ss []*slackConfig - for _, slackStr := range slacks { - m := strToMap(slackStr) - if len(m) == 0 { - return nil, fmt.Errorf("invalid slack: %s, slack config should be in the format of api_url=my-api-url,channel=my-channel,username=my-username", slackStr) - } - s := slackConfig{TitleLink: ""} - for k, v := range m { - // check slackConfig keys - switch slackKey(k) { - case slackAPIURL: - if valid, err := urlIsValid(v); !valid { - return nil, fmt.Errorf("invalid slack api_url: %s, %v", v, err) - } - s.APIURL = v - case slackChannel: - s.Channel = "#" + v - case slackUsername: - s.Username = v - default: - return nil, fmt.Errorf("invalid slack config key: %s", k) - } - } - ss = append(ss, &s) - } - return ss, nil -} - -// buildEmailConfigs builds emailConfig from email options -func buildEmailConfigs(emails []string) []*emailConfig { - var es []*emailConfig - for _, email := range emails { - strs := strings.Split(email, ",") - for _, str := range strs { - es = append(es, &emailConfig{To: str}) - } - } - return es -} - -func updateConfig(client kubernetes.Interface, cm *corev1.ConfigMap, key string, data map[string]interface{}) error { - newValue, err := yaml.Marshal(data) - if err != nil { - return err - } - _, err = client.CoreV1().ConfigMaps(cm.Namespace).Patch(context.TODO(), cm.Name, apitypes.JSONPatchType, - []byte(fmt.Sprintf("[{\"op\": \"replace\", \"path\": \"/data/%s\", \"value\": %s }]", - key, strconv.Quote(string(newValue)))), metav1.PatchOptions{}) - return err -} diff --git a/pkg/cmd/alert/add_receiver_test.go b/pkg/cmd/alert/add_receiver_test.go deleted file mode 100644 index c1b764e61..000000000 --- a/pkg/cmd/alert/add_receiver_test.go +++ /dev/null @@ -1,172 +0,0 @@ -/* -Copyright (C) 2022-2024 ApeCloud Co., Ltd - -This file is part of KubeBlocks project - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU Affero General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU Affero General Public License for more details. - -You should have received a copy of the GNU Affero General Public License -along with this program. If not, see . -*/ - -package alert - -import ( - . "github.com/onsi/ginkgo/v2" - . "github.com/onsi/gomega" - - corev1 "k8s.io/api/core/v1" - "k8s.io/cli-runtime/pkg/genericiooptions" - clientfake "k8s.io/client-go/rest/fake" - cmdtesting "k8s.io/kubectl/pkg/cmd/testing" - - "github.com/apecloud/kbcli/pkg/testing" -) - -const ( - testNamespace = "test" -) - -var mockConfigmap = func(name string, key string, value string) *corev1.ConfigMap { - cm := &corev1.ConfigMap{} - cm.Name = name - cm.Namespace = testNamespace - cm.Data = map[string]string{key: value} - return cm -} - -var mockBaseOptions = func(s genericiooptions.IOStreams) baseOptions { - o := baseOptions{IOStreams: s} - alertManagerConfig := ` - global: - smtp_from: user@kubeblocks.io - smtp_smarthost: smtp.feishu.cn:587 - smtp_auth_username: admin@kubeblocks.io - smtp_auth_password: 123456abc - smtp_auth_identity: admin@kubeblocks.io - receivers: - - name: default-receiver - - name: receiver-7pb52 - webhook_configs: - - max_alerts: 10 - url: http://kubeblocks-webhook-adaptor-config.default:5001/api/v1/notify/receiver-7pb52 - route: - group_interval: 30s - group_wait: 5s - receiver: default-receiver - repeat_interval: 10m - routes: - - continue: true - matchers: - - app_kubernetes_io_instance=~a|b|c - - severity=~info|warning - receiver: receiver-7pb52` - webhookAdaptorConfig := ` - receivers: - - name: receiver-7pb52 - params: - url: https://oapi.dingtalk.com/robot/send?access_token=123456 - type: dingtalk-webhook` - alertCM := mockConfigmap(alertConfigmapName, alertConfigFileName, alertManagerConfig) - webhookAdaptorCM := mockConfigmap(webhookAdaptorConfigmapName, webhookAdaptorFileName, webhookAdaptorConfig) - o.alertConfigMap = alertCM - o.webhookConfigMap = webhookAdaptorCM - return o -} - -var _ = Describe("add receiver", func() { - var f *cmdtesting.TestFactory - var s genericiooptions.IOStreams - - BeforeEach(func() { - f = cmdtesting.NewTestFactory() - f.Client = &clientfake.RESTClient{} - s, _, _, _ = genericiooptions.NewTestIOStreams() - }) - - AfterEach(func() { - f.Cleanup() - }) - - It("create new add receiver cmd", func() { - cmd := newAddReceiverCmd(f, s) - Expect(cmd).NotTo(BeNil()) - Expect(cmd.HasSubCommands()).Should(BeFalse()) - }) - - It("complete", func() { - o := baseOptions{Factory: f, IOStreams: s} - Expect(o.complete()).Should(HaveOccurred()) - }) - - It("validate", func() { - By("nothing to be input, should fail") - o := NewAddReceiverOption(f, s) - Expect(o.validate()).Should(HaveOccurred()) - - By("set email, do not specify the name") - o.Emails = []string{"user@kubeblocks.io"} - o.alertConfigMap = mockConfigmap(alertConfigmapName, alertConfigFileName, "") - Expect(o.validate()).Should(HaveOccurred()) - Expect(o.Name).ShouldNot(BeEmpty()) - - By("set email, specify the name") - o.InputName = []string{"test"} - Expect(o.validate()).Should(HaveOccurred()) - Expect(o.Name).Should(Equal("test")) - - By("set email, set smtp config in configmap") - baseOptions := mockBaseOptions(s) - o.alertConfigMap = baseOptions.alertConfigMap - o.InputName = []string{} - o.AlertConfigFileName = alertConfigFileName - Expect(o.validate()).Should(Succeed()) - }) - - It("build receiver", func() { - o := AddReceiverOptions{baseOptions: baseOptions{IOStreams: s}} - o.Emails = []string{"user@kubeblocks.io", "user1@kubeblocks.io,user2@kubeblocks.io"} - o.Webhooks = []string{"url=https://oapi.dingtalk.com/robot/send", "url=https://oapi.dingtalk.com/robot/send,url=https://oapi.dingtalk.com/robot/send?"} - o.Slacks = []string{"api_url=https://foo.com,channel=foo,username=test"} - o.webhookConfigMap = mockConfigmap(webhookAdaptorConfigmapName, webhookAdaptorFileName, "") - Expect(o.buildReceiver()).Should(Succeed()) - Expect(o.receiver).ShouldNot(BeNil()) - Expect(o.receiver.EmailConfigs).Should(HaveLen(3)) - Expect(o.receiver.WebhookConfigs).Should(HaveLen(2)) - Expect(o.receiver.SlackConfigs).Should(HaveLen(1)) - }) - - It("build routes", func() { - o := AddReceiverOptions{baseOptions: baseOptions{IOStreams: s}} - o.Name = "receiver-test" - o.Clusters = []string{"cluster1", "cluster2"} - o.Severities = []string{"critical", "warning"} - o.buildRoute() - Expect(o.route).ShouldNot(BeNil()) - Expect(o.route.Receiver).Should(Equal(o.Name)) - Expect(o.route.Matchers).Should(HaveLen(4)) - Expect(o.route.Matchers[0]).Should(ContainSubstring(routeMatcherClusterKey)) - Expect(o.route.Matchers[1]).Should(ContainSubstring(routeMatcherSeverityKey)) - }) - - It("run", func() { - o := AddReceiverOptions{baseOptions: baseOptions{IOStreams: s}} - alertCM := mockConfigmap(alertConfigmapName, alertConfigFileName, "") - webhookAdaptorCM := mockConfigmap(webhookAdaptorConfigmapName, webhookAdaptorFileName, "") - o.baseOptions.alertConfigMap = alertCM - o.baseOptions.webhookConfigMap = webhookAdaptorCM - o.client = testing.FakeClientSet(alertCM, webhookAdaptorCM) - o.Name = "receiver-test" - o.AlertConfigFileName = alertConfigFileName - Expect(o.addReceiver()).Should(Succeed()) - Expect(o.addWebhookReceivers()).Should(Succeed()) - }) -}) diff --git a/pkg/cmd/alert/alert_test.go b/pkg/cmd/alert/alert_test.go deleted file mode 100644 index f1bd5a7a6..000000000 --- a/pkg/cmd/alert/alert_test.go +++ /dev/null @@ -1,40 +0,0 @@ -/* -Copyright (C) 2022-2024 ApeCloud Co., Ltd - -This file is part of KubeBlocks project - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU Affero General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU Affero General Public License for more details. - -You should have received a copy of the GNU Affero General Public License -along with this program. If not, see . -*/ - -package alert - -import ( - . "github.com/onsi/ginkgo/v2" - . "github.com/onsi/gomega" - - "k8s.io/cli-runtime/pkg/genericiooptions" - cmdtesting "k8s.io/kubectl/pkg/cmd/testing" -) - -var _ = Describe("alter", func() { - f := cmdtesting.NewTestFactory() - s, _, _, _ := genericiooptions.NewTestIOStreams() - defer f.Cleanup() - - It("create new alert cmd", func() { - cmd := NewAlertCmd(f, s) - Expect(cmd).NotTo(BeNil()) - Expect(cmd.HasSubCommands()).Should(BeTrue()) - }) -}) diff --git a/pkg/cmd/alert/alter.go b/pkg/cmd/alert/alter.go deleted file mode 100644 index 499f75bfa..000000000 --- a/pkg/cmd/alert/alter.go +++ /dev/null @@ -1,41 +0,0 @@ -/* -Copyright (C) 2022-2024 ApeCloud Co., Ltd - -This file is part of KubeBlocks project - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU Affero General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU Affero General Public License for more details. - -You should have received a copy of the GNU Affero General Public License -along with this program. If not, see . -*/ - -package alert - -import ( - "github.com/spf13/cobra" - "k8s.io/cli-runtime/pkg/genericiooptions" - cmdutil "k8s.io/kubectl/pkg/cmd/util" -) - -func NewAlertCmd(f cmdutil.Factory, streams genericiooptions.IOStreams) *cobra.Command { - cmd := &cobra.Command{ - Use: "alert [add-receiver|list-receivers|delete-receiver]", - Short: "Manage alert receiver, include add, list and delete receiver.", - } - cmd.AddCommand( - newAddReceiverCmd(f, streams), - newDeleteReceiverCmd(f, streams), - newListReceiversCmd(f, streams), - newConfigSMTPServerCmd(f, streams), - newListSMTPServerCmd(f, streams), - ) - return cmd -} diff --git a/pkg/cmd/alert/config_smtpserver.go b/pkg/cmd/alert/config_smtpserver.go deleted file mode 100644 index da6f62475..000000000 --- a/pkg/cmd/alert/config_smtpserver.go +++ /dev/null @@ -1,109 +0,0 @@ -/* -Copyright (C) 2022-2024 ApeCloud Co., Ltd - -This file is part of KubeBlocks project - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU Affero General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU Affero General Public License for more details. - -You should have received a copy of the GNU Affero General Public License -along with this program. If not, see . -*/ - -package alert - -import ( - "fmt" - - "github.com/spf13/cobra" - "k8s.io/cli-runtime/pkg/genericiooptions" - cmdutil "k8s.io/kubectl/pkg/cmd/util" -) - -var ( - configSMTPServerExample = ` - # Set smtp server config - kbcli alert config-smtpserver --smtp-from alert-test@apecloud.com --smtp-smarthost smtp.feishu.cn:587 --smtp-auth-username alert-test@apecloud.com --smtp-auth-password 123456abc --smtp-auth-identity alert-test@apecloud.com - ` -) - -type configSMTPServerOptions struct { - smtpFrom string - smtpSmarthost string - smtpAuthUsername string - smtpAuthPassword string - smtpAuthIdentity string - - baseOptions -} - -func newConfigSMTPServerCmd(f cmdutil.Factory, streams genericiooptions.IOStreams) *cobra.Command { - o := &configSMTPServerOptions{baseOptions: baseOptions{Factory: f, IOStreams: streams}} - cmd := &cobra.Command{ - Use: "config-smtpserver", - Short: "Set smtp server config", - Example: configSMTPServerExample, - Run: func(cmd *cobra.Command, args []string) { - cmdutil.CheckErr(o.complete()) - cmdutil.CheckErr(o.validate()) - cmdutil.CheckErr(o.run()) - }, - } - - cmd.Flags().StringVar(&o.smtpFrom, "smtp-from", "", "The email address to send alert.") - cmd.Flags().StringVar(&o.smtpSmarthost, "smtp-smarthost", "", "The smtp host to send alert.") - cmd.Flags().StringVar(&o.smtpAuthUsername, "smtp-auth-username", "", "The username to authenticate to the smarthost.") - cmd.Flags().StringVar(&o.smtpAuthPassword, "smtp-auth-password", "", "The password to authenticate to the smarthost.") - cmd.Flags().StringVar(&o.smtpAuthIdentity, "smtp-auth-identity", "", "The identity to authenticate to the smarthost.") - - return cmd -} - -func (o *configSMTPServerOptions) validate() error { - if !validEmail(o.smtpFrom) { - return fmt.Errorf("smtp-from is invalid") - } - - if o.smtpSmarthost == "" { - return fmt.Errorf("smtp-smarthost is required") - } - - if o.smtpAuthUsername == "" { - return fmt.Errorf("smtp-auth-username is required") - } - - if o.smtpAuthPassword == "" { - return fmt.Errorf("smtp-auth-password is required") - } - - return nil -} - -func (o *configSMTPServerOptions) run() error { - data, err := getConfigData(o.alertConfigMap, o.AlertConfigFileName) - if err != nil { - return err - } - - // get global - global := getGlobalFromData(data) - - // write smtp server config - global["smtp_from"] = o.smtpFrom - global["smtp_smarthost"] = o.smtpSmarthost - global["smtp_auth_username"] = o.smtpAuthUsername - global["smtp_auth_password"] = o.smtpAuthPassword - global["smtp_auth_identity"] = o.smtpAuthIdentity - - data["global"] = global - - // update global config - return updateConfig(o.client, o.alertConfigMap, o.AlertConfigFileName, data) -} diff --git a/pkg/cmd/alert/config_smtpserver_test.go b/pkg/cmd/alert/config_smtpserver_test.go deleted file mode 100644 index 67fcdc837..000000000 --- a/pkg/cmd/alert/config_smtpserver_test.go +++ /dev/null @@ -1,110 +0,0 @@ -/* -Copyright (C) 2022-2024 ApeCloud Co., Ltd - -This file is part of KubeBlocks project - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU Affero General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU Affero General Public License for more details. - -You should have received a copy of the GNU Affero General Public License -along with this program. If not, see . -*/ - -package alert - -import ( - . "github.com/onsi/ginkgo/v2" - . "github.com/onsi/gomega" - - "k8s.io/cli-runtime/pkg/genericiooptions" - clientfake "k8s.io/client-go/rest/fake" - cmdtesting "k8s.io/kubectl/pkg/cmd/testing" - - "github.com/apecloud/kbcli/pkg/testing" -) - -var mockBaseOptionsWithoutGlobal = func(s genericiooptions.IOStreams) baseOptions { - o := baseOptions{IOStreams: s} - alertManagerConfig := ` - receivers: - - name: default-receiver - - name: receiver-7pb52 - webhook_configs: - - max_alerts: 10 - url: http://kubeblocks-webhook-adaptor-config.default:5001/api/v1/notify/receiver-7pb52 - route: - group_interval: 30s - group_wait: 5s - receiver: default-receiver - repeat_interval: 10m - routes: - - continue: true - matchers: - - app_kubernetes_io_instance=~a|b|c - - severity=~info|warning - receiver: receiver-7pb52` - webhookAdaptorConfig := ` - receivers: - - name: receiver-7pb52 - params: - url: https://oapi.dingtalk.com/robot/send?access_token=123456 - type: dingtalk-webhook` - alertCM := mockConfigmap(alertConfigmapName, alertConfigFileName, alertManagerConfig) - webhookAdaptorCM := mockConfigmap(webhookAdaptorConfigmapName, webhookAdaptorFileName, webhookAdaptorConfig) - o.alertConfigMap = alertCM - o.webhookConfigMap = webhookAdaptorCM - return o -} - -var _ = Describe("config smtpserver", func() { - var f *cmdtesting.TestFactory - var s genericiooptions.IOStreams - - BeforeEach(func() { - f = cmdtesting.NewTestFactory() - f.Client = &clientfake.RESTClient{} - s, _, _, _ = genericiooptions.NewTestIOStreams() - }) - - AfterEach(func() { - f.Cleanup() - }) - - It("validate", func() { - By("nothing to be input, should fail") - o := &configSMTPServerOptions{baseOptions: baseOptions{IOStreams: s}} - Expect(o.validate()).Should(HaveOccurred()) - - By("set smtp-from, do not set smtp-smarthost, should fail") - Expect(o.validate()).Should(HaveOccurred()) - - By("set smtp-from, set smtp-smarthost, do not set smtp-auth-username, should fail") - Expect(o.validate()).Should(HaveOccurred()) - - By("set smtp-from, set smtp-smarthost, set smtp-auth-username, do not set smtp-auth-password, should fail") - Expect(o.validate()).Should(HaveOccurred()) - - By("set smtp-from, set smtp-smarthost, set smtp-auth-username, set smtp-auth-password, should pass") - Expect(o.validate()).ShouldNot(Succeed()) - }) - - It("set global", func() { - o := configSMTPServerOptions{baseOptions: mockBaseOptionsWithoutGlobal(s)} - o.smtpFrom = "user@kubeblocks.io" - o.smtpSmarthost = "smtp.feishu.cn:587" - o.smtpAuthUsername = "admin@kubeblocks.io" - o.smtpAuthPassword = "123456abc" - o.smtpAuthIdentity = "admin@kubeblocks.io" - o.client = testing.FakeClientSet(o.alertConfigMap, o.webhookConfigMap) - o.AlertConfigFileName = alertConfigFileName - Expect(o.validate()).Should(Succeed()) - Expect(o.run()).Should(Succeed()) - }) -}) diff --git a/pkg/cmd/alert/delete_receiver.go b/pkg/cmd/alert/delete_receiver.go deleted file mode 100644 index b7084e19f..000000000 --- a/pkg/cmd/alert/delete_receiver.go +++ /dev/null @@ -1,186 +0,0 @@ -/* -Copyright (C) 2022-2024 ApeCloud Co., Ltd - -This file is part of KubeBlocks project - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU Affero General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU Affero General Public License for more details. - -You should have received a copy of the GNU Affero General Public License -along with this program. If not, see . -*/ - -package alert - -import ( - "fmt" - "strings" - - "github.com/spf13/cobra" - "k8s.io/cli-runtime/pkg/genericiooptions" - "k8s.io/klog/v2" - cmdutil "k8s.io/kubectl/pkg/cmd/util" - "k8s.io/kubectl/pkg/util/templates" - - "github.com/apecloud/kbcli/pkg/util" -) - -var ( - deleteReceiverExample = templates.Examples(` - # delete a receiver named my-receiver, all receivers can be found by command: kbcli alert list-receivers - kbcli alert delete-receiver my-receiver`) -) - -type DeleteReceiverOptions struct { - baseOptions - Names []string -} - -func NewDeleteReceiverOption(f cmdutil.Factory, streams genericiooptions.IOStreams) *DeleteReceiverOptions { - return &DeleteReceiverOptions{baseOptions: baseOptions{Factory: f, IOStreams: streams}} -} - -func newDeleteReceiverCmd(f cmdutil.Factory, streams genericiooptions.IOStreams) *cobra.Command { - o := NewDeleteReceiverOption(f, streams) - cmd := &cobra.Command{ - Use: "delete-receiver NAME", - Short: "Delete alert receiver.", - Example: deleteReceiverExample, - Run: func(cmd *cobra.Command, args []string) { - o.Names = args - util.CheckErr(o.Exec()) - }, - } - return cmd -} - -func (o *DeleteReceiverOptions) Exec() error { - if err := o.complete(); err != nil { - return err - } - if err := o.validate(); err != nil { - return err - } - if err := o.run(); err != nil { - return err - } - return nil -} - -func (o *DeleteReceiverOptions) validate() error { - if len(o.Names) == 0 { - return fmt.Errorf("receiver name is required") - } - return nil -} - -func (o *DeleteReceiverOptions) run() error { - // delete receiver from alert manager config - if err := o.deleteReceiver(); err != nil { - return err - } - - // delete receiver from webhook config - if err := o.deleteWebhookReceivers(); err != nil { - return err - } - - fmt.Fprintf(o.Out, "Receiver %s deleted successfully\n", strings.Join(o.Names, ",")) - return nil -} - -func (o *DeleteReceiverOptions) deleteReceiver() error { - data, err := getConfigData(o.alertConfigMap, o.AlertConfigFileName) - if err != nil { - return err - } - - var newTimeIntervals []interface{} - var newReceivers []interface{} - var newRoutes []interface{} - - timeIntervals := getTimeIntervalsFromData(data) - for i, ti := range timeIntervals { - var found bool - name := ti.(map[string]interface{})["name"].(string) - for _, n := range o.Names { - if n == name { - found = true - break - } - } - if !found { - newTimeIntervals = append(newTimeIntervals, timeIntervals[i]) - } - } - - // build receiver route map, key is receiver name, value is route - receiverRouteMap := make(map[string]interface{}) - routes := getRoutesFromData(data) - for i, r := range routes { - name := r.(map[string]interface{})["receiver"].(string) - receiverRouteMap[name] = routes[i] - } - - receivers := getReceiversFromData(data) - for i, rec := range receivers { - var found bool - name := rec.(map[string]interface{})["name"].(string) - for _, n := range o.Names { - if n == name { - found = true - break - } - } - if !found { - newReceivers = append(newReceivers, receivers[i]) - r, ok := receiverRouteMap[name] - if !ok { - klog.V(1).Infof("receiver %s not found in routes\n", name) - continue - } - newRoutes = append(newRoutes, r) - } - } - - // check if receiver exists - if len(receivers) == len(newReceivers) { - return fmt.Errorf("receiver %s not found", strings.Join(o.Names, ",")) - } - - data["time_intervals"] = newTimeIntervals - data["receivers"] = newReceivers - data["route"].(map[string]interface{})["routes"] = newRoutes - return updateConfig(o.client, o.alertConfigMap, o.AlertConfigFileName, data) -} - -func (o *DeleteReceiverOptions) deleteWebhookReceivers() error { - data, err := getConfigData(o.webhookConfigMap, webhookAdaptorFileName) - if err != nil { - return err - } - var newReceivers []interface{} - receivers := getReceiversFromData(data) - for i, rec := range receivers { - var found bool - name := rec.(map[string]interface{})["name"].(string) - for _, n := range o.Names { - if n == name { - found = true - break - } - } - if !found { - newReceivers = append(newReceivers, receivers[i]) - } - } - data["receivers"] = newReceivers - return updateConfig(o.client, o.webhookConfigMap, webhookAdaptorFileName, data) -} diff --git a/pkg/cmd/alert/delete_receiver_test.go b/pkg/cmd/alert/delete_receiver_test.go deleted file mode 100644 index 4fd852faf..000000000 --- a/pkg/cmd/alert/delete_receiver_test.go +++ /dev/null @@ -1,67 +0,0 @@ -/* -Copyright (C) 2022-2024 ApeCloud Co., Ltd - -This file is part of KubeBlocks project - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU Affero General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU Affero General Public License for more details. - -You should have received a copy of the GNU Affero General Public License -along with this program. If not, see . -*/ - -package alert - -import ( - . "github.com/onsi/ginkgo/v2" - . "github.com/onsi/gomega" - - "k8s.io/cli-runtime/pkg/genericiooptions" - clientfake "k8s.io/client-go/rest/fake" - cmdtesting "k8s.io/kubectl/pkg/cmd/testing" - - "github.com/apecloud/kbcli/pkg/testing" -) - -var _ = Describe("alert", func() { - var f *cmdtesting.TestFactory - var s genericiooptions.IOStreams - - BeforeEach(func() { - f = cmdtesting.NewTestFactory() - f.Client = &clientfake.RESTClient{} - s, _, _, _ = genericiooptions.NewTestIOStreams() - }) - - AfterEach(func() { - f.Cleanup() - }) - - It("create new delete receiver cmd", func() { - cmd := newDeleteReceiverCmd(f, s) - Expect(cmd).NotTo(BeNil()) - }) - - It("validate", func() { - o := &DeleteReceiverOptions{baseOptions: baseOptions{IOStreams: s}} - o.Names = []string{} - Expect(o.validate()).Should(HaveOccurred()) - o.Names = []string{"test"} - Expect(o.validate()).Should(Succeed()) - }) - - It("run", func() { - o := &DeleteReceiverOptions{baseOptions: mockBaseOptions(s)} - o.client = testing.FakeClientSet(o.baseOptions.alertConfigMap, o.baseOptions.webhookConfigMap) - o.Names = []string{"receiver-7pb52"} - o.AlertConfigFileName = alertConfigFileName - Expect(o.run()).Should(Succeed()) - }) -}) diff --git a/pkg/cmd/alert/list_receivers.go b/pkg/cmd/alert/list_receivers.go deleted file mode 100644 index f331c298a..000000000 --- a/pkg/cmd/alert/list_receivers.go +++ /dev/null @@ -1,191 +0,0 @@ -/* -Copyright (C) 2022-2024 ApeCloud Co., Ltd - -This file is part of KubeBlocks project - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU Affero General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU Affero General Public License for more details. - -You should have received a copy of the GNU Affero General Public License -along with this program. If not, see . -*/ - -package alert - -import ( - "fmt" - "strings" - - "github.com/mitchellh/mapstructure" - "github.com/spf13/cobra" - "k8s.io/cli-runtime/pkg/genericiooptions" - cmdutil "k8s.io/kubectl/pkg/cmd/util" - "k8s.io/kubectl/pkg/util/templates" - - "github.com/apecloud/kbcli/pkg/printer" - "github.com/apecloud/kbcli/pkg/util" -) - -var ( - listReceiversExample = templates.Examples(` - # list all alert receivers - kbcli alert list-receivers`) -) - -type listReceiversOptions struct { - baseOptions -} - -func newListReceiversCmd(f cmdutil.Factory, streams genericiooptions.IOStreams) *cobra.Command { - o := &listReceiversOptions{baseOptions: baseOptions{Factory: f, IOStreams: streams}} - cmd := &cobra.Command{ - Use: "list-receivers", - Short: "List all alert receivers.", - Example: listReceiversExample, - Run: func(cmd *cobra.Command, args []string) { - util.CheckErr(o.complete()) - util.CheckErr(o.run()) - }, - } - return cmd -} - -func (o *listReceiversOptions) run() error { - data, err := getConfigData(o.alertConfigMap, o.AlertConfigFileName) - if err != nil { - return err - } - - webhookData, err := getConfigData(o.webhookConfigMap, webhookAdaptorFileName) - if err != nil { - return err - } - - receivers := getReceiversFromData(data) - if len(receivers) == 0 { - fmt.Fprintf(o.Out, "No receivers found in alertmanager config %s\n", alertConfigmapName) - return nil - } - webhookReceivers := getReceiversFromData(webhookData) - if len(receivers) == 0 { - fmt.Fprintf(o.Out, "No receivers found in webhook adaptor config %s\n", webhookAdaptorConfigmapName) - return nil - } - - // build receiver webhook map, key is receiver name, value is webhook config that with - // the real webhook url - receiverWebhookMap := make(map[string][]webhookConfig) - for _, r := range receivers { - var cfgs []webhookConfig - name := r.(map[string]interface{})["name"].(string) - for _, w := range webhookReceivers { - obj := w.(map[string]interface{}) - if obj["name"] == name { - cfg := webhookConfig{} - params := obj["params"].(map[string]interface{}) - cfg.URL = params["url"].(string) - cfgs = append(cfgs, cfg) - } - } - receiverWebhookMap[name] = cfgs - } - - // build receiver route map, key is receiver name, value is route - receiverRouteMap := make(map[string]*route) - routes := getRoutesFromData(data) - for _, r := range routes { - res := &route{} - if err = mapstructure.Decode(r, &res); err != nil { - return err - } - receiverRouteMap[res.Receiver] = res - } - - tbl := printer.NewTablePrinter(o.Out) - tbl.SetHeader("NAME", "WEBHOOK", "EMAIL", "SLACK", "CLUSTER", "SEVERITY") - for _, rec := range receivers { - recMap := rec.(map[string]interface{}) - name := recMap["name"].(string) - routeInfo := getRouteInfo(receiverRouteMap[name]) - webhookCfgs := receiverWebhookMap[name] - tbl.AddRow(name, joinWebhookConfigs(webhookCfgs), - joinConfigs(recMap, "email_configs"), - joinConfigs(recMap, "slack_configs"), - strings.Join(routeInfo[routeMatcherClusterKey], ","), - strings.Join(routeInfo[routeMatcherSeverityKey], ",")) - } - tbl.Print() - return nil -} - -// getRouteInfo gets route clusters and severity -func getRouteInfo(route *route) map[string][]string { - routeInfoMap := map[string][]string{ - routeMatcherClusterKey: {}, - routeMatcherSeverityKey: {}, - } - if route == nil { - return routeInfoMap - } - - fetchInfo := func(m, t string) { - if !strings.Contains(m, t) { - return - } - matcher := strings.Split(m, routeMatcherOperator) - if len(matcher) != 2 { - return - } - info := removeDuplicateStr(strings.Split(matcher[1], "|")) - routeInfoMap[t] = append(routeInfoMap[t], info...) - } - - for _, m := range route.Matchers { - fetchInfo(m, routeMatcherClusterKey) - fetchInfo(m, routeMatcherSeverityKey) - } - return routeInfoMap -} - -func joinWebhookConfigs(cfgs []webhookConfig) string { - var result []string - for _, c := range cfgs { - result = append(result, c.string()) - } - return strings.Join(result, "\n") -} - -func joinConfigs(rec map[string]interface{}, key string) string { - var result []string - if rec == nil { - return "" - } - - cfg, ok := rec[key] - if !ok { - return "" - } - - switch key { - case "slack_configs": - for _, c := range cfg.([]interface{}) { - var slack slackConfig - _ = mapstructure.Decode(c, &slack) - result = append(result, slack.string()) - } - case "email_configs": - for _, c := range cfg.([]interface{}) { - var email emailConfig - _ = mapstructure.Decode(c, &email) - result = append(result, email.string()) - } - } - return strings.Join(result, "\n") -} diff --git a/pkg/cmd/alert/list_receivers_test.go b/pkg/cmd/alert/list_receivers_test.go deleted file mode 100644 index 1145796ed..000000000 --- a/pkg/cmd/alert/list_receivers_test.go +++ /dev/null @@ -1,58 +0,0 @@ -/* -Copyright (C) 2022-2024 ApeCloud Co., Ltd - -This file is part of KubeBlocks project - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU Affero General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU Affero General Public License for more details. - -You should have received a copy of the GNU Affero General Public License -along with this program. If not, see . -*/ - -package alert - -import ( - . "github.com/onsi/ginkgo/v2" - . "github.com/onsi/gomega" - clientfake "k8s.io/client-go/rest/fake" - - "k8s.io/cli-runtime/pkg/genericiooptions" - cmdtesting "k8s.io/kubectl/pkg/cmd/testing" - - "github.com/apecloud/kbcli/pkg/testing" -) - -var _ = Describe("alert", func() { - var f *cmdtesting.TestFactory - var s genericiooptions.IOStreams - - BeforeEach(func() { - f = cmdtesting.NewTestFactory() - f.Client = &clientfake.RESTClient{} - s, _, _, _ = genericiooptions.NewTestIOStreams() - }) - - AfterEach(func() { - f.Cleanup() - }) - - It("create new list receiver cmd", func() { - cmd := newListReceiversCmd(f, s) - Expect(cmd).NotTo(BeNil()) - }) - - It("run", func() { - o := &listReceiversOptions{baseOptions: mockBaseOptions(s)} - o.client = testing.FakeClientSet(o.baseOptions.alertConfigMap, o.baseOptions.webhookConfigMap) - o.AlertConfigFileName = alertConfigFileName - Expect(o.run()).Should(Succeed()) - }) -}) diff --git a/pkg/cmd/alert/list_smtpserver.go b/pkg/cmd/alert/list_smtpserver.go deleted file mode 100644 index bf529e804..000000000 --- a/pkg/cmd/alert/list_smtpserver.go +++ /dev/null @@ -1,70 +0,0 @@ -/* -Copyright (C) 2022-2024 ApeCloud Co., Ltd - -This file is part of KubeBlocks project - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU Affero General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU Affero General Public License for more details. - -You should have received a copy of the GNU Affero General Public License -along with this program. If not, see . -*/ - -package alert - -import ( - "github.com/spf13/cobra" - "k8s.io/cli-runtime/pkg/genericiooptions" - cmdutil "k8s.io/kubectl/pkg/cmd/util" - "k8s.io/kubectl/pkg/util/templates" - - "github.com/apecloud/kbcli/pkg/printer" - "github.com/apecloud/kbcli/pkg/util" -) - -var ( - listSMTPServerExample = templates.Examples(` - # list alert smtp servers config - kbcli alert list-smtpserver`) -) - -type listSMTPServerOptions struct { - baseOptions -} - -func newListSMTPServerCmd(f cmdutil.Factory, streams genericiooptions.IOStreams) *cobra.Command { - o := &listSMTPServerOptions{baseOptions: baseOptions{Factory: f, IOStreams: streams}} - cmd := &cobra.Command{ - Use: "list-smtpserver", - Short: "List alert smtp servers config.", - Example: listSMTPServerExample, - Run: func(cmd *cobra.Command, args []string) { - util.CheckErr(o.complete()) - util.CheckErr(o.run()) - }, - } - return cmd -} - -func (o *listSMTPServerOptions) run() error { - data, err := getConfigData(o.alertConfigMap, o.AlertConfigFileName) - if err != nil { - return err - } - - // get global - global := getGlobalFromData(data) - - tbl := printer.NewTablePrinter(o.Out) - tbl.SetHeader("IDENTITY", "PASSWORD", "USERNAME", "FROM", "SMARTHOST") - tbl.AddRow(global["smtp_auth_identity"], global["smtp_auth_password"], global["smtp_auth_username"], global["smtp_from"], global["smtp_smarthost"]) - tbl.Print() - return nil -} diff --git a/pkg/cmd/alert/list_smtpserver_test.go b/pkg/cmd/alert/list_smtpserver_test.go deleted file mode 100644 index c41c5b807..000000000 --- a/pkg/cmd/alert/list_smtpserver_test.go +++ /dev/null @@ -1,58 +0,0 @@ -/* -Copyright (C) 2022-2024 ApeCloud Co., Ltd - -This file is part of KubeBlocks project - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU Affero General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU Affero General Public License for more details. - -You should have received a copy of the GNU Affero General Public License -along with this program. If not, see . -*/ - -package alert - -import ( - . "github.com/onsi/ginkgo/v2" - . "github.com/onsi/gomega" - - "k8s.io/cli-runtime/pkg/genericiooptions" - clientfake "k8s.io/client-go/rest/fake" - cmdtesting "k8s.io/kubectl/pkg/cmd/testing" - - "github.com/apecloud/kbcli/pkg/testing" -) - -var _ = Describe("list smtpserver", func() { - var f *cmdtesting.TestFactory - var s genericiooptions.IOStreams - - BeforeEach(func() { - f = cmdtesting.NewTestFactory() - f.Client = &clientfake.RESTClient{} - s, _, _, _ = genericiooptions.NewTestIOStreams() - }) - - AfterEach(func() { - f.Cleanup() - }) - - It("create new list smtpserver cmd", func() { - cmd := newListSMTPServerCmd(f, s) - Expect(cmd).NotTo(BeNil()) - }) - - It("run", func() { - o := &listSMTPServerOptions{baseOptions: mockBaseOptions(s)} - o.client = testing.FakeClientSet(o.baseOptions.alertConfigMap, o.baseOptions.webhookConfigMap) - o.AlertConfigFileName = alertConfigFileName - Expect(o.run()).Should(Succeed()) - }) -}) diff --git a/pkg/cmd/alert/suite_test.go b/pkg/cmd/alert/suite_test.go deleted file mode 100644 index 1cc8aefe8..000000000 --- a/pkg/cmd/alert/suite_test.go +++ /dev/null @@ -1,32 +0,0 @@ -/* -Copyright (C) 2022-2024 ApeCloud Co., Ltd - -This file is part of KubeBlocks project - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU Affero General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU Affero General Public License for more details. - -You should have received a copy of the GNU Affero General Public License -along with this program. If not, see . -*/ - -package alert - -import ( - "testing" - - . "github.com/onsi/ginkgo/v2" - . "github.com/onsi/gomega" -) - -func TestAlert(t *testing.T) { - RegisterFailHandler(Fail) - RunSpecs(t, "Alert Command Test Suite") -} diff --git a/pkg/cmd/alert/types.go b/pkg/cmd/alert/types.go deleted file mode 100644 index ff82d3e5e..000000000 --- a/pkg/cmd/alert/types.go +++ /dev/null @@ -1,184 +0,0 @@ -/* -Copyright (C) 2022-2024 ApeCloud Co., Ltd - -This file is part of KubeBlocks project - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU Affero General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU Affero General Public License for more details. - -You should have received a copy of the GNU Affero General Public License -along with this program. If not, see . -*/ - -package alert - -import ( - "fmt" - "strings" -) - -// addon name -const ( - // alertManagerAddonName is the name of alertmanager addon - alertManagerAddonName = "prometheus" - - // webhookAdaptorAddonName is the name of webhook adaptor addon - webhookAdaptorAddonName = "alertmanager-webhook-adaptor" -) - -var ( - addonCMSuffix = map[string]string{ - alertManagerAddonName: alertConfigMapNameSuffix, - webhookAdaptorAddonName: webhookAdaptorConfigMapNameSuffix, - } -) - -// configmap name suffix -const ( - // alertConfigMapNameSuffix is the suffix of alertmanager configmap name - alertConfigMapNameSuffix = "alertmanager-config" - - // webhookAdaptorConfigMapNameSuffix is the suffix of webhook adaptor configmap name - webhookAdaptorConfigMapNameSuffix = "config" -) - -// config file name -const ( - // alertConfigFileName is the name of alertmanager config file - alertConfigFileName = "alertmanager.yml" - - // webhookAdaptorFileName is the name of webhook adaptor config file - webhookAdaptorFileName = "config.yml" -) - -const ( - routeMatcherClusterKey = "app_kubernetes_io_instance" - routeMatcherSeverityKey = "severity" - routeMatcherTypeKey = "app_kubernetes_io_component" - routeMatcherRuleKey = "alertname" - routeMatcherOperator = "=~" -) - -const ( - routeMatcherClusterType = "cluster" - routeMatcherSeverityType = "severity" - routeMatcherTypeType = "type" - routeMatcherRuleType = "rule" -) - -// severity is the severity level of alert -type severity string - -const ( - // severityCritical is the critical severity - severityCritical severity = "critical" - // severityWarning is the warning severity - severityWarning severity = "warning" - // severityInfo is the info severity - severityInfo severity = "info" -) - -type webhookKey string - -// webhook keys -const ( - webhookURL webhookKey = "url" - webhookToken webhookKey = "token" -) - -type webhookType string - -const ( - feishuWebhookType webhookType = "feishu-webhook" - wechatWebhookType webhookType = "wechat-webhook" - dingtalkWebhookType webhookType = "dingtalk-webhook" - unknownWebhookType webhookType = "unknown" -) - -type slackKey string - -// slackConfig keys -const ( - slackAPIURL slackKey = "api_url" - slackChannel slackKey = "channel" - slackUsername slackKey = "username" - slackTitleLink slackKey = "title_link" -) - -// emailConfig is the email config of receiver -type emailConfig struct { - To string `json:"to"` -} - -// webhookConfig is the webhook config of receiver -type webhookConfig struct { - URL string `json:"url"` - SendResolved bool `json:"send_resolved"` - MaxAlerts int `json:"max_alerts,omitempty"` -} - -// slackConfig is the alertmanager slack config of receiver -// ref: https://prometheus.io/docs/alerting/latest/configuration/#slack_config -type slackConfig struct { - APIURL string `json:"api_url,omitempty"` - Channel string `json:"channel,omitempty"` - Username string `json:"username,omitempty"` - TitleLink string `json:"title_link"` -} - -// receiver is the receiver of alert -type receiver struct { - Name string `json:"name"` - EmailConfigs []*emailConfig `json:"email_configs,omitempty"` - SlackConfigs []*slackConfig `json:"slack_configs,omitempty"` - WebhookConfigs []*webhookConfig `json:"webhook_configs,omitempty"` -} - -// route is the route of receiver -type route struct { - Receiver string `json:"receiver"` - Continue bool `json:"continue,omitempty"` - Matchers []string `json:"matchers,omitempty"` - RepeatInterval string `json:"repeat_interval,omitempty"` - MuteTimeIntervals []string `json:"mute_time_intervals,omitempty"` -} - -type webhookAdaptorReceiverParams struct { - URL string `json:"url"` - Secret string `json:"secret,omitempty"` -} - -type webhookAdaptorReceiver struct { - Name string `json:"name"` - Type string `json:"type"` - Params webhookAdaptorReceiverParams `json:"params"` -} - -func (w *webhookConfig) string() string { - return fmt.Sprintf("url=%s", w.URL) -} - -func (s *slackConfig) string() string { - var cfgs []string - if s.APIURL != "" { - cfgs = append(cfgs, fmt.Sprintf("api_url=%s", s.APIURL)) - } - if s.Channel != "" { - cfgs = append(cfgs, fmt.Sprintf("channel=%s", s.Channel)) - } - if s.Username != "" { - cfgs = append(cfgs, fmt.Sprintf("username=%s", s.Username)) - } - return strings.Join(cfgs, ",") -} - -func (e *emailConfig) string() string { - return e.To -} diff --git a/pkg/cmd/alert/util.go b/pkg/cmd/alert/util.go deleted file mode 100644 index ffde5c929..000000000 --- a/pkg/cmd/alert/util.go +++ /dev/null @@ -1,151 +0,0 @@ -/* -Copyright (C) 2022-2024 ApeCloud Co., Ltd - -This file is part of KubeBlocks project - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU Affero General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU Affero General Public License for more details. - -You should have received a copy of the GNU Affero General Public License -along with this program. If not, see . -*/ - -package alert - -import ( - "fmt" - "net/url" - "strings" - - "golang.org/x/exp/slices" - corev1 "k8s.io/api/core/v1" - "k8s.io/apimachinery/pkg/util/rand" - "k8s.io/apimachinery/pkg/util/yaml" - - "github.com/apecloud/kbcli/pkg/util" -) - -// strToMap parses string to map, string format is key1=value1,key2=value2 -func strToMap(set string) map[string]string { - m := make(map[string]string) - for _, s := range strings.Split(set, ",") { - pair := strings.Split(s, "=") - if len(pair) >= 2 { - m[pair[0]] = strings.Join(pair[1:], "=") - } - } - return m -} - -func severities() []string { - return []string{string(severityCritical), string(severityWarning), string(severityInfo)} -} - -func generateReceiverName() string { - return fmt.Sprintf("receiver-%s", rand.String(5)) -} - -func getConfigData(cm *corev1.ConfigMap, key string) (map[string]interface{}, error) { - dataStr, ok := cm.Data[key] - if !ok { - return nil, fmt.Errorf("configmap %s has no data named %s", cm.Name, key) - } - - data := make(map[string]interface{}) - if err := yaml.Unmarshal([]byte(dataStr), &data); err != nil { - return nil, err - } - return data, nil -} - -func getTimeIntervalsFromData(data map[string]interface{}) []interface{} { - timeIntervals, ok := data["time_intervals"] - if !ok || timeIntervals == nil { - timeIntervals = []interface{}{} // init timeIntervals - } - return timeIntervals.([]interface{}) -} - -func getReceiversFromData(data map[string]interface{}) []interface{} { - receivers, ok := data["receivers"] - if !ok || receivers == nil { - receivers = []interface{}{} // init receivers - } - return receivers.([]interface{}) -} - -func getRoutesFromData(data map[string]interface{}) []interface{} { - route, ok := data["route"] - if !ok || route == nil { - data["route"] = map[string]interface{}{"routes": []interface{}{}} - } - routes, ok := data["route"].(map[string]interface{})["routes"] - if !ok || routes == nil { - routes = []interface{}{} - } - return routes.([]interface{}) -} - -func getGlobalFromData(data map[string]interface{}) map[string]interface{} { - global, ok := data["global"] - if !ok || global == nil { - global = map[string]interface{}{} - } - return global.(map[string]interface{}) -} - -func getWebhookType(url string) webhookType { - if strings.Contains(url, "oapi.dingtalk.com") { - return dingtalkWebhookType - } - if strings.Contains(url, "qyapi.weixin.qq.com") { - return wechatWebhookType - } - if strings.Contains(url, "open.feishu.cn") { - return feishuWebhookType - } - return unknownWebhookType -} - -func getWebhookAdaptorURL(name string, namespace string) string { - return fmt.Sprintf("http://%s.%s:5001/api/v1/notify/%s", util.BuildAddonReleaseName(webhookAdaptorAddonName), namespace, name) -} - -func removeDuplicateStr(strArray []string) []string { - var result []string - for _, s := range strArray { - if !slices.Contains(result, s) { - result = append(result, s) - } - } - return result -} - -func urlIsValid(urlStr string) (bool, error) { - _, err := url.ParseRequestURI(urlStr) - if err != nil { - return false, err - } - return true, nil -} - -func getConfigMapName(addon string) string { - return fmt.Sprintf("%s-%s", util.BuildAddonReleaseName(addon), addonCMSuffix[addon]) -} - -func validEmail(email string) bool { - if email == "" { - return false - } - if !strings.Contains(email, "@") { - return false - } - return true -} diff --git a/pkg/cmd/alert/util_test.go b/pkg/cmd/alert/util_test.go deleted file mode 100644 index e33c4dca1..000000000 --- a/pkg/cmd/alert/util_test.go +++ /dev/null @@ -1,98 +0,0 @@ -/* -Copyright (C) 2022-2024 ApeCloud Co., Ltd - -This file is part of KubeBlocks project - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU Affero General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU Affero General Public License for more details. - -You should have received a copy of the GNU Affero General Public License -along with this program. If not, see . -*/ - -package alert - -import ( - "fmt" - - . "github.com/onsi/ginkgo/v2" - . "github.com/onsi/gomega" -) - -var _ = Describe("alter", func() { - const ( - webhookURL = "https://oapi.dingtalk.com/robot/send?access_token=123456" - ) - It("string to map", func() { - key := "url" - str := key + "=" + webhookURL - res := strToMap(str) - Expect(res).ShouldNot(BeNil()) - Expect(res["url"]).Should(Equal(webhookURL)) - }) - - It("get url webhook type", func() { - testCases := []struct { - url string - expected webhookType - }{ - {url: "", expected: unknownWebhookType}, - {url: "https://test.com", expected: unknownWebhookType}, - {url: webhookURL, expected: dingtalkWebhookType}, - {url: "https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=123456", expected: wechatWebhookType}, - {url: "https://open.feishu.cn/open-apis/bot/v2/hook/123456", expected: feishuWebhookType}, - } - for _, tc := range testCases { - webhookType := getWebhookType(tc.url) - Expect(webhookType).Should(Equal(tc.expected)) - } - }) - - It("remove duplicated string from slice", func() { - slice := []string{"a", "b", "a", "c"} - res := removeDuplicateStr(slice) - Expect(res).ShouldNot(BeNil()) - Expect(res).Should(Equal([]string{"a", "b", "c"})) - }) - - It("url validation", func() { - testCases := []struct { - url string - expected bool - }{ - {url: "", expected: false}, - {url: "https://test.com", expected: true}, - {url: "/foo/bar", expected: true}, - {url: "\"https://test.com\"", expected: false}, - } - for _, tc := range testCases { - By(fmt.Sprintf("url: %s, expected: %t", tc.url, tc.expected)) - res, _ := urlIsValid(tc.url) - Expect(res).Should(Equal(tc.expected)) - } - }) - - It("email validation", func() { - testCases := []struct { - email string - expected bool - }{ - {email: "", expected: false}, - {email: "test.com", expected: false}, - {email: "test@com", expected: true}, - } - for _, tc := range testCases { - By(fmt.Sprintf("email: %s, expected: %t", tc.email, tc.expected)) - res := validEmail(tc.email) - Expect(res).Should(Equal(tc.expected)) - } - }) - -}) diff --git a/pkg/cmd/auth/authorize/authenticator/authenticator.go b/pkg/cmd/auth/authorize/authenticator/authenticator.go deleted file mode 100644 index c591ac996..000000000 --- a/pkg/cmd/auth/authorize/authenticator/authenticator.go +++ /dev/null @@ -1,70 +0,0 @@ -/* -Copyright (C) 2022-2024 ApeCloud Co., Ltd - -This file is part of KubeBlocks project - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU Affero General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU Affero General Public License for more details. - -You should have received a copy of the GNU Affero General Public License -along with this program. If not, see . -*/ - -package authenticator - -import ( - "context" - "fmt" - "net/http" -) - -const ( - PKCE = "pkce" - Device = "device" -) - -type Authenticator interface { - GetAuthorization(ctx context.Context, openURLFunc func(URL string), states ...string) (interface{}, error) - GetToken(ctx context.Context, authorization interface{}) (*TokenResponse, error) - GetUserInfo(ctx context.Context, token string) (*UserInfoResponse, error) - Logout(ctx context.Context, token string, openURLFunc func(URL string)) error - RefreshToken(ctx context.Context, refreshToken string) (*TokenResponse, error) -} - -type TokenResponse struct { - AccessToken string `json:"access_token"` - RefreshToken string `json:"refresh_token"` - IDToken string `json:"id_token"` - ExpiresIn int `json:"expires_in"` -} - -type RefreshTokenResponse struct { - AccessToken string `json:"access_token"` - ExpiresIn int `json:"expires_in"` - Scope string `json:"scope"` - IDToken string `json:"id_token"` - TokenType string `json:"token_type"` -} - -type UserInfoResponse struct { - Name string `json:"name"` - Email string `json:"email"` - Locale string `json:"locale"` - Subject string `json:"sub"` -} - -func NewAuthenticator(typeAuth string, client *http.Client, clientID string, authURL string) (Authenticator, error) { - if typeAuth == PKCE { - return newPKCEAuthenticator(client, clientID, authURL) - } else if typeAuth == Device { - return newDeviceAuthenticator(client, clientID, authURL) - } - return nil, fmt.Errorf("invalid type of authentication") -} diff --git a/pkg/cmd/auth/authorize/authenticator/callback_html/complete.html b/pkg/cmd/auth/authorize/authenticator/callback_html/complete.html deleted file mode 100644 index 2d26a250b..000000000 --- a/pkg/cmd/auth/authorize/authenticator/callback_html/complete.html +++ /dev/null @@ -1,56 +0,0 @@ - - - - - - - - Apecloud - - - - -
- -

Verification Complete!

-

You have successfully logged in kubeblocks cloud.

-
- - - \ No newline at end of file diff --git a/pkg/cmd/auth/authorize/authenticator/callback_html/error.html b/pkg/cmd/auth/authorize/authenticator/callback_html/error.html deleted file mode 100644 index 147fcd942..000000000 --- a/pkg/cmd/auth/authorize/authenticator/callback_html/error.html +++ /dev/null @@ -1,30 +0,0 @@ - - - - Auth0 Verification Complete - - - -

An error occurred. Please check terminal for output.

-

Click the button below to close this page.

- - - - - - diff --git a/pkg/cmd/auth/authorize/authenticator/callback_listener.go b/pkg/cmd/auth/authorize/authenticator/callback_listener.go deleted file mode 100644 index b53ecff57..000000000 --- a/pkg/cmd/auth/authorize/authenticator/callback_listener.go +++ /dev/null @@ -1,140 +0,0 @@ -/* -Copyright (C) 2022-2024 ApeCloud Co., Ltd - -This file is part of KubeBlocks project - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU Affero General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU Affero General Public License for more details. - -You should have received a copy of the GNU Affero General Public License -along with this program. If not, see . -*/ - -package authenticator - -import ( - "context" - "embed" - "errors" - "fmt" - "log" - "net/http" - "os" - "os/signal" - "strings" - - "github.com/leaanthony/debme" -) - -var ( - //go:embed callback_html/* - callbackHTML embed.FS -) - -const ( - ListenerAddress = "127.0.0.1" -) - -type HTTPServer interface { - start(addr string) - shutdown() -} - -// CallbackService is used to handle the callback received in the PKCE flow -type CallbackService struct { - addr string - httpServer HTTPServer -} - -type callbackServer struct { - server *http.Server -} - -func newCallbackService(port string) *CallbackService { - return &CallbackService{ - strings.Join([]string{ListenerAddress, port}, ":"), - &callbackServer{}, - } -} - -func (s *callbackServer) start(addr string) { - s.server = &http.Server{ - Addr: addr, - } - go func() { - if err := s.server.ListenAndServe(); err != http.ErrServerClosed { - panic(err) - } - }() - - signalCh := make(chan os.Signal, 1) - signal.Notify(signalCh, os.Interrupt) - go func() { - <-signalCh - s.shutdown() - os.Exit(0) - }() -} - -func (s *callbackServer) shutdown() { - if err := s.server.Shutdown(context.Background()); err != nil { - log.Printf("HTTP server Shutdown error: %v", err) - } -} - -func (c *CallbackService) getCallbackURL() string { - return fmt.Sprintf("http://%s/callback", c.addr) -} - -func (c *CallbackService) close() { - c.httpServer.shutdown() -} - -// AwaitResponse sets up the response channel to receive the code that comes in -// the from authorization code callback handler -func (c *CallbackService) awaitResponse(callbackResponse chan CallbackResponse, state string) { - c.httpServer.start(c.addr) - - http.HandleFunc("/callback", func(w http.ResponseWriter, r *http.Request) { - response := CallbackResponse{} - if r.URL.Query().Get("state") != state { - response.Error = errors.New("callback completed with incorrect state") - writeHTML(w, "error.html") - } else if callbackErr := r.URL.Query().Get("error"); callbackErr != "" { - response.Error = fmt.Errorf("%s: %s", callbackErr, r.URL.Query().Get("error_description")) - writeHTML(w, "error.html") - } else if code := r.URL.Query().Get("code"); code != "" { - response.Code = code - writeHTML(w, "complete.html") - } else { - response.Error = errors.New("callback completed with no error or code") - writeHTML(w, "error.html") - } - callbackResponse <- response - }) -} - -func writeHTML(w http.ResponseWriter, fileName string) { - tmplFs, _ := debme.FS(callbackHTML, "callback_html") - tmlBytes, err := tmplFs.ReadFile(fileName) - if err != nil { - http.Error(w, "Failed to read HTML file", http.StatusInternalServerError) - return - } - w.Header().Set("Content-Type", "text/html") - write(w, tmlBytes) -} - -func write(w http.ResponseWriter, msg []byte) { - _, err := w.Write(msg) - if err != nil { - fmt.Println("Error writing response:", err) - } -} diff --git a/pkg/cmd/auth/authorize/authenticator/device_authenticator.go b/pkg/cmd/auth/authorize/authenticator/device_authenticator.go deleted file mode 100644 index 40012730b..000000000 --- a/pkg/cmd/auth/authorize/authenticator/device_authenticator.go +++ /dev/null @@ -1,305 +0,0 @@ -/* -Copyright (C) 2022-2024 ApeCloud Co., Ltd - -This file is part of KubeBlocks project - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU Affero General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU Affero General Public License for more details. - -You should have received a copy of the GNU Affero General Public License -along with this program. If not, see . -*/ - -package authenticator - -import ( - "context" - "encoding/json" - "fmt" - "net/http" - "net/url" - "strings" - "time" - - "github.com/benbjohnson/clock" - "github.com/hashicorp/go-cleanhttp" - "github.com/pkg/errors" -) - -// DeviceAuthenticator performs the authentication flow for logging in. -type DeviceAuthenticator struct { - client *http.Client - AuthURL *url.URL - AuthAudience string - Clock clock.Clock - ClientID string -} - -type DeviceVerification struct { - // DeviceCode is the unique code for the device. When the user goes to the VerificationURL in their browser-based device, this code will be bound to their session. - DeviceCode string - // UserCode contains the code that should be input at the VerificationURL to authorize the device. - UserCode string - // VerificationURL contains the URL the user should visit to authorize the device. - VerificationURL string - // VerificationCompleteURL contains the complete URL the user should visit to authorize the device. This allows your app to embed the user_code in the URL, if you so choose. - VerificationCompleteURL string - // CheckInterval indicates the interval (in seconds) at which the app should poll the token URL to request a token. - Interval time.Duration - // ExpiresAt indicates the lifetime (in seconds) of the device_code and user_code. - ExpiresAt time.Time -} - -type DeviceCodeResponse struct { - DeviceCode string `json:"device_code"` - UserCode string `json:"user_code"` - VerificationURI string `json:"verification_uri"` - VerificationCompleteURI string `json:"verification_uri_complete"` - ExpiresIn int `json:"expires_in"` - PollingInterval int `json:"interval"` -} - -type ErrorResponse struct { - ErrorCode string `json:"error"` - Description string `json:"error_description"` -} - -func (e ErrorResponse) Error() string { - return e.Description -} - -func newDeviceAuthenticator(client *http.Client, clientID string, authURL string) (*DeviceAuthenticator, error) { - if client == nil { - client = cleanhttp.DefaultClient() - } - - baseURL, err := url.Parse(authURL) - if err != nil { - return nil, err - } - - authenticator := &DeviceAuthenticator{ - client: client, - AuthURL: baseURL, - AuthAudience: authURL + "/api/v2/", - Clock: clock.New(), - ClientID: clientID, - } - return authenticator, nil -} - -// GetAuthorization performs the device verification API calls. -func (d *DeviceAuthenticator) GetAuthorization(ctx context.Context, openURLFunc func(URL string), states ...string) (interface{}, error) { - req, err := d.newRequest(ctx, "oauth/device/code", url.Values{ - "client_id": []string{d.ClientID}, - "audience": []string{d.AuthAudience}, - "scope": []string{strings.Join([]string{ - "read_databases", "write_databases", "read_user", "read_organization", "offline_access", "openid", "profile", "email", - }, " ")}, - }) - if err != nil { - return nil, err - } - res, err := d.client.Do(req) - if err != nil { - return nil, err - } - defer res.Body.Close() - - if _, err = checkErrorResponse(res); err != nil { - return nil, err - } - - deviceCodeRes := &DeviceCodeResponse{} - err = json.NewDecoder(res.Body).Decode(deviceCodeRes) - if err != nil { - return nil, errors.Wrap(err, "error decoding device code response") - } - - interval := time.Duration(deviceCodeRes.PollingInterval) * time.Second - if interval == 0 { - interval = time.Duration(5) * time.Second - } - - expiresAt := d.Clock.Now().Add(time.Duration(deviceCodeRes.ExpiresIn) * time.Second) - - openURLFunc(deviceCodeRes.VerificationURI) - - return &DeviceVerification{ - DeviceCode: deviceCodeRes.DeviceCode, - UserCode: deviceCodeRes.UserCode, - VerificationCompleteURL: deviceCodeRes.VerificationCompleteURI, - VerificationURL: deviceCodeRes.VerificationURI, - ExpiresAt: expiresAt, - Interval: interval, - }, nil -} - -func (d *DeviceAuthenticator) GetToken(ctx context.Context, authorization interface{}) (*TokenResponse, error) { - v, ok := authorization.(*DeviceVerification) - if !ok { - return nil, errors.New("invalid authorization") - } - - for { - // This loop begins right after we open the user's browser to send an - // authentication code. We don't request a token immediately because the - // has to complete that authentication flow before we can provide a - // token anyway. - select { - case <-ctx.Done(): - return nil, ctx.Err() - case <-time.After(v.Interval): - } - tokenResponse, err := d.requestToken(ctx, v.DeviceCode, d.ClientID) - if err != nil { - // Fatal error. - return nil, err - } - - if tokenResponse != nil { - return tokenResponse, nil - } - - if tokenResponse == nil && d.Clock.Now().After(v.ExpiresAt) { - return nil, errors.New("authentication timed out") - } - } -} - -func (d *DeviceAuthenticator) requestToken(ctx context.Context, deviceCode string, clientID string) (*TokenResponse, error) { - req, err := d.newRequest(ctx, "oauth/token", url.Values{ - "grant_type": []string{"urn:ietf:params:oauth:grant-type:device_code"}, - "device_code": []string{deviceCode}, - "client_id": []string{clientID}, - }) - if err != nil { - return nil, errors.Wrap(err, "error creating request") - } - - res, err := d.client.Do(req) - if err != nil { - return nil, errors.Wrap(err, "error performing http request") - } - defer res.Body.Close() - - isRetryable, err := checkErrorResponse(res) - if err != nil { - return nil, err - } - - if isRetryable { - return nil, nil - } - - tokenRes := &TokenResponse{} - - err = json.NewDecoder(res.Body).Decode(tokenRes) - if err != nil { - return nil, errors.Wrap(err, "error decoding token response") - } - return tokenRes, nil -} - -func (d *DeviceAuthenticator) GetUserInfo(ctx context.Context, token string) (*UserInfoResponse, error) { - req, err := d.newRequest(ctx, "userinfo", url.Values{ - "access_token": []string{token}, - }) - if err != nil { - return nil, errors.Wrap(err, "error creating request") - } - - res, err := d.client.Do(req) - if err != nil { - return nil, errors.Wrap(err, "error performing http request") - } - defer res.Body.Close() - - userInfo := &UserInfoResponse{} - err = json.NewDecoder(res.Body).Decode(userInfo) - if err != nil { - return nil, errors.Wrap(err, "error decoding userinfo") - } - - return userInfo, err -} - -// RefreshToken The device authenticator needs the clientSecret when refreshing the token, -// and the kbcli client does not hold it, so this method does not need to be implemented. -func (d *DeviceAuthenticator) RefreshToken(ctx context.Context, refreshToken string) (*TokenResponse, error) { - return nil, nil -} - -func (d *DeviceAuthenticator) Logout(ctx context.Context, token string, openURLFunc func(URL string)) error { - req, err := d.newRequest(ctx, "oidc/logout", url.Values{ - "id_token_hint": []string{token}, - "client_id": []string{d.ClientID}, - }) - if err != nil { - return errors.Wrap(err, "error creating request") - } - - res, err := d.client.Do(req) - fmt.Println(res.StatusCode) - if err != nil { - return errors.Wrap(err, "error performing http request") - } - defer res.Body.Close() - if _, err = checkErrorResponse(res); err != nil { - return err - } - - logoutURL := fmt.Sprintf(d.AuthURL.Path + "/oidc/logout?federated") - openURLFunc(logoutURL) - - return nil -} - -func (d *DeviceAuthenticator) newRequest(ctx context.Context, path string, payload url.Values) (*http.Request, error) { - u, err := d.AuthURL.Parse(path) - if err != nil { - return nil, err - } - - req, err := http.NewRequestWithContext( - ctx, - http.MethodPost, - u.String(), - strings.NewReader(payload.Encode()), - ) - if err != nil { - return nil, err - } - - req.Header.Set("Content-Type", "application/x-www-form-urlencoded") - req.Header.Set("Accept", "application/json") - return req, nil -} - -// CheckErrorResponse returns whether the error is retryable or not and the error itself. -func checkErrorResponse(res *http.Response) (bool, error) { - if res.StatusCode < 400 { - return false, nil - } - - // Client or server error. - errorRes := &ErrorResponse{} - err := json.NewDecoder(res.Body).Decode(errorRes) - if err != nil { - return false, errors.Wrap(err, "error decoding response") - } - - // Authentication is not yet complete or requests need to be slowed down. - if errorRes.ErrorCode == "authorization_pending" || errorRes.ErrorCode == "slow_down" { - return true, nil - } - - return false, errorRes -} diff --git a/pkg/cmd/auth/authorize/authenticator/devide_authenticator_test.go b/pkg/cmd/auth/authorize/authenticator/devide_authenticator_test.go deleted file mode 100644 index ece88b29e..000000000 --- a/pkg/cmd/auth/authorize/authenticator/devide_authenticator_test.go +++ /dev/null @@ -1,164 +0,0 @@ -/* -Copyright (C) 2022-2024 ApeCloud Co., Ltd - -This file is part of KubeBlocks project - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU Affero General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU Affero General Public License for more details. - -You should have received a copy of the GNU Affero General Public License -along with this program. If not, see . -*/ - -package authenticator - -import ( - . "github.com/onsi/ginkgo/v2" - . "github.com/onsi/gomega" - - "context" - "encoding/json" - "fmt" - "log" - "net/http" - "net/http/httptest" -) - -func mockDeviceServer() *httptest.Server { - return httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - switch r.URL.Path { - case "/oauth/device/code": - deviceCodeResponse := DeviceCodeResponse{ - DeviceCode: "test_device_code", - UserCode: "test_user_code", - PollingInterval: 5, - ExpiresIn: 1800, - VerificationURI: "https://example.com/device", - VerificationCompleteURI: "https://example.com/device?user_code=test_user_code", - } - - jsonData, err := json.Marshal(deviceCodeResponse) - if err != nil { - log.Fatalf("failed to marshal JSON: %v", err) - } - - w.Header().Set("Content-Type", "application/json") - w.WriteHeader(http.StatusOK) - _, _ = w.Write(jsonData) - - case "/oauth/token": - tokenResp := TokenResponse{ - AccessToken: "test_access_token", - RefreshToken: "test_refresh_token", - IDToken: "test_id_token", - ExpiresIn: 3600, - } - - jsonData, err := json.Marshal(tokenResp) - if err != nil { - log.Fatalf("failed to marshal JSON: %v", err) - } - - w.Header().Set("Content-Type", "application/json") - w.WriteHeader(http.StatusOK) - _, _ = w.Write(jsonData) - - case "/userinfo": - user := UserInfoResponse{ - Name: "John Doe", - Email: "john.doe@example.com", - Locale: "en-US", - Subject: "apecloud", - } - jsonData, err := json.Marshal(user) - if err != nil { - log.Fatalf("failed to marshal JSON: %v", err) - } - - w.Header().Set("Content-Type", "application/json") - w.WriteHeader(http.StatusOK) - _, _ = w.Write(jsonData) - - case "/oidc/logout": - w.WriteHeader(http.StatusOK) - } - })) -} - -var _ = Describe("PKCE_Authenticator", func() { - var ( - clientID = "test_clientID" - a *DeviceAuthenticator - err error - server *httptest.Server - ) - - BeforeEach(func() { - server = mockDeviceServer() - ExpectWithOffset(1, func() error { - a, err = newDeviceAuthenticator(nil, clientID, server.URL) - return err - }()).To(BeNil()) - }) - - AfterEach(func() { - server.Close() - }) - - Context("test Authorization", func() { - It("test get Authorization", func() { - ExpectWithOffset(1, func() error { - openFunc := func(URL string) { - fmt.Println(URL) - } - _, err := a.GetAuthorization(context.TODO(), openFunc) - return err - }()).To(BeNil()) - }) - - It("test get userInfo", func() { - ExpectWithOffset(1, func() error { - _, err := a.GetUserInfo(context.TODO(), "test_token") - return err - }()).To(BeNil()) - }) - - It("test get token", func() { - authorizationResponse := &DeviceVerification{ - DeviceCode: "test_device_code", - UserCode: "test_user_code", - Interval: 5, - VerificationURL: "https://example.com/device", - VerificationCompleteURL: "https://example.com/device?user_code=test_user_code", - } - ExpectWithOffset(1, func() error { - _, err := a.GetToken(context.TODO(), authorizationResponse) - return err - }()).To(BeNil()) - }) - - It("test get refreshToken", func() { - ExpectWithOffset(1, func() error { - _, err := a.RefreshToken(context.TODO(), "test_refresh_token") - return err - }()).To(BeNil()) - }) - - It("test logout", func() { - openFunc := func(URL string) { - fmt.Println(URL) - } - ExpectWithOffset(1, func() error { - err := a.Logout(context.TODO(), "test_token", openFunc) - return err - }()).To(BeNil()) - }) - }) -}) diff --git a/pkg/cmd/auth/authorize/authenticator/pkce_authenticator.go b/pkg/cmd/auth/authorize/authenticator/pkce_authenticator.go deleted file mode 100644 index 327ccc64d..000000000 --- a/pkg/cmd/auth/authorize/authenticator/pkce_authenticator.go +++ /dev/null @@ -1,337 +0,0 @@ -/* -Copyright (C) 2022-2024 ApeCloud Co., Ltd - -This file is part of KubeBlocks project - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU Affero General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU Affero General Public License for more details. - -You should have received a copy of the GNU Affero General Public License -along with this program. If not, see . -*/ - -package authenticator - -import ( - "context" - "crypto/rand" - "crypto/sha256" - "encoding/base64" - "encoding/json" - "fmt" - "net/http" - "net/url" - "path" - "strings" - - viper "github.com/apecloud/kubeblocks/pkg/viperx" - "github.com/benbjohnson/clock" - "github.com/hashicorp/go-cleanhttp" - "github.com/pkg/errors" - - "github.com/apecloud/kbcli/pkg/cmd/auth/utils" - "github.com/apecloud/kbcli/pkg/types" -) - -type OIDCWellKnownEndpoints struct { - AuthorizationEndpoint string `json:"authorization_endpoint"` - TokenEndpoint string `json:"token_endpoint"` -} - -type PKCEAuthenticator struct { - client *http.Client - Clock clock.Clock - ClientID string - AuthURL string - AuthAudience string - Challenge Challenge - WellKnownEndpoints *OIDCWellKnownEndpoints -} - -// Challenge holds challenge and verification data needed for the PKCE flow -type Challenge struct { - Code string - Verifier string - Method string -} - -// CallbackResponse holds the code gotten from the authorization callback. -// Error will hold an error struct if an error occurred. -type CallbackResponse struct { - Code string - Error error -} - -type AuthorizationResponse struct { - CallbackURL string - Code string -} - -func newPKCEAuthenticator(client *http.Client, clientID string, authURL string) (*PKCEAuthenticator, error) { - if client == nil { - client = cleanhttp.DefaultClient() - } - p := &PKCEAuthenticator{ - client: client, - Clock: clock.New(), - ClientID: clientID, - AuthURL: authURL, - AuthAudience: authURL + "/api/v2/", - } - var err error - p.Challenge, err = defaultChallengeGenerator() - if err != nil { - return nil, errors.Wrap(err, "failed to generate PKCE challenge") - } - - return p, nil -} - -func (p *PKCEAuthenticator) GetAuthorization(ctx context.Context, openURLFunc func(URL string), states ...string) (interface{}, error) { - callbackService := newCallbackService("8000") - codeReceiverCh := make(chan CallbackResponse) - defer close(codeReceiverCh) - - var state string - var err error - if states == nil { - state, err = defaultStateGenerator() - if err != nil { - return nil, errors.Wrap(err, "failed to generate state") - } - } else { - state = states[0] - } - - go callbackService.awaitResponse(codeReceiverCh, state) - - var endpoint string - if err = p.getOIDCWellKnownEndpoints(p.AuthURL); err != nil { - endpoint = strings.Join([]string{p.AuthURL, "authorization"}, "/") - } else { - endpoint = p.WellKnownEndpoints.AuthorizationEndpoint - } - - params := url.Values{ - "audience": []string{p.AuthAudience}, - "client_id": []string{p.ClientID}, - "code_challenge": []string{p.Challenge.Code}, - "code_challenge_method": []string{p.Challenge.Method}, - "response_type": []string{"code"}, - "state": []string{state}, - "redirect_uri": []string{callbackService.getCallbackURL()}, - "scope": []string{strings.Join([]string{ - "read_databases", "write_databases", "read_user", "read_organization", "offline_access", "openid", "profile", "email", - }, " ")}, - } - - URL := fmt.Sprintf("%s?%s", - endpoint, - params.Encode(), - ) - openURLFunc(URL) - - callbackResult, ok := <-codeReceiverCh - if !ok { - return nil, errors.New("codeReceiverCh closed") - } - if callbackResult.Error != nil { - return nil, callbackResult.Error - } - callbackService.close() - - return &AuthorizationResponse{ - Code: callbackResult.Code, - CallbackURL: callbackService.getCallbackURL(), - }, nil -} - -func (p *PKCEAuthenticator) GetToken(ctx context.Context, authorization interface{}) (*TokenResponse, error) { - authorize, ok := authorization.(*AuthorizationResponse) - if !ok { - return nil, errors.New("invalid authorization response") - } - - var endpoint string - if err := p.getOIDCWellKnownEndpoints(p.AuthURL); err != nil { - endpoint = strings.Join([]string{p.AuthURL, "oauth/token"}, "/") - } else { - endpoint = p.WellKnownEndpoints.TokenEndpoint - } - - req, err := utils.NewRequest(ctx, endpoint, url.Values{ - "grant_type": []string{"authorization_code"}, - "code_verifier": []string{p.Challenge.Verifier}, - "client_id": []string{p.ClientID}, - "code": []string{authorize.Code}, - "redirect_uri": []string{authorize.CallbackURL}, - }) - if err != nil { - return nil, errors.Wrap(err, "error creating request for token") - } - - res, err := p.client.Do(req) - if err != nil { - return nil, errors.Wrap(err, "error performing http request for token") - } - defer res.Body.Close() - - if _, err = checkErrorResponse(res); err != nil { - return nil, err - } - - tokenRes := &TokenResponse{} - err = json.NewDecoder(res.Body).Decode(tokenRes) - if err != nil { - return nil, errors.Wrap(err, "error decoding token response") - } - - return tokenRes, nil -} - -func (p *PKCEAuthenticator) GetUserInfo(ctx context.Context, token string) (*UserInfoResponse, error) { - URL := fmt.Sprintf("%s/api/v1/user", viper.GetString(types.CfgKeyOpenAPIServer)) - req, err := utils.NewFullRequest(ctx, URL, http.MethodGet, map[string]string{ - "Authorization": "Bearer " + token, - }, "") - if err != nil { - return nil, errors.Wrap(err, "error creating request for userinfo") - } - - res, err := p.client.Do(req) - if err != nil { - return nil, errors.Wrap(err, "error performing http request for userinfo") - } - defer res.Body.Close() - - if _, err = checkErrorResponse(res); err != nil { - return nil, err - } - - userInfo := &UserInfoResponse{} - err = json.NewDecoder(res.Body).Decode(userInfo) - if err != nil { - return nil, errors.Wrap(err, "error decoding userinfo") - } - - return userInfo, err -} - -func (p *PKCEAuthenticator) RefreshToken(ctx context.Context, refreshToken string) (*TokenResponse, error) { - var endpoint string - if err := p.getOIDCWellKnownEndpoints(p.AuthURL); err != nil { - endpoint = strings.Join([]string{p.AuthURL, "oauth/token"}, "/") - } else { - endpoint = p.WellKnownEndpoints.TokenEndpoint - } - - req, err := utils.NewRequest(ctx, endpoint, url.Values{ - "grant_type": []string{"refresh_token"}, - "client_id": []string{p.ClientID}, - "refresh_token": []string{refreshToken}, - }) - if err != nil { - return nil, errors.Wrap(err, "error creating request for refresh token") - } - - res, err := p.client.Do(req) - if err != nil { - return nil, errors.Wrap(err, "error performing http request for refresh token") - } - defer res.Body.Close() - - if _, err = checkErrorResponse(res); err != nil { - return nil, err - } - - refreshTokenRes := &RefreshTokenResponse{} - err = json.NewDecoder(res.Body).Decode(refreshTokenRes) - if err != nil { - return nil, errors.Wrap(err, "error decoding refresh token response") - } - - return &TokenResponse{ - AccessToken: refreshTokenRes.AccessToken, - IDToken: refreshTokenRes.IDToken, - RefreshToken: refreshToken, - ExpiresIn: refreshTokenRes.ExpiresIn, - }, nil -} - -func (p *PKCEAuthenticator) Logout(ctx context.Context, token string, openURLFunc func(URL string)) error { - - logoutURL := fmt.Sprintf(p.AuthURL + "/session/end?id_token_hint=" + token) - openURLFunc(logoutURL) - - return nil -} - -// Get authorize endpoint and token endpoint -func (p *PKCEAuthenticator) getOIDCWellKnownEndpoints(authURL string) error { - u, err := url.Parse(authURL) - if err != nil { - return errors.Wrap(err, "could not parse issuer url to build well known endpoints") - } - u.Path = path.Join(u.Path, ".well-known/openid-configuration") - - r, err := http.Get(u.String()) - if err != nil { - return errors.Wrapf(err, "could not get well known endpoints from url %s", u.String()) - } - - if _, err = checkErrorResponse(r); err != nil { - return err - } - - var wkEndpoints OIDCWellKnownEndpoints - err = json.NewDecoder(r.Body).Decode(&wkEndpoints) - if err != nil { - return errors.Wrap(err, "could not decode json body when getting well known endpoints") - } - - p.WellKnownEndpoints = &wkEndpoints - return nil -} - -// generateRandomString returns a URL-safe, base64 encoded -// securely generated random string. -func generateRandomString(n int) (string, error) { - b := make([]byte, n) - _, err := rand.Read(b) - if err != nil { - return "", err - } - - return base64.RawURLEncoding.EncodeToString(b), nil -} - -func generateChallenge(length int) (Challenge, error) { - c := Challenge{} - - var err error - c.Verifier, err = generateRandomString(length) - if err != nil { - return c, err - } - - sum := sha256.Sum256([]byte(c.Verifier)) - c.Code = base64.RawURLEncoding.EncodeToString(sum[:]) - c.Method = "S256" - - return c, nil -} - -func defaultChallengeGenerator() (Challenge, error) { - return generateChallenge(32) -} - -func defaultStateGenerator() (string, error) { - return generateRandomString(32) -} diff --git a/pkg/cmd/auth/authorize/authenticator/pkce_authenticator_test.go b/pkg/cmd/auth/authorize/authenticator/pkce_authenticator_test.go deleted file mode 100644 index 14718dfcb..000000000 --- a/pkg/cmd/auth/authorize/authenticator/pkce_authenticator_test.go +++ /dev/null @@ -1,130 +0,0 @@ -/* -Copyright (C) 2022-2024 ApeCloud Co., Ltd - -This file is part of KubeBlocks project - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU Affero General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU Affero General Public License for more details. - -You should have received a copy of the GNU Affero General Public License -along with this program. If not, see . -*/ - -package authenticator - -import ( - . "github.com/onsi/ginkgo/v2" - . "github.com/onsi/gomega" - - "context" - "encoding/json" - "fmt" - "log" - "net/http" - "net/http/httptest" -) - -func mockServer() *httptest.Server { - return httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - switch r.URL.Path { - case "/oauth/token": - tokenResp := TokenResponse{ - AccessToken: "test_access_token", - RefreshToken: "test_refresh_token", - IDToken: "test_id_token", - ExpiresIn: 3600, - } - - jsonData, err := json.Marshal(tokenResp) - if err != nil { - log.Fatalf("failed to marshal JSON: %v", err) - } - - w.Header().Set("Content-Type", "application/json") - w.WriteHeader(http.StatusOK) - _, _ = w.Write(jsonData) - - case "/userinfo": - user := UserInfoResponse{ - Name: "John Doe", - Email: "john.doe@example.com", - Locale: "en-US", - Subject: "apecloud", - } - jsonData, err := json.Marshal(user) - if err != nil { - log.Fatalf("failed to marshal JSON: %v", err) - } - - w.Header().Set("Content-Type", "application/json") - w.WriteHeader(http.StatusOK) - _, _ = w.Write(jsonData) - - case "/oidc/logout": - w.WriteHeader(http.StatusOK) - } - })) -} - -var _ = Describe("PKCE_Authenticator", func() { - var ( - clientID = "test_clientID" - a *PKCEAuthenticator - err error - server *httptest.Server - ) - - BeforeEach(func() { - server = mockServer() - ExpectWithOffset(1, func() error { - a, err = newPKCEAuthenticator(nil, clientID, server.URL) - return err - }()).To(BeNil()) - }) - - AfterEach(func() { - server.Close() - }) - - Context("test Authorization", func() { - It("test get userInfo", func() { - _, err := a.GetUserInfo(context.TODO(), "test_token") - Expect(err).Should(HaveOccurred()) - }) - - It("test get token", func() { - authorizationResponse := &AuthorizationResponse{ - CallbackURL: server.URL + "?code=test_code&state=test_state", - Code: "test_code", - } - ExpectWithOffset(1, func() error { - _, err := a.GetToken(context.TODO(), authorizationResponse) - return err - }()).To(BeNil()) - }) - - It("test get refreshToken", func() { - ExpectWithOffset(1, func() error { - _, err := a.RefreshToken(context.TODO(), "test_refresh_token") - return err - }()).To(BeNil()) - }) - - It("test logout", func() { - openFunc := func(URL string) { - fmt.Println(URL) - } - ExpectWithOffset(1, func() error { - err := a.Logout(context.TODO(), "test_token", openFunc) - return err - }()).To(BeNil()) - }) - }) -}) diff --git a/pkg/cmd/auth/authorize/authenticator/suite_test.go b/pkg/cmd/auth/authorize/authenticator/suite_test.go deleted file mode 100644 index 1533c2b05..000000000 --- a/pkg/cmd/auth/authorize/authenticator/suite_test.go +++ /dev/null @@ -1,32 +0,0 @@ -/* -Copyright (C) 2022-2024 ApeCloud Co., Ltd - -This file is part of KubeBlocks project - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU Affero General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU Affero General Public License for more details. - -You should have received a copy of the GNU Affero General Public License -along with this program. If not, see . -*/ - -package authenticator - -import ( - "testing" - - . "github.com/onsi/ginkgo/v2" - . "github.com/onsi/gomega" -) - -func TestAuthenticator(t *testing.T) { - RegisterFailHandler(Fail) - RunSpecs(t, "Authenticator Suite") -} diff --git a/pkg/cmd/auth/authorize/cached_provider.go b/pkg/cmd/auth/authorize/cached_provider.go deleted file mode 100644 index 37f0a513e..000000000 --- a/pkg/cmd/auth/authorize/cached_provider.go +++ /dev/null @@ -1,320 +0,0 @@ -/* -Copyright (C) 2022-2024 ApeCloud Co., Ltd - -This file is part of KubeBlocks project - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU Affero General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU Affero General Public License for more details. - -You should have received a copy of the GNU Affero General Public License -along with this program. If not, see . -*/ - -package authorize - -import ( - "encoding/json" - "log" - "os" - "path/filepath" - - "github.com/99designs/keyring" - "github.com/pkg/errors" - - "github.com/apecloud/kbcli/pkg/cmd/auth/authorize/authenticator" - "github.com/apecloud/kbcli/pkg/util" -) - -const ( - authDir = "auth" - userInfoFile = "user_info.json" - tokenFile = "token.json" - - keyringKey = "token" - keyringService = "kubeblocks" - keyringLabel = "KUBEBLOCKS CLI" - - fileMode = 0o600 -) - -type KeyringCached struct { - key string - valid bool - keyring keyring.Keyring -} - -func (k *KeyringCached) isValid() bool { - return k.valid -} - -func (k *KeyringCached) get() ([]byte, error) { - item, err := k.keyring.Get(k.key) - if err != nil { - return nil, err - } - return item.Data, nil -} - -func (k *KeyringCached) set(data []byte) error { - return k.keyring.Set(keyring.Item{ - Key: k.key, - Data: data, - Label: keyringLabel, - }) -} - -func (k *KeyringCached) remove() error { - return k.keyring.Remove(k.key) -} - -type FileCached struct { - tokenFilename string - userInfoFilename string -} - -type KeyringCachedTokenProvider struct { - keyringCached KeyringProvider - fileCached FileCached -} - -func NewKeyringCachedTokenProvider(keyringCached *KeyringProvider) *KeyringCachedTokenProvider { - fileCached := FileCached{ - tokenFilename: tokenFile, - userInfoFilename: userInfoFile, - } - - if keyringCached == nil { - defaultKeyring, isValid := getDefaultKeyring() - return &KeyringCachedTokenProvider{ - keyringCached: &KeyringCached{ - key: keyringKey, - valid: isValid, - keyring: defaultKeyring, - }, - fileCached: fileCached, - } - } - - return &KeyringCachedTokenProvider{ - keyringCached: *keyringCached, - fileCached: fileCached, - } -} - -func getDefaultKeyring() (keyring.Keyring, bool) { - k, err := keyring.Open(keyring.Config{ - AllowedBackends: []keyring.BackendType{ - keyring.SecretServiceBackend, - keyring.KWalletBackend, - keyring.KeychainBackend, - keyring.WinCredBackend, - }, - ServiceName: keyringService, - KeychainTrustApplication: true, - KeychainSynchronizable: true, - }) - - if err != nil { - return nil, false - } - return k, true -} - -func (k *KeyringCachedTokenProvider) GetTokens() (*authenticator.TokenResponse, error) { - if !k.keyringCached.isValid() { - token, tokenErr := k.fileCached.readToken() - if os.IsNotExist(tokenErr) { - return nil, nil - } - return token, tokenErr - } - - data, err := k.keyringCached.get() - if err != nil { - if err == keyring.ErrKeyNotFound { - return nil, nil - } - return nil, errors.Wrap(err, "error getting token information from keyring") - } - - var tokenResponse authenticator.TokenResponse - err = json.Unmarshal(data, &tokenResponse) - if err != nil { - return nil, errors.Wrap(err, "could not unmarshal token data from keyring") - } - - return &tokenResponse, nil -} - -func (k *KeyringCachedTokenProvider) cacheTokens(tokenResponse *authenticator.TokenResponse) error { - data, err := json.Marshal(tokenResponse) - if err != nil { - return errors.Wrap(err, "could not marshal token data for keyring") - } - - if !k.keyringCached.isValid() { - return k.fileCached.writeToken(data) - } - - return k.keyringCached.set(data) -} - -func (k *KeyringCachedTokenProvider) deleteTokens() error { - if !k.keyringCached.isValid() { - return k.fileCached.deleteToken() - } - - return k.keyringCached.remove() -} - -func (k *KeyringCachedTokenProvider) cacheUserInfo(userInfo *authenticator.UserInfoResponse) error { - saveDir, err := k.fileCached.getConfigDir() - if err != nil { - return err - } - - if err := os.MkdirAll(saveDir, os.ModePerm); err != nil { - return errors.Wrap(err, "failed to create config directory") - } - savePath := filepath.Join(saveDir, k.fileCached.userInfoFilename) - - newData, err := json.Marshal(userInfo) - if err != nil { - return errors.Wrap(err, "failed to marshal user info") - } - - if err := os.WriteFile(savePath, newData, fileMode); err != nil { - return errors.Wrap(err, "failed to write user info file") - } - return nil -} - -func (k *KeyringCachedTokenProvider) getUserInfo() (*authenticator.UserInfoResponse, error) { - saveDir, err := k.fileCached.getConfigDir() - if err != nil { - return nil, err - } - savePath := filepath.Join(saveDir, k.fileCached.userInfoFilename) - data, err := os.ReadFile(savePath) - if err != nil { - return nil, errors.Wrap(err, "failed to read user info file") - } - - var userInfo authenticator.UserInfoResponse - if err := json.Unmarshal(data, &userInfo); err != nil { - return nil, errors.Wrap(err, "failed to unmarshal user info") - } - return &userInfo, nil -} - -func (f *FileCached) getConfigDir() (string, error) { - cliHomeDir, err := util.GetCliHomeDir() - if err != nil { - return "", err - } - return filepath.Join(cliHomeDir, authDir), nil -} - -func (f *FileCached) getTokenPath() (string, error) { - dir, err := f.getConfigDir() - if err != nil { - return "", err - } - - return filepath.Join(dir, f.tokenFilename), nil -} - -func (f *FileCached) writeToken(data []byte) error { - tokenPath, err := f.getTokenPath() - if err != nil { - return err - } - - configDir := filepath.Dir(tokenPath) - - _, err = os.Stat(configDir) - if os.IsNotExist(err) { - err = os.MkdirAll(configDir, os.ModePerm) - if err != nil { - return errors.New("error creating config directory") - } - } else if err != nil { - return err - } - - err = os.WriteFile(tokenPath, data, fileMode) - if err != nil { - return errors.Wrap(err, "error writing token") - } - - return nil -} - -func (f *FileCached) readToken() (*authenticator.TokenResponse, error) { - var data []byte - tokenPath, err := f.getTokenPath() - if err != nil { - return nil, err - } - - stat, err := os.Stat(tokenPath) - if err != nil { - if !os.IsNotExist(err) { - log.Fatal(err) - } - return nil, err - } else { - if stat.Mode()&^fileMode != 0 { - err = os.Chmod(tokenPath, fileMode) - if err != nil { - log.Printf("Unable to change %v file mode to 0%o: %v", tokenPath, fileMode, err) - } - } - data, err = os.ReadFile(tokenPath) - if err != nil { - log.Fatal(err) - } - } - - var tokenResponse *authenticator.TokenResponse - err = json.Unmarshal(data, tokenResponse) - if err != nil { - return nil, err - } - - return tokenResponse, nil -} - -func (f *FileCached) deleteToken() error { - tokenPath, err := f.getTokenPath() - if err != nil { - return err - } - - err = os.Remove(tokenPath) - if err != nil { - if !os.IsNotExist(err) { - return errors.Wrap(err, "error removing access token file") - } - } - - configFile, err := f.getConfigDir() - if err != nil { - return err - } - - err = os.Remove(configFile) - if err != nil { - if !os.IsNotExist(err) { - return errors.Wrap(err, "error removing default config file") - } - } - return nil -} diff --git a/pkg/cmd/auth/authorize/cached_provider_test.go b/pkg/cmd/auth/authorize/cached_provider_test.go deleted file mode 100644 index efd21a1ea..000000000 --- a/pkg/cmd/auth/authorize/cached_provider_test.go +++ /dev/null @@ -1,121 +0,0 @@ -/* -Copyright (C) 2022-2024 ApeCloud Co., Ltd - -This file is part of KubeBlocks project - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU Affero General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU Affero General Public License for more details. - -You should have received a copy of the GNU Affero General Public License -along with this program. If not, see . -*/ - -package authorize - -import ( - . "github.com/onsi/ginkgo/v2" - . "github.com/onsi/gomega" - - "github.com/apecloud/kbcli/pkg/cmd/auth/authorize/authenticator" -) - -type MockKeyring struct { - key string - value []byte -} - -func (m *MockKeyring) set(value []byte) error { - m.value = value - return nil -} - -func (m *MockKeyring) get() ([]byte, error) { - return m.value, nil -} - -func (m *MockKeyring) remove() error { - m.key = "" - m.value = nil - return nil -} - -func (m *MockKeyring) isValid() bool { - return true -} - -var _ = Describe("cache", func() { - var ( - mockKeyring KeyringProvider - cached *KeyringCachedTokenProvider - tokenResponse authenticator.TokenResponse - ) - - BeforeEach(func() { - tokenResponse = authenticator.TokenResponse{ - AccessToken: "test", - RefreshToken: "test", - } - mockKeyring = &MockKeyring{} - cached = NewKeyringCachedTokenProvider(&mockKeyring) - }) - - AfterEach(func() { - }) - - Context("test cache", func() { - It("test cached token", func() { - ExpectWithOffset(1, func() error { - err := cached.cacheTokens(&tokenResponse) - return err - }()).To(BeNil()) - }) - - It("test get token", func() { - ExpectWithOffset(1, func() error { - err := cached.cacheTokens(&tokenResponse) - return err - }()).To(BeNil()) - ExpectWithOffset(1, func() error { - tokenResponse, err := cached.GetTokens() - Expect(tokenResponse.AccessToken).To(Equal("test")) - return err - }()).To(BeNil()) - }) - - It("test fail to get token", func() { - ExpectWithOffset(1, func() error { - err := cached.cacheTokens(&tokenResponse) - return err - }()).To(BeNil()) - ExpectWithOffset(1, func() error { - tokenResponse, err := cached.GetTokens() - Expect(tokenResponse.AccessToken).NotTo(Equal("cloud")) - return err - }()).To(BeNil()) - }) - - It("test delete token", func() { - ExpectWithOffset(1, func() error { - err := cached.cacheTokens(&tokenResponse) - return err - }()).To(BeNil()) - - ExpectWithOffset(1, func() error { - err := cached.deleteTokens() - return err - }()).To(BeNil()) - - ExpectWithOffset(1, func() error { - _, err := cached.GetTokens() - return err - }()).NotTo(BeNil()) - }) - }) -}) diff --git a/pkg/cmd/auth/authorize/issued_provider.go b/pkg/cmd/auth/authorize/issued_provider.go deleted file mode 100644 index d6e2e120e..000000000 --- a/pkg/cmd/auth/authorize/issued_provider.go +++ /dev/null @@ -1,146 +0,0 @@ -/* -Copyright (C) 2022-2024 ApeCloud Co., Ltd - -This file is part of KubeBlocks project - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU Affero General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU Affero General Public License for more details. - -You should have received a copy of the GNU Affero General Public License -along with this program. If not, see . -*/ - -package authorize - -import ( - "context" - "fmt" - "os" - "os/signal" - "syscall" - "time" - - "github.com/briandowns/spinner" - "github.com/hashicorp/go-cleanhttp" - "github.com/pkg/errors" - "k8s.io/cli-runtime/pkg/genericiooptions" - - "github.com/apecloud/kbcli/pkg/cmd/auth/authorize/authenticator" - "github.com/apecloud/kbcli/pkg/cmd/auth/utils" - "github.com/apecloud/kbcli/pkg/printer" - "github.com/apecloud/kbcli/pkg/util" -) - -type Options struct { - ClientID string `json:"client_id"` - AuthURL string - NoBrowser bool - genericiooptions.IOStreams -} - -type CloudIssuedTokenProvider struct { - Options - Authenticator authenticator.Authenticator -} - -func newDefaultIssuedTokenProvider(o Options) (*CloudIssuedTokenProvider, error) { - authenticator, err := authenticator.NewAuthenticator(authenticator.PKCE, cleanhttp.DefaultClient(), o.ClientID, o.AuthURL) - if err != nil { - return nil, errors.Wrap(err, "failed to create authenticator") - } - return &CloudIssuedTokenProvider{ - Options: o, - Authenticator: authenticator, - }, nil -} - -func newIssuedTokenProvider(o Options, authenticator authenticator.Authenticator) (*CloudIssuedTokenProvider, error) { - return &CloudIssuedTokenProvider{ - Options: o, - Authenticator: authenticator, - }, nil -} - -func (c *CloudIssuedTokenProvider) authenticate(ctx context.Context) (*authenticator.TokenResponse, error) { - authorizeResponse, err := c.Authenticator.GetAuthorization(ctx, c.openURLFunc) - if err != nil { - return nil, err - } - - end := c.printProgress("Waiting for confirmation...") - defer end() - - tokenResponse, err := c.Authenticator.GetToken(ctx, authorizeResponse) - if err != nil { - return nil, err - } - return tokenResponse, nil -} - -func (c *CloudIssuedTokenProvider) getUserInfo(token string) (*authenticator.UserInfoResponse, error) { - return c.Authenticator.GetUserInfo(context.TODO(), token) -} - -func (c *CloudIssuedTokenProvider) refreshToken(refreshToken string) (*authenticator.TokenResponse, error) { - tokenResponse, err := c.Authenticator.RefreshToken(context.TODO(), refreshToken) - if err != nil { - return nil, err - } - return tokenResponse, nil -} - -func (c *CloudIssuedTokenProvider) logout(ctx context.Context, token string) error { - end := c.printProgress("Logging out...") - defer end() - err := c.Authenticator.Logout(ctx, token, c.openURLFunc) - if err != nil { - return err - } - return nil -} - -func (c *CloudIssuedTokenProvider) printProgress(message string) func() { - if !utils.IsTTY() { - fmt.Fprintln(c.Out, message) - return func() {} - } - - s := spinner.New(spinner.CharSets[14], 100*time.Millisecond, spinner.WithWriter(c.Out)) - s.Suffix = fmt.Sprintf(" %s", message) - - _ = s.Color("bold", "green") - s.Start() - - sig := make(chan os.Signal, 1) - signal.Notify(sig, os.Interrupt, syscall.SIGTERM) - go func() { - <-sig - fmt.Fprintf(c.Out, "\033[?25h") - os.Exit(0) - }() - - return func() { - s.Stop() - fmt.Fprintf(c.Out, "\033[?25h") - } -} - -func (c *CloudIssuedTokenProvider) openURLFunc(url string) { - if !c.NoBrowser { - err := util.OpenBrowser(url) - if err != nil { - msg := fmt.Sprintf("failed to open a browser: %s", printer.BoldRed(err.Error())) - fmt.Fprint(c.Out, msg) - } - } else { - msg := fmt.Sprintf("\nPlease paste this URL into your browser: %s\n\n", printer.BoldGreen(url)) - fmt.Fprint(c.Out, msg) - } -} diff --git a/pkg/cmd/auth/authorize/issued_provoder_test.go b/pkg/cmd/auth/authorize/issued_provoder_test.go deleted file mode 100644 index cf3c8466c..000000000 --- a/pkg/cmd/auth/authorize/issued_provoder_test.go +++ /dev/null @@ -1,182 +0,0 @@ -/* -Copyright (C) 2022-2024 ApeCloud Co., Ltd - -This file is part of KubeBlocks project - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU Affero General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU Affero General Public License for more details. - -You should have received a copy of the GNU Affero General Public License -along with this program. If not, see . -*/ - -package authorize - -import ( - . "github.com/onsi/ginkgo/v2" - . "github.com/onsi/gomega" - - "context" - "fmt" - - "k8s.io/cli-runtime/pkg/genericiooptions" - - "github.com/apecloud/kbcli/pkg/cmd/auth/authorize/authenticator" -) - -var authorizationRes = authenticator.AuthorizationResponse{ - Code: "test_code", - CallbackURL: "test_callback_url", -} - -type MockAuthenticator struct { - userInfoResponse *authenticator.UserInfoResponse - tokenResponse *authenticator.TokenResponse - authorizationResponse *authenticator.AuthorizationResponse -} - -func NewMockAuthenticator() *MockAuthenticator { - return &MockAuthenticator{ - userInfoResponse: &userInfoResponse, - tokenResponse: &tokenResponse, - authorizationResponse: &authorizationRes, - } -} - -func (m *MockAuthenticator) GetAuthorization(ctx context.Context, openURLFunc func(URL string), states ...string) (interface{}, error) { - return m.authorizationResponse, nil -} - -func (m *MockAuthenticator) GetToken(ctx context.Context, authorization interface{}) (*authenticator.TokenResponse, error) { - if response, ok := authorization.(*authenticator.AuthorizationResponse); ok { - if response.Code == m.authorizationResponse.Code { - return m.tokenResponse, nil - } - } - return nil, fmt.Errorf("authorization not match") -} - -func (m *MockAuthenticator) GetUserInfo(ctx context.Context, token string) (*authenticator.UserInfoResponse, error) { - if token == m.tokenResponse.AccessToken { - return m.userInfoResponse, nil - } - return nil, fmt.Errorf("token not match") -} - -func (m *MockAuthenticator) Logout(ctx context.Context, token string, openURLFunc func(URL string)) error { - if token == m.tokenResponse.AccessToken { - return nil - } - return fmt.Errorf("token not match") -} - -func (m *MockAuthenticator) RefreshToken(ctx context.Context, refreshToken string) (*authenticator.TokenResponse, error) { - if refreshToken == m.tokenResponse.RefreshToken { - m.tokenResponse.AccessToken = "newAccessToken" - return m.tokenResponse, nil - } - return nil, fmt.Errorf("refresh token not match") -} - -var _ = Describe("issued provider", func() { - var ( - mockAuthenticator *MockAuthenticator - issuedTokenProvider *CloudIssuedTokenProvider - tokenRes *authenticator.TokenResponse - o Options - streams genericiooptions.IOStreams - ) - - BeforeEach(func() { - mockAuthenticator = NewMockAuthenticator() - streams, _, _, _ = genericiooptions.NewTestIOStreams() - o = Options{ - ClientID: "test_client_id", - AuthURL: "test_auth_url", - NoBrowser: true, - IOStreams: streams, - } - }) - - AfterEach(func() { - }) - - Context("test issued provider", func() { - It("test authenticate", func() { - ExpectWithOffset(1, func() error { - var err error - issuedTokenProvider, err = newIssuedTokenProvider(o, mockAuthenticator) - return err - }()).To(BeNil()) - - ExpectWithOffset(1, func() error { - _, err := issuedTokenProvider.authenticate(context.Background()) - return err - }()).To(BeNil()) - }) - - It("test getUserInfo", func() { - ExpectWithOffset(1, func() error { - var err error - issuedTokenProvider, err = newIssuedTokenProvider(o, mockAuthenticator) - return err - }()).To(BeNil()) - - ExpectWithOffset(1, func() error { - var err error - tokenRes, err = issuedTokenProvider.authenticate(context.Background()) - return err - }()).To(BeNil()) - - ExpectWithOffset(1, func() error { - _, err := issuedTokenProvider.getUserInfo(tokenRes.AccessToken) - return err - }()).To(BeNil()) - }) - - It("test refreshToken", func() { - ExpectWithOffset(1, func() error { - var err error - issuedTokenProvider, err = newIssuedTokenProvider(o, mockAuthenticator) - return err - }()).To(BeNil()) - - ExpectWithOffset(1, func() error { - var err error - tokenRes, err = issuedTokenProvider.authenticate(context.Background()) - return err - }()).To(BeNil()) - - ExpectWithOffset(1, func() error { - _, err := issuedTokenProvider.refreshToken(tokenRes.RefreshToken) - return err - }()).To(BeNil()) - }) - - It("test logout", func() { - ExpectWithOffset(1, func() error { - var err error - issuedTokenProvider, err = newIssuedTokenProvider(o, mockAuthenticator) - return err - }()).To(BeNil()) - - ExpectWithOffset(1, func() error { - var err error - tokenRes, err = issuedTokenProvider.authenticate(context.Background()) - return err - }()).To(BeNil()) - - ExpectWithOffset(1, func() error { - err := issuedTokenProvider.logout(context.Background(), tokenRes.AccessToken) - return err - }()).To(BeNil()) - }) - }) -}) diff --git a/pkg/cmd/auth/authorize/provider_interface.go b/pkg/cmd/auth/authorize/provider_interface.go deleted file mode 100644 index 1668995ae..000000000 --- a/pkg/cmd/auth/authorize/provider_interface.go +++ /dev/null @@ -1,53 +0,0 @@ -/* -Copyright (C) 2022-2024 ApeCloud Co., Ltd - -This file is part of KubeBlocks project - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU Affero General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU Affero General Public License for more details. - -You should have received a copy of the GNU Affero General Public License -along with this program. If not, see . -*/ - -package authorize - -import ( - "context" - - "github.com/apecloud/kbcli/pkg/cmd/auth/authorize/authenticator" -) - -type CachedTokenProvider interface { - GetTokens() (*authenticator.TokenResponse, error) - cacheTokens(*authenticator.TokenResponse) error - deleteTokens() error - cacheUserInfo(info *authenticator.UserInfoResponse) error - getUserInfo() (*authenticator.UserInfoResponse, error) -} - -type KeyringProvider interface { - get() ([]byte, error) - set(data []byte) error - remove() error - isValid() bool -} - -type IssuedTokenProvider interface { - authenticate(ctx context.Context) (*authenticator.TokenResponse, error) - refreshToken(refreshToken string) (*authenticator.TokenResponse, error) - getUserInfo(token string) (*authenticator.UserInfoResponse, error) - logout(ctx context.Context, token string) error -} - -type Provider interface { - Login(ctx context.Context) (*authenticator.UserInfoResponse, string, error) - Logout(ctx context.Context) error -} diff --git a/pkg/cmd/auth/authorize/suite_test.go b/pkg/cmd/auth/authorize/suite_test.go deleted file mode 100644 index 5d6f0e5ce..000000000 --- a/pkg/cmd/auth/authorize/suite_test.go +++ /dev/null @@ -1,32 +0,0 @@ -/* -Copyright (C) 2022-2024 ApeCloud Co., Ltd - -This file is part of KubeBlocks project - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU Affero General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU Affero General Public License for more details. - -You should have received a copy of the GNU Affero General Public License -along with this program. If not, see . -*/ - -package authorize - -import ( - "testing" - - . "github.com/onsi/ginkgo/v2" - . "github.com/onsi/gomega" -) - -func TestProvider(t *testing.T) { - RegisterFailHandler(Fail) - RunSpecs(t, "Provider Suite") -} diff --git a/pkg/cmd/auth/authorize/token_provider.go b/pkg/cmd/auth/authorize/token_provider.go deleted file mode 100644 index 4ac3962ee..000000000 --- a/pkg/cmd/auth/authorize/token_provider.go +++ /dev/null @@ -1,141 +0,0 @@ -/* -Copyright (C) 2022-2024 ApeCloud Co., Ltd - -This file is part of KubeBlocks project - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU Affero General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU Affero General Public License for more details. - -You should have received a copy of the GNU Affero General Public License -along with this program. If not, see . -*/ - -package authorize - -import ( - "context" - "fmt" - "time" - - "github.com/golang-jwt/jwt" - "github.com/pkg/errors" - - "github.com/apecloud/kbcli/pkg/cmd/auth/authorize/authenticator" -) - -type TokenProvider struct { - cached CachedTokenProvider - issued IssuedTokenProvider -} - -// NewTokenProvider default constructor. -func NewTokenProvider(o Options) (Provider, error) { - cached := NewKeyringCachedTokenProvider(nil) - issued, err := newDefaultIssuedTokenProvider(o) - if err != nil { - return nil, errors.Wrap(err, "could not create cloud issued token provider") - } - return &TokenProvider{ - cached: cached, - issued: issued, - }, nil -} - -// Abstract constructor -func newTokenProvider(cached CachedTokenProvider, issued IssuedTokenProvider) Provider { - return &TokenProvider{ - cached: cached, - issued: issued, - } -} - -func (p *TokenProvider) Login(ctx context.Context) (*authenticator.UserInfoResponse, string, error) { - tokenResult, err := p.issued.authenticate(ctx) - if err != nil { - return nil, "", errors.Wrap(err, "could not authenticate with cloud") - } - userInfo, err := p.issued.getUserInfo(tokenResult.IDToken) - if err != nil { - return nil, "", errors.Wrap(err, "could not get user info from cloud") - } - err = p.cached.cacheUserInfo(userInfo) - if err != nil { - return nil, "", errors.Wrap(err, "could not store user info") - } - - err = p.cached.cacheTokens(tokenResult) - if err != nil { - return nil, "", errors.Wrap(err, "could not cache tokens") - } - - return userInfo, tokenResult.IDToken, nil -} - -func (p *TokenProvider) Logout(ctx context.Context) error { - tokenResult, err := p.cached.GetTokens() - if err != nil { - return err - } - if tokenResult == nil { - return fmt.Errorf("token not found in cache, already logged out") - } - - err = p.cached.deleteTokens() - if err != nil { - return err - } - - err = p.issued.logout(ctx, tokenResult.IDToken) - if err != nil { - return err - } - return nil -} - -func (p *TokenProvider) getTokenFromCache(isTokenValid func(authenticator.TokenResponse) bool) (*authenticator.TokenResponse, error) { - tokenResult, err := p.cached.GetTokens() - if err != nil { - return nil, errors.Wrap(err, "could get tokens from the cache") - } - // if the token is not in the cache, return nil - if tokenResult == nil { - return nil, nil - } - - if isTokenValid(*tokenResult) { - return tokenResult, nil - } - - if tokenResult.RefreshToken == "" { - return nil, nil - } - - return p.getRefreshToken(tokenResult.RefreshToken), nil -} - -// getRefreshToken gets a new token from the refresh token -func (p *TokenProvider) getRefreshToken(refreshToken string) *authenticator.TokenResponse { - tokenResult, err := p.issued.refreshToken(refreshToken) - if err != nil { - return nil - } - return tokenResult -} - -// IsValidToken checks to see if the token is valid and has not expired -func IsValidToken(tokenString string) bool { - jwtParser := jwt.Parser{} - claims := jwt.MapClaims{} - if _, _, err := jwtParser.ParseUnverified(tokenString, claims); err != nil { - fmt.Println("Token parsing failed:", err) - return false - } - return claims.VerifyExpiresAt(time.Now().Unix(), true) -} diff --git a/pkg/cmd/auth/authorize/token_provider_test.go b/pkg/cmd/auth/authorize/token_provider_test.go deleted file mode 100644 index fe9f434f0..000000000 --- a/pkg/cmd/auth/authorize/token_provider_test.go +++ /dev/null @@ -1,164 +0,0 @@ -/* -Copyright (C) 2022-2024 ApeCloud Co., Ltd - -This file is part of KubeBlocks project - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU Affero General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU Affero General Public License for more details. - -You should have received a copy of the GNU Affero General Public License -along with this program. If not, see . -*/ - -package authorize - -import ( - . "github.com/onsi/ginkgo/v2" - . "github.com/onsi/gomega" - - "context" - "fmt" - - "github.com/apecloud/kbcli/pkg/cmd/auth/authorize/authenticator" -) - -type MockIssued struct { - tokenResponse *authenticator.TokenResponse - userInfoResponse *authenticator.UserInfoResponse -} - -var tokenResponse = authenticator.TokenResponse{ - AccessToken: "test_access_token", - RefreshToken: "test_refresh_token", - IDToken: "test_id_token", - ExpiresIn: 3600000000000, -} - -var userInfoResponse = authenticator.UserInfoResponse{ - Name: "test_name", - Email: "test_email", - Locale: "test_locale", - Subject: "test_subject", -} - -func (m *MockIssued) authenticate(ctx context.Context) (*authenticator.TokenResponse, error) { - return m.tokenResponse, nil -} - -func (m *MockIssued) refreshToken(refreshToken string) (*authenticator.TokenResponse, error) { - if refreshToken == m.tokenResponse.RefreshToken { - m.tokenResponse.AccessToken = "newAccessToken" - return m.tokenResponse, nil - } - return nil, fmt.Errorf("refresh token not match") -} - -func (m *MockIssued) getUserInfo(token string) (*authenticator.UserInfoResponse, error) { - if token == m.tokenResponse.AccessToken { - return m.userInfoResponse, nil - } - return nil, fmt.Errorf("token not match") -} - -func (m *MockIssued) logout(ctx context.Context, token string) error { - if token == m.tokenResponse.IDToken { - return nil - } - return fmt.Errorf("token not match") -} - -type MockCached struct { - tokenResponse *authenticator.TokenResponse - userInfoResponse *authenticator.UserInfoResponse -} - -func (m *MockCached) cacheTokens(tokenResponse *authenticator.TokenResponse) error { - m.tokenResponse = tokenResponse - return nil -} - -func (m *MockCached) deleteTokens() error { - m.tokenResponse = nil - return nil -} - -func (m *MockCached) cacheUserInfo(userInfoResponse *authenticator.UserInfoResponse) error { - m.userInfoResponse = userInfoResponse - return nil -} - -func (m *MockCached) GetTokens() (*authenticator.TokenResponse, error) { - return m.tokenResponse, nil -} - -func (m *MockCached) getUserInfo() (*authenticator.UserInfoResponse, error) { - return m.userInfoResponse, nil -} - -var _ = Describe("token provider", func() { - var ( - mockIssued *MockIssued - mockCached *MockCached - ) - - BeforeEach(func() { - mockIssued = &MockIssued{ - tokenResponse: &tokenResponse, - userInfoResponse: &userInfoResponse, - } - - mockCached = &MockCached{ - tokenResponse: &tokenResponse, - userInfoResponse: &userInfoResponse, - } - }) - - AfterEach(func() { - }) - - Context("test token provider", func() { - It("test login", func() { - tokenProvider := newTokenProvider(mockCached, mockIssued) - _, _, err := tokenProvider.Login(context.Background()) - Expect(err).Should(HaveOccurred()) - }) - - It("test logout", func() { - tokenProvider := newTokenProvider(mockCached, mockIssued) - - ExpectWithOffset(1, func() error { - err := tokenProvider.Logout(context.Background()) - return err - }()).To(BeNil()) - }) - - It("test IsValidToken", func() { - Expect(IsValidToken("test_token")).To(BeFalse()) - }) - - It("test getTokenFromCache", func() { - tokenProvider := &TokenProvider{ - cached: mockCached, - issued: mockIssued, - } - isAccessTokenValid := func(tokenResponse authenticator.TokenResponse) bool { return IsValidToken(tokenResponse.AccessToken) } - _, err := tokenProvider.getTokenFromCache(isAccessTokenValid) - Expect(err).ShouldNot(HaveOccurred()) - }) - - It("test getRefreshToken", func() { - tokenProvider := &TokenProvider{ - cached: mockCached, - issued: mockIssued, - } - Expect(tokenProvider.getRefreshToken("")).Should(BeNil()) - }) - }) -}) diff --git a/pkg/cmd/auth/login.go b/pkg/cmd/auth/login.go deleted file mode 100644 index babb00a83..000000000 --- a/pkg/cmd/auth/login.go +++ /dev/null @@ -1,308 +0,0 @@ -/* -Copyright (C) 2022-2024 ApeCloud Co., Ltd - -This file is part of KubeBlocks project - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU Affero General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU Affero General Public License for more details. - -You should have received a copy of the GNU Affero General Public License -along with this program. If not, see . -*/ - -package auth - -import ( - "context" - "encoding/json" - "fmt" - "io" - "net/http" - - viper "github.com/apecloud/kubeblocks/pkg/viperx" - "github.com/spf13/cobra" - "k8s.io/cli-runtime/pkg/genericiooptions" - - "github.com/apecloud/kbcli/pkg/cmd/auth/authorize" - "github.com/apecloud/kbcli/pkg/cmd/auth/utils" - cloudctx "github.com/apecloud/kbcli/pkg/cmd/context" - "github.com/apecloud/kbcli/pkg/cmd/organization" - "github.com/apecloud/kbcli/pkg/types" -) - -type LoginOptions struct { - authorize.Options - Region string - OrgName string - ContextName string - - Provider authorize.Provider -} - -func NewLogin(streams genericiooptions.IOStreams) *cobra.Command { - o := &LoginOptions{Options: authorize.Options{IOStreams: streams}} - cmd := &cobra.Command{ - Use: "login", - Short: "Authenticate with the KubeBlocks Cloud", - Run: func(cmd *cobra.Command, args []string) { - cobra.CheckErr(o.complete()) - cobra.CheckErr(o.validate()) - cobra.CheckErr(o.run(cmd.Context())) - }, - } - - cmd.Flags().StringVarP(&o.Region, "region", "r", "jp", "Specify the region [jp] to log in.") - cmd.Flags().BoolVar(&o.NoBrowser, "no-browser", false, "Do not open the browser for authentication.") - cmd.Flags().StringVarP(&o.OrgName, "org", "o", "", "Organization name.") - cmd.Flags().StringVarP(&o.ContextName, "context", "c", "", "Context name.") - return cmd -} - -func (o *LoginOptions) complete() error { - o.AuthURL = getAuthURL(o.Region) - - var err error - o.Provider, err = authorize.NewTokenProvider(o.Options) - if err != nil { - return err - } - - if o.ClientID == "" { - return o.loadConfig() - } - return nil -} - -func (o *LoginOptions) validate() error { - if o.ClientID == "" { - return fmt.Errorf("client-id is required") - } - return nil -} - -func (o *LoginOptions) run(ctx context.Context) error { - if o.OrgName != "" { - if o.ContextName != "" { - return o.loginWithOrgAndContext(ctx) - } - return o.loginWithOrg(ctx) - } - - if o.ContextName != "" { - return o.loginWithContext(ctx) - } - - return o.loginWithDefault(ctx) -} - -func (o *LoginOptions) login(ctx context.Context) (string, error) { - if !utils.IsTTY() { - return "", fmt.Errorf("the 'login' command requires an interactive shell") - } - - userInfo, idToken, err := o.Provider.Login(ctx) - if err != nil { - return "", err - } - - msg := fmt.Sprintf("Successfully logged in as \"%s\" for organization \"%s\" (\"%s\") \"%s\".", userInfo.Email, userInfo.Subject, userInfo.Name, userInfo.Locale) - fmt.Fprintln(o.Out, msg) - - return idToken, nil -} - -func (o *LoginOptions) loadConfig() error { - data, err := utils.Asset("config/config.enc") - if err != nil { - return err - } - err = json.Unmarshal(data, &o.Options) - if err != nil { - return err - } - - o.Provider, err = authorize.NewTokenProvider(o.Options) - if err != nil { - return err - } - - return nil -} - -func (o *LoginOptions) loginWithOrg(ctx context.Context) error { - token, err := o.login(ctx) - if err != nil { - return err - } - - org := &organization.OrganizationOption{ - Organization: &organization.CloudOrganization{ - Token: token, - APIURL: viper.GetString(types.CfgKeyOpenAPIServer), - APIPath: utils.APIPathV1, - }, - } - if ok, err := org.Organization.IsValidOrganization(o.OrgName); !ok { - return err - } - - firstContextName := getFirstContext(token, o.OrgName) - if err != nil { - return err - } - - return o.setCurrentConfig(o.OrgName, firstContextName) -} - -func (o *LoginOptions) loginWithContext(ctx context.Context) error { - token, err := o.login(ctx) - if err != nil { - return err - } - - firstOrgName := getFirstOrg(token) - if err != nil { - return err - } - - return o.setCurrentConfig(firstOrgName, o.ContextName) -} - -func (o *LoginOptions) loginWithOrgAndContext(ctx context.Context) error { - _, err := o.login(ctx) - if err != nil { - return err - } - return o.setCurrentConfig(o.OrgName, o.ContextName) -} - -func (o *LoginOptions) loginWithDefault(ctx context.Context) error { - token, err := o.login(ctx) - if err != nil { - return err - } - - firstOrgName := getFirstOrg(token) - if err != nil { - return err - } - - firstContextName := getFirstContext(token, firstOrgName) - if err != nil { - return err - } - - return o.setCurrentConfig(firstOrgName, firstContextName) -} - -func (o *LoginOptions) setCurrentConfig(orgName, contextName string) error { - currentOrgAndContext := organization.CurrentOrgAndContext{ - CurrentOrganization: orgName, - CurrentContext: contextName, - } - - err := organization.SetCurrentOrgAndContext(¤tOrgAndContext) - if err != nil { - return err - } - - fmt.Fprintf(o.Out, "You are now logged in to the organization: %s and the context: %s.\n", orgName, contextName) - return nil -} - -func getFirstOrg(token string) string { - org := &organization.OrganizationOption{ - Organization: &organization.CloudOrganization{ - Token: token, - APIURL: viper.GetString(types.CfgKeyOpenAPIServer), - APIPath: utils.APIPathV1, - }, - } - organizations, err := org.Organization.GetOrganizations() - if err != nil { - return "" - } - - if organizations != nil && len(organizations.Items) > 0 { - return organizations.Items[0].Name - } - return "" -} - -func getFirstContext(token string, orgName string) string { - c := &cloudctx.CloudContext{ - OrgName: orgName, - Token: token, - APIURL: viper.GetString(types.CfgKeyOpenAPIServer), - APIPath: utils.APIPathV1, - } - contexts, err := c.GetContexts() - if err != nil { - return "" - } - - if len(contexts) > 0 { - return contexts[0].Name - } - return "" -} - -func IsLoggedIn() bool { - cached := authorize.NewKeyringCachedTokenProvider(nil) - tokenResult, err := cached.GetTokens() - if err != nil { - return false - } - if tokenResult == nil { - return false - } - - if !authorize.IsValidToken(tokenResult.IDToken) { - return false - } - - return checkTokenAvailable(tokenResult.IDToken) -} - -// CheckTokenAvailable Check whether the token is available by getting user info. -func checkTokenAvailable(token string) bool { - URL := fmt.Sprintf("%s/api/v1/user", viper.GetString(types.CfgKeyOpenAPIServer)) - req, err := utils.NewFullRequest(context.TODO(), URL, http.MethodGet, map[string]string{ - "Authorization": "Bearer " + token, - }, "") - if err != nil { - return false - } - - client := &http.Client{} - resp, err := client.Do(req) - if err != nil { - return false - } - defer resp.Body.Close() - - if resp.StatusCode != http.StatusOK { - return false - } - _, err = io.ReadAll(resp.Body) - - return err == nil -} - -func getAuthURL(region string) string { - var authURL string - switch region { - case "jp": - authURL = viper.GetString(types.CfgKeyAuthURL) - default: - authURL = viper.GetString(types.CfgKeyAuthURL) - } - return authURL -} diff --git a/pkg/cmd/auth/logout.go b/pkg/cmd/auth/logout.go deleted file mode 100644 index 7d01b1105..000000000 --- a/pkg/cmd/auth/logout.go +++ /dev/null @@ -1,116 +0,0 @@ -/* -Copyright (C) 2022-2024 ApeCloud Co., Ltd - -This file is part of KubeBlocks project - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU Affero General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU Affero General Public License for more details. - -You should have received a copy of the GNU Affero General Public License -along with this program. If not, see . -*/ - -package auth - -import ( - "bufio" - "encoding/json" - "fmt" - "io" - - "github.com/spf13/cobra" - "k8s.io/cli-runtime/pkg/genericiooptions" - - "github.com/apecloud/kbcli/pkg/cmd/auth/authorize" - "github.com/apecloud/kbcli/pkg/cmd/auth/utils" -) - -type LogOutOptions struct { - authorize.Options - Region string - - Provider authorize.Provider -} - -func NewLogout(streams genericiooptions.IOStreams) *cobra.Command { - o := &LogOutOptions{Options: authorize.Options{IOStreams: streams}} - cmd := &cobra.Command{ - Use: "logout", - Short: "Log out of the KubeBlocks Cloud", - Run: func(cmd *cobra.Command, args []string) { - cobra.CheckErr(o.complete()) - cobra.CheckErr(o.validate()) - cobra.CheckErr(o.run(cmd)) - }, - } - - cmd.Flags().StringVarP(&o.Region, "region", "r", "jp", "Specify the region [jp] to log in.") - return cmd -} - -func (o *LogOutOptions) complete() error { - o.AuthURL = getAuthURL(o.Region) - - var err error - o.Provider, err = authorize.NewTokenProvider(o.Options) - if err != nil { - return err - } - if o.ClientID == "" { - return o.loadConfig() - } - return nil -} - -func (o *LogOutOptions) validate() error { - if o.ClientID == "" { - return fmt.Errorf("client ID is required") - } - return nil -} - -func (o *LogOutOptions) run(cmd *cobra.Command) error { - if utils.IsTTY() { - fmt.Fprintln(o.Out, "Press Enter to log out of the KubeBlocks Cloud.") - _ = waitForEnter(cmd.InOrStdin()) - } - - err := o.Provider.Logout(cmd.Context()) - if err != nil { - return err - } - - fmt.Fprintln(o.Out, "Successfully logged out.") - return nil -} - -func waitForEnter(r io.Reader) error { - scanner := bufio.NewScanner(r) - scanner.Scan() - return scanner.Err() -} - -func (o *LogOutOptions) loadConfig() error { - data, err := utils.Asset("config/config.enc") - if err != nil { - return err - } - - err = json.Unmarshal(data, &o.Options) - if err != nil { - return err - } - - o.Provider, err = authorize.NewTokenProvider(o.Options) - if err != nil { - return err - } - return nil -} diff --git a/pkg/cmd/auth/utils/bindata.go b/pkg/cmd/auth/utils/bindata.go deleted file mode 100644 index 5e3451f35..000000000 --- a/pkg/cmd/auth/utils/bindata.go +++ /dev/null @@ -1,234 +0,0 @@ -/* -Copyright (C) 2022-2024 ApeCloud Co., Ltd - -This file is part of KubeBlocks project - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU Affero General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU Affero General Public License for more details. - -You should have received a copy of the GNU Affero General Public License -along with this program. If not, see . -*/ - -// Code generated for package auth by go-bindata DO NOT EDIT. (@generated) -// sources: -// config/config.enc -package utils - -import ( - "fmt" - "io/ioutil" - "os" - "path/filepath" - "strings" - "time" - - viper "github.com/apecloud/kubeblocks/pkg/viperx" - - "github.com/apecloud/kbcli/pkg/types" -) - -type asset struct { - bytes []byte - info os.FileInfo -} - -type bindataFileInfo struct { - name string - size int64 - mode os.FileMode - modTime time.Time -} - -// Name return file name -func (fi bindataFileInfo) Name() string { - return fi.name -} - -// Size return file size -func (fi bindataFileInfo) Size() int64 { - return fi.size -} - -// Mode return file mode -func (fi bindataFileInfo) Mode() os.FileMode { - return fi.mode -} - -// Mode return file modify time -func (fi bindataFileInfo) ModTime() time.Time { - return fi.modTime -} - -// IsDir return file whether a directory -func (fi bindataFileInfo) IsDir() bool { - return fi.mode&os.ModeDir != 0 -} - -// Sys return file is sys mode -func (fi bindataFileInfo) Sys() interface{} { - return nil -} - -func configConfigEnc() (*asset, error) { - info := bindataFileInfo{name: "config/config.enc", size: 53, mode: os.FileMode(0420), modTime: time.Unix(1688544460, 0)} - a := &asset{bytes: []byte(fmt.Sprintf(`{"client_id": "%s"}`, viper.GetString(types.CfgKeyClientID))), info: info} - return a, nil -} - -// Asset loads and returns the asset for the given name. -// It returns an error if the asset could not be found or -// could not be loaded. -func Asset(name string) ([]byte, error) { - cannonicalName := strings.Replace(name, "\\", "/", -1) - if f, ok := _bindata[cannonicalName]; ok { - a, err := f() - if err != nil { - return nil, fmt.Errorf("Asset %s can't read by error: %v", name, err) - } - return a.bytes, nil - } - return nil, fmt.Errorf("Asset %s not found", name) -} - -// MustAsset is like Asset but panics when Asset would return an error. -// It simplifies safe initialization of global variables. -func MustAsset(name string) []byte { - a, err := Asset(name) - if err != nil { - panic("asset: Asset(" + name + "): " + err.Error()) - } - - return a -} - -// AssetInfo loads and returns the asset info for the given name. -// It returns an error if the asset could not be found or -// could not be loaded. -func AssetInfo(name string) (os.FileInfo, error) { - cannonicalName := strings.Replace(name, "\\", "/", -1) - if f, ok := _bindata[cannonicalName]; ok { - a, err := f() - if err != nil { - return nil, fmt.Errorf("AssetInfo %s can't read by error: %v", name, err) - } - return a.info, nil - } - return nil, fmt.Errorf("AssetInfo %s not found", name) -} - -// AssetNames returns the names of the assets. -func AssetNames() []string { - names := make([]string, 0, len(_bindata)) - for name := range _bindata { - names = append(names, name) - } - return names -} - -// _bindata is a table, holding each asset generator, mapped to its name. -var _bindata = map[string]func() (*asset, error){ - "config/config.enc": configConfigEnc, -} - -// AssetDir returns the file names below a certain -// directory embedded in the file by go-bindata. -// For example if you run go-bindata on data/... and data contains the -// following hierarchy: -// -// data/ -// foo.txt -// img/ -// a.png -// b.png -// -// then AssetDir("data") would return []string{"foo.txt", "img"} -// AssetDir("data/img") would return []string{"a.png", "b.png"} -// AssetDir("foo.txt") and AssetDir("notexist") would return an error -// AssetDir("") will return []string{"data"}. -func AssetDir(name string) ([]string, error) { - node := _bintree - if len(name) != 0 { - cannonicalName := strings.Replace(name, "\\", "/", -1) - pathList := strings.Split(cannonicalName, "/") - for _, p := range pathList { - node = node.Children[p] - if node == nil { - return nil, fmt.Errorf("Asset %s not found", name) - } - } - } - if node.Func != nil { - return nil, fmt.Errorf("Asset %s not found", name) - } - rv := make([]string, 0, len(node.Children)) - for childName := range node.Children { - rv = append(rv, childName) - } - return rv, nil -} - -type bintree struct { - Func func() (*asset, error) - Children map[string]*bintree -} - -var _bintree = &bintree{nil, map[string]*bintree{ - "config": {nil, map[string]*bintree{ - "config.enc": {configConfigEnc, map[string]*bintree{}}, - }}, -}} - -// RestoreAsset restores an asset under the given directory -func RestoreAsset(dir, name string) error { - data, err := Asset(name) - if err != nil { - return err - } - info, err := AssetInfo(name) - if err != nil { - return err - } - err = os.MkdirAll(_filePath(dir, filepath.Dir(name)), os.FileMode(0755)) - if err != nil { - return err - } - err = ioutil.WriteFile(_filePath(dir, name), data, info.Mode()) - if err != nil { - return err - } - err = os.Chtimes(_filePath(dir, name), info.ModTime(), info.ModTime()) - if err != nil { - return err - } - return nil -} - -// RestoreAssets restores an asset under the given directory recursively -func RestoreAssets(dir, name string) error { - children, err := AssetDir(name) - // File - if err != nil { - return RestoreAsset(dir, name) - } - // Dir - for _, child := range children { - err = RestoreAssets(dir, filepath.Join(name, child)) - if err != nil { - return err - } - } - return nil -} - -func _filePath(dir, name string) string { - cannonicalName := strings.Replace(name, "\\", "/", -1) - return filepath.Join(append([]string{dir}, strings.Split(cannonicalName, "/")...)...) -} diff --git a/pkg/cmd/auth/utils/const.go b/pkg/cmd/auth/utils/const.go deleted file mode 100644 index 0600b5d52..000000000 --- a/pkg/cmd/auth/utils/const.go +++ /dev/null @@ -1,25 +0,0 @@ -/* -Copyright (C) 2022-2024 ApeCloud Co., Ltd - -This file is part of KubeBlocks project - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU Affero General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU Affero General Public License for more details. - -You should have received a copy of the GNU Affero General Public License -along with this program. If not, see . -*/ - -package utils - -const ( - APIPathV1 = "api/v1" - APIPathV2 = "api/v2" -) diff --git a/pkg/cmd/auth/utils/utils.go b/pkg/cmd/auth/utils/utils.go deleted file mode 100644 index d714c315e..000000000 --- a/pkg/cmd/auth/utils/utils.go +++ /dev/null @@ -1,67 +0,0 @@ -/* -Copyright (C) 2022-2024 ApeCloud Co., Ltd - -This file is part of KubeBlocks project - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU Affero General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU Affero General Public License for more details. - -You should have received a copy of the GNU Affero General Public License -along with this program. If not, see . -*/ - -package utils - -import ( - "context" - "net/http" - "net/url" - "os" - "strings" - - "github.com/mattn/go-isatty" -) - -func IsTTY() bool { - return isatty.IsTerminal(os.Stdout.Fd()) || isatty.IsCygwinTerminal(os.Stdout.Fd()) -} - -func NewRequest(ctx context.Context, url string, payload url.Values) (*http.Request, error) { - req, err := http.NewRequestWithContext( - ctx, - http.MethodPost, - url, - strings.NewReader(payload.Encode()), - ) - if err != nil { - return nil, err - } - req.Header.Set("Content-Type", "application/x-www-form-urlencoded") - req.Header.Set("Accept", "application/json") - return req, nil -} - -func NewFullRequest(ctx context.Context, url string, method string, header map[string]string, body string) (*http.Request, error) { - req, err := http.NewRequestWithContext( - ctx, - method, - url, - strings.NewReader(body), - ) - if err != nil { - return nil, err - } - req.Header.Set("Content-Type", "application/x-www-form-urlencoded") - req.Header.Set("Accept", "application/json") - for key, value := range header { - req.Header.Set(key, value) - } - return req, nil -} diff --git a/pkg/cmd/backuprepo/common.go b/pkg/cmd/backuprepo/common.go index d6bc3b67d..f794776e0 100644 --- a/pkg/cmd/backuprepo/common.go +++ b/pkg/cmd/backuprepo/common.go @@ -21,9 +21,19 @@ package backuprepo import ( "encoding/json" + "fmt" jsonpatch "github.com/evanphx/json-patch" + apierrors "k8s.io/apimachinery/pkg/api/errors" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" + "k8s.io/client-go/dynamic" + + dpv1alpha1 "github.com/apecloud/kubeblocks/apis/dataprotection/v1alpha1" + storagev1alpha1 "github.com/apecloud/kubeblocks/apis/storage/v1alpha1" + + "github.com/apecloud/kbcli/pkg/types" + "github.com/apecloud/kbcli/pkg/util" ) const ( @@ -43,3 +53,51 @@ func createPatchData(oldObj, newObj runtime.Object) ([]byte, error) { } return jsonpatch.CreateMergePatch(oldData, newData) } + +func tryConvertLegacyStorageProvider(dynamic dynamic.Interface, name string) (*dpv1alpha1.StorageProvider, error) { + provider := &storagev1alpha1.StorageProvider{} + err := util.GetK8SClientObject(dynamic, provider, types.LegacyStorageProviderGVR(), "", name) + if err != nil { + if apierrors.IsNotFound(err) { + return nil, fmt.Errorf("storage provider \"%s\" is not found", name) + } + return nil, err + } + + var parametersSchema *dpv1alpha1.ParametersSchema + if provider.Spec.ParametersSchema != nil { + parametersSchema = &dpv1alpha1.ParametersSchema{ + OpenAPIV3Schema: provider.Spec.ParametersSchema.OpenAPIV3Schema, + CredentialFields: provider.Spec.ParametersSchema.CredentialFields, + } + } + + newProvider := &dpv1alpha1.StorageProvider{ + ObjectMeta: metav1.ObjectMeta{ + Name: provider.Name, + Labels: provider.Labels, + Annotations: provider.Annotations, + }, + Spec: dpv1alpha1.StorageProviderSpec{ + CSIDriverName: provider.Spec.CSIDriverName, + CSIDriverSecretTemplate: provider.Spec.CSIDriverSecretTemplate, + StorageClassTemplate: provider.Spec.StorageClassTemplate, + PersistentVolumeClaimTemplate: provider.Spec.PersistentVolumeClaimTemplate, + DatasafedConfigTemplate: provider.Spec.DatasafedConfigTemplate, + ParametersSchema: parametersSchema, + }, + } + return newProvider, nil +} + +func getStorageProvider(dynamic dynamic.Interface, name string) (*dpv1alpha1.StorageProvider, error) { + provider := &dpv1alpha1.StorageProvider{} + err := util.GetK8SClientObject(dynamic, provider, types.StorageProviderGVR(), "", name) + if err != nil { + if apierrors.IsNotFound(err) { + return tryConvertLegacyStorageProvider(dynamic, name) + } + return nil, err + } + return provider, nil +} diff --git a/pkg/cmd/backuprepo/create.go b/pkg/cmd/backuprepo/create.go index f2bcc13ef..83503bd2c 100644 --- a/pkg/cmd/backuprepo/create.go +++ b/pkg/cmd/backuprepo/create.go @@ -46,7 +46,6 @@ import ( "golang.org/x/exp/slices" dpv1alpha1 "github.com/apecloud/kubeblocks/apis/dataprotection/v1alpha1" - storagev1alpha1 "github.com/apecloud/kubeblocks/apis/storage/v1alpha1" dptypes "github.com/apecloud/kubeblocks/pkg/dataprotection/types" "github.com/apecloud/kbcli/pkg/printer" @@ -78,7 +77,7 @@ type createOptions struct { accessMethod string storageProvider string - providerObject *storagev1alpha1.StorageProvider + providerObject *dpv1alpha1.StorageProvider isDefault bool pvReclaimPolicy string volumeCapacity string @@ -206,12 +205,8 @@ func (o *createOptions) parseProviderFlags(cmd *cobra.Command, args []string, f cmd.Example = "" return flags.BuildFlagsWithOpenAPISchema(cmd, args, func() (*apiextensionsv1.JSONSchemaProps, error) { // Get provider info from API server - provider := &storagev1alpha1.StorageProvider{} - err := util.GetK8SClientObject(o.dynamic, provider, types.StorageProviderGVR(), "", o.storageProvider) + provider, err := getStorageProvider(o.dynamic, o.storageProvider) if err != nil { - if apierrors.IsNotFound(err) { - return nil, fmt.Errorf("storage provider \"%s\" is not found", o.storageProvider) - } return nil, err } o.providerObject = provider @@ -475,7 +470,11 @@ func registerFlagCompletionFunc(cmd *cobra.Command, f cmdutil.Factory) { util.CheckErr(cmd.RegisterFlagCompletionFunc( providerFlagName, func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { - return utilcomp.CompGetResource(f, util.GVRToString(types.StorageProviderGVR()), toComplete), cobra.ShellCompDirectiveNoFileComp + candidates := utilcomp.CompGetResource(f, util.GVRToString(types.StorageProviderGVR()), toComplete) + if len(candidates) == 0 { + candidates = utilcomp.CompGetResource(f, util.GVRToString(types.LegacyStorageProviderGVR()), toComplete) + } + return candidates, cobra.ShellCompDirectiveNoFileComp })) util.CheckErr(cmd.RegisterFlagCompletionFunc( "access-method", diff --git a/pkg/cmd/backuprepo/update.go b/pkg/cmd/backuprepo/update.go index 10d7b31af..25aafacc5 100644 --- a/pkg/cmd/backuprepo/update.go +++ b/pkg/cmd/backuprepo/update.go @@ -40,7 +40,6 @@ import ( "k8s.io/kubectl/pkg/util/templates" dpv1alpha1 "github.com/apecloud/kubeblocks/apis/dataprotection/v1alpha1" - storagev1alpha1 "github.com/apecloud/kubeblocks/apis/storage/v1alpha1" dptypes "github.com/apecloud/kubeblocks/pkg/dataprotection/types" "github.com/apecloud/kbcli/pkg/printer" @@ -70,7 +69,7 @@ type updateOptions struct { repo *dpv1alpha1.BackupRepo storageProvider string - providerObject *storagev1alpha1.StorageProvider + providerObject *dpv1alpha1.StorageProvider isDefault bool repoName string config map[string]string @@ -158,11 +157,8 @@ func (o *updateOptions) parseFlags(cmd *cobra.Command, args []string, f cmdutil. o.repo = repo // Get provider info from API server o.storageProvider = repo.Spec.StorageProviderRef - provider := &storagev1alpha1.StorageProvider{} - if err := util.GetK8SClientObject(o.dynamic, provider, types.StorageProviderGVR(), "", o.storageProvider); err != nil { - if apierrors.IsNotFound(err) { - return nil, fmt.Errorf("storage provider \"%s\" is not found", o.storageProvider) - } + provider, err := getStorageProvider(o.dynamic, o.storageProvider) + if err != nil { return nil, err } o.providerObject = provider diff --git a/pkg/cmd/bench/bench.go b/pkg/cmd/bench/bench.go index 61de5cab8..f3eee2133 100644 --- a/pkg/cmd/bench/bench.go +++ b/pkg/cmd/bench/bench.go @@ -197,6 +197,7 @@ func NewBenchCmd(f cmdutil.Factory, streams genericiooptions.IOStreams) *cobra.C NewPgBenchCmd(f, streams), NewYcsbCmd(f, streams), NewTpccCmd(f, streams), + NewTpcdsCmd(f, streams), NewTpchCmd(f, streams), NewRedisBenchmarkCmd(f, streams), newListCmd(f, streams), diff --git a/pkg/cmd/bench/pgbench.go b/pkg/cmd/bench/pgbench.go index 5a74594fd..47aa139d1 100644 --- a/pkg/cmd/bench/pgbench.go +++ b/pkg/cmd/bench/pgbench.go @@ -46,7 +46,7 @@ var pgbenchExample = templates.Examples(` kbcli bench pgbench mytest --cluster pgcluster --database postgres --user xxx --password xxx # pgbench run on a cluster, but with cpu and memory limits set - kbcli bench pgbench mytest --cluster pgcluster --database postgres --user xxx --password xxx --cpu 1 --memory 1Gi + kbcli bench pgbench mytest --cluster pgcluster --database postgres --user xxx --password xxx --limit-cpu 1 --limit-memory 1Gi # pgbench run on a cluster with cleanup, only cleanup by deleting the testdata kbcli bench pgbench cleanup mytest --cluster pgcluster --database postgres --user xxx --password xxx diff --git a/pkg/cmd/bench/redis-benchmark.go b/pkg/cmd/bench/redis-benchmark.go index 53ce13f22..6d9b5b5b2 100644 --- a/pkg/cmd/bench/redis-benchmark.go +++ b/pkg/cmd/bench/redis-benchmark.go @@ -46,7 +46,7 @@ var redisBenchExample = templates.Examples(` kbcli bench redis-benchmark mytest --cluster rediscluster --clients 50 --requests 10000 --password xxx # redis-benchmark run on a cluster, but with cpu and memory limits set - kbcli bench redis-benchmark mytest --cluster rediscluster --clients 50 --requests 10000 --cpu 1 --memory 1Gi --password xxx + kbcli bench redis-benchmark mytest --cluster rediscluster --clients 50 --requests 10000 --limit-cpu 1 --limit-memory 1Gi --password xxx # redis-benchmark run on a cluster, just test set/get kbcli bench redis-benchmark mytest --cluster rediscluster --clients 50 --requests 10000 --tests set,get --password xxx diff --git a/pkg/cmd/bench/sysbench.go b/pkg/cmd/bench/sysbench.go index 2c0cb353f..5d14188b3 100644 --- a/pkg/cmd/bench/sysbench.go +++ b/pkg/cmd/bench/sysbench.go @@ -51,7 +51,7 @@ var sysbenchExample = templates.Examples(` kbcli bench sysbench mytest --cluster mycluster --user xxx --password xxx --database mydb # sysbench on a cluster, but with cpu and memory limits set - kbcli bench sysbench mytest --cluster mycluster --user xxx --password xxx --database mydb --cpu 1 --memory 1Gi + kbcli bench sysbench mytest --cluster mycluster --user xxx --password xxx --database mydb --limit-cpu 1 --limit-memory 1Gi # sysbench run on a cluster with cleanup, only cleanup by deleting the testdata kbcli bench sysbench cleanup mytest --cluster mycluster --user xxx --password xxx --database mydb diff --git a/pkg/cmd/bench/tpcc.go b/pkg/cmd/bench/tpcc.go index 2d9d4e187..30d5832e3 100644 --- a/pkg/cmd/bench/tpcc.go +++ b/pkg/cmd/bench/tpcc.go @@ -51,7 +51,7 @@ var tpccExample = templates.Examples(` kbcli bench tpcc mytest --cluster mycluster --user xxx --password xxx --database mydb # tpcc on a cluster, but with cpu and memory limits set - kbcli bench tpcc mytest --cluster mycluster --user xxx --password xxx --database mydb --cpu 1 --memory 1Gi + kbcli bench tpcc mytest --cluster mycluster --user xxx --password xxx --database mydb --limit-cpu 1 --limit-memory 1Gi # tpcc on a cluster with cleanup, only cleanup by deleting the testdata kbcli bench tpcc cleanup mytest --cluster mycluster --user xxx --password xxx --database mydb diff --git a/pkg/cmd/bench/tpcds.go b/pkg/cmd/bench/tpcds.go new file mode 100644 index 000000000..3b0604787 --- /dev/null +++ b/pkg/cmd/bench/tpcds.go @@ -0,0 +1,228 @@ +/* +Copyright (C) 2022-2024 ApeCloud Co., Ltd + +This file is part of KubeBlocks project + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ + +package bench + +import ( + "context" + "fmt" + "strings" + + "github.com/spf13/cobra" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/cli-runtime/pkg/genericiooptions" + cmdutil "k8s.io/kubectl/pkg/cmd/util" + "k8s.io/kubectl/pkg/util/templates" + + "github.com/apecloud/kubebench/api/v1alpha1" + + "github.com/apecloud/kbcli/pkg/cluster" + "github.com/apecloud/kbcli/pkg/types" +) + +var ( + tpcdsDriverMap = map[string]string{ + "mysql": "mysql", + "postgresql": "postgresql", + } + tpcdsSupportedDrivers = []string{"mysql", "postgresql"} +) + +type TpcdsOptions struct { + BenchBaseOptions + + Size int + UseKey bool +} + +var tpcdsExample = templates.Examples(` + # tpcds on a cluster, that will exec for all steps, cleanup, prepare and run + kbcli bench tpcds mytest --cluster mycluster --user xxx --password xxx --database mydb + + # tpcds on a cluster, but with cpu and memory limits set + kbcli bench tpcds mytest --cluster mycluster --user xxx --password xxx --database mydb --limit-cpu 1 --limit-memory 1Gi + + # tpcds on a cluster with 10GB data + kbcli bench tpcds mytest --cluster mycluster --user xxx --password xxx --database mydb --size 10 +`) + +func NewTpcdsCmd(f cmdutil.Factory, streams genericiooptions.IOStreams) *cobra.Command { + o := &TpcdsOptions{ + BenchBaseOptions: BenchBaseOptions{ + IOStreams: streams, + factory: f, + }, + } + + cmd := &cobra.Command{ + Use: "tpcds [Step] [Benchmark]", + Short: "Run TPC-DS benchmark", + Example: tpcdsExample, + Run: func(cmd *cobra.Command, args []string) { + cmdutil.CheckErr(o.Complete(args)) + cmdutil.CheckErr(o.Validate()) + cmdutil.CheckErr(o.Run()) + }, + } + + o.AddFlags(cmd) + cmd.Flags().IntVar(&o.Size, "size", 1, "specify the scale factor of the benchmark, 1 means 1GB data") + cmd.Flags().BoolVar(&o.UseKey, "use-key", false, "specify whether to create pk and fk, it will take extra time to create the keys") + + return cmd +} + +func (o *TpcdsOptions) Complete(args []string) error { + var err error + var driver string + var host string + var port int + + if err := o.BenchBaseOptions.BaseComplete(); err != nil { + return err + } + + o.Step, o.name = parseStepAndName(args, "tpcds") + + o.namespace, _, err = o.factory.ToRawKubeConfigLoader().Namespace() + if err != nil { + return err + } + + if o.dynamic, err = o.factory.DynamicClient(); err != nil { + return err + } + + if o.client, err = o.factory.KubernetesClientSet(); err != nil { + return err + } + + if o.ClusterName != "" { + clusterGetter := cluster.ObjectsGetter{ + Client: o.client, + Dynamic: o.dynamic, + Name: o.ClusterName, + Namespace: o.namespace, + GetOptions: cluster.GetOptions{ + WithClusterDef: cluster.Maybe, + WithService: cluster.Need, + WithPod: cluster.Need, + WithEvent: cluster.Need, + WithPVC: cluster.Need, + WithDataProtection: cluster.Need, + }, + } + if o.ClusterObjects, err = clusterGetter.Get(); err != nil { + return err + } + driver, host, port, err = getDriverAndHostAndPort(o.Cluster, o.Services) + if err != nil { + return err + } + } + + // don't overwrite the driver if it's already set + if v, ok := tpcdsDriverMap[driver]; ok && o.Driver == "" { + o.Driver = v + } + + // don't overwrite the host and port if they are already set + if o.Host == "" && o.Port == 0 { + o.Host = host + o.Port = port + } + + return nil +} + +func (o *TpcdsOptions) Validate() error { + if err := o.BenchBaseOptions.BaseValidate(); err != nil { + return err + } + + var supported bool + for _, v := range tpcdsDriverMap { + if o.Driver == v { + supported = true + break + } + } + if !supported { + return fmt.Errorf("tpcds now only supports drivers in [%s], current cluster driver is %s", + strings.Join(tpcdsSupportedDrivers, ","), o.Driver) + } + + if o.User == "" { + return fmt.Errorf("user is required") + } + + return nil +} + +func (o *TpcdsOptions) Run() error { + tpcds := v1alpha1.Tpcds{ + TypeMeta: metav1.TypeMeta{ + Kind: "Tpcds", + APIVersion: types.TpcdsGVR().GroupVersion().String(), + }, + ObjectMeta: metav1.ObjectMeta{ + Name: o.name, + Namespace: o.namespace, + }, + Spec: v1alpha1.TpcdsSpec{ + BenchCommon: v1alpha1.BenchCommon{ + ExtraArgs: o.ExtraArgs, + Step: o.Step, + Tolerations: o.Tolerations, + Target: v1alpha1.Target{ + Driver: o.Driver, + Host: o.Host, + Port: o.Port, + User: o.User, + Password: o.Password, + Database: o.Database, + }, + }, + Size: o.Size, + UseKey: o.UseKey, + }, + } + + // set cpu and memory if specified + setCPUAndMemory(&tpcds.Spec.BenchCommon, o.RequestCPU, o.RequestMemory, o.LimitCPU, o.LimitMemory) + + obj := &unstructured.Unstructured{ + Object: map[string]interface{}{}, + } + data, err := runtime.DefaultUnstructuredConverter.ToUnstructured(&tpcds) + if err != nil { + return err + } + obj.SetUnstructuredContent(data) + + obj, err = o.dynamic.Resource(types.TpcdsGVR()).Namespace(o.namespace).Create(context.TODO(), obj, metav1.CreateOptions{}) + if err != nil { + return err + } + + fmt.Fprintf(o.Out, "%s %s created\n", obj.GetKind(), obj.GetName()) + return nil +} diff --git a/pkg/cmd/bench/tpch.go b/pkg/cmd/bench/tpch.go index 0816aa311..eb8dd48fa 100644 --- a/pkg/cmd/bench/tpch.go +++ b/pkg/cmd/bench/tpch.go @@ -50,7 +50,7 @@ var tpchExample = templates.Examples(` kbcli bench tpch mytest --cluster mycluster --user xxx --password xxx --database mydb # tpch on a cluster, but with cpu and memory limits set - kbcli bench tpch mytest --cluster mycluster --user xxx --password xxx --database mydb --cpu 1 --memory 1Gi + kbcli bench tpch mytest --cluster mycluster --user xxx --password xxx --database mydb --limit-cpu 1 --limit-memory 1Gi # tpch on a cluster with run, just run by running the test kbcli bench tpch run mytest --cluster mycluster --user xxx --password xxx --database mydb @@ -58,6 +58,7 @@ var tpchExample = templates.Examples(` type TpchOptions struct { BenchBaseOptions + Size int } func NewTpchCmd(f cmdutil.Factory, streams genericiooptions.IOStreams) *cobra.Command { @@ -79,6 +80,7 @@ func NewTpchCmd(f cmdutil.Factory, streams genericiooptions.IOStreams) *cobra.Co } o.AddFlags(cmd) + cmd.Flags().IntVar(&o.Size, "size", 1, "specify the overall database size scaling parameter, 1 means 1GB") return cmd } @@ -198,6 +200,7 @@ func (o *TpchOptions) Run() error { Database: o.Database, }, }, + Size: o.Size, }, } diff --git a/pkg/cmd/bench/ycsb.go b/pkg/cmd/bench/ycsb.go index 4f6f44e70..39e984c3a 100644 --- a/pkg/cmd/bench/ycsb.go +++ b/pkg/cmd/bench/ycsb.go @@ -53,7 +53,7 @@ var ycsbExample = templates.Examples(` kbcli bench ycsb mytest --cluster mycluster --user xxx --password xxx --database mydb # ycsb on a cluster, but with cpu and memory limits set - kbcli bench ycsb mytest --cluster mycluster --user xxx --password xxx --database mydb --cpu 1 --memory 1Gi + kbcli bench ycsb mytest --cluster mycluster --user xxx --password xxx --database mydb --limit-cpu 1 --limit-memory 1Gi # ycsb on a cluster with cleanup, only cleanup by deleting the testdata kbcli bench ycsb cleanup mytest --cluster mycluster --user xxx --password xxx --database mydb diff --git a/pkg/cmd/builder/builder.go b/pkg/cmd/builder/builder.go deleted file mode 100644 index 9e882528f..000000000 --- a/pkg/cmd/builder/builder.go +++ /dev/null @@ -1,42 +0,0 @@ -/* -Copyright (C) 2022-2024 ApeCloud Co., Ltd - -This file is part of KubeBlocks project - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU Affero General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU Affero General Public License for more details. - -You should have received a copy of the GNU Affero General Public License -along with this program. If not, see . -*/ - -package builder - -import ( - "github.com/spf13/cobra" - "k8s.io/cli-runtime/pkg/genericiooptions" - cmdutil "k8s.io/kubectl/pkg/cmd/util" - - "github.com/apecloud/kbcli/pkg/cmd/builder/template" - "github.com/apecloud/kbcli/pkg/cmd/builder/tools" -) - -// NewBuilderCmd for builder functions -func NewBuilderCmd(f cmdutil.Factory, streams genericiooptions.IOStreams) *cobra.Command { - cmd := &cobra.Command{ - Use: "builder", - Short: "builder command.", - } - cmd.AddCommand( - template.NewComponentTemplateRenderCmd(f, streams), - tools.NewMigrateHelmScriptsCmd(f, streams), - ) - return cmd -} diff --git a/pkg/cmd/builder/builder_test.go b/pkg/cmd/builder/builder_test.go deleted file mode 100644 index f2ae9b88d..000000000 --- a/pkg/cmd/builder/builder_test.go +++ /dev/null @@ -1,47 +0,0 @@ -/* -Copyright (C) 2022-2024 ApeCloud Co., Ltd - -This file is part of KubeBlocks project - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU Affero General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU Affero General Public License for more details. - -You should have received a copy of the GNU Affero General Public License -along with this program. If not, see . -*/ - -package builder - -import ( - . "github.com/onsi/ginkgo/v2" - . "github.com/onsi/gomega" - - "k8s.io/cli-runtime/pkg/genericiooptions" - cmdtesting "k8s.io/kubectl/pkg/cmd/testing" -) - -var _ = Describe("builder", func() { - var streams genericiooptions.IOStreams - var tf *cmdtesting.TestFactory - - BeforeEach(func() { - streams, _, _, _ = genericiooptions.NewTestIOStreams() - tf = cmdtesting.NewTestFactory() - }) - - AfterEach(func() { - tf.Cleanup() - }) - - It("command should succeed", func() { - cmd := NewBuilderCmd(tf, streams) - Expect(cmd).ShouldNot(BeNil()) - }) -}) diff --git a/pkg/cmd/builder/suite_test.go b/pkg/cmd/builder/suite_test.go deleted file mode 100644 index 5eec80fe3..000000000 --- a/pkg/cmd/builder/suite_test.go +++ /dev/null @@ -1,32 +0,0 @@ -/* -Copyright (C) 2022-2024 ApeCloud Co., Ltd - -This file is part of KubeBlocks project - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU Affero General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU Affero General Public License for more details. - -You should have received a copy of the GNU Affero General Public License -along with this program. If not, see . -*/ - -package builder - -import ( - "testing" - - . "github.com/onsi/ginkgo/v2" - . "github.com/onsi/gomega" -) - -func TestAppp(t *testing.T) { - RegisterFailHandler(Fail) - RunSpecs(t, "Builder Cmd Test Suite") -} diff --git a/pkg/cmd/builder/template/component_wrapper.go b/pkg/cmd/builder/template/component_wrapper.go deleted file mode 100644 index 0aa7ae8cc..000000000 --- a/pkg/cmd/builder/template/component_wrapper.go +++ /dev/null @@ -1,351 +0,0 @@ -/* -Copyright (C) 2022-2024 ApeCloud Co., Ltd - -This file is part of KubeBlocks project - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU Affero General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU Affero General Public License for more details. - -You should have received a copy of the GNU Affero General Public License -along with this program. If not, see . -*/ - -package template - -import ( - "context" - "fmt" - "os" - "path/filepath" - "reflect" - "strings" - - corev1 "k8s.io/api/core/v1" - "k8s.io/apimachinery/pkg/runtime" - "sigs.k8s.io/controller-runtime/pkg/client" - "sigs.k8s.io/controller-runtime/pkg/log" - "sigs.k8s.io/yaml" - - appsv1alpha1 "github.com/apecloud/kubeblocks/apis/apps/v1alpha1" - "github.com/apecloud/kubeblocks/pkg/configuration/core" - "github.com/apecloud/kubeblocks/pkg/constant" - "github.com/apecloud/kubeblocks/pkg/controller/builder" - "github.com/apecloud/kubeblocks/pkg/controller/component" - "github.com/apecloud/kubeblocks/pkg/controller/factory" - "github.com/apecloud/kubeblocks/pkg/controller/graph" - "github.com/apecloud/kubeblocks/pkg/controller/model" - intctrlutil "github.com/apecloud/kubeblocks/pkg/controllerutil" - "github.com/apecloud/kubeblocks/pkg/generics" - - "github.com/apecloud/kbcli/pkg/printer" -) - -type templateRenderWorkflow struct { - renderedOpts RenderedOptions - clusterYaml string - localObjects []client.Object - - clusterDefObj *appsv1alpha1.ClusterDefinition - clusterVersionObj *appsv1alpha1.ClusterVersion - - clusterDefComponents []appsv1alpha1.ClusterComponentDefinition - clusterVersionComponents []appsv1alpha1.ClusterComponentVersion -} - -func (w *templateRenderWorkflow) Do(outputDir string) error { - var err error - var cluster *appsv1alpha1.Cluster - - cli := newMockClient(w.localObjects) - ctx := intctrlutil.RequestCtx{ - Ctx: context.Background(), - Log: log.Log.WithName("ctool"), - } - - if cluster, err = w.createClusterObject(); err != nil { - return err - } - ctx.Log.V(1).Info(fmt.Sprintf("cluster object : %v", cluster)) - - components := w.clusterDefComponents - if w.renderedOpts.ConfigSpec != "" { - comp := w.getComponentWithConfigSpec(w.renderedOpts.ConfigSpec) - if comp == nil { - return core.MakeError("config spec[%s] is not found", w.renderedOpts.ConfigSpec) - } - components = []appsv1alpha1.ClusterComponentDefinition{*comp} - } - - for _, component := range components { - synthesizedComponent, objects, err := generateComponentObjects(w, ctx, cli, component.Name, cluster) - if err != nil { - return err - } - if len(objects) == 0 { - continue - } - if err := w.dumpRenderedTemplates(outputDir, objects, component, w.renderedOpts.ConfigSpec, synthesizedComponent, cluster); err != nil { - return err - } - } - return nil -} - -func (w *templateRenderWorkflow) getComponentName(componentType string, cluster *appsv1alpha1.Cluster) (string, error) { - clusterCompSpec := cluster.Spec.GetDefNameMappingComponents()[componentType] - if len(clusterCompSpec) == 0 { - return "", core.MakeError("component[%s] is not defined in cluster definition", componentType) - } - return clusterCompSpec[0].Name, nil -} - -func checkTemplateExist[T any](arrs []T, name string) bool { - for _, a := range arrs { - v := reflect.ValueOf(a) - if v.Kind() == reflect.Ptr { - v = v.Elem() - } - v = v.FieldByName("Name") - if v.Kind() == reflect.String && v.String() == name { - return true - } - } - return false -} - -func (w *templateRenderWorkflow) getComponentWithConfigSpec(name string) *appsv1alpha1.ClusterComponentDefinition { - var compMap map[string]*appsv1alpha1.ClusterComponentVersion - - if w.clusterVersionObj != nil { - compMap = w.clusterVersionObj.Spec.GetDefNameMappingComponents() - } - for _, component := range w.clusterDefComponents { - if checkTemplateExist(component.ConfigSpecs, name) { - return &component - } - if checkTemplateExist(component.ScriptSpecs, name) { - return &component - } - if compMap != nil && compMap[component.Name] != nil { - if checkTemplateExist(compMap[component.Name].ConfigSpecs, name) { - return &component - } - } - } - return nil -} - -func (w *templateRenderWorkflow) createClusterObject() (*appsv1alpha1.Cluster, error) { - if w.clusterYaml != "" { - return CustomizedObjFromYaml(w.clusterYaml, generics.ClusterSignature) - } - return mockClusterObject(w.clusterDefObj, w.renderedOpts, w.clusterVersionObj), nil -} - -func (w *templateRenderWorkflow) dumpRenderedTemplates(outputDir string, objects []client.Object, componentDef appsv1alpha1.ClusterComponentDefinition, name string, synthesizedComponent *component.SynthesizedComponent, cluster *appsv1alpha1.Cluster) error { - fromTemplate := func(component *component.SynthesizedComponent) []appsv1alpha1.ComponentTemplateSpec { - templates := make([]appsv1alpha1.ComponentTemplateSpec, 0, len(component.ConfigTemplates)+len(component.ScriptTemplates)) - for _, tpl := range component.ConfigTemplates { - templates = append(templates, tpl.ComponentTemplateSpec) - } - templates = append(templates, component.ScriptTemplates...) - return templates - } - foundConfigSpec := func(component *component.SynthesizedComponent, name string) *appsv1alpha1.ComponentConfigSpec { - for i := range component.ConfigTemplates { - template := &component.ConfigTemplates[i] - if template.Name == name { - return template - } - } - return nil - } - - for _, template := range fromTemplate(synthesizedComponent) { - if name != "" && name != template.Name { - continue - } - comName, _ := w.getComponentName(componentDef.Name, cluster) - cfgName := core.GetComponentCfgName(cluster.Name, comName, template.Name) - if err := dumpTemplate(template, outputDir, objects, componentDef.Name, cfgName, foundConfigSpec(synthesizedComponent, template.Name)); err != nil { - return err - } - } - return nil -} - -func getClusterDefComponents(clusterDefObj *appsv1alpha1.ClusterDefinition, componentName string) []appsv1alpha1.ClusterComponentDefinition { - if componentName == "" { - return clusterDefObj.Spec.ComponentDefs - } - component := clusterDefObj.GetComponentDefByName(componentName) - if component == nil { - return nil - } - return []appsv1alpha1.ClusterComponentDefinition{*component} -} - -func getClusterVersionComponents(clusterVersionObj *appsv1alpha1.ClusterVersion, componentName string) []appsv1alpha1.ClusterComponentVersion { - if clusterVersionObj == nil { - return nil - } - if componentName == "" { - return clusterVersionObj.Spec.ComponentVersions - } - componentMap := clusterVersionObj.Spec.GetDefNameMappingComponents() - if component, ok := componentMap[componentName]; ok { - return []appsv1alpha1.ClusterComponentVersion{*component} - } - return nil -} - -func NewWorkflowTemplateRender(helmTemplateDir string, opts RenderedOptions, clusterDef, clusterVersion string) (*templateRenderWorkflow, error) { - foundCVResource := func(allObjects []client.Object) *appsv1alpha1.ClusterVersion { - cvObj := GetTypedResourceObjectBySignature(allObjects, generics.ClusterVersionSignature, - func(object client.Object) bool { - if clusterVersion != "" { - return object.GetName() == clusterVersion - } - return object.GetAnnotations() != nil && object.GetAnnotations()[constant.DefaultClusterVersionAnnotationKey] == "true" - }) - if clusterVersion == "" && cvObj == nil { - cvObj = GetTypedResourceObjectBySignature(allObjects, generics.ClusterVersionSignature) - } - return cvObj - } - - if _, err := os.Stat(helmTemplateDir); err != nil { - panic("cluster definition yaml file is required") - } - - allObjects, err := CreateObjectsFromDirectory(helmTemplateDir) - if err != nil { - return nil, err - } - - clusterDefObj := GetTypedResourceObjectBySignature(allObjects, generics.ClusterDefinitionSignature, WithResourceName(clusterDef)) - if clusterDefObj == nil { - return nil, core.MakeError("cluster definition object is not found in helm template directory[%s]", helmTemplateDir) - } - - // hack apiserver auto filefield - checkAndFillPortProtocol(clusterDefObj.Spec.ComponentDefs) - - var cdComponents []appsv1alpha1.ClusterComponentDefinition - if cdComponents = getClusterDefComponents(clusterDefObj, opts.ComponentName); cdComponents == nil { - return nil, core.MakeError("component[%s] is not defined in cluster definition", opts.ComponentName) - } - clusterVersionObj := foundCVResource(allObjects) - return &templateRenderWorkflow{ - renderedOpts: opts, - clusterDefObj: clusterDefObj, - clusterVersionObj: clusterVersionObj, - localObjects: allObjects, - clusterDefComponents: cdComponents, - clusterVersionComponents: getClusterVersionComponents(clusterVersionObj, opts.ComponentName), - }, nil -} - -func dumpTemplate(template appsv1alpha1.ComponentTemplateSpec, outputDir string, objects []client.Object, componentDefName string, cfgName string, configSpec *appsv1alpha1.ComponentConfigSpec) error { - output := filepath.Join(outputDir, cfgName) - fmt.Printf("dump rendering template spec: %s, output directory: %s\n", - printer.BoldYellow(fmt.Sprintf("%s.%s", componentDefName, template.Name)), output) - - if err := os.MkdirAll(output, 0755); err != nil { - return err - } - - var ok bool - var cm *corev1.ConfigMap - for _, obj := range objects { - if cm, ok = obj.(*corev1.ConfigMap); !ok || !isTemplateOwner(cm, configSpec, cfgName) { - continue - } - if isTemplateObject(cm, cfgName) { - for file, val := range cm.Data { - if err := os.WriteFile(filepath.Join(output, file), []byte(val), 0755); err != nil { - return err - } - } - } - if isTemplateEnvFromObject(cm, configSpec, cfgName) { - val, err := yaml.Marshal(cm) - if err != nil { - return err - } - yamlFile := fmt.Sprintf("%s.yaml", cm.Name[len(cfgName)+1:]) - if err := os.WriteFile(filepath.Join(output, yamlFile), val, 0755); err != nil { - return err - } - } - } - return nil -} - -func isTemplateObject(cm *corev1.ConfigMap, cfgName string) bool { - return cm.Name == cfgName -} - -func isTemplateEnvFromObject(cm *corev1.ConfigMap, configSpec *appsv1alpha1.ComponentConfigSpec, cfgName string) bool { - if configSpec == nil || len(configSpec.AsEnvFrom) == 0 || configSpec.ConfigConstraintRef == "" || len(cm.Labels) == 0 { - return false - } - return cm.Labels[constant.CMTemplateNameLabelKey] == configSpec.Name && strings.HasPrefix(cm.Name, cfgName) -} - -func isTemplateOwner(cm *corev1.ConfigMap, configSpec *appsv1alpha1.ComponentConfigSpec, cfgName string) bool { - return isTemplateObject(cm, cfgName) || isTemplateEnvFromObject(cm, configSpec, cfgName) -} - -func generateComponentObjects(w *templateRenderWorkflow, reqCtx intctrlutil.RequestCtx, cli *mockClient, - componentType string, cluster *appsv1alpha1.Cluster) (*component.SynthesizedComponent, []client.Object, error) { - cmGVK := generics.ToGVK(&corev1.ConfigMap{}) - - objs := make([]client.Object, 0) - cli.SetResourceHandler(&ResourceHandler{ - Matcher: []ResourceMatcher{func(obj runtime.Object) bool { - res := obj.(client.Object) - return generics.ToGVK(res) == cmGVK && - res.GetLabels() != nil && - res.GetLabels()[constant.CMTemplateNameLabelKey] != "" - }}, - Handler: func(obj runtime.Object) error { - objs = append(objs, obj.(client.Object)) - return nil - }, - }) - - compName, err := w.getComponentName(componentType, cluster) - if err != nil { - return nil, nil, err - } - dag := graph.NewDAG() - root := builder.NewReplicatedStateMachineBuilder(cluster.Namespace, fmt.Sprintf("%s-%s", cluster.Name, compName)).GetObject() - model.NewGraphClient(nil).Root(dag, nil, root, nil) - - compSpec := cluster.Spec.GetComponentByName(compName) - comp, err := component.BuildComponent(cluster, compSpec, nil, nil) - if err != nil { - return nil, nil, err - } - _, synthesizeComp, err := component.BuildSynthesizedComponent4Generated(reqCtx, cli, cluster, comp) - if err != nil { - return nil, nil, err - } - secret := factory.BuildConnCredential(w.clusterDefObj, cluster, synthesizeComp) - cli.AppendMockObjects(secret) - - // TODO(xingran & zhangtao): this is the logic before the componentDefinition refactoring. component.Create has already been removed during the refactoring - // if any functionality depend on it, please check to replace it with tne new approach - /* if err = component.Create(ctx, cli); err != nil { - return nil, nil, err - }*/ - return synthesizeComp, objs, nil -} diff --git a/pkg/cmd/builder/template/helm_helper.go b/pkg/cmd/builder/template/helm_helper.go deleted file mode 100644 index a7fe70823..000000000 --- a/pkg/cmd/builder/template/helm_helper.go +++ /dev/null @@ -1,128 +0,0 @@ -/* -Copyright (C) 2022-2024 ApeCloud Co., Ltd - -This file is part of KubeBlocks project - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU Affero General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU Affero General Public License for more details. - -You should have received a copy of the GNU Affero General Public License -along with this program. If not, see . -*/ - -package template - -import ( - "bufio" - "bytes" - "os" - "path/filepath" - - corev1 "k8s.io/api/core/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/util/yaml" - "sigs.k8s.io/controller-runtime/pkg/client" - - appsv1alpha1 "github.com/apecloud/kubeblocks/apis/apps/v1alpha1" - dpv1alpha1 "github.com/apecloud/kubeblocks/apis/dataprotection/v1alpha1" - "github.com/apecloud/kubeblocks/pkg/generics" -) - -func scanDirectoryPath(rootPath string) ([]string, error) { - dirs, err := os.ReadDir(rootPath) - if err != nil { - return nil, err - } - resourceList := make([]string, 0) - for _, d := range dirs { - if d.IsDir() { - subDirectory, err := scanDirectoryPath(filepath.Join(rootPath, d.Name())) - if err != nil { - return nil, err - } - resourceList = append(resourceList, subDirectory...) - continue - } - if filepath.Ext(d.Name()) != ".yaml" { - continue - } - resourceList = append(resourceList, filepath.Join(rootPath, d.Name())) - } - return resourceList, nil -} - -func getResourceMeta(yamlBytes []byte) (metav1.TypeMeta, error) { - type k8sObj struct { - metav1.TypeMeta `json:",inline"` - } - var o k8sObj - err := yaml.Unmarshal(yamlBytes, &o) - if err != nil { - return metav1.TypeMeta{}, err - } - return o.TypeMeta, nil -} - -func CreateObjectsFromDirectory(rootPath string) ([]client.Object, error) { - allObjs := make([]client.Object, 0) - - // create cr from yaml - resourceList, err := scanDirectoryPath(rootPath) - if err != nil { - return nil, err - } - for _, resourceFile := range resourceList { - yamlBytes, err := os.ReadFile(resourceFile) - if err != nil { - return nil, err - } - objects, err := createObjectsFromYaml(yamlBytes) - if err != nil { - return nil, err - } - allObjs = append(allObjs, objects...) - } - return allObjs, nil -} - -func createObjectsFromYaml(yamlBytes []byte) ([]client.Object, error) { - objects := make([]client.Object, 0) - reader := bufio.NewReader(bytes.NewReader(yamlBytes)) - for { - doc, err := yaml.NewYAMLReader(reader).Read() - if len(doc) == 0 { - break - } - if err != nil { - return nil, err - } - meta, err := getResourceMeta(doc) - if err != nil { - return nil, err - } - switch meta.Kind { - case kindFromResource(corev1.ConfigMap{}): - objects = append(objects, CreateTypedObjectFromYamlByte(doc, generics.ConfigMapSignature)) - case kindFromResource(corev1.Secret{}): - objects = append(objects, CreateTypedObjectFromYamlByte(doc, generics.SecretSignature)) - case kindFromResource(appsv1alpha1.ConfigConstraint{}): - objects = append(objects, CreateTypedObjectFromYamlByte(doc, generics.ConfigConstraintSignature)) - case kindFromResource(appsv1alpha1.ClusterDefinition{}): - objects = append(objects, CreateTypedObjectFromYamlByte(doc, generics.ClusterDefinitionSignature)) - case kindFromResource(appsv1alpha1.ClusterVersion{}): - objects = append(objects, CreateTypedObjectFromYamlByte(doc, generics.ClusterVersionSignature)) - case kindFromResource(appsv1alpha1.BackupPolicyTemplate{}): - objects = append(objects, CreateTypedObjectFromYamlByte(doc, generics.BackupPolicyTemplateSignature)) - case kindFromResource(dpv1alpha1.ActionSet{}): - objects = append(objects, CreateTypedObjectFromYamlByte(doc, generics.ActionSetSignature)) - } - } - return objects, nil -} diff --git a/pkg/cmd/builder/template/k8s_resource.go b/pkg/cmd/builder/template/k8s_resource.go deleted file mode 100644 index 487223253..000000000 --- a/pkg/cmd/builder/template/k8s_resource.go +++ /dev/null @@ -1,98 +0,0 @@ -/* -Copyright (C) 2022-2024 ApeCloud Co., Ltd - -This file is part of KubeBlocks project - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU Affero General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU Affero General Public License for more details. - -You should have received a copy of the GNU Affero General Public License -along with this program. If not, see . -*/ - -package template - -import ( - "bufio" - "bytes" - "os" - - "k8s.io/apimachinery/pkg/util/yaml" - "sigs.k8s.io/controller-runtime/pkg/client" - - "github.com/apecloud/kubeblocks/pkg/generics" -) - -type MatchResourceFunc func(object client.Object) bool - -func CustomizedObjFromYaml[T generics.Object, PT generics.PObject[T], L generics.ObjList[T], PL generics.PObjList[T, L]](filePath string, signature func(T, PT, L, PL)) (PT, error) { - objList, err := CustomizedObjectListFromYaml[T, PT, L, PL](filePath, signature) - if err != nil { - return nil, err - } - if len(objList) == 0 { - return nil, nil - } - return objList[0], nil -} - -func CustomizedObjectListFromYaml[T generics.Object, PT generics.PObject[T], L generics.ObjList[T], PL generics.PObjList[T, L]](yamlfile string, signature func(T, PT, L, PL)) ([]PT, error) { - objBytes, err := os.ReadFile(yamlfile) - if err != nil { - return nil, err - } - objList := make([]PT, 0) - reader := bufio.NewReader(bytes.NewReader(objBytes)) - for { - doc, err := yaml.NewYAMLReader(reader).Read() - if len(doc) == 0 { - break - } - if err != nil { - return nil, err - } - objList = append(objList, CreateTypedObjectFromYamlByte[T, PT, L, PL](doc, signature)) - } - return objList, nil -} - -func CreateTypedObjectFromYamlByte[T generics.Object, PT generics.PObject[T], L generics.ObjList[T], PL generics.PObjList[T, L]](yamlBytes []byte, _ func(T, PT, L, PL)) PT { - var obj PT - if err := yaml.Unmarshal(yamlBytes, &obj); err != nil { - return nil - } - return obj -} - -func GetTypedResourceObjectBySignature[T generics.Object, PT generics.PObject[T], L generics.ObjList[T], PL generics.PObjList[T, L]](objects []client.Object, _ func(T, PT, L, PL), matchers ...MatchResourceFunc) PT { - for _, object := range objects { - obj, ok := object.(PT) - if !ok { - continue - } - found := true - for _, matcher := range matchers { - if !matcher(obj) { - found = false - break - } - } - if found { - return obj - } - } - return nil -} - -func WithResourceName(name string) MatchResourceFunc { - return func(object client.Object) bool { - return name == "" || object.GetName() == name - } -} diff --git a/pkg/cmd/builder/template/mock_client.go b/pkg/cmd/builder/template/mock_client.go deleted file mode 100644 index 5c5e4ac21..000000000 --- a/pkg/cmd/builder/template/mock_client.go +++ /dev/null @@ -1,175 +0,0 @@ -/* -Copyright (C) 2022-2024 ApeCloud Co., Ltd - -This file is part of KubeBlocks project - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU Affero General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU Affero General Public License for more details. - -You should have received a copy of the GNU Affero General Public License -along with this program. If not, see . -*/ - -package template - -import ( - "context" - "reflect" - - corev1 "k8s.io/api/core/v1" - apierrors "k8s.io/apimachinery/pkg/api/errors" - "k8s.io/apimachinery/pkg/api/meta" - "k8s.io/apimachinery/pkg/runtime" - "k8s.io/apimachinery/pkg/runtime/schema" - "sigs.k8s.io/controller-runtime/pkg/client" - - cfgcore "github.com/apecloud/kubeblocks/pkg/configuration/core" -) - -type ResourceMatcher = func(obj runtime.Object) bool -type Handler = func(obj runtime.Object) error - -type ResourceHandler struct { - Matcher []ResourceMatcher - Handler Handler -} - -type mockClient struct { - objects map[client.ObjectKey]client.Object - kindObjectList map[string][]runtime.Object - - hander *ResourceHandler -} - -func newMockClient(objs []client.Object) *mockClient { - return &mockClient{ - objects: fromObjects(objs), - kindObjectList: splitRuntimeObject(objs), - } -} - -func (m *mockClient) SetResourceHandler(resourceHandler *ResourceHandler) { - m.hander = resourceHandler -} - -func fromObjects(objs []client.Object) map[client.ObjectKey]client.Object { - r := make(map[client.ObjectKey]client.Object) - for _, obj := range objs { - if obj != nil { - r[client.ObjectKeyFromObject(obj)] = obj - } - } - return r -} - -func (m *mockClient) AppendMockObjects(obj client.Object) { - objKey := client.ObjectKeyFromObject(obj) - if _, ok := m.objects[objKey]; ok { - return - } - m.objects[objKey] = obj -} - -func splitRuntimeObject(objects []client.Object) map[string][]runtime.Object { - r := make(map[string][]runtime.Object) - for _, object := range objects { - kind := object.GetObjectKind().GroupVersionKind().Kind - if _, ok := r[kind]; !ok { - r[kind] = make([]runtime.Object, 0) - } - r[kind] = append(r[kind], object) - } - return r -} - -func (m *mockClient) Get(ctx context.Context, key client.ObjectKey, obj client.Object, opts ...client.GetOption) error { - objKey := key - if object, ok := m.objects[objKey]; ok { - SetGetReturnedObject(obj, object) - return nil - } - objKey.Namespace = "" - if object, ok := m.objects[objKey]; ok { - SetGetReturnedObject(obj, object) - return nil - } - return apierrors.NewNotFound(corev1.SchemeGroupVersion.WithResource("mock_resource").GroupResource(), key.String()) -} - -func (m *mockClient) List(ctx context.Context, list client.ObjectList, opts ...client.ListOption) error { - r := m.kindObjectList[list.GetObjectKind().GroupVersionKind().Kind] - if r != nil { - return SetListReturnedObjects(list, r) - } - return nil -} - -func (m *mockClient) Create(ctx context.Context, obj client.Object, opts ...client.CreateOption) error { - if m.hander == nil || len(m.hander.Matcher) == 0 { - return nil - } - - for _, matcher := range m.hander.Matcher { - if !matcher(obj) { - return nil - } - } - return m.hander.Handler(obj) -} - -func (m *mockClient) Delete(ctx context.Context, obj client.Object, opts ...client.DeleteOption) error { - return nil -} - -func (m *mockClient) Update(ctx context.Context, obj client.Object, opts ...client.UpdateOption) error { - return nil -} - -func (m *mockClient) Patch(ctx context.Context, obj client.Object, patch client.Patch, opts ...client.PatchOption) error { - return nil -} - -func (m *mockClient) DeleteAllOf(ctx context.Context, obj client.Object, opts ...client.DeleteAllOfOption) error { - return cfgcore.MakeError("not support") -} - -func (m *mockClient) Status() client.SubResourceWriter { - panic("implement me") -} - -func (m *mockClient) SubResource(subResource string) client.SubResourceClient { - panic("implement me") -} - -func (m *mockClient) Scheme() *runtime.Scheme { - panic("implement me") -} - -func (m *mockClient) RESTMapper() meta.RESTMapper { - panic("implement me") -} - -func (m *mockClient) GroupVersionKindFor(obj runtime.Object) (schema.GroupVersionKind, error) { - panic("implement me") -} - -func (m *mockClient) IsObjectNamespaced(obj runtime.Object) (bool, error) { - panic("implement me") -} - -func SetGetReturnedObject(out client.Object, expectedObj client.Object) { - outVal := reflect.ValueOf(out) - objVal := reflect.ValueOf(expectedObj) - reflect.Indirect(outVal).Set(reflect.Indirect(objVal)) -} - -func SetListReturnedObjects(list client.ObjectList, objects []runtime.Object) error { - return meta.SetList(list, objects) -} diff --git a/pkg/cmd/builder/template/suite_test.go b/pkg/cmd/builder/template/suite_test.go deleted file mode 100644 index 58c00a3b2..000000000 --- a/pkg/cmd/builder/template/suite_test.go +++ /dev/null @@ -1,32 +0,0 @@ -/* -Copyright (C) 2022-2024 ApeCloud Co., Ltd - -This file is part of KubeBlocks project - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU Affero General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU Affero General Public License for more details. - -You should have received a copy of the GNU Affero General Public License -along with this program. If not, see . -*/ - -package template - -import ( - "testing" - - . "github.com/onsi/ginkgo/v2" - . "github.com/onsi/gomega" -) - -func TestAppp(t *testing.T) { - RegisterFailHandler(Fail) - RunSpecs(t, "Template Cmd Test Suite") -} diff --git a/pkg/cmd/builder/template/template.go b/pkg/cmd/builder/template/template.go deleted file mode 100644 index 4039b49ad..000000000 --- a/pkg/cmd/builder/template/template.go +++ /dev/null @@ -1,145 +0,0 @@ -/* -Copyright (C) 2022-2024 ApeCloud Co., Ltd - -This file is part of KubeBlocks project - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU Affero General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU Affero General Public License for more details. - -You should have received a copy of the GNU Affero General Public License -along with this program. If not, see . -*/ - -package template - -import ( - "os" - "path/filepath" - - "github.com/spf13/cobra" - "k8s.io/cli-runtime/pkg/genericiooptions" - cmdutil "k8s.io/kubectl/pkg/cmd/util" - "k8s.io/kubectl/pkg/util/templates" - - cfgcore "github.com/apecloud/kubeblocks/pkg/configuration/core" - "github.com/apecloud/kubeblocks/pkg/constant" - viper "github.com/apecloud/kubeblocks/pkg/viperx" - - "github.com/apecloud/kbcli/pkg/util" -) - -type renderTPLCmdOpts struct { - genericiooptions.IOStreams - - Factory cmdutil.Factory - // dynamic dynamic.Interface - - clusterYaml string - clusterDef string - clusterVersion string - - outputDir string - clearOutputDir bool - helmOutputDir string - helmTemplateDir string - - opts RenderedOptions -} - -func (o *renderTPLCmdOpts) complete() error { - if err := o.checkAndHelmTemplate(); err != nil { - return err - } - - if o.helmOutputDir == "" { - return cfgcore.MakeError("helm template dir is empty") - } - - if o.clearOutputDir && o.outputDir != "" { - _ = os.RemoveAll(o.outputDir) - } - if o.outputDir == "" { - o.outputDir = filepath.Join("./output", RandomString(6)) - } - return nil -} - -func (o *renderTPLCmdOpts) run() error { - viper.SetDefault(constant.KubernetesClusterDomainEnv, constant.DefaultDNSDomain) - workflow, err := NewWorkflowTemplateRender(o.helmOutputDir, o.opts, o.clusterDef, o.clusterVersion) - if err != nil { - return err - } - return workflow.Do(o.outputDir) -} - -var templateExamples = templates.Examples(` - # builder template: Provides a mechanism to rendered template for ComponentConfigSpec and ComponentScriptSpec in the ClusterComponentDefinition. - # builder template --helm deploy/redis --memory=64Gi --cpu=16 --replicas=3 --component-name=redis --config-spec=redis-replication-config - - # build all configspec - kbcli builder template --helm deploy/redis -a -`) - -// buildReconfigureCommonFlags build common flags for reconfigure command -func (o *renderTPLCmdOpts) buildTemplateFlags(cmd *cobra.Command) { - cmd.Flags().StringVar(&o.clusterYaml, "cluster", "", "the cluster yaml file") - cmd.Flags().StringVar(&o.clusterVersion, "cluster-version", "", "specify the cluster version name") - cmd.Flags().StringVar(&o.clusterDef, "cluster-definition", "", "specify the cluster definition name") - cmd.Flags().StringVarP(&o.outputDir, "output-dir", "o", "", "specify the output directory") - - cmd.Flags().StringVar(&o.opts.ConfigSpec, "config-spec", "", "specify the config spec to be rendered") - - // mock cluster object - cmd.Flags().Int32VarP(&o.opts.Replicas, "replicas", "r", 1, "specify the replicas of the component") - cmd.Flags().StringVar(&o.opts.DataVolumeName, "volume-name", "", "specify the data volume name of the component") - cmd.Flags().StringVar(&o.opts.ComponentName, "component-name", "", "specify the component name of the clusterdefinition") - cmd.Flags().StringVar(&o.helmTemplateDir, "helm", "", "specify the helm template dir") - cmd.Flags().StringVar(&o.helmOutputDir, "helm-output", "", "specify the helm template output dir") - cmd.Flags().StringVar(&o.opts.CPU, "cpu", "", "specify the cpu of the component") - cmd.Flags().StringVar(&o.opts.Memory, "memory", "", "specify the memory of the component") - cmd.Flags().BoolVar(&o.clearOutputDir, "clean", false, "specify whether to clear the output dir") -} - -func (o *renderTPLCmdOpts) checkAndHelmTemplate() error { - if o.helmTemplateDir == "" || o.helmOutputDir != "" { - return nil - } - - if o.helmTemplateDir != "" && o.helmOutputDir == "" { - o.helmOutputDir = filepath.Join("./helm-output", RandomString(6)) - } - - return HelmTemplate(o.helmTemplateDir, o.helmOutputDir) -} - -func NewComponentTemplateRenderCmd(f cmdutil.Factory, streams genericiooptions.IOStreams) *cobra.Command { - o := &renderTPLCmdOpts{ - Factory: f, - IOStreams: streams, - opts: RenderedOptions{ - // for mock cluster object - Namespace: "default", - Name: "cluster-" + RandomString(6), - }, - } - cmd := &cobra.Command{ - Use: "template", - Aliases: []string{"tpl"}, - Short: "tpl - a developer tool integrated with KubeBlocks that can help developers quickly generate rendered configurations or scripts based on Helm templates, and discover errors in the template before creating the database cluster.", - Example: templateExamples, - Run: func(cmd *cobra.Command, args []string) { - util.CheckErr(o.complete()) - util.CheckErr(o.run()) - }, - } - o.buildTemplateFlags(cmd) - return cmd -} diff --git a/pkg/cmd/builder/template/template_test.go b/pkg/cmd/builder/template/template_test.go deleted file mode 100644 index 895342005..000000000 --- a/pkg/cmd/builder/template/template_test.go +++ /dev/null @@ -1,94 +0,0 @@ -/* -Copyright (C) 2022-2024 ApeCloud Co., Ltd - -This file is part of KubeBlocks project - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU Affero General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU Affero General Public License for more details. - -You should have received a copy of the GNU Affero General Public License -along with this program. If not, see . -*/ - -package template - -import ( - "os" - "path/filepath" - - . "github.com/onsi/ginkgo/v2" - . "github.com/onsi/gomega" - - "k8s.io/cli-runtime/pkg/genericiooptions" - cmdtesting "k8s.io/kubectl/pkg/cmd/testing" - - "github.com/apecloud/kubeblocks/test/testdata" - - "github.com/apecloud/kbcli/pkg/testing" -) - -var _ = Describe("template", func() { - var ( - tf *cmdtesting.TestFactory - streams genericiooptions.IOStreams - ) - - BeforeEach(func() { - streams, _, _, _ = genericiooptions.NewTestIOStreams() - tf = testing.NewTestFactory("default") - }) - - AfterEach(func() { - tf.Cleanup() - }) - - testComponentTemplate := func(helmPath string, helmOutput string) { - cmd := NewComponentTemplateRenderCmd(tf, streams) - Expect(cmd).ShouldNot(BeNil()) - - if helmPath != "" { - _ = cmd.Flags().Set("helm", helmPath) - } - if helmOutput != "" { - _ = cmd.Flags().Set("helm-output", helmOutput) - } - _ = cmd.Flags().Set("memory", "8Gi") - _ = cmd.Flags().Set("cpu", "8") - _ = cmd.Flags().Set("replicas", "3") - _ = cmd.Flags().Set("all", "true") - cmd.Run(cmd, []string{}) - } - - It("should succeed", func() { - Skip("helm charts in ../../deploy are moved to other repos") - componentRootPath := testdata.SubTestDataPath("../../deploy") - testComponents := []string{ - "apecloud-mysql", - "postgresql", - "redis", - "clickhouse", - "kafka", - } - helmOutputRoot, err := os.MkdirTemp(os.TempDir(), "test") - Expect(err).Should(Succeed()) - defer os.RemoveAll(helmOutputRoot) - - _, err = os.ReadDir(componentRootPath) - Expect(err).Should(Succeed()) - for _, component := range testComponents { - componentPath := filepath.Join(componentRootPath, component) - _, err := os.ReadDir(componentPath) - Expect(err).Should(Succeed()) - helmOutput := filepath.Join(helmOutputRoot, component) - Expect(HelmTemplate(componentPath, helmOutput)).Should(Succeed()) - testComponentTemplate(componentPath, helmOutput) - } - }) -}) diff --git a/pkg/cmd/builder/template/util.go b/pkg/cmd/builder/template/util.go deleted file mode 100644 index 1e3b445d2..000000000 --- a/pkg/cmd/builder/template/util.go +++ /dev/null @@ -1,136 +0,0 @@ -/* -Copyright (C) 2022-2024 ApeCloud Co., Ltd - -This file is part of KubeBlocks project - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU Affero General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU Affero General Public License for more details. - -You should have received a copy of the GNU Affero General Public License -along with this program. If not, see . -*/ - -package template - -import ( - "reflect" - "strings" - - "github.com/sethvargo/go-password/password" - "helm.sh/helm/v3/pkg/cli/values" - corev1 "k8s.io/api/core/v1" - "k8s.io/apimachinery/pkg/api/resource" - - appsv1alpha1 "github.com/apecloud/kubeblocks/apis/apps/v1alpha1" - testapps "github.com/apecloud/kubeblocks/pkg/testutil/apps" - - "github.com/apecloud/kbcli/pkg/testing" - "github.com/apecloud/kbcli/pkg/util/helm" - "github.com/apecloud/kbcli/version" -) - -type RenderedOptions struct { - ConfigSpec string - - // mock cluster object - Name string - Namespace string - - Replicas int32 - DataVolumeName string - ComponentName string - - CPU string - Memory string -} - -func mockClusterObject(clusterDefObj *appsv1alpha1.ClusterDefinition, renderedOpts RenderedOptions, clusterVersion *appsv1alpha1.ClusterVersion) *appsv1alpha1.Cluster { - cvReference := "" - if clusterVersion != nil { - cvReference = clusterVersion.Name - } - factory := testapps.NewClusterFactory(renderedOpts.Namespace, renderedOpts.Name, clusterDefObj.Name, cvReference) - for _, component := range clusterDefObj.Spec.ComponentDefs { - factory.AddComponent(component.CharacterType+"-"+RandomString(3), component.Name) - factory.SetReplicas(renderedOpts.Replicas) - if renderedOpts.DataVolumeName != "" { - fields := strings.SplitN(renderedOpts.DataVolumeName, ":", 2) - if len(fields) == 1 { - fields = append(fields, "10Gi") - } - pvcSpec := testapps.NewPVCSpec(fields[1]) - factory.AddVolumeClaimTemplate(fields[0], pvcSpec) - } - if renderedOpts.CPU != "" || renderedOpts.Memory != "" { - factory.SetResources(fromResource(renderedOpts)) - } - } - return factory.GetObject() -} - -func fromResource(opts RenderedOptions) corev1.ResourceRequirements { - cpu := opts.CPU - memory := opts.Memory - if cpu == "" { - cpu = "1" - } - if memory == "" { - memory = "1Gi" - } - return corev1.ResourceRequirements{ - Limits: corev1.ResourceList{ - "cpu": resource.MustParse(cpu), - "memory": resource.MustParse(memory), - }, - } -} - -func kindFromResource[T any](resource T) string { - t := reflect.TypeOf(resource) - if t.Kind() == reflect.Ptr { - t = t.Elem() - } - return t.Name() -} - -func RandomString(n int) string { - s, _ := password.Generate(n, 0, 0, false, false) - return s -} - -func HelmTemplate(helmPath string, helmOutput string) error { - o := helm.InstallOpts{ - Name: testing.KubeBlocksChartName, - Chart: helmPath, - Namespace: "default", - Version: version.DefaultKubeBlocksVersion, - - DryRun: func() *bool { r := true; return &r }(), - OutputDir: helmOutput, - ValueOpts: &values.Options{Values: []string{}}, - } - _, err := o.Install(helm.NewFakeConfig("default")) - return err -} - -func checkAndFillPortProtocol(clusterDefComponents []appsv1alpha1.ClusterComponentDefinition) { - // set a default protocol with 'TCP' to avoid failure in BuildHeadlessSvc - for i := range clusterDefComponents { - for j := range clusterDefComponents[i].PodSpec.Containers { - container := &clusterDefComponents[i].PodSpec.Containers[j] - for k := range container.Ports { - port := &container.Ports[k] - if port.Protocol == "" { - port.Protocol = corev1.ProtocolTCP - } - } - } - } -} diff --git a/pkg/cmd/builder/tools/migrate_scripts.go b/pkg/cmd/builder/tools/migrate_scripts.go deleted file mode 100644 index cbad9619a..000000000 --- a/pkg/cmd/builder/tools/migrate_scripts.go +++ /dev/null @@ -1,172 +0,0 @@ -/* -Copyright (C) 2022-2024 ApeCloud Co., Ltd - -This file is part of KubeBlocks project - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU Affero General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU Affero General Public License for more details. - -You should have received a copy of the GNU Affero General Public License -along with this program. If not, see . -*/ - -package tools - -import ( - "fmt" - "io" - "os" - "path/filepath" - "strings" - - "github.com/spf13/cobra" - corev1 "k8s.io/api/core/v1" - "k8s.io/cli-runtime/pkg/genericiooptions" - cmdutil "k8s.io/kubectl/pkg/cmd/util" - "k8s.io/kubectl/pkg/util/templates" - "sigs.k8s.io/controller-runtime/pkg/client" - - cfgcore "github.com/apecloud/kubeblocks/pkg/configuration/core" - cfgutil "github.com/apecloud/kubeblocks/pkg/configuration/util" - "github.com/apecloud/kubeblocks/pkg/generics" - - "github.com/apecloud/kbcli/pkg/cmd/builder/template" - "github.com/apecloud/kbcli/pkg/printer" - "github.com/apecloud/kbcli/pkg/util" -) - -type migrateOptions struct { - genericiooptions.IOStreams - - Factory cmdutil.Factory - // dynamic dynamic.Interface - - helmTemplateDir string - scriptsOutputPath string - regex string - cmName string - overwrite bool -} - -func (o *migrateOptions) complete() error { - if o.helmTemplateDir == "" { - return cfgcore.MakeError("helm template dir is required") - } - if ok, _ := cfgutil.CheckPathExists(o.helmTemplateDir); !ok { - return cfgcore.MakeError("helm template dir is not exists") - } - if o.regex == "" && o.cmName == "" { - return cfgcore.MakeError("regex or cm name are required") - } - - if o.scriptsOutputPath == "" { - return cfgcore.MakeError("scripts output path is required") - } - - ok, err := cfgutil.CheckPathExists(o.scriptsOutputPath) - if err != nil { - return err - } - if !ok { - err = os.MkdirAll(o.scriptsOutputPath, os.ModePerm) - } - return err -} - -func (o *migrateOptions) run() error { - tmpDir, err := os.MkdirTemp(os.TempDir(), "tmp-") - if err != nil { - return err - } - defer os.RemoveAll(tmpDir) - - output := filepath.Join(tmpDir, "helm-output") - if err := template.HelmTemplate(o.helmTemplateDir, output); err != nil { - return err - } - - allObjects, err := template.CreateObjectsFromDirectory(output) - if err != nil { - return err - } - - if o.cmName != "" { - return o.processSpecConfigMap(allObjects) - } - _ = template.GetTypedResourceObjectBySignature(allObjects, generics.ConfigMapSignature, o.processConfigMap) - return nil -} - -func (o *migrateOptions) processSpecConfigMap(objects []client.Object) error { - cm := template.GetTypedResourceObjectBySignature(objects, generics.ConfigMapSignature, template.WithResourceName(o.cmName)) - if cm == nil { - return cfgcore.MakeError("configmap %s not found", o.cmName) - } - dumpHelmScripts(cm.Data, o.scriptsOutputPath, o.Out, o.overwrite) - return nil -} - -func (o *migrateOptions) processConfigMap(object client.Object) (r bool) { - r = false - cm, ok := object.(*corev1.ConfigMap) - if !ok { - return - } - if strings.Contains(cm.Name, "script") { - dumpHelmScripts(cm.Data, o.scriptsOutputPath, o.Out, o.overwrite) - } - return -} - -func dumpHelmScripts(data map[string]string, outputPath string, out io.Writer, overwrite bool) { - if outputPath == "" { - return - } - for k, v := range data { - f := filepath.Join(outputPath, k) - if ok, _ := cfgutil.CheckPathExists(f); ok { - fmt.Fprintf(out, "file [%s] is exists\n", printer.BoldRed(k)) - if !overwrite { - os.Exit(-1) - } - } - util.CheckErr(os.WriteFile(f, []byte(v), os.ModePerm)) - } -} - -func (o *migrateOptions) buildFlags(cmd *cobra.Command) { - cmd.Flags().StringVar(&o.helmTemplateDir, "helm", "", "specify the helm template dir") - cmd.Flags().StringVar(&o.scriptsOutputPath, "output", "", "specify the scripts output path") - cmd.Flags().StringVar(&o.cmName, "configmap", "", "specify the configmap name") - cmd.Flags().StringVar(&o.regex, "regex", "", "specify the regex for configmap") - cmd.Flags().BoolVar(&o.overwrite, "force", false, "whether overwrite the exists file") -} - -var migrateExamples = templates.Examples(` -`) - -func NewMigrateHelmScriptsCmd(f cmdutil.Factory, streams genericiooptions.IOStreams) *cobra.Command { - o := &migrateOptions{ - Factory: f, - IOStreams: streams, - } - cmd := &cobra.Command{ - Use: "migrate-scripts", - Aliases: []string{"migrate"}, - Short: "migrate - a developer tool.", - Example: migrateExamples, - Run: func(cmd *cobra.Command, args []string) { - util.CheckErr(o.complete()) - util.CheckErr(o.run()) - }, - } - o.buildFlags(cmd) - return cmd -} diff --git a/pkg/cmd/class/class.go b/pkg/cmd/class/class.go deleted file mode 100644 index 916de829b..000000000 --- a/pkg/cmd/class/class.go +++ /dev/null @@ -1,40 +0,0 @@ -/* -Copyright (C) 2022-2024 ApeCloud Co., Ltd - -This file is part of KubeBlocks project - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU Affero General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU Affero General Public License for more details. - -You should have received a copy of the GNU Affero General Public License -along with this program. If not, see . -*/ - -package class - -import ( - "github.com/spf13/cobra" - "k8s.io/cli-runtime/pkg/genericiooptions" - cmdutil "k8s.io/kubectl/pkg/cmd/util" -) - -func NewClassCommand(f cmdutil.Factory, streams genericiooptions.IOStreams) *cobra.Command { - cmd := &cobra.Command{ - Use: "class", - Short: "Manage classes", - Deprecated: "This command is deprecated.", - } - - cmd.AddCommand(NewCreateCommand(f, streams)) - cmd.AddCommand(NewListCommand(f, streams)) - cmd.AddCommand(NewTemplateCmd(streams)) - - return cmd -} diff --git a/pkg/cmd/class/class_test.go b/pkg/cmd/class/class_test.go deleted file mode 100644 index 3a4afd918..000000000 --- a/pkg/cmd/class/class_test.go +++ /dev/null @@ -1,47 +0,0 @@ -/* -Copyright (C) 2022-2024 ApeCloud Co., Ltd - -This file is part of KubeBlocks project - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU Affero General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU Affero General Public License for more details. - -You should have received a copy of the GNU Affero General Public License -along with this program. If not, see . -*/ - -package class - -import ( - . "github.com/onsi/ginkgo/v2" - . "github.com/onsi/gomega" - - "k8s.io/cli-runtime/pkg/genericiooptions" - cmdtesting "k8s.io/kubectl/pkg/cmd/testing" -) - -var _ = Describe("class", func() { - var streams genericiooptions.IOStreams - var tf *cmdtesting.TestFactory - - BeforeEach(func() { - streams, _, _, _ = genericiooptions.NewTestIOStreams() - tf = cmdtesting.NewTestFactory() - }) - - AfterEach(func() { - tf.Cleanup() - }) - - It("command should succeed", func() { - cmd := NewClassCommand(tf, streams) - Expect(cmd).ShouldNot(BeNil()) - }) -}) diff --git a/pkg/cmd/class/create.go b/pkg/cmd/class/create.go deleted file mode 100644 index 3ef4c1332..000000000 --- a/pkg/cmd/class/create.go +++ /dev/null @@ -1,309 +0,0 @@ -/* -Copyright (C) 2022-2024 ApeCloud Co., Ltd - -This file is part of KubeBlocks project - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU Affero General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU Affero General Public License for more details. - -You should have received a copy of the GNU Affero General Public License -along with this program. If not, see . -*/ - -package class - -import ( - "context" - "fmt" - "os" - "strings" - - "github.com/ghodss/yaml" - "github.com/spf13/cobra" - corev1 "k8s.io/api/core/v1" - "k8s.io/apimachinery/pkg/api/errors" - "k8s.io/apimachinery/pkg/api/resource" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" - "k8s.io/apimachinery/pkg/runtime" - "k8s.io/cli-runtime/pkg/genericiooptions" - "k8s.io/client-go/dynamic" - cmdutil "k8s.io/kubectl/pkg/cmd/util" - utilcomp "k8s.io/kubectl/pkg/util/completion" - "k8s.io/kubectl/pkg/util/templates" - - "github.com/apecloud/kubeblocks/apis/apps/v1alpha1" - "github.com/apecloud/kubeblocks/pkg/constant" - "github.com/apecloud/kubeblocks/pkg/controller/component" - - "github.com/apecloud/kbcli/pkg/types" - "github.com/apecloud/kbcli/pkg/util" -) - -type CreateOptions struct { - genericiooptions.IOStreams - - // REVIEW: make this field a parameter which can be set by user - objectName string - - Factory cmdutil.Factory - dynamic dynamic.Interface - ClusterDefRef string - ComponentType string - ClassName string - CPU string - Memory string - File string -} - -var classCreateExamples = templates.Examples(` - # Create a class for component mysql in cluster definition apecloud-mysql, which has 1 CPU core and 1Gi memory - kbcli class create custom-1c1g --cluster-definition apecloud-mysql --type mysql --cpu 1 --memory 1Gi - - # Create classes for component mysql in cluster definition apecloud-mysql, with classes defined in file - kbcli class create --cluster-definition apecloud-mysql --type mysql --file ./classes.yaml -`) - -func NewCreateCommand(f cmdutil.Factory, streams genericiooptions.IOStreams) *cobra.Command { - o := CreateOptions{IOStreams: streams} - cmd := &cobra.Command{ - Use: "create [NAME]", - Short: "Create a class", - Example: classCreateExamples, - Run: func(cmd *cobra.Command, args []string) { - util.CheckErr(o.complete(f)) - util.CheckErr(o.validate(args)) - util.CheckErr(o.run()) - }, - } - cmd.Flags().StringVar(&o.ClusterDefRef, "cluster-definition", "", "Specify cluster definition, run \"kbcli clusterdefinition list\" to show all available cluster definitions") - util.CheckErr(cmd.MarkFlagRequired("cluster-definition")) - cmd.Flags().StringVar(&o.ComponentType, "type", "", "Specify component type") - util.CheckErr(cmd.MarkFlagRequired("type")) - - cmd.Flags().StringVar(&o.CPU, corev1.ResourceCPU.String(), "", "Specify component CPU cores") - cmd.Flags().StringVar(&o.Memory, corev1.ResourceMemory.String(), "", "Specify component memory size") - - cmd.Flags().StringVar(&o.File, "file", "", "Specify file path of class definition YAML") - - // register flag completion func - registerFlagCompletionFunc(cmd, f) - - return cmd -} - -func (o *CreateOptions) validate(args []string) error { - // validate creating by resource arguments - if o.File != "" { - return nil - } - - // validate cpu and memory - if _, err := resource.ParseQuantity(o.CPU); err != nil { - return err - } - if _, err := resource.ParseQuantity(o.Memory); err != nil { - return err - } - - // validate class name - if len(args) == 0 { - return fmt.Errorf("missing class name") - } - o.ClassName = args[0] - - return nil -} - -func (o *CreateOptions) complete(f cmdutil.Factory) error { - var err error - o.dynamic, err = f.DynamicClient() - return err -} - -func (o *CreateOptions) run() error { - clsMgr, _, err := GetManager(o.dynamic, o.ClusterDefRef) - if err != nil { - return err - } - - constraints, err := GetResourceConstraints(o.dynamic) - if err != nil { - return err - } - - var ( - classInstances []*v1alpha1.ComponentClass - componentClassGroups []v1alpha1.ComponentClassGroup - ) - - if o.File != "" { - data, err := os.ReadFile(o.File) - if err != nil { - return err - } - if err := yaml.Unmarshal(data, &componentClassGroups); err != nil { - return err - } - classDefinition := v1alpha1.ComponentClassDefinition{ - Spec: v1alpha1.ComponentClassDefinitionSpec{Groups: componentClassGroups}, - } - newClasses, err := component.ParseComponentClasses(classDefinition) - if err != nil { - return err - } - for _, cls := range newClasses { - classInstances = append(classInstances, cls) - } - } else { - cls := v1alpha1.ComponentClass{Name: o.ClassName, CPU: resource.MustParse(o.CPU), Memory: resource.MustParse(o.Memory)} - if err != nil { - return err - } - componentClassGroups = []v1alpha1.ComponentClassGroup{ - { - Series: []v1alpha1.ComponentClassSeries{ - { - Classes: []v1alpha1.ComponentClass{cls}, - }, - }, - }, - } - classInstances = append(classInstances, &cls) - } - - var ( - classNames []string - objName = o.objectName - ) - if objName == "" { - objName = GetCustomClassObjectName(o.ClusterDefRef, o.ComponentType) - } - - var rules []v1alpha1.ResourceConstraintRule - for _, constraint := range constraints { - rules = append(rules, constraint.FindRules(o.ClusterDefRef, o.ComponentType)...) - } - - for _, item := range classInstances { - clsDefRef := v1alpha1.ClassDefRef{Name: objName, Class: item.Name} - if clsMgr.HasClass(o.ComponentType, clsDefRef) { - return fmt.Errorf("class name conflicted %s", item.Name) - } - classNames = append(classNames, item.Name) - - if len(rules) == 0 { - continue - } - - match := false - for _, rule := range rules { - if rule.ValidateResources(item.ToResourceRequirements().Requests) { - match = true - break - } - } - if !match { - return fmt.Errorf("class %s does not conform to its constraints", item.Name) - } - } - - obj, err := o.dynamic.Resource(types.ComponentClassDefinitionGVR()).Get(context.TODO(), objName, metav1.GetOptions{}) - if err != nil && !errors.IsNotFound(err) { - return err - } - - var classDefinition v1alpha1.ComponentClassDefinition - if err == nil { - if err = runtime.DefaultUnstructuredConverter.FromUnstructured(obj.Object, &classDefinition); err != nil { - return err - } - classDefinition.Spec.Groups = append(classDefinition.Spec.Groups, componentClassGroups...) - unstructuredMap, err := runtime.DefaultUnstructuredConverter.ToUnstructured(&classDefinition) - if err != nil { - return err - } - if _, err = o.dynamic.Resource(types.ComponentClassDefinitionGVR()).Update( - context.Background(), &unstructured.Unstructured{Object: unstructuredMap}, metav1.UpdateOptions{}); err != nil { - return err - } - } else { - gvr := types.ComponentClassDefinitionGVR() - classDefinition = v1alpha1.ComponentClassDefinition{ - TypeMeta: metav1.TypeMeta{ - Kind: types.KindComponentClassDefinition, - APIVersion: gvr.Group + "/" + gvr.Version, - }, - ObjectMeta: metav1.ObjectMeta{ - Name: GetCustomClassObjectName(o.ClusterDefRef, o.ComponentType), - Labels: map[string]string{ - constant.ClusterDefLabelKey: o.ClusterDefRef, - types.ClassProviderLabelKey: "user", - constant.KBAppComponentDefRefLabelKey: o.ComponentType, - }, - }, - Spec: v1alpha1.ComponentClassDefinitionSpec{ - Groups: componentClassGroups, - }, - } - unstructuredMap, err := runtime.DefaultUnstructuredConverter.ToUnstructured(&classDefinition) - if err != nil { - return err - } - if _, err = o.dynamic.Resource(types.ComponentClassDefinitionGVR()).Create( - context.Background(), &unstructured.Unstructured{Object: unstructuredMap}, metav1.CreateOptions{}); err != nil { - return err - } - } - _, _ = fmt.Fprintf(o.Out, "Successfully create class [%s].\n", strings.Join(classNames, ",")) - return nil -} - -func registerFlagCompletionFunc(cmd *cobra.Command, f cmdutil.Factory) { - util.CheckErr(cmd.RegisterFlagCompletionFunc( - "cluster-definition", - func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { - return utilcomp.CompGetResource(f, util.GVRToString(types.ClusterDefGVR()), toComplete), cobra.ShellCompDirectiveNoFileComp - })) - util.CheckErr(cmd.RegisterFlagCompletionFunc( - "type", - func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { - var ( - componentTypes []string - selector string - compTypeLabel = "apps.kubeblocks.io/component-def-ref" - ) - - client, err := f.DynamicClient() - if err != nil { - return componentTypes, cobra.ShellCompDirectiveNoFileComp - } - - clusterDefinition, err := cmd.Flags().GetString("cluster-definition") - if err == nil && clusterDefinition != "" { - selector = fmt.Sprintf("%s=%s,%s", constant.ClusterDefLabelKey, clusterDefinition, types.ClassProviderLabelKey) - } - objs, err := client.Resource(types.ComponentClassDefinitionGVR()).List(context.Background(), metav1.ListOptions{LabelSelector: selector}) - if err != nil { - return componentTypes, cobra.ShellCompDirectiveNoFileComp - } - var classDefinitionList v1alpha1.ComponentClassDefinitionList - if err = runtime.DefaultUnstructuredConverter.FromUnstructured(objs.UnstructuredContent(), &classDefinitionList); err != nil { - return componentTypes, cobra.ShellCompDirectiveNoFileComp - } - for _, item := range classDefinitionList.Items { - componentType := item.Labels[compTypeLabel] - if componentType != "" { - componentTypes = append(componentTypes, componentType) - } - } - return componentTypes, cobra.ShellCompDirectiveNoFileComp - })) -} diff --git a/pkg/cmd/class/create_test.go b/pkg/cmd/class/create_test.go deleted file mode 100644 index d95e66724..000000000 --- a/pkg/cmd/class/create_test.go +++ /dev/null @@ -1,157 +0,0 @@ -/* -Copyright (C) 2022-2024 ApeCloud Co., Ltd - -This file is part of KubeBlocks project - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU Affero General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU Affero General Public License for more details. - -You should have received a copy of the GNU Affero General Public License -along with this program. If not, see . -*/ - -package class - -import ( - "bytes" - "fmt" - - . "github.com/onsi/ginkgo/v2" - . "github.com/onsi/gomega" - "k8s.io/cli-runtime/pkg/genericiooptions" - - "k8s.io/client-go/kubernetes/scheme" - cmdtesting "k8s.io/kubectl/pkg/cmd/testing" - - appsv1alpha1 "github.com/apecloud/kubeblocks/apis/apps/v1alpha1" - - "github.com/apecloud/kbcli/pkg/testing" -) - -var _ = Describe("create", func() { - var ( - createOptions *CreateOptions - out *bytes.Buffer - tf *cmdtesting.TestFactory - streams genericiooptions.IOStreams - ) - - fillResources := func(o *CreateOptions, cpu string, memory string) { - o.CPU = cpu - o.Memory = memory - o.ClassName = fmt.Sprintf("custom-%s-%s", cpu, memory) - } - - BeforeEach(func() { - streams, _, out, _ = genericiooptions.NewTestIOStreams() - tf = testing.NewTestFactory(namespace) - _ = appsv1alpha1.AddToScheme(scheme.Scheme) - createOptions = &CreateOptions{ - IOStreams: streams, - ClusterDefRef: "apecloud-mysql", - ComponentType: "mysql", - } - }) - - AfterEach(func() { - tf.Cleanup() - }) - - It("should succeed to new command", func() { - cmd := NewCreateCommand(tf, streams) - Expect(cmd).ShouldNot(BeNil()) - }) - - Context("with resource arguments", func() { - - Context("without constraints", func() { - BeforeEach(func() { - tf.FakeDynamicClient = testing.FakeDynamicClient(&classDef, &generalResourceConstraintWithoutSelector) - createOptions.Factory = tf - Expect(createOptions.complete(tf)).ShouldNot(HaveOccurred()) - }) - - It("should succeed if component don't have any constraints", func() { - fillResources(createOptions, "1", "100Gi") - Expect(createOptions.run()).ShouldNot(HaveOccurred()) - }) - - }) - - Context("with constraints", func() { - BeforeEach(func() { - tf.FakeDynamicClient = testing.FakeDynamicClient(&classDef, &generalResourceConstraint, &memoryOptimizedResourceConstraint) - createOptions.Factory = tf - Expect(createOptions.complete(tf)).ShouldNot(HaveOccurred()) - }) - - It("should fail if required arguments is missing", func() { - fillResources(createOptions, "", "48Gi") - Expect(createOptions.validate([]string{"general-12c48g"})).Should(HaveOccurred()) - fillResources(createOptions, "12", "") - Expect(createOptions.validate([]string{"general-12c48g"})).Should(HaveOccurred()) - fillResources(createOptions, "12", "48g") - Expect(createOptions.validate([]string{})).Should(HaveOccurred()) - }) - - It("should succeed with required arguments", func() { - fillResources(createOptions, "96", "384Gi") - Expect(createOptions.validate([]string{"general-96c384g"})).ShouldNot(HaveOccurred()) - Expect(createOptions.run()).ShouldNot(HaveOccurred()) - Expect(out.String()).Should(ContainSubstring(createOptions.ClassName)) - }) - - It("should fail if not conformed to constraint", func() { - By("memory not conformed to constraint") - fillResources(createOptions, "2", "9Gi") - Expect(createOptions.run()).Should(HaveOccurred()) - - By("CPU with invalid step") - fillResources(createOptions, "0.6", "0.6Gi") - Expect(createOptions.run()).Should(HaveOccurred()) - }) - - It("should fail if class name is conflicted", func() { - // class may be conflict only within the same object, so we set the objectName to be consistent with the name of the object classDef - createOptions.objectName = "kb.classes.default.apecloud-mysql.mysql" - - fillResources(createOptions, "1", "1Gi") - createOptions.ClassName = "general-1c1g" - Expect(createOptions.run()).Should(HaveOccurred()) - - fillResources(createOptions, "0.5", "0.5Gi") - Expect(createOptions.run()).ShouldNot(HaveOccurred()) - - fillResources(createOptions, "0.5", "0.5Gi") - Expect(createOptions.run()).Should(HaveOccurred()) - }) - }) - }) - - Context("with class definitions file", func() { - BeforeEach(func() { - tf.FakeDynamicClient = testing.FakeDynamicClient(&classDef, &generalResourceConstraint, &memoryOptimizedResourceConstraint) - createOptions.Factory = tf - Expect(createOptions.complete(tf)).ShouldNot(HaveOccurred()) - }) - - It("should succeed", func() { - createOptions.File = testCustomClassDefsPath - Expect(createOptions.run()).ShouldNot(HaveOccurred()) - Expect(out.String()).Should(ContainSubstring("custom-1c1g")) - Expect(out.String()).Should(ContainSubstring("custom-4c16g")) - // memory optimized classes - Expect(out.String()).Should(ContainSubstring("custom-2c16g")) - Expect(out.String()).Should(ContainSubstring("custom-4c64g")) - }) - - }) - -}) diff --git a/pkg/cmd/class/list.go b/pkg/cmd/class/list.go deleted file mode 100644 index afdbc185c..000000000 --- a/pkg/cmd/class/list.go +++ /dev/null @@ -1,121 +0,0 @@ -/* -Copyright (C) 2022-2024 ApeCloud Co., Ltd - -This file is part of KubeBlocks project - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU Affero General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU Affero General Public License for more details. - -You should have received a copy of the GNU Affero General Public License -along with this program. If not, see . -*/ - -package class - -import ( - "fmt" - "sort" - "strings" - - "github.com/spf13/cobra" - "k8s.io/apimachinery/pkg/api/resource" - "k8s.io/cli-runtime/pkg/genericiooptions" - "k8s.io/client-go/dynamic" - cmdutil "k8s.io/kubectl/pkg/cmd/util" - "k8s.io/kubectl/pkg/util/templates" - - "github.com/apecloud/kubeblocks/pkg/controller/component" - - "github.com/apecloud/kbcli/pkg/printer" - "github.com/apecloud/kbcli/pkg/util" - "github.com/apecloud/kbcli/pkg/util/flags" -) - -type ListOptions struct { - ClusterDefRef string - Factory cmdutil.Factory - dynamic dynamic.Interface - genericiooptions.IOStreams -} - -var listClassExamples = templates.Examples(` - # List all components classes in cluster definition apecloud-mysql - kbcli class list --cluster-definition apecloud-mysql -`) - -func NewListCommand(f cmdutil.Factory, streams genericiooptions.IOStreams) *cobra.Command { - o := &ListOptions{IOStreams: streams} - cmd := &cobra.Command{ - Use: "list", - Short: "List classes", - Example: listClassExamples, - Run: func(cmd *cobra.Command, args []string) { - util.CheckErr(o.complete(f)) - util.CheckErr(o.run()) - }, - } - flags.AddClusterDefinitionFlag(f, cmd, &o.ClusterDefRef) - util.CheckErr(cmd.MarkFlagRequired("cluster-definition")) - return cmd -} - -func (o *ListOptions) complete(f cmdutil.Factory) error { - var err error - o.dynamic, err = f.DynamicClient() - return err -} - -func (o *ListOptions) run() error { - clsMgr, _, err := GetManager(o.dynamic, o.ClusterDefRef) - if err != nil { - return err - } - for compName, classes := range clsMgr.GetClasses() { - o.printClass(compName, classes) - } - return nil -} - -func (o *ListOptions) printClass(compName string, classes []*component.ComponentClassWithRef) { - tbl := printer.NewTablePrinter(o.Out) - tbl.SetHeader("COMPONENT", "CLASS", "CPU", "MEMORY") - sort.Sort(component.ByClassResource(classes)) - for _, cls := range classes { - tbl.AddRow(compName, cls.Name, cls.CPU.String(), normalizeMemory(cls.Memory)) - } - tbl.Print() -} - -func normalizeMemory(mem resource.Quantity) string { - if !strings.HasSuffix(mem.String(), "m") { - return mem.String() - } - - var ( - value float64 - suffix string - bytes = float64(mem.MilliValue()) / 1000 - ) - switch { - case bytes < 1024: - value = bytes / 1024 - suffix = "Ki" - case bytes < 1024*1024: - value = bytes / 1024 / 1024 - suffix = "Mi" - case bytes < 1024*1024*1024: - value = bytes / 1024 / 1024 / 1024 - suffix = "Gi" - default: - value = bytes / 1024 / 1024 / 1024 / 1024 - suffix = "Ti" - } - return strings.TrimRight(fmt.Sprintf("%.3f", value), "0") + suffix -} diff --git a/pkg/cmd/class/list_test.go b/pkg/cmd/class/list_test.go deleted file mode 100644 index f549d8705..000000000 --- a/pkg/cmd/class/list_test.go +++ /dev/null @@ -1,106 +0,0 @@ -/* -Copyright (C) 2022-2024 ApeCloud Co., Ltd - -This file is part of KubeBlocks project - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU Affero General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU Affero General Public License for more details. - -You should have received a copy of the GNU Affero General Public License -along with this program. If not, see . -*/ - -package class - -import ( - "bytes" - - . "github.com/onsi/ginkgo/v2" - . "github.com/onsi/gomega" - "k8s.io/apimachinery/pkg/api/resource" - "k8s.io/cli-runtime/pkg/genericiooptions" - "k8s.io/client-go/kubernetes/scheme" - cmdtesting "k8s.io/kubectl/pkg/cmd/testing" - - appsv1alpha1 "github.com/apecloud/kubeblocks/apis/apps/v1alpha1" - - "github.com/apecloud/kbcli/pkg/testing" -) - -var _ = Describe("list", func() { - var ( - out *bytes.Buffer - tf *cmdtesting.TestFactory - streams genericiooptions.IOStreams - ) - - BeforeEach(func() { - streams, _, out, _ = genericiooptions.NewTestIOStreams() - tf = testing.NewTestFactory(namespace) - _ = appsv1alpha1.AddToScheme(scheme.Scheme) - tf.FakeDynamicClient = testing.FakeDynamicClient(&classDef) - }) - - AfterEach(func() { - tf.Cleanup() - }) - - It("should succeed", func() { - cmd := NewListCommand(tf, streams) - Expect(cmd).ShouldNot(BeNil()) - _ = cmd.Flags().Set("cluster-definition", "apecloud-mysql") - cmd.Run(cmd, []string{}) - Expect(out.String()).To(ContainSubstring("general-1c1g")) - Expect(out.String()).To(ContainSubstring("mysql")) - }) - - It("memory should be normalized", func() { - cases := []struct { - memory string - normalized string - }{ - { - memory: "0.2Gi", - normalized: "0.2Gi", - }, - { - memory: "0.2Mi", - normalized: "0.2Mi", - }, - { - memory: "0.2Ki", - normalized: "0.2Ki", - }, - { - memory: "1024Mi", - normalized: "1Gi", - }, - { - memory: "1025Mi", - normalized: "1025Mi", - }, - { - memory: "1023Mi", - normalized: "1023Mi", - }, - { - memory: "1Gi", - normalized: "1Gi", - }, - { - memory: "512Mi", - normalized: "512Mi", - }, - } - for _, item := range cases { - Expect(normalizeMemory(resource.MustParse(item.memory))).Should(Equal(item.normalized)) - } - }) -}) diff --git a/pkg/cmd/class/suite_test.go b/pkg/cmd/class/suite_test.go deleted file mode 100644 index d80ed5c58..000000000 --- a/pkg/cmd/class/suite_test.go +++ /dev/null @@ -1,86 +0,0 @@ -/* -Copyright (C) 2022-2024 ApeCloud Co., Ltd - -This file is part of KubeBlocks project - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU Affero General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU Affero General Public License for more details. - -You should have received a copy of the GNU Affero General Public License -along with this program. If not, see . -*/ - -package class - -import ( - "os" - "testing" - - . "github.com/onsi/ginkgo/v2" - . "github.com/onsi/gomega" - - corev1 "k8s.io/api/core/v1" - "k8s.io/apimachinery/pkg/util/yaml" - "k8s.io/client-go/kubernetes/scheme" - - appsv1alpha1 "github.com/apecloud/kubeblocks/apis/apps/v1alpha1" -) - -const ( - namespace = "test" - testDefaultClassDefsPath = "../../testing/testdata/class.yaml" - testCustomClassDefsPath = "../../testing/testdata/custom_class.yaml" - testGeneralResourceConstraintPath = "../../testing/testdata/resource-constraint-general.yaml" - testMemoryOptimizedResourceConstraintPath = "../../testing/testdata/resource-constraint-memory-optimized.yaml" - testGeneralResourceConstraintWithoutSelectorPath = "../../testing/testdata/resource-constraint-general-without-selector.yaml" -) - -var ( - classDef appsv1alpha1.ComponentClassDefinition - generalResourceConstraint appsv1alpha1.ComponentResourceConstraint - generalResourceConstraintWithoutSelector appsv1alpha1.ComponentResourceConstraint - memoryOptimizedResourceConstraint appsv1alpha1.ComponentResourceConstraint -) - -var _ = BeforeSuite(func() { - var err error - - classDefBytes, err := os.ReadFile(testDefaultClassDefsPath) - Expect(err).ShouldNot(HaveOccurred()) - err = yaml.Unmarshal(classDefBytes, &classDef) - Expect(err).ShouldNot(HaveOccurred()) - - generalResourceConstraintBytes, err := os.ReadFile(testGeneralResourceConstraintPath) - Expect(err).ShouldNot(HaveOccurred()) - err = yaml.Unmarshal(generalResourceConstraintBytes, &generalResourceConstraint) - Expect(err).ShouldNot(HaveOccurred()) - - generalResourceConstraintWithoutSelectorBytes, err := os.ReadFile(testGeneralResourceConstraintWithoutSelectorPath) - Expect(err).ShouldNot(HaveOccurred()) - err = yaml.Unmarshal(generalResourceConstraintWithoutSelectorBytes, &generalResourceConstraintWithoutSelector) - Expect(err).ShouldNot(HaveOccurred()) - - memoryOptimizedResourceConstraintBytes, err := os.ReadFile(testMemoryOptimizedResourceConstraintPath) - Expect(err).ShouldNot(HaveOccurred()) - err = yaml.Unmarshal(memoryOptimizedResourceConstraintBytes, &memoryOptimizedResourceConstraint) - Expect(err).ShouldNot(HaveOccurred()) - - err = appsv1alpha1.AddToScheme(scheme.Scheme) - Expect(err).ShouldNot(HaveOccurred()) - - err = corev1.AddToScheme(scheme.Scheme) - Expect(err).ShouldNot(HaveOccurred()) - -}) - -func TestClass(t *testing.T) { - RegisterFailHandler(Fail) - RunSpecs(t, "Class Suite") -} diff --git a/pkg/cmd/class/template.go b/pkg/cmd/class/template.go deleted file mode 100644 index b380fd17d..000000000 --- a/pkg/cmd/class/template.go +++ /dev/null @@ -1,77 +0,0 @@ -/* -Copyright (C) 2022-2024 ApeCloud Co., Ltd - -This file is part of KubeBlocks project - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU Affero General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU Affero General Public License for more details. - -You should have received a copy of the GNU Affero General Public License -along with this program. If not, see . -*/ - -package class - -import ( - "fmt" - "os" - - "github.com/spf13/cobra" - "k8s.io/cli-runtime/pkg/genericiooptions" - - "github.com/apecloud/kbcli/pkg/util" -) - -const ComponentClassTemplate = ` -- # class template, you can declare variables and set default values here - template: | - cpu: "{{ or .cpu 1 }}" - memory: "{{ or .memory 4 }}Gi" - # template variables used to define classes - vars: [cpu, memory] - series: - - # class naming template, you can reference variables in class template - # it's also ok to define static class name in the following class definitions - namingTemplate: "custom-{{ .cpu }}c{{ .memory }}g" - - # class definitions, we support two kinds of class definitions: - # 1. dynamically classes rendered with defined values & template variables - # 2. statically defined classes - classes: - - args: [1, 1] -` - -type TemplateOptions struct { - genericiooptions.IOStreams - - outputFile string -} - -func NewTemplateCmd(streams genericiooptions.IOStreams) *cobra.Command { - o := &TemplateOptions{IOStreams: streams} - cmd := &cobra.Command{ - Use: "template", - Short: "Generate class definition template", - Run: func(cmd *cobra.Command, args []string) { - util.CheckErr(o.run()) - }, - } - cmd.Flags().StringVarP(&o.outputFile, "output", "o", "", "Output class definition template to a file") - return cmd -} - -func (o *TemplateOptions) run() error { - if o.outputFile != "" { - return os.WriteFile(o.outputFile, []byte(ComponentClassTemplate), 0644) - } - - _, err := fmt.Fprint(o.Out, ComponentClassTemplate) - return err -} diff --git a/pkg/cmd/class/template_test.go b/pkg/cmd/class/template_test.go deleted file mode 100644 index d138ab7c3..000000000 --- a/pkg/cmd/class/template_test.go +++ /dev/null @@ -1,48 +0,0 @@ -/* -Copyright (C) 2022-2024 ApeCloud Co., Ltd - -This file is part of KubeBlocks project - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU Affero General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU Affero General Public License for more details. - -You should have received a copy of the GNU Affero General Public License -along with this program. If not, see . -*/ - -package class - -import ( - "bytes" - - . "github.com/onsi/ginkgo/v2" - . "github.com/onsi/gomega" - - "k8s.io/cli-runtime/pkg/genericiooptions" -) - -var _ = Describe("template", func() { - var ( - out *bytes.Buffer - streams genericiooptions.IOStreams - ) - - BeforeEach(func() { - streams, _, out, _ = genericiooptions.NewTestIOStreams() - }) - - It("command should succeed", func() { - cmd := NewTemplateCmd(streams) - Expect(cmd).ShouldNot(BeNil()) - - cmd.Run(cmd, []string{}) - Expect(out.String()).ShouldNot(BeEmpty()) - }) -}) diff --git a/pkg/cmd/class/utils.go b/pkg/cmd/class/utils.go deleted file mode 100644 index 08e963fa7..000000000 --- a/pkg/cmd/class/utils.go +++ /dev/null @@ -1,130 +0,0 @@ -/* -Copyright (C) 2022-2024 ApeCloud Co., Ltd - -This file is part of KubeBlocks project - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU Affero General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU Affero General Public License for more details. - -You should have received a copy of the GNU Affero General Public License -along with this program. If not, see . -*/ - -package class - -import ( - "context" - "fmt" - - "github.com/apecloud/kubeblocks/pkg/controller/component" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/runtime" - "k8s.io/client-go/dynamic" - - "github.com/apecloud/kubeblocks/apis/apps/v1alpha1" - "github.com/apecloud/kubeblocks/pkg/constant" - - "github.com/apecloud/kbcli/pkg/types" -) - -// GetManager gets a class manager which manages default classes and user custom classes -func GetManager(client dynamic.Interface, cdName string) (*component.Manager, *v1alpha1.ComponentResourceConstraintList, error) { - selector := fmt.Sprintf("%s=%s,%s", constant.ClusterDefLabelKey, cdName, types.ClassProviderLabelKey) - classObjs, err := client.Resource(types.ComponentClassDefinitionGVR()).Namespace("").List(context.TODO(), metav1.ListOptions{ - LabelSelector: selector, - }) - if err != nil { - return nil, nil, err - } - var classDefinitionList v1alpha1.ComponentClassDefinitionList - if err = runtime.DefaultUnstructuredConverter.FromUnstructured(classObjs.UnstructuredContent(), &classDefinitionList); err != nil { - return nil, nil, err - } - - constraintObjs, err := client.Resource(types.ComponentResourceConstraintGVR()).Namespace("").List(context.TODO(), metav1.ListOptions{}) - if err != nil { - return nil, nil, err - } - var resourceConstraintList v1alpha1.ComponentResourceConstraintList - if err = runtime.DefaultUnstructuredConverter.FromUnstructured(constraintObjs.UnstructuredContent(), &resourceConstraintList); err != nil { - return nil, nil, err - } - mgr, err := component.NewManager(classDefinitionList, resourceConstraintList) - return mgr, &resourceConstraintList, err -} - -// GetResourceConstraints gets all resource constraints -func GetResourceConstraints(dynamic dynamic.Interface) (map[string]*v1alpha1.ComponentResourceConstraint, error) { - objs, err := dynamic.Resource(types.ComponentResourceConstraintGVR()).List(context.TODO(), metav1.ListOptions{ - // LabelSelector: types.ResourceConstraintProviderLabelKey, - }) - if err != nil { - return nil, err - } - var constraintsList v1alpha1.ComponentResourceConstraintList - if err = runtime.DefaultUnstructuredConverter.FromUnstructured(objs.UnstructuredContent(), &constraintsList); err != nil { - return nil, err - } - - result := make(map[string]*v1alpha1.ComponentResourceConstraint) - for idx := range constraintsList.Items { - cf := constraintsList.Items[idx] - if _, ok := cf.GetLabels()[constant.ResourceConstraintProviderLabelKey]; !ok { - continue - } - result[cf.GetName()] = &cf - } - return result, nil -} - -// GetCustomClassObjectName returns the name of the ComponentClassDefinition object containing the custom classes -func GetCustomClassObjectName(cdName string, componentName string) string { - return fmt.Sprintf("kb.classes.custom.%s.%s", cdName, componentName) -} - -func ValidateResources(clsMGR *component.Manager, - resourceConstraintList *v1alpha1.ComponentResourceConstraintList, - clusterDefRef string, - comp *v1alpha1.ClusterComponentSpec) error { - if comp.ClassDefRef != nil && comp.ClassDefRef.Class != "" { - if clsMGR.HasClass(comp.ComponentDefRef, *comp.ClassDefRef) { - return nil - } - return fmt.Errorf("class not found") - } - - var rules []v1alpha1.ResourceConstraintRule - for _, constraint := range resourceConstraintList.Items { - rules = append(rules, constraint.FindRules(clusterDefRef, comp.ComponentDefRef)...) - } - if len(rules) == 0 { - return nil - } - - for _, rule := range rules { - if !rule.ValidateResources(comp.Resources.Requests) { - continue - } - - // validate volume - match := true - // all volumes should match the rules - for _, volume := range comp.VolumeClaimTemplates { - if !rule.ValidateStorage(volume.Spec.Resources.Requests.Storage()) { - match = false - break - } - } - if match { - return nil - } - } - return fmt.Errorf("resource is not conform to the constraints, please check the ComponentResourceConstraint API") -} diff --git a/pkg/cmd/cli.go b/pkg/cmd/cli.go index 3ae3ff5db..9b7d6bcf2 100644 --- a/pkg/cmd/cli.go +++ b/pkg/cmd/cli.go @@ -34,27 +34,20 @@ import ( cmdutil "k8s.io/kubectl/pkg/cmd/util" utilcomp "k8s.io/kubectl/pkg/util/completion" "k8s.io/kubectl/pkg/util/templates" + ctrl "sigs.k8s.io/controller-runtime" viper "github.com/apecloud/kubeblocks/pkg/viperx" "github.com/apecloud/kbcli/pkg/cmd/addon" - "github.com/apecloud/kbcli/pkg/cmd/alert" - "github.com/apecloud/kbcli/pkg/cmd/auth" "github.com/apecloud/kbcli/pkg/cmd/backuprepo" "github.com/apecloud/kbcli/pkg/cmd/bench" - "github.com/apecloud/kbcli/pkg/cmd/builder" - "github.com/apecloud/kbcli/pkg/cmd/class" "github.com/apecloud/kbcli/pkg/cmd/cluster" "github.com/apecloud/kbcli/pkg/cmd/clusterdefinition" "github.com/apecloud/kbcli/pkg/cmd/clusterversion" - "github.com/apecloud/kbcli/pkg/cmd/context" "github.com/apecloud/kbcli/pkg/cmd/dashboard" "github.com/apecloud/kbcli/pkg/cmd/dataprotection" - "github.com/apecloud/kbcli/pkg/cmd/fault" "github.com/apecloud/kbcli/pkg/cmd/kubeblocks" - "github.com/apecloud/kbcli/pkg/cmd/migration" "github.com/apecloud/kbcli/pkg/cmd/options" - "github.com/apecloud/kbcli/pkg/cmd/organization" "github.com/apecloud/kbcli/pkg/cmd/playground" "github.com/apecloud/kbcli/pkg/cmd/plugin" "github.com/apecloud/kbcli/pkg/cmd/report" @@ -67,13 +60,6 @@ const ( cliName = "kbcli" ) -// TODO: add more commands -var cloudCmds = map[string]bool{ - "org": true, - "logout": true, - "context": true, -} - func init() { if _, err := util.GetCliHomeDir(); err != nil { fmt.Println("Failed to create kbcli home dir:", err) @@ -156,16 +142,6 @@ A Command Line Interface for KubeBlocks`, if cmd.Name() == cobra.ShellCompRequestCmd { kcplugin.SetupPluginCompletion(cmd, args) } - - commandPath := cmd.CommandPath() - parts := strings.Split(commandPath, " ") - if len(parts) < 2 { - return nil - } - subCommand := parts[1] - if cloudCmds[subCommand] && !auth.IsLoggedIn() { - return fmt.Errorf("use 'kbcli login' to login first") - } return nil }, } @@ -190,10 +166,6 @@ A Command Line Interface for KubeBlocks`, // Add subcommands cmd.AddCommand( - auth.NewLogin(ioStreams), - auth.NewLogout(ioStreams), - organization.NewOrganizationCmd(ioStreams), - context.NewContextCmd(ioStreams), playground.NewPlaygroundCmd(ioStreams), kubeblocks.NewKubeBlocksCmd(f, ioStreams), bench.NewBenchCmd(f, ioStreams), @@ -202,13 +174,8 @@ A Command Line Interface for KubeBlocks`, dashboard.NewDashboardCmd(f, ioStreams), clusterversion.NewClusterVersionCmd(f, ioStreams), clusterdefinition.NewClusterDefinitionCmd(f, ioStreams), - class.NewClassCommand(f, ioStreams), - alert.NewAlertCmd(f, ioStreams), addon.NewAddonCmd(f, ioStreams), - migration.NewMigrationCmd(f, ioStreams), plugin.NewPluginCmd(ioStreams), - fault.NewFaultCmd(f, ioStreams), - builder.NewBuilderCmd(f, ioStreams), report.NewReportCmd(f, ioStreams), backuprepo.NewBackupRepoCmd(f, ioStreams), dataprotection.NewDataProtectionCmd(f, ioStreams), @@ -229,10 +196,14 @@ A Command Line Interface for KubeBlocks`, utilcomp.SetFactoryForCompletion(f) registerCompletionFuncForGlobalFlags(cmd, f) - cobra.OnInitialize(initConfig) + cobra.OnInitialize(initConfig, initLog) return cmd } +func initLog() { + ctrl.SetLogger(klog.NewKlogr()) +} + // initConfig reads in config file and ENV variables if set. func initConfig() { viper.SetConfigName("config") @@ -252,11 +223,6 @@ func initConfig() { if err := viper.ReadInConfig(); err == nil { klog.V(2).Infof("Using config file: %s", viper.ConfigFileUsed()) } - - // cloud - viper.SetDefault(types.CfgKeyOpenAPIServer, "https://cloudapi.apecloud.cn") - viper.SetDefault(types.CfgKeyAuthURL, "https://apecloud.authing.cn/oidc") - viper.SetDefault(types.CfgKeyClientID, "64e42ca02df49bffa50719a9") } func registerCompletionFuncForGlobalFlags(cmd *cobra.Command, f cmdutil.Factory) { diff --git a/pkg/cmd/cluster/cluster_test.go b/pkg/cmd/cluster/cluster_test.go index 9c1601023..41f5e9fcd 100644 --- a/pkg/cmd/cluster/cluster_test.go +++ b/pkg/cmd/cluster/cluster_test.go @@ -43,12 +43,8 @@ import ( var _ = Describe("Cluster", func() { const ( - testComponentPath = "../../testing/testdata/component.yaml" - testComponentWithClassPath = "../../testing/testdata/component_with_class_1c1g.yaml" - testComponentWithInvalidClassPath = "../../testing/testdata/component_with_invalid_class.yaml" - testComponentWithResourcePath = "../../testing/testdata/component_with_resource_1c1g.yaml" - testComponentWithInvalidResourcePath = "../../testing/testdata/component_with_invalid_resource.yaml" - testClusterPath = "../../testing/testdata/cluster.yaml" + testComponentPath = "../../testing/testdata/component.yaml" + testClusterPath = "../../testing/testdata/cluster.yaml" ) const ( @@ -177,69 +173,6 @@ var _ = Describe("Cluster", func() { Expect(o.Validate()).Should(HaveOccurred()) }) - It("should succeed if component with valid class", func() { - o.Values = []string{fmt.Sprintf("type=%s,class=%s", testing.ComponentDefName, testapps.Class1c1gName)} - Expect(o.Complete()).Should(Succeed()) - Expect(o.Validate()).Should(Succeed()) - Run() - }) - - It("should fail if component with invalid class", func() { - o.Values = []string{fmt.Sprintf("type=%s,class=class-not-exists", testing.ComponentDefName)} - Expect(o.Complete()).Should(HaveOccurred()) - }) - - It("should succeed if component with resource meets the resource constraint", func() { - o.Values = []string{fmt.Sprintf("type=%s,cpu=1,memory=1Gi", testing.ComponentDefName)} - Expect(o.Complete()).Should(Succeed()) - Expect(o.Validate()).Should(Succeed()) - Run() - }) - - It("should succeed if component with resource with smaller unit meets the constraint", func() { - o.Values = []string{fmt.Sprintf("type=%s,cpu=1000m,memory=1024Mi", testing.ComponentDefName)} - Expect(o.Complete()).Should(Succeed()) - Expect(o.Validate()).Should(Succeed()) - Run() - }) - - It("should fail if component with resource not meets the constraint", func() { - o.Values = []string{fmt.Sprintf("type=%s,cpu=1,memory=100Gi", testing.ComponentDefName)} - Expect(o.Complete()).Should(HaveOccurred()) - }) - - It("should succeed if component with cpu meets the constraint", func() { - o.Values = []string{fmt.Sprintf("type=%s,cpu=1", testing.ComponentDefName)} - Expect(o.Complete()).Should(Succeed()) - Expect(o.Validate()).Should(Succeed()) - Run() - }) - - It("should fail if component with cpu not meets the constraint", func() { - o.Values = []string{fmt.Sprintf("type=%s,cpu=1024", testing.ComponentDefName)} - Expect(o.Complete()).Should(HaveOccurred()) - }) - - It("should fail if component with memory not meets the constraint", func() { - o.Values = []string{fmt.Sprintf("type=%s,memory=1Ti", testing.ComponentDefName)} - Expect(o.Complete()).Should(HaveOccurred()) - }) - - It("should succeed if component doesn't have class definition", func() { - o.Values = []string{fmt.Sprintf("type=%s,cpu=3,memory=7Gi", testing.ExtraComponentDefName)} - Expect(o.Complete()).Should(Succeed()) - Expect(o.Validate()).Should(Succeed()) - Run() - }) - - It("should fail if component with storage not meets the constraint", func() { - o.Values = []string{fmt.Sprintf("type=%s,storage=500Mi", testing.ComponentDefName)} - Expect(o.Complete()).Should(HaveOccurred()) - - o.Values = []string{fmt.Sprintf("type=%s,storage=1Pi", testing.ComponentDefName)} - Expect(o.Complete()).Should(HaveOccurred()) - }) - It("should fail if create cluster by non-existed file", func() { o.SetFile = "test.yaml" Expect(o.Complete()).Should(HaveOccurred()) @@ -259,25 +192,6 @@ var _ = Describe("Cluster", func() { Run() }) - It("should succeed if create cluster by file with class", func() { - o.SetFile = testComponentWithClassPath - Expect(o.Complete()).Should(Succeed()) - Expect(o.Validate()).Should(Succeed()) - Run() - }) - - It("should succeed if create cluster by file with resource", func() { - o.SetFile = testComponentWithResourcePath - Expect(o.Complete()).Should(Succeed()) - Expect(o.Validate()).Should(Succeed()) - Run() - }) - - It("should fail if create cluster by file with non-existed class", func() { - o.SetFile = testComponentWithInvalidClassPath - Expect(o.Complete()).Should(HaveOccurred()) - }) - It("should succeed if create cluster with a complete config file", func() { o.SetFile = testClusterPath Expect(o.Complete()).Should(Succeed()) diff --git a/pkg/cmd/cluster/config_diff.go b/pkg/cmd/cluster/config_diff.go index ebc659b70..e16f1eea2 100644 --- a/pkg/cmd/cluster/config_diff.go +++ b/pkg/cmd/cluster/config_diff.go @@ -31,6 +31,7 @@ import ( "sigs.k8s.io/controller-runtime/pkg/client" appsv1alpha1 "github.com/apecloud/kubeblocks/apis/apps/v1alpha1" + appsv1beta1 "github.com/apecloud/kubeblocks/apis/apps/v1beta1" "github.com/apecloud/kubeblocks/pkg/configuration/core" "github.com/apecloud/kubeblocks/pkg/constant" "github.com/apecloud/kubeblocks/pkg/unstructured" @@ -224,7 +225,7 @@ func (o *configDiffOptions) maybeCompareOps(base *appsv1alpha1.OpsRequest, diff func (o *configDiffOptions) diffConfig(tplName string) ([]core.VisualizedParam, map[string]unstructured.ConfigObject, error) { var ( tpl *appsv1alpha1.ComponentConfigSpec - configConstraint = &appsv1alpha1.ConfigConstraint{} + configConstraint = &appsv1beta1.ConfigConstraint{} ) tplList, err := util.GetConfigTemplateList(o.clusterName, o.baseOptions.namespace, o.baseOptions.dynamic, o.componentName, true) @@ -241,7 +242,7 @@ func (o *configDiffOptions) diffConfig(tplName string) ([]core.VisualizedParam, return nil, nil, err } - formatCfg := configConstraint.Spec.FormatterConfig + formatCfg := configConstraint.Spec.FileFormatConfig base := findTemplateStatusByName(o.baseVersion.Status.ReconfiguringStatus, tplName) diff := findTemplateStatusByName(o.diffVersion.Status.ReconfiguringStatus, tplName) diff --git a/pkg/cmd/cluster/config_edit.go b/pkg/cmd/cluster/config_edit.go index 92d2c3b24..5ae0223b4 100644 --- a/pkg/cmd/cluster/config_edit.go +++ b/pkg/cmd/cluster/config_edit.go @@ -36,6 +36,7 @@ import ( "sigs.k8s.io/controller-runtime/pkg/client" appsv1alpha1 "github.com/apecloud/kubeblocks/apis/apps/v1alpha1" + appsv1beta1 "github.com/apecloud/kubeblocks/apis/apps/v1beta1" cfgcm "github.com/apecloud/kubeblocks/pkg/configuration/config_manager" "github.com/apecloud/kubeblocks/pkg/configuration/core" "github.com/apecloud/kubeblocks/pkg/configuration/validate" @@ -53,7 +54,7 @@ type editConfigOptions struct { } var ( - editConfigUse = "edit-config NAME [--component=component-name] [--config-spec=config-spec-name] [--config-file=config-file]" + editConfigUse = "edit-config NAME [--components=component-name] [--config-spec=config-spec-name] [--config-file=config-file]" editConfigExample = templates.Examples(` # update mysql max_connections, cluster name is mycluster @@ -120,11 +121,11 @@ func (o *editConfigOptions) runWithConfigConstraints(cfgEditContext *configEditC Namespace: "", Name: configSpec.ConfigConstraintRef, } - configConstraint := appsv1alpha1.ConfigConstraint{} + configConstraint := appsv1beta1.ConfigConstraint{} if err := util.GetResourceObjectFromGVR(types.ConfigConstraintGVR(), configConstraintKey, o.Dynamic, &configConstraint); err != nil { return err } - formatterConfig := configConstraint.Spec.FormatterConfig + formatterConfig := configConstraint.Spec.FileFormatConfig if formatterConfig == nil { return core.MakeError("config spec[%s] not support reconfiguring!", configSpec.Name) } @@ -139,12 +140,12 @@ func (o *editConfigOptions) runWithConfigConstraints(cfgEditContext *configEditC fmt.Fprintf(o.Out, "Config patch(updated parameters): \n%s\n\n", string(configPatch.UpdateConfig[o.CfgFile])) if !o.enableDelete { - if err := core.ValidateConfigPatch(configPatch, configConstraint.Spec.FormatterConfig); err != nil { + if err := core.ValidateConfigPatch(configPatch, configConstraint.Spec.FileFormatConfig); err != nil { return err } } - params := core.GenerateVisualizedParamsList(configPatch, configConstraint.Spec.FormatterConfig, nil) + params := core.GenerateVisualizedParamsList(configPatch, configConstraint.Spec.FileFormatConfig, nil) // check immutable parameters if len(configConstraint.Spec.ImmutableParameters) > 0 { if err = util.ValidateParametersModified2(sets.KeySet(fromKeyValuesToMap(params, o.CfgFile)), configConstraint.Spec); err != nil { @@ -175,7 +176,7 @@ func (o *editConfigOptions) runWithConfigConstraints(cfgEditContext *configEditC return fn() } -func generateReconfiguringPrompt(fileUpdated bool, configPatch *core.ConfigPatchInfo, cc *appsv1alpha1.ConfigConstraintSpec, fileName string) (string, error) { +func generateReconfiguringPrompt(fileUpdated bool, configPatch *core.ConfigPatchInfo, cc *appsv1beta1.ConfigConstraintSpec, fileName string) (string, error) { if fileUpdated { return restartConfirmPrompt, nil } @@ -186,7 +187,7 @@ func generateReconfiguringPrompt(fileUpdated bool, configPatch *core.ConfigPatch } confirmPrompt := confirmApplyReconfigurePrompt - if !dynamicUpdated || !cfgcm.IsSupportReload(cc.ReloadOptions) { + if !dynamicUpdated || !cfgcm.IsSupportReload(cc.ReloadAction) { confirmPrompt = restartConfirmPrompt } return confirmPrompt, nil diff --git a/pkg/cmd/cluster/config_observer.go b/pkg/cmd/cluster/config_observer.go index ae59b975d..24cee708e 100644 --- a/pkg/cmd/cluster/config_observer.go +++ b/pkg/cmd/cluster/config_observer.go @@ -167,18 +167,18 @@ func (r *configObserverOptions) printExplainConfigure(configSpecs configSpecsTyp } confSpec := tpl.ConfigConstraint.Spec - if confSpec.ConfigurationSchema == nil { + if confSpec.ParametersSchema == nil { fmt.Printf("\n%s\n", fmt.Sprintf(notConfigSchemaPrompt, printer.BoldYellow(tplName))) return nil } - schema := confSpec.ConfigurationSchema.DeepCopy() - if schema.Schema == nil { + schema := confSpec.ParametersSchema.DeepCopy() + if schema.SchemaInJSON == nil { if schema.CUE == "" { fmt.Printf("\n%s\n", fmt.Sprintf(notConfigSchemaPrompt, printer.BoldYellow(tplName))) return nil } - apiSchema, err := openapi.GenerateOpenAPISchema(schema.CUE, confSpec.CfgSchemaTopLevelName) + apiSchema, err := openapi.GenerateOpenAPISchema(schema.CUE, schema.TopLevelKey) if err != nil { return cfgcore.WrapError(err, "failed to generate open api schema") } @@ -186,9 +186,9 @@ func (r *configObserverOptions) printExplainConfigure(configSpecs configSpecsTyp fmt.Printf("\n%s\n", cue2openAPISchemaFailedPrompt) return nil } - schema.Schema = apiSchema + schema.SchemaInJSON = apiSchema } - return r.printConfigConstraint(schema.Schema, + return r.printConfigConstraint(schema.SchemaInJSON, cfgutil.NewSet(confSpec.StaticParameters...), cfgutil.NewSet(confSpec.DynamicParameters...), cfgutil.NewSet(confSpec.ImmutableParameters...)) @@ -267,7 +267,7 @@ func (r *configObserverOptions) printConfigureHistory(component string) error { tplNames := getTemplateNameFromOps(ops.Spec) keyNames := getKeyNameFromOps(ops.Spec) tbl.AddRow(ops.Name, - ops.Spec.ClusterRef, + ops.Spec.GetClusterName(), components, tplNames, keyNames, diff --git a/pkg/cmd/cluster/config_ops.go b/pkg/cmd/cluster/config_ops.go index 81b387c59..e23149ddd 100644 --- a/pkg/cmd/cluster/config_ops.go +++ b/pkg/cmd/cluster/config_ops.go @@ -32,6 +32,7 @@ import ( "sigs.k8s.io/controller-runtime/pkg/client" appsv1alpha1 "github.com/apecloud/kubeblocks/apis/apps/v1alpha1" + appsv1beta1 "github.com/apecloud/kubeblocks/apis/apps/v1beta1" cfgcm "github.com/apecloud/kubeblocks/pkg/configuration/config_manager" "github.com/apecloud/kubeblocks/pkg/configuration/core" "github.com/apecloud/kubeblocks/pkg/controllerutil" @@ -142,7 +143,7 @@ func (o *configOpsOptions) validateConfigParams(tpl *appsv1alpha1.ComponentConfi Namespace: "", Name: tpl.ConfigConstraintRef, } - configConstraint := appsv1alpha1.ConfigConstraint{} + configConstraint := appsv1beta1.ConfigConstraint{} if err := util.GetResourceObjectFromGVR(types.ConfigConstraintGVR(), configConstraintKey, o.Dynamic, &configConstraint); err != nil { return err } @@ -163,7 +164,7 @@ func (o *configOpsOptions) validateConfigParams(tpl *appsv1alpha1.ComponentConfi return o.checkChangedParamsAndDoubleConfirm(&configConstraint.Spec, newConfigData, tpl) } -func (o *configOpsOptions) checkChangedParamsAndDoubleConfirm(cc *appsv1alpha1.ConfigConstraintSpec, data map[string]string, tpl *appsv1alpha1.ComponentConfigSpec) error { +func (o *configOpsOptions) checkChangedParamsAndDoubleConfirm(cc *appsv1beta1.ConfigConstraintSpec, data map[string]string, tpl *appsv1alpha1.ComponentConfigSpec) error { mockEmptyData := func(m map[string]string) map[string]string { r := make(map[string]string, len(data)) for key := range m { @@ -172,11 +173,11 @@ func (o *configOpsOptions) checkChangedParamsAndDoubleConfirm(cc *appsv1alpha1.C return r } - if !cfgcm.IsSupportReload(cc.ReloadOptions) { + if !cfgcm.IsSupportReload(cc.ReloadAction) { return o.confirmReconfigureWithRestart() } - configPatch, restart, err := core.CreateConfigPatch(mockEmptyData(data), data, cc.FormatterConfig.Format, tpl.Keys, o.FileContent != "") + configPatch, restart, err := core.CreateConfigPatch(mockEmptyData(data), data, cc.FileFormatConfig.Format, tpl.Keys, o.FileContent != "") if err != nil { return err } diff --git a/pkg/cmd/cluster/config_ops_test.go b/pkg/cmd/cluster/config_ops_test.go index b9c30d929..e5c595434 100644 --- a/pkg/cmd/cluster/config_ops_test.go +++ b/pkg/cmd/cluster/config_ops_test.go @@ -33,6 +33,7 @@ import ( cmdtesting "k8s.io/kubectl/pkg/cmd/testing" appsv1alpha1 "github.com/apecloud/kubeblocks/apis/apps/v1alpha1" + appsv1beta1 "github.com/apecloud/kubeblocks/apis/apps/v1beta1" cfgcore "github.com/apecloud/kubeblocks/pkg/configuration/core" "github.com/apecloud/kubeblocks/pkg/controller/builder" testapps "github.com/apecloud/kubeblocks/pkg/testutil/apps" @@ -84,7 +85,7 @@ var _ = Describe("reconfigure test", func() { By("Create configmap and config constraint obj") configmap := testapps.NewCustomizedObj("resources/mysql-config-template.yaml", &corev1.ConfigMap{}, testapps.WithNamespace(ns)) constraint := testapps.NewCustomizedObj("resources/mysql-config-constraint.yaml", - &appsv1alpha1.ConfigConstraint{}) + &appsv1beta1.ConfigConstraint{}) componentConfig := testapps.NewConfigMap(ns, cfgcore.GetComponentCfgName(clusterName, statefulCompName, configSpecName), testapps.SetConfigMapData("my.cnf", "")) By("Create a clusterDefinition obj") clusterDefObj := testapps.NewClusterDefFactory(clusterDefName). diff --git a/pkg/cmd/cluster/config_resource.go b/pkg/cmd/cluster/config_resource.go index a231eff05..a1e59a241 100644 --- a/pkg/cmd/cluster/config_resource.go +++ b/pkg/cmd/cluster/config_resource.go @@ -26,6 +26,7 @@ import ( "sigs.k8s.io/controller-runtime/pkg/client" appsv1alpha1 "github.com/apecloud/kubeblocks/apis/apps/v1alpha1" + appsv1beta1 "github.com/apecloud/kubeblocks/apis/apps/v1beta1" "github.com/apecloud/kubeblocks/pkg/configuration/core" "github.com/apecloud/kbcli/pkg/types" @@ -39,7 +40,7 @@ type configSpecMeta struct { ConfigMap *corev1.ConfigMap ConfigSpec *appsv1alpha1.ComponentConfigSpec - ConfigConstraint *appsv1alpha1.ConfigConstraint + ConfigConstraint *appsv1beta1.ConfigConstraint } type ConfigRelatedObjects struct { @@ -116,7 +117,7 @@ func (w *configObjectsWrapper) configConstraint(specName string, out *configSpec Namespace: "", Name: specName, } - out.ConfigConstraint = &appsv1alpha1.ConfigConstraint{} + out.ConfigConstraint = &appsv1beta1.ConfigConstraint{} return util.GetResourceObjectFromGVR(types.ConfigConstraintGVR(), key, w.cli, out.ConfigConstraint) } return w.objectWrapper(fn) diff --git a/pkg/cmd/cluster/config_util_test.go b/pkg/cmd/cluster/config_util_test.go index 36dae8301..c443b8859 100644 --- a/pkg/cmd/cluster/config_util_test.go +++ b/pkg/cmd/cluster/config_util_test.go @@ -27,8 +27,6 @@ import ( "k8s.io/client-go/kubernetes/scheme" cmdtesting "k8s.io/kubectl/pkg/cmd/testing" - appsv1alpha1 "github.com/apecloud/kubeblocks/apis/apps/v1alpha1" - "github.com/apecloud/kbcli/pkg/action" "github.com/apecloud/kbcli/pkg/types" ) @@ -42,11 +40,6 @@ func NewFakeOperationsOptions(ns, cName string, objs ...runtime.Object) (*cmdtes Namespace: ns, } - err := appsv1alpha1.AddToScheme(scheme.Scheme) - if err != nil { - panic(err) - } - // TODO using GroupVersionResource of FakeKubeObjectHelper listMapping := map[schema.GroupVersionResource]string{ types.ClusterDefGVR(): types.KindClusterDef + "List", diff --git a/pkg/cmd/cluster/connect.go b/pkg/cmd/cluster/connect.go index ac81c7c10..2b6778dd2 100644 --- a/pkg/cmd/cluster/connect.go +++ b/pkg/cmd/cluster/connect.go @@ -167,7 +167,7 @@ func (o *ConnectOptions) runShowExample() error { // connect cluster from localhost if o.privateEndPoint { fmt.Fprintf(o.Out, "# cluster %s does not have public endpoints, you can run following command and connect cluster from localhost\n"+ - "kubectl port-forward service/%s %s:%s\n\n", o.clusterName, o.svc.Name, info.Port, info.Port) + "kubectl port-forward -n %s service/%s %s:%s\n\n", o.clusterName, o.Namespace, o.svc.Name, info.Port, info.Port) info.Host = "127.0.0.1" } diff --git a/pkg/cmd/cluster/create.go b/pkg/cmd/cluster/create.go index e2dfeacad..203932ca1 100755 --- a/pkg/cmd/cluster/create.go +++ b/pkg/cmd/cluster/create.go @@ -31,7 +31,6 @@ import ( "strconv" "strings" - "github.com/apecloud/kubeblocks/pkg/controller/component" "github.com/ghodss/yaml" "github.com/robfig/cron/v3" "github.com/spf13/cobra" @@ -54,6 +53,7 @@ import ( appsv1alpha1 "github.com/apecloud/kubeblocks/apis/apps/v1alpha1" dpv1alpha1 "github.com/apecloud/kubeblocks/apis/dataprotection/v1alpha1" + cfgutil "github.com/apecloud/kubeblocks/pkg/configuration/util" "github.com/apecloud/kubeblocks/pkg/constant" "github.com/apecloud/kubeblocks/pkg/dataprotection/restore" @@ -63,7 +63,6 @@ import ( "github.com/apecloud/kbcli/pkg/action" "github.com/apecloud/kbcli/pkg/cluster" - classutil "github.com/apecloud/kbcli/pkg/cmd/class" "github.com/apecloud/kbcli/pkg/printer" "github.com/apecloud/kbcli/pkg/types" "github.com/apecloud/kbcli/pkg/util" @@ -166,7 +165,6 @@ type setKey string const ( keyType setKey = "type" keyCPU setKey = "cpu" - keyClass setKey = "class" keyMemory setKey = "memory" keyReplicas setKey = "replicas" keyStorage setKey = "storage" @@ -174,7 +172,7 @@ const ( keySwitchPolicy setKey = "switchPolicy" keyCompNum setKey = "compNum" keyUnknown setKey = "unknown" - keyMonitor setKey = "monitor" + keyMonitor setKey = "disableExporter" ) var setKeyCfg = map[setKey]string{ @@ -220,8 +218,8 @@ type UpdatableFlags struct { TerminationPolicy string `json:"terminationPolicy"` // Add-on switches for cluster observability - MonitoringInterval uint8 `json:"monitor"` - EnableAllLogs bool `json:"enableAllLogs"` + DisableExporter bool `json:"monitor"` + EnableAllLogs bool `json:"enableAllLogs"` // Configuration and options for cluster affinity and tolerations PodAntiAffinity string `json:"podAntiAffinity"` @@ -293,7 +291,7 @@ func NewCreateCmd(f cmdutil.Factory, streams genericiooptions.IOStreams) *cobra. cmd.Flags().StringVar(&o.ClusterDefRef, "cluster-definition", "", "Specify cluster definition, run \"kbcli cd list\" to show all available cluster definitions") cmd.Flags().StringVar(&o.ClusterVersionRef, "cluster-version", "", "Specify cluster version, run \"kbcli cv list\" to show all available cluster versions, use the latest version if not specified") cmd.Flags().StringVarP(&o.SetFile, "set-file", "f", "", "Use yaml file, URL, or stdin to set the cluster resource") - cmd.Flags().StringArrayVar(&o.Values, "set", []string{}, "Set the cluster resource including cpu, memory, replicas and storage, each set corresponds to a component.(e.g. --set cpu=1,memory=1Gi,replicas=3,storage=20Gi or --set class=general-1c1g)") + cmd.Flags().StringArrayVar(&o.Values, "set", []string{}, "Set the cluster resource including cpu, memory, replicas and storage, each set corresponds to a component.(e.g. --set cpu=1,memory=1Gi,replicas=3,storage=20Gi)") cmd.Flags().BoolVar(&o.CreateOnlySet, "create-only-set", false, "Create components exclusively configured in 'set'") cmd.Flags().StringArrayVar(&o.Storages, "pvc", []string{}, "Set the cluster detail persistent volume claim, each '--pvc' corresponds to a component, and will override the simple configurations about storage by --set (e.g. --pvc type=mysql,name=data,mode=ReadWriteOnce,size=20Gi --pvc type=mysql,name=log,mode=ReadWriteOnce,size=1Gi)") cmd.Flags().StringArrayVar(&o.ServiceRef, "service-reference", []string{}, "Set the other KubeBlocks cluster dependencies, each '--service-reference' corresponds to a cluster service. (e.g --service-reference name=pulsarZookeeper,cluster=zookeeper,namespace=default)") @@ -395,9 +393,9 @@ func fillClusterInfoFromBackup(o *CreateOptions, cls **appsv1alpha1.Cluster) err return nil } -func setBackup(o *CreateOptions, components []map[string]interface{}) error { +func setBackup(o *CreateOptions, cluster *appsv1alpha1.Cluster) error { backupName := o.Backup - if len(backupName) == 0 || len(components) == 0 { + if len(backupName) == 0 { return nil } backup := &dpv1alpha1.Backup{} @@ -412,13 +410,13 @@ func setBackup(o *CreateOptions, components []map[string]interface{}) error { if err != nil { return err } - var componentSpecs []appsv1alpha1.ClusterComponentSpec - for _, v := range components { - compSpec := appsv1alpha1.ClusterComponentSpec{} - _ = runtime.DefaultUnstructuredConverter.FromUnstructured(v, &compSpec) - componentSpecs = append(componentSpecs, compSpec) - } - restoreAnnotation, err := restore.GetRestoreFromBackupAnnotation(backup, componentSpecs, o.VolumeRestorePolicy, restoreTimeStr, false) + // var componentSpecs []appsv1alpha1.ClusterComponentSpec + // for _, v := range components { + // compSpec := appsv1alpha1.ClusterComponentSpec{} + // _ = runtime.DefaultUnstructuredConverter.FromUnstructured(v, &compSpec) + // componentSpecs = append(componentSpecs, compSpec) + // } + restoreAnnotation, err := restore.GetRestoreFromBackupAnnotation(backup, o.VolumeRestorePolicy, restoreTimeStr, false) if err != nil { return err } @@ -550,7 +548,7 @@ func (o *CreateOptions) Complete() error { return err } - if err = setBackup(o, components); err != nil { + if err = setBackup(o, cls); err != nil { return err } o.ComponentSpecs = components @@ -589,10 +587,6 @@ func (o *CreateOptions) buildComponents(clusterCompSpecs []appsv1alpha1.ClusterC if err != nil { return nil, err } - clsMgr, resourceConstraintList, err := classutil.GetManager(o.Dynamic, o.ClusterDefRef) - if err != nil { - return nil, err - } compSets, err := buildCompSetsMap(o.Values, cd) if err != nil { @@ -613,8 +607,6 @@ func (o *CreateOptions) buildComponents(clusterCompSpecs []appsv1alpha1.ClusterC case keyCPU: comp.Resources.Requests[corev1.ResourceCPU] = setComp.Resources.Requests[corev1.ResourceCPU] comp.Resources.Limits[corev1.ResourceCPU] = setComp.Resources.Limits[corev1.ResourceCPU] - case keyClass: - comp.ClassDefRef = setComp.ClassDefRef case keyMemory: comp.Resources.Requests[corev1.ResourceMemory] = setComp.Resources.Requests[corev1.ResourceMemory] comp.Resources.Limits[corev1.ResourceMemory] = setComp.Resources.Limits[corev1.ResourceMemory] @@ -633,7 +625,7 @@ func (o *CreateOptions) buildComponents(clusterCompSpecs []appsv1alpha1.ClusterC } if clusterCompSpecs != nil { - setsCompSpecs, err := buildClusterComp(cd, compSets, clsMgr, o.MonitoringInterval, o.CreateOnlySet) + setsCompSpecs, err := buildClusterComp(cd, compSets, o.DisableExporter, o.CreateOnlySet) if err != nil { return nil, err } @@ -647,7 +639,7 @@ func (o *CreateOptions) buildComponents(clusterCompSpecs []appsv1alpha1.ClusterC compSpecs = append(compSpecs, &comp) } } else { - compSpecs, err = buildClusterComp(cd, compSets, clsMgr, o.MonitoringInterval, o.CreateOnlySet) + compSpecs, err = buildClusterComp(cd, compSets, o.DisableExporter, o.CreateOnlySet) if err != nil { return nil, err } @@ -667,11 +659,6 @@ func (o *CreateOptions) buildComponents(clusterCompSpecs []appsv1alpha1.ClusterC var comps []map[string]interface{} for _, compSpec := range compSpecs { - // validate component classes - if err = classutil.ValidateResources(clsMgr, resourceConstraintList, o.ClusterDefRef, compSpec); err != nil { - return nil, err - } - // cpu oversell if o.CPUOversellRatio > 1 { cpuRequest := compSpec.Resources.Requests[corev1.ResourceCPU] @@ -1006,8 +993,7 @@ func setEnableAllLogs(c *appsv1alpha1.Cluster, cd *appsv1alpha1.ClusterDefinitio func buildClusterComp(cd *appsv1alpha1.ClusterDefinition, setsMap map[string]map[setKey]string, - clsMgr *component.Manager, - monitoringInterval uint8, + disableExporter bool, createOnlySet bool) ([]*appsv1alpha1.ClusterComponentSpec, error) { // get value from set values and environment variables, the second return value is // true if the value is from environment variables @@ -1106,33 +1092,9 @@ func buildClusterComp(cd *appsv1alpha1.ClusterDefinition, Replicas: int32(setReplicas), } - // class has higher priority than other resource related parameters - resourceList := make(corev1.ResourceList) - if clsMgr.HasClass(compObj.ComponentDefRef, component.Any) { - if className := getVal(&c, keyClass, sets); className != "" { - clsDefRef := appsv1alpha1.ClassDefRef{} - parts := strings.SplitN(className, ":", 2) - if len(parts) == 1 { - clsDefRef.Class = parts[0] - } else { - clsDefRef.Name = parts[0] - clsDefRef.Class = parts[1] - } - compObj.ClassDefRef = &clsDefRef - } else { - resourceList = corev1.ResourceList{ - corev1.ResourceCPU: resource.MustParse(getVal(&c, keyCPU, sets)), - corev1.ResourceMemory: resource.MustParse(getVal(&c, keyMemory, sets)), - } - } - } else { - if className := getVal(&c, keyClass, sets); className != "" { - return nil, fmt.Errorf("can not find class %s for component type %s", className, c.Name) - } - resourceList = corev1.ResourceList{ - corev1.ResourceCPU: resource.MustParse(getVal(&c, keyCPU, sets)), - corev1.ResourceMemory: resource.MustParse(getVal(&c, keyMemory, sets)), - } + resourceList := corev1.ResourceList{ + corev1.ResourceCPU: resource.MustParse(getVal(&c, keyCPU, sets)), + corev1.ResourceMemory: resource.MustParse(getVal(&c, keyMemory, sets)), } compObj.Resources = corev1.ResourceRequirements{ // deepcopy to make requests and limits point to different resources @@ -1173,12 +1135,13 @@ func buildClusterComp(cd *appsv1alpha1.ClusterDefinition, // set component monitor monitor := getVal(&c, keyMonitor, sets) if monitor == "" { - compObj.Monitor = monitoringInterval != 0 + compObj.DisableExporter = cfgutil.ToPointer(disableExporter) } else { - compObj.Monitor, err = strconv.ParseBool(monitor) + enabled, err := strconv.ParseBool(monitor) if err != nil { return nil, fmt.Errorf("parsing monitor failed: %s", err.Error()) } + compObj.DisableExporter = cfgutil.ToPointer(enabled) } comps = append(comps, compObj) compNum := 0 @@ -1303,7 +1266,7 @@ func generateClusterName(dynamic dynamic.Interface, namespace string) (string, e func (f *UpdatableFlags) addFlags(cmd *cobra.Command) { cmd.Flags().StringVar(&f.PodAntiAffinity, "pod-anti-affinity", "Preferred", "Pod anti-affinity type, one of: (Preferred, Required)") - cmd.Flags().Uint8Var(&f.MonitoringInterval, "monitoring-interval", 0, "The monitoring interval of cluster, 0 is disabled, the unit is second, any non-zero value means enabling monitoring.") + cmd.Flags().BoolVar(&f.DisableExporter, "disable-exporter", true, "Enable or disable monitoring") cmd.Flags().BoolVar(&f.EnableAllLogs, "enable-all-logs", false, "Enable advanced application all log extraction, set to true will ignore enabledLogs of component level, default is false") cmd.Flags().StringVar(&f.TerminationPolicy, "termination-policy", "Delete", "Termination policy, one of: (DoNotTerminate, Halt, Delete, WipeOut)") cmd.Flags().StringArrayVar(&f.TopologyKeys, "topology-keys", nil, "Topology keys for affinity") @@ -1621,7 +1584,6 @@ func setKeys() []string { string(keyStorage), string(keyMemory), string(keyReplicas), - string(keyClass), string(keyStorageClass), string(keySwitchPolicy), string(keyMonitor), diff --git a/pkg/cmd/cluster/create_subcmds.go b/pkg/cmd/cluster/create_subcmds.go index 5852a30fa..f8aceb787 100644 --- a/pkg/cmd/cluster/create_subcmds.go +++ b/pkg/cmd/cluster/create_subcmds.go @@ -155,14 +155,10 @@ func (o *CreateSubCmdsOptions) complete(cmd *cobra.Command) error { } func (o *CreateSubCmdsOptions) validate() error { - if err := o.validateVersion(); err != nil { - return err - } return cluster.ValidateValues(o.ChartInfo, o.Values) } func (o *CreateSubCmdsOptions) Run() error { - objs, err := o.getObjectsInfo() if err != nil { return err @@ -240,44 +236,6 @@ func (o *CreateSubCmdsOptions) Run() error { return nil } -func (o *CreateSubCmdsOptions) validateVersion() error { - var err error - cv, ok := o.Values[cluster.VersionSchemaProp.String()].(string) - if ok && cv != "" { - if err = cluster.ValidateClusterVersion(o.Dynamic, o.ChartInfo.ClusterDef, cv); err == nil { - return nil - } - if err = cluster.ValidateClusterVersionByComponentDef(o.Dynamic, o.ChartInfo.ComponentDef, cv); err == nil { - return nil - } - return fmt.Errorf("cluster version \"%s\" does not exist", cv) - } - if o.ChartInfo.ClusterDef != "" { - cv, _ = cluster.GetDefaultVersion(o.Dynamic, o.ChartInfo.ClusterDef) - } - if len(o.ChartInfo.ComponentDef) != 0 { - cv, _ = cluster.GetDefaultVersionByCompDefs(o.Dynamic, o.ChartInfo.ComponentDef) - } - if cv == "" { - return fmt.Errorf(": failed to find default cluster version referencing cluster definition or component definition") - } - - // set cluster version - o.Values[cluster.VersionSchemaProp.String()] = cv - - dryRun, err := o.GetDryRunStrategy() - if err != nil { - return err - } - // if dryRun is set, run in quiet mode, avoid to output yaml file with the info - if dryRun != action.DryRunNone { - return nil - } - - fmt.Fprintf(o.Out, "Info: --version is not specified, %s is applied by default.\n", cv) - return nil -} - // getObjectsInfo returns all objects in helm charts along with their GVK information. func (o *CreateSubCmdsOptions) getObjectsInfo() ([]*objectInfo, error) { // move values that belong to sub chart to sub map diff --git a/pkg/cmd/cluster/create_test.go b/pkg/cmd/cluster/create_test.go index 284eec4ea..89bf4d58b 100644 --- a/pkg/cmd/cluster/create_test.go +++ b/pkg/cmd/cluster/create_test.go @@ -28,7 +28,6 @@ import ( "strings" "time" - "github.com/apecloud/kubeblocks/pkg/controller/component" . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" corev1 "k8s.io/api/core/v1" @@ -65,8 +64,6 @@ func getResource(res corev1.ResourceRequirements, name corev1.ResourceName) inte } var _ = Describe("create", func() { - var clsMgr = &component.Manager{} - Context("setEnableAllLogs Test", func() { var cluster *appsv1alpha1.Cluster var clusterDef *appsv1alpha1.ClusterDefinition @@ -140,13 +137,12 @@ var _ = Describe("create", func() { } else { Expect(*comp.VolumeClaimTemplates[0].Spec.StorageClassName).Should(Equal(storageClassName)) } - } It("build default cluster component without environment", func() { dynamic := testing.FakeDynamicClient(testing.FakeClusterDef()) cd, _ := cluster.GetClusterDefByName(dynamic, testing.ClusterDefName) - comps, err := buildClusterComp(cd, nil, clsMgr, 15, false) + comps, err := buildClusterComp(cd, nil, true, false) Expect(err).ShouldNot(HaveOccurred()) checkComponent(comps, "20Gi", 1, "1", "1Gi", "", 0) }) @@ -158,7 +154,7 @@ var _ = Describe("create", func() { viper.Set(types.CfgKeyClusterDefaultMemory, "2Gi") dynamic := testing.FakeDynamicClient(testing.FakeClusterDef()) cd, _ := cluster.GetClusterDefByName(dynamic, testing.ClusterDefName) - comps, err := buildClusterComp(cd, nil, clsMgr, 15, false) + comps, err := buildClusterComp(cd, nil, true, false) Expect(err).ShouldNot(HaveOccurred()) checkComponent(comps, "5Gi", 1, "2", "2Gi", "", 0) }) @@ -175,13 +171,13 @@ var _ = Describe("create", func() { keyStorageClass: "test", }, } - comps, err := buildClusterComp(cd, setsMap, clsMgr, 0, false) + comps, err := buildClusterComp(cd, setsMap, false, false) Expect(err).Should(Succeed()) checkComponent(comps, "10Gi", 10, "10", "2Gi", "test", 0) setsMap[testing.ComponentDefName][keySwitchPolicy] = "invalid" cd.Spec.ComponentDefs[0].WorkloadType = appsv1alpha1.Replication - _, err = buildClusterComp(cd, setsMap, clsMgr, 0, false) + _, err = buildClusterComp(cd, setsMap, false, false) Expect(err).Should(HaveOccurred()) }) @@ -203,13 +199,13 @@ var _ = Describe("create", func() { keyStorageClass: "test-other", }, } - comps, err := buildClusterComp(cd, setsMap, clsMgr, 15, false) + comps, err := buildClusterComp(cd, setsMap, true, false) Expect(err).Should(Succeed()) checkComponent(comps, "10Gi", 10, "10", "2Gi", "test", 0) checkComponent(comps, "5Gi", 5, "5", "1Gi", "test-other", 1) setsMap[testing.ComponentDefName][keySwitchPolicy] = "invalid" cd.Spec.ComponentDefs[0].WorkloadType = appsv1alpha1.Replication - _, err = buildClusterComp(cd, setsMap, clsMgr, 15, false) + _, err = buildClusterComp(cd, setsMap, true, false) Expect(err).Should(HaveOccurred()) }) @@ -250,14 +246,13 @@ var _ = Describe("create", func() { true, }, { - []string{"cpu=1,memory=2Gi,storage=10Gi,class=general-1c2g"}, + []string{"cpu=1,memory=2Gi,storage=10Gi"}, []string{"my-comp"}, map[string]map[setKey]string{ "my-comp": { keyCPU: "1", keyMemory: "2Gi", keyStorage: "10Gi", - keyClass: "general-1c2g", }, }, true, @@ -316,20 +311,18 @@ var _ = Describe("create", func() { true, }, { - []string{"type=comp1,cpu=1,memory=2Gi,class=general-2c4g", "type=comp2,storage=10Gi,cpu=2,class=mo-1c8g,replicas=3"}, + []string{"type=comp1,cpu=1,memory=2Gi", "type=comp2,storage=10Gi,cpu=2,replicas=3"}, []string{"comp1", "comp2"}, map[string]map[setKey]string{ "comp1": { keyType: "comp1", keyCPU: "1", keyMemory: "2Gi", - keyClass: "general-2c4g", }, "comp2": { keyType: "comp2", keyCPU: "2", keyStorage: "10Gi", - keyClass: "mo-1c8g", keyReplicas: "3", }, }, @@ -393,16 +386,16 @@ var _ = Describe("create", func() { o.Dynamic = dynamic o.Namespace = testing.Namespace o.Backup = backupName - components := []map[string]interface{}{ - { - "name": "mysql", - }, - } - Expect(setBackup(o, components).Error()).Should(ContainSubstring("is not completed")) + // components := []map[string]interface{}{ + // { + // "name": "mysql", + // }, + // } + Expect(setBackup(o, cluster).Error()).Should(ContainSubstring("is not completed")) By("test backup is completed") mockBackupInfo(dynamic, backupName, clusterName, nil, "") - Expect(setBackup(o, components)).Should(Succeed()) + Expect(setBackup(o, cluster)).Should(Succeed()) }) It("test fillClusterMetadataFromBackup", func() { @@ -650,7 +643,7 @@ var _ = Describe("create", func() { }) It("rebuild clusterComponentSpec VolumeClaimTemplates by --pvc", func() { - comps, err := buildClusterComp(mockCD([]string{"comp1", "comp2"}), nil, clsMgr, 0, false) + comps, err := buildClusterComp(mockCD([]string{"comp1", "comp2"}), nil, false, false) Expect(err).Should(Succeed()) Expect(comps).ShouldNot(BeNil()) diff --git a/pkg/cmd/cluster/dataprotection.go b/pkg/cmd/cluster/dataprotection.go index 2d2bbb233..14b1fac73 100644 --- a/pkg/cmd/cluster/dataprotection.go +++ b/pkg/cmd/cluster/dataprotection.go @@ -126,11 +126,11 @@ var ( const TrueValue = "true" type CreateBackupOptions struct { - BackupSpec appsv1alpha1.BackupSpec `json:"backupSpec"` - ClusterRef string `json:"clusterRef"` - OpsType string `json:"opsType"` - OpsRequestName string `json:"opsRequestName"` - Force bool `json:"force"` + BackupSpec appsv1alpha1.Backup `json:"backupSpec"` + ClusterName string `json:"clusterName"` + OpsType string `json:"opsType"` + OpsRequestName string `json:"opsRequestName"` + Force bool `json:"force"` action.CreateOptions `json:"-"` } @@ -162,10 +162,10 @@ func (o *CreateBackupOptions) CompleteBackup() error { o.BackupSpec.BackupName = strings.Join([]string{"backup", o.Namespace, o.Name, time.Now().Format("20060102150405")}, "-") } - // set ops type, ops request name and clusterRef + // set ops type, ops request name and clusterName o.OpsType = string(appsv1alpha1.BackupType) o.OpsRequestName = o.BackupSpec.BackupName - o.ClusterRef = o.Name + o.ClusterName = o.Name return o.CreateOptions.Complete() } @@ -191,6 +191,21 @@ func (o *CreateBackupOptions) Validate() error { if o.BackupSpec.BackupMethod == "" { return fmt.Errorf("backup method can not be empty, you can specify it by --method") } + + // check if the backup method exists in backup policy + exist, availableMethods := false, make([]string, 0) + for _, method := range backupPolicy.Spec.BackupMethods { + availableMethods = append(availableMethods, method.Name) + if o.BackupSpec.BackupMethod == method.Name { + exist = true + break + } + } + if !exist { + return fmt.Errorf("specified backup method %s does not exist in backup policy %s, available methods: [%s]", + o.BackupSpec.BackupMethod, backupPolicy.Name, strings.Join(availableMethods, ", ")) + } + // TODO: check if pvc exists // valid retention period @@ -410,7 +425,7 @@ func PrintBackupList(o ListBackupOptions) error { } } if availableReplicas != nil { - statusString = fmt.Sprintf("%s(AvailablePods: %d)", statusString, availableReplicas) + statusString = fmt.Sprintf("%s(AvailablePods: %d)", statusString, *availableReplicas) } tbl.AddRow(backup.Name, backup.Namespace, sourceCluster, backup.Spec.BackupMethod, statusString, backup.Status.TotalSize, durationStr, util.TimeFormat(&backup.CreationTimestamp), util.TimeFormat(backup.Status.CompletionTimestamp), @@ -504,11 +519,11 @@ func completeForDeleteBackup(o *action.DeleteOptions, args []string) error { } type CreateRestoreOptions struct { - RestoreSpec appsv1alpha1.RestoreSpec `json:"restoreSpec"` - ClusterRef string `json:"clusterRef"` - OpsType string `json:"opsType"` - OpsRequestName string `json:"opsRequestName"` - Force bool `json:"force"` + RestoreSpec appsv1alpha1.Restore `json:"restoreSpec"` + ClusterName string `json:"clusterName"` + OpsType string `json:"opsType"` + OpsRequestName string `json:"opsRequestName"` + Force bool `json:"force"` action.CreateOptions `json:"-"` } @@ -529,9 +544,9 @@ func (o *CreateRestoreOptions) Validate() error { o.Name = name } - // set ops type, ops request name and clusterRef + // set ops type, ops request name and clusterName o.OpsType = string(appsv1alpha1.RestoreType) - o.ClusterRef = o.Name + o.ClusterName = o.Name o.OpsRequestName = o.Name return nil @@ -567,7 +582,7 @@ func NewCreateRestoreCmd(f cmdutil.Factory, streams genericiooptions.IOStreams) } cmd.Flags().StringVar(&o.RestoreSpec.BackupName, "backup", "", "Backup name") - cmd.Flags().StringVar(&o.RestoreSpec.RestoreTimeStr, "restore-to-time", "", "point in time recovery(PITR)") + cmd.Flags().StringVar(&o.RestoreSpec.RestorePointInTime, "restore-to-time", "", "point in time recovery(PITR)") cmd.Flags().StringVar(&o.RestoreSpec.VolumeRestorePolicy, "volume-restore-policy", "Parallel", "the volume claim restore policy, supported values: [Serial, Parallel]") return cmd } diff --git a/pkg/cmd/cluster/dataprotection_test.go b/pkg/cmd/cluster/dataprotection_test.go index cc793b389..303fac5eb 100644 --- a/pkg/cmd/cluster/dataprotection_test.go +++ b/pkg/cmd/cluster/dataprotection_test.go @@ -243,7 +243,7 @@ var _ = Describe("DataProtection", func() { CueTemplateName: "backup_template.cue", Name: testing.ClusterName, }, - BackupSpec: appsv1alpha1.BackupSpec{ + BackupSpec: appsv1alpha1.Backup{ BackupPolicyName: otherBackupPolicy.Name, BackupMethod: testing.BackupMethodName, }, diff --git a/pkg/cmd/cluster/delete_ops_test.go b/pkg/cmd/cluster/delete_ops_test.go index 385b5b890..8fd82f2eb 100644 --- a/pkg/cmd/cluster/delete_ops_test.go +++ b/pkg/cmd/cluster/delete_ops_test.go @@ -62,8 +62,8 @@ var _ = Describe("Expose", func() { Namespace: namespace, }, Spec: appsv1alpha1.OpsRequestSpec{ - ClusterRef: "test-cluster", - Type: "Restart", + ClusterName: "test-cluster", + Type: "Restart", }, Status: appsv1alpha1.OpsRequestStatus{ Phase: phase, diff --git a/pkg/cmd/cluster/describe.go b/pkg/cmd/cluster/describe.go index 5f1419ac8..3434d75da 100644 --- a/pkg/cmd/cluster/describe.go +++ b/pkg/cmd/cluster/describe.go @@ -23,8 +23,11 @@ import ( "context" "fmt" "io" + "sort" "strings" + "time" + "github.com/apecloud/kubeblocks/pkg/constant" "github.com/spf13/cobra" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -38,6 +41,7 @@ import ( appsv1alpha1 "github.com/apecloud/kubeblocks/apis/apps/v1alpha1" dpv1alpha1 "github.com/apecloud/kubeblocks/apis/dataprotection/v1alpha1" + dptypes "github.com/apecloud/kubeblocks/pkg/dataprotection/types" "github.com/apecloud/kubeblocks/pkg/dataprotection/utils/boolptr" "github.com/apecloud/kbcli/pkg/cluster" @@ -169,7 +173,11 @@ func (o *describeOptions) describeCluster(name string) error { if err != nil { return err } - showDataProtection(o.BackupPolicies, o.BackupSchedules, defaultBackupRepo, o.Out) + recoverableTime, continuousMethod, err := o.getBackupRecoverableTime() + if err != nil { + return err + } + showDataProtection(o.BackupPolicies, o.BackupSchedules, defaultBackupRepo, continuousMethod, recoverableTime, o.Out) // events showEvents(o.Cluster.Name, o.Cluster.Namespace, o.Out) @@ -251,11 +259,17 @@ func showEndpoints(c *appsv1alpha1.Cluster, svcList *corev1.ServiceList, out io. tbl.Print() } -func showDataProtection(backupPolicies []dpv1alpha1.BackupPolicy, backupSchedules []dpv1alpha1.BackupSchedule, defaultBackupRepo string, out io.Writer) { +func showDataProtection(backupPolicies []dpv1alpha1.BackupPolicy, backupSchedules []dpv1alpha1.BackupSchedule, defaultBackupRepo, continuousMethod, recoverableTimeRange string, out io.Writer) { if len(backupPolicies) == 0 || len(backupSchedules) == 0 { return } - tbl := newTbl(out, "\nData Protection:", "BACKUP-REPO", "AUTO-BACKUP", "BACKUP-SCHEDULE", "BACKUP-METHOD", "BACKUP-RETENTION") + tbl := newTbl(out, "\nData Protection:", "BACKUP-REPO", "AUTO-BACKUP", "BACKUP-SCHEDULE", "BACKUP-METHOD", "BACKUP-RETENTION", "RECOVERABLE-TIME") + getEnableString := func(enable bool) string { + if enable { + return "Enabled" + } + return "Disabled" + } for _, schedule := range backupSchedules { backupRepo := defaultBackupRepo for _, policy := range backupPolicies { @@ -267,34 +281,80 @@ func showDataProtection(backupPolicies []dpv1alpha1.BackupPolicy, backupSchedule } } for _, schedulePolicy := range schedule.Spec.Schedules { - if !boolptr.IsSetToTrue(schedulePolicy.Enabled) { - continue + if recoverableTimeRange != "" && continuousMethod == schedulePolicy.BackupMethod { + // continuous backup with recoverable time + tbl.AddRow(backupRepo, getEnableString(boolptr.IsSetToTrue(schedulePolicy.Enabled)), schedulePolicy.CronExpression, schedulePolicy.BackupMethod, schedulePolicy.RetentionPeriod.String(), recoverableTimeRange) + } else if boolptr.IsSetToTrue(schedulePolicy.Enabled) { + tbl.AddRow(backupRepo, "Enabled", schedulePolicy.CronExpression, schedulePolicy.BackupMethod, schedulePolicy.RetentionPeriod.String(), "") } - - tbl.AddRow(backupRepo, "Enabled", schedulePolicy.CronExpression, schedulePolicy.BackupMethod, schedulePolicy.RetentionPeriod.String()) } } tbl.Print() } -// getBackupRecoverableTime returns the recoverable time range string -// func getBackupRecoverableTime(backups []dpv1alpha1.Backup) string { -// recoverabelTime := dpv1alpha1.GetRecoverableTimeRange(backups) -// var result string -// for _, i := range recoverabelTime { -// result = addTimeRange(result, i.StartTime, i.StopTime) -// } -// if result == "" { -// return printer.NoneString -// } -// return result -// } - -// func addTimeRange(result string, start, end *metav1.Time) string { -// if result != "" { -// result += ", " -// } -// result += fmt.Sprintf("%s ~ %s", util.TimeFormatWithDuration(start, time.Second), -// util.TimeFormatWithDuration(end, time.Second)) -// return result -// } +// getBackupRecoverableTime returns the recoverable time range string +func (o *describeOptions) getBackupRecoverableTime() (string, string, error) { + continuousBackups, err := o.getBackupList(dpv1alpha1.BackupTypeContinuous) + if err != nil { + return "", "", err + } + if len(continuousBackups) == 0 { + return "", "", nil + } + continuousBackup := continuousBackups[0] + if continuousBackup.GetStartTime() == nil || continuousBackup.GetEndTime() == nil { + return "", "", nil + } + fullBackups, err := o.getBackupList(dpv1alpha1.BackupTypeFull) + if err != nil { + return "", "", err + } + isTimeInRange := func(t metav1.Time, start *metav1.Time, end *metav1.Time) bool { + return !t.Before(start) && !t.After(end.Time) + } + sortBackup(fullBackups, false) + for _, backup := range fullBackups { + completeTime := backup.GetEndTime() + if completeTime != nil && isTimeInRange(*completeTime, continuousBackup.GetStartTime(), continuousBackup.GetEndTime()) { + return fmt.Sprintf("%s ~ %s", util.TimeFormatWithDuration(completeTime, time.Second), + util.TimeFormatWithDuration(continuousBackup.GetEndTime(), time.Second)), continuousBackup.Spec.BackupMethod, nil + } + } + return "", "", nil +} + +func (o *describeOptions) getBackupList(backupType dpv1alpha1.BackupType) ([]*dpv1alpha1.Backup, error) { + backupList, err := o.dynamic.Resource(types.BackupGVR()).Namespace(o.namespace).List(context.TODO(), metav1.ListOptions{ + LabelSelector: fmt.Sprintf("%s=%s,%s=%s", + constant.AppInstanceLabelKey, o.Cluster.Name, + dptypes.BackupTypeLabelKey, backupType), + }) + if err != nil { + return nil, err + } + var backups []*dpv1alpha1.Backup + for i := range backupList.Items { + fullBackup := &dpv1alpha1.Backup{} + if err = runtime.DefaultUnstructuredConverter.FromUnstructured(backupList.Items[i].Object, fullBackup); err != nil { + return nil, err + } + backups = append(backups, fullBackup) + } + return backups, nil +} + +func sortBackup(backups []*dpv1alpha1.Backup, reverse bool) []*dpv1alpha1.Backup { + sort.Slice(backups, func(i, j int) bool { + if reverse { + i, j = j, i + } + if backups[i].GetEndTime() == nil { + return false + } + if backups[j].GetEndTime() == nil { + return true + } + return backups[i].GetEndTime().Before(backups[j].GetEndTime()) + }) + return backups +} diff --git a/pkg/cmd/cluster/describe_ops.go b/pkg/cmd/cluster/describe_ops.go index 4f9db51f5..2a1d0892c 100644 --- a/pkg/cmd/cluster/describe_ops.go +++ b/pkg/cmd/cluster/describe_ops.go @@ -166,7 +166,7 @@ func (o *describeOpsOptions) printOpsRequest(ops *appsv1alpha1.OpsRequest) error // first pair string printer.NewPair(" Name", ops.Name), printer.NewPair("NameSpace", ops.Namespace), - printer.NewPair("Cluster", ops.Spec.ClusterRef), + printer.NewPair("Cluster", ops.Spec.GetClusterName()), printer.NewPair("Type", string(ops.Spec.Type)), ) @@ -234,7 +234,7 @@ func (o *describeOpsOptions) getRestartCommand(spec appsv1alpha1.OpsRequestSpec) componentNames[i] = v.ComponentName } return []string{ - fmt.Sprintf("kbcli cluster restart %s --components=%s", spec.ClusterRef, + fmt.Sprintf("kbcli cluster restart %s --components=%s", spec.GetClusterName(), strings.Join(componentNames, ",")), } } @@ -242,7 +242,7 @@ func (o *describeOpsOptions) getRestartCommand(spec appsv1alpha1.OpsRequestSpec) // getUpgradeCommand gets the command of the Upgrade OpsRequest. func (o *describeOpsOptions) getUpgradeCommand(spec appsv1alpha1.OpsRequestSpec) []string { return []string{ - fmt.Sprintf("kbcli cluster upgrade %s --cluster-version=%s", spec.ClusterRef, + fmt.Sprintf("kbcli cluster upgrade %s --cluster-version=%v", spec.GetClusterName(), spec.Upgrade.ClusterVersionRef), } } @@ -271,19 +271,10 @@ func (o *describeOpsOptions) getVerticalScalingCommand(spec appsv1alpha1.OpsRequ commands := make([]string, len(componentNameSlice)) for i := range componentNameSlice { commands[i] = fmt.Sprintf("kbcli cluster vscale %s --components=%s", - spec.ClusterRef, strings.Join(componentNameSlice[i], ",")) - clsRef := spec.VerticalScalingList[i].ClassDefRef - if clsRef != nil { - class := clsRef.Class - if clsRef.Name != "" { - class = fmt.Sprintf("%s:%s", clsRef.Name, class) - } - commands[i] += fmt.Sprintf("--class=%s", class) - } else { - resource := resourceSlice[i].(corev1.ResourceRequirements) - commands[i] += o.addResourceFlag("cpu", resource.Limits.Cpu()) - commands[i] += o.addResourceFlag("memory", resource.Limits.Memory()) - } + spec.GetClusterName(), strings.Join(componentNameSlice[i], ",")) + resource := resourceSlice[i].(corev1.ResourceRequirements) + commands[i] += o.addResourceFlag("cpu", resource.Limits.Cpu()) + commands[i] += o.addResourceFlag("memory", resource.Limits.Memory()) } return commands } @@ -304,7 +295,7 @@ func (o *describeOpsOptions) getHorizontalScalingCommand(spec appsv1alpha1.OpsRe commands := make([]string, len(componentNameSlice)) for i := range componentNameSlice { commands[i] = fmt.Sprintf("kbcli cluster hscale %s --components=%s --replicas=%d", - spec.ClusterRef, strings.Join(componentNameSlice[i], ","), replicasSlice[i].(int32)) + spec.GetClusterName(), strings.Join(componentNameSlice[i], ","), replicasSlice[i].(int32)) } return commands } @@ -324,7 +315,7 @@ func (o *describeOpsOptions) getVolumeExpansionCommand(spec appsv1alpha1.OpsRequ for i := range vctNameSlice { storage := storageSlice[i].(resource.Quantity) commands = append(commands, fmt.Sprintf("kbcli cluster volume-expand %s --components=%s --volume-claim-template-names=%s --storage=%s", - spec.ClusterRef, v.ComponentName, strings.Join(vctNameSlice[i], ","), storage.String())) + spec.GetClusterName(), v.ComponentName, strings.Join(vctNameSlice[i], ","), storage.String())) } } return commands @@ -333,7 +324,7 @@ func (o *describeOpsOptions) getVolumeExpansionCommand(spec appsv1alpha1.OpsRequ // getReconfiguringCommand gets the command of the VolumeExpansion command. func (o *describeOpsOptions) getReconfiguringCommand(spec appsv1alpha1.OpsRequestSpec) []string { if spec.Reconfigure != nil { - return generateReconfiguringCommand(spec.ClusterRef, spec.Reconfigure, []string{spec.Reconfigure.ComponentName}) + return generateReconfiguringCommand(spec.GetClusterName(), spec.Reconfigure, []string{spec.Reconfigure.ComponentName}) } if len(spec.Reconfigures) == 0 { @@ -343,10 +334,10 @@ func (o *describeOpsOptions) getReconfiguringCommand(spec appsv1alpha1.OpsReques for i, reconfigure := range spec.Reconfigures { components[i] = reconfigure.ComponentName } - return generateReconfiguringCommand(spec.ClusterRef, &spec.Reconfigures[0], components) + return generateReconfiguringCommand(spec.GetClusterName(), &spec.Reconfigures[0], components) } -func generateReconfiguringCommand(clusterRef string, updatedParams *appsv1alpha1.Reconfigure, components []string) []string { +func generateReconfiguringCommand(clusterName string, updatedParams *appsv1alpha1.Reconfigure, components []string) []string { if len(updatedParams.Configurations) == 0 { return nil } @@ -360,7 +351,7 @@ func generateReconfiguringCommand(clusterRef string, updatedParams *appsv1alpha1 commandArgs = append(commandArgs, "kbcli") commandArgs = append(commandArgs, "cluster") commandArgs = append(commandArgs, "configure") - commandArgs = append(commandArgs, clusterRef) + commandArgs = append(commandArgs, clusterName) commandArgs = append(commandArgs, fmt.Sprintf("--components=%s", strings.Join(components, ","))) commandArgs = append(commandArgs, fmt.Sprintf("--config-spec=%s", configuration.Name)) diff --git a/pkg/cmd/cluster/describe_ops_test.go b/pkg/cmd/cluster/describe_ops_test.go index 818919bde..95cabd169 100644 --- a/pkg/cmd/cluster/describe_ops_test.go +++ b/pkg/cmd/cluster/describe_ops_test.go @@ -38,8 +38,10 @@ import ( "k8s.io/client-go/kubernetes/scheme" clientfake "k8s.io/client-go/rest/fake" cmdtesting "k8s.io/kubectl/pkg/cmd/testing" + "k8s.io/utils/pointer" appsv1alpha1 "github.com/apecloud/kubeblocks/apis/apps/v1alpha1" + cfgutil "github.com/apecloud/kubeblocks/pkg/configuration/util" clitesting "github.com/apecloud/kbcli/pkg/testing" "github.com/apecloud/kbcli/pkg/types" @@ -111,8 +113,8 @@ var _ = Describe("Expose", func() { Namespace: namespace, }, Spec: appsv1alpha1.OpsRequestSpec{ - ClusterRef: "test-cluster", - Type: opsType, + ClusterName: "test-cluster", + Type: opsType, }, } } @@ -194,7 +196,7 @@ var _ = Describe("Expose", func() { By("test describe Upgrade") describeOps(appsv1alpha1.UpgradeType, func(ops *appsv1alpha1.OpsRequest) { ops.Spec.Upgrade = &appsv1alpha1.Upgrade{ - ClusterVersionRef: clusterVersionName, + ClusterVersionRef: cfgutil.ToPointer(clusterVersionName), } }) @@ -238,7 +240,7 @@ var _ = Describe("Expose", func() { ComponentOps: appsv1alpha1.ComponentOps{ ComponentName: componentName, }, - Replicas: 1, + Replicas: pointer.Int32(1), }, } }) diff --git a/pkg/cmd/cluster/describe_test.go b/pkg/cmd/cluster/describe_test.go index e0037266f..94f029db4 100644 --- a/pkg/cmd/cluster/describe_test.go +++ b/pkg/cmd/cluster/describe_test.go @@ -121,7 +121,7 @@ var _ = Describe("Expose", func() { *testing.FakeBackupSchedule("backup-schedule-test", "backup-policy-test"), } - showDataProtection(fakeBackupPolicies, fakeBackupSchedules, "test-repository", out) + showDataProtection(fakeBackupPolicies, fakeBackupSchedules, "test-repository", "", "", out) strs := strings.Split(out.String(), "\n") Expect(strs).ShouldNot(BeEmpty()) }) diff --git a/pkg/cmd/cluster/errors.go b/pkg/cmd/cluster/errors.go index 195a78547..4459d652b 100644 --- a/pkg/cmd/cluster/errors.go +++ b/pkg/cmd/cluster/errors.go @@ -30,7 +30,7 @@ var ( missingClusterArgErrMassage = "cluster name should be specified, using --help." missingUpdatedParametersErrMessage = "missing updated parameters, using --help." - multiComponentsErrorMessage = "when multi components exist, specify a component, using --component" + multiComponentsErrorMessage = "when multi components exist, specify a component, using --components" multiConfigTemplateErrorMessage = "when multi config templates exist, specify a config template, using --config-spec" multiConfigFileErrorMessage = "when multi config files exist, specify a config file, using --config-file" diff --git a/pkg/cmd/cluster/list_ops.go b/pkg/cmd/cluster/list_ops.go index ae1f79695..00776725b 100644 --- a/pkg/cmd/cluster/list_ops.go +++ b/pkg/cmd/cluster/list_ops.go @@ -133,7 +133,7 @@ func (o *opsListOptions) printOpsList() error { opsType := string(ops.Spec.Type) if len(o.opsRequestName) != 0 { if ops.Name == o.opsRequestName { - tblPrinter.AddRow(ops.Name, ops.GetNamespace(), opsType, ops.Spec.ClusterRef, getComponentNameFromOps(ops), phase, ops.Status.Progress, util.TimeFormat(&ops.CreationTimestamp)) + tblPrinter.AddRow(ops.Name, ops.GetNamespace(), opsType, ops.Spec.GetClusterName(), getComponentNameFromOps(ops), phase, ops.Status.Progress, util.TimeFormat(&ops.CreationTimestamp)) } continue } @@ -145,7 +145,7 @@ func (o *opsListOptions) printOpsList() error { if len(o.opsType) != 0 && !o.containsIgnoreCase(o.opsType, opsType) { continue } - tblPrinter.AddRow(ops.Name, ops.GetNamespace(), opsType, ops.Spec.ClusterRef, getComponentNameFromOps(ops), phase, ops.Status.Progress, util.TimeFormat(&ops.CreationTimestamp)) + tblPrinter.AddRow(ops.Name, ops.GetNamespace(), opsType, ops.Spec.GetClusterName(), getComponentNameFromOps(ops), phase, ops.Status.Progress, util.TimeFormat(&ops.CreationTimestamp)) } if tblPrinter.Tbl.Length() != 0 { tblPrinter.Print() diff --git a/pkg/cmd/cluster/list_ops_test.go b/pkg/cmd/cluster/list_ops_test.go index 6471a5368..5d3f3408c 100644 --- a/pkg/cmd/cluster/list_ops_test.go +++ b/pkg/cmd/cluster/list_ops_test.go @@ -73,8 +73,8 @@ var _ = Describe("Expose", func() { Namespace: namespace, }, Spec: appsv1alpha1.OpsRequestSpec{ - ClusterRef: "test-cluster", - Type: opsType, + ClusterName: "test-cluster", + Type: opsType, }, Status: appsv1alpha1.OpsRequestStatus{ Phase: phase, diff --git a/pkg/cmd/cluster/operations.go b/pkg/cmd/cluster/operations.go index 3211c3bb7..b66ae46d0 100755 --- a/pkg/cmd/cluster/operations.go +++ b/pkg/cmd/cluster/operations.go @@ -49,7 +49,6 @@ import ( "github.com/apecloud/kbcli/pkg/action" "github.com/apecloud/kbcli/pkg/cluster" - classutil "github.com/apecloud/kbcli/pkg/cmd/class" "github.com/apecloud/kbcli/pkg/printer" "github.com/apecloud/kbcli/pkg/types" "github.com/apecloud/kbcli/pkg/util" @@ -76,13 +75,13 @@ type OperationsOptions struct { OpsTypeLower string `json:"typeLower"` // Upgrade options - ClusterVersionRef string `json:"clusterVersionRef"` + ClusterVersionRef string `json:"clusterVersionRef"` + ComponentDefinitionName string `json:"componentDefinitionName"` + ServiceVersion string `json:"serviceVersion"` // VerticalScaling options - CPU string `json:"cpu"` - Memory string `json:"memory"` - Class string `json:"class"` - ClassDefRef appsv1alpha1.ClassDefRef `json:"classDefRef,omitempty"` + CPU string `json:"cpu"` + Memory string `json:"memory"` // HorizontalScaling options Replicas int `json:"replicas"` @@ -102,6 +101,7 @@ type OperationsOptions struct { // Expose options ExposeType string `json:"-"` + ExposeSubType string `json:"-"` ExposeEnabled string `json:"exposeEnabled,omitempty"` Services []appsv1alpha1.OpsService `json:"services,omitempty"` @@ -177,9 +177,12 @@ func (o *OperationsOptions) CompleteRestartOps() error { return err } componentSpecs := clusterObj.Spec.ComponentSpecs - o.ComponentNames = make([]string, len(componentSpecs)) + o.ComponentNames = make([]string, 0) for i := range componentSpecs { - o.ComponentNames[i] = componentSpecs[i].Name + o.ComponentNames = append(o.ComponentNames, componentSpecs[i].Name) + } + for i := range clusterObj.Spec.ShardingSpecs { + o.ComponentNames = append(o.ComponentNames, clusterObj.Spec.ShardingSpecs[i].Name) } return nil } @@ -325,10 +328,13 @@ func (o *OperationsOptions) CompleteHaEnabled() { } func (o *OperationsOptions) validateUpgrade() error { - if len(o.ClusterVersionRef) == 0 { - return fmt.Errorf("missing cluster-version") + if len(o.ClusterVersionRef) > 0 { + return nil } - return nil + if len(o.ComponentNames) > 0 { + return nil + } + return fmt.Errorf("missing cluster-version or components") } func (o *OperationsOptions) validateVolumeExpansion() error { @@ -374,50 +380,28 @@ func (o *OperationsOptions) validateVolumeExpansion() error { } func (o *OperationsOptions) validateVScale(cluster *appsv1alpha1.Cluster) error { - if o.Class != "" && (o.CPU != "" || o.Memory != "") { - return fmt.Errorf("class and cpu/memory cannot be both specified") - } - if o.Class == "" && o.CPU == "" && o.Memory == "" { - return fmt.Errorf("class or cpu/memory must be specified") + if o.CPU == "" && o.Memory == "" { + return fmt.Errorf("cpu or memory must be specified") } - clsMgr, resourceConstraintList, err := classutil.GetManager(o.Dynamic, cluster.Spec.ClusterDefRef) - if err != nil { - return err - } - - fillClassParams := func(comp *appsv1alpha1.ClusterComponentSpec) error { - if o.Class != "" { - clsDefRef := appsv1alpha1.ClassDefRef{} - parts := strings.SplitN(o.Class, ":", 2) - if len(parts) == 1 { - clsDefRef.Class = parts[0] - } else { - clsDefRef.Name = parts[0] - clsDefRef.Class = parts[1] - } - comp.ClassDefRef = &clsDefRef - comp.Resources = corev1.ResourceRequirements{} - } else { - comp.ClassDefRef = &appsv1alpha1.ClassDefRef{} - requests := make(corev1.ResourceList) - if o.CPU != "" { - cpu, err := resource.ParseQuantity(o.CPU) - if err != nil { - return fmt.Errorf("cannot parse '%v', %v", o.CPU, err) - } - requests[corev1.ResourceCPU] = cpu + fillResource := func(comp *appsv1alpha1.ClusterComponentSpec) error { + requests := make(corev1.ResourceList) + if o.CPU != "" { + cpu, err := resource.ParseQuantity(o.CPU) + if err != nil { + return fmt.Errorf("cannot parse '%v', %v", o.CPU, err) } - if o.Memory != "" { - memory, err := resource.ParseQuantity(o.Memory) - if err != nil { - return fmt.Errorf("cannot parse '%v', %v", o.Memory, err) - } - requests[corev1.ResourceMemory] = memory + requests[corev1.ResourceCPU] = cpu + } + if o.Memory != "" { + memory, err := resource.ParseQuantity(o.Memory) + if err != nil { + return fmt.Errorf("cannot parse '%v', %v", o.Memory, err) } - requests.DeepCopyInto(&comp.Resources.Requests) - requests.DeepCopyInto(&comp.Resources.Limits) + requests[corev1.ResourceMemory] = memory } + requests.DeepCopyInto(&comp.Resources.Requests) + requests.DeepCopyInto(&comp.Resources.Limits) return nil } @@ -426,11 +410,7 @@ func (o *OperationsOptions) validateVScale(cluster *appsv1alpha1.Cluster) error if comp.Name != name { continue } - if err := fillClassParams(&comp); err != nil { - return err - } - // validate component classes - if err = classutil.ValidateResources(clsMgr, resourceConstraintList, cluster.Spec.ClusterDefRef, &comp); err != nil { + if err := fillResource(&comp); err != nil { return err } } @@ -452,7 +432,7 @@ func (o *OperationsOptions) Validate() error { // common validate for componentOps if o.HasComponentNamesFlag && len(o.ComponentNames) == 0 { - return fmt.Errorf(`missing components, please specify the "--components" flag for multi-components cluster`) + return fmt.Errorf(`missing components, please specify the "--components" flag for the cluster`) } switch o.OpsType { @@ -633,11 +613,18 @@ func (o *OperationsOptions) validateExpose() error { return fmt.Errorf("invalid expose type %q", o.ExposeType) } + switch o.ExposeSubType { + case util.LoadBalancer, util.NodePort: + default: + return fmt.Errorf("invalid expose subtype %q", o.ExposeSubType) + } + switch strings.ToLower(o.ExposeEnabled) { case util.EnableValue, util.DisableValue: default: return fmt.Errorf("invalid value for enable flag: %s", o.ExposeEnabled) } + return nil } @@ -651,23 +638,64 @@ func (o *OperationsOptions) fillExpose() error { return err } + if len(o.ComponentNames) == 0 { + return fmt.Errorf("there are multiple components in cluster, please use --components to specify the component for expose") + } + if len(o.ComponentNames) > 1 { + return fmt.Errorf("only one component can be exposed at a time") + } + componentName := o.ComponentNames[0] + // default expose to internet exposeType := util.ExposeType(o.ExposeType) if exposeType == "" { exposeType = util.ExposeToInternet } + clusterObj, err := cluster.GetClusterByName(o.Dynamic, o.Name, o.Namespace) + if err != nil { + return err + } + + var componentSpec *appsv1alpha1.ClusterComponentSpec + for _, compSpec := range clusterObj.Spec.ComponentSpecs { + if compSpec.Name == componentName { + componentSpec = &compSpec + break + } + } + if componentSpec == nil { + return fmt.Errorf("component %s not found", componentName) + } + annotations, err := util.GetExposeAnnotations(provider, exposeType) if err != nil { return err } - o.Services = append(o.Services, appsv1alpha1.OpsService{ + svc := appsv1alpha1.OpsService{ // currently, we use the expose type as service name Name: string(exposeType), - ServiceType: corev1.ServiceTypeLoadBalancer, Annotations: annotations, - }) + } + if exposeType == util.ExposeToVPC { + if o.ExposeSubType == "" { + svc.ServiceType = corev1.ServiceTypeLoadBalancer + } else { + svc.ServiceType = corev1.ServiceType(o.ExposeSubType) + } + } else { + svc.ServiceType = corev1.ServiceTypeLoadBalancer + } + + roleSelector, err := util.GetDefaultRoleSelector(o.Dynamic, clusterObj, componentSpec.ComponentDef, componentSpec.ComponentDefRef) + if err != nil { + return err + } + if len(roleSelector) > 0 { + svc.RoleSelector = roleSelector + } + o.Services = append(o.Services, svc) return nil } @@ -709,6 +737,8 @@ var upgradeExample = templates.Examples(` // NewUpgradeCmd creates an upgrade command func NewUpgradeCmd(f cmdutil.Factory, streams genericiooptions.IOStreams) *cobra.Command { o := newBaseOperationsOptions(f, streams, appsv1alpha1.UpgradeType, false) + compDefFlag := "component-definition" + serviceVersionFlag := "service-version" cmd := &cobra.Command{ Use: "upgrade NAME", Short: "Upgrade the cluster version.", @@ -723,18 +753,17 @@ func NewUpgradeCmd(f cmdutil.Factory, streams genericiooptions.IOStreams) *cobra }, } o.addCommonFlags(cmd, f) - cmd.Flags().StringVar(&o.ClusterVersionRef, "cluster-version", "", "Reference cluster version (required)") + cmd.Flags().StringVar(&o.ClusterVersionRef, "cluster-version", "", "Referring to the ClusterVersion CR(deprecated)") + cmd.Flags().StringVar(&o.ComponentDefinitionName, compDefFlag, "nil", "Referring to the ComponentDefinition") + cmd.Flags().StringVar(&o.ServiceVersion, serviceVersionFlag, "nil", "Referring to the serviceVersion that is provided by ComponentDefinition and ComponentVersion") cmd.Flags().BoolVar(&o.AutoApprove, "auto-approve", false, "Skip interactive approval before upgrading the cluster") - _ = cmd.MarkFlagRequired("cluster-version") + flags.AddComponentsFlag(f, cmd, &o.ComponentNames, "Component names to this operations") return cmd } var verticalScalingExample = templates.Examples(` # scale the computing resources of specified components, separate with commas for multiple components kbcli cluster vscale mycluster --components=mysql --cpu=500m --memory=500Mi - - # scale the computing resources of specified components by class, run command 'kbcli class list --cluster-definition cluster-definition-name' to get available classes - kbcli cluster vscale mycluster --components=mysql --class=general-2c4g `) // NewVerticalScalingCmd creates a vertical scaling command @@ -757,7 +786,6 @@ func NewVerticalScalingCmd(f cmdutil.Factory, streams genericiooptions.IOStreams o.addCommonFlags(cmd, f) cmd.Flags().StringVar(&o.CPU, "cpu", "", "Request and limit size of component cpu") cmd.Flags().StringVar(&o.Memory, "memory", "", "Request and limit size of component memory") - cmd.Flags().StringVar(&o.Class, "class", "", "Component class") cmd.Flags().BoolVar(&o.AutoApprove, "auto-approve", false, "Skip interactive approval before vertically scaling the cluster") _ = cmd.MarkFlagRequired("components") return cmd @@ -787,7 +815,7 @@ func NewHorizontalScalingCmd(f cmdutil.Factory, streams genericiooptions.IOStrea } o.addCommonFlags(cmd, f) - cmd.Flags().IntVar(&o.Replicas, "replicas", o.Replicas, "Replicas with the specified components") + cmd.Flags().IntVar(&o.Replicas, "replicas", 0, "Replicas with the specified components") cmd.Flags().BoolVar(&o.AutoApprove, "auto-approve", false, "Skip interactive approval before horizontally scaling the cluster") _ = cmd.MarkFlagRequired("replicas") _ = cmd.MarkFlagRequired("components") @@ -859,12 +887,16 @@ func NewExposeCmd(f cmdutil.Factory, streams genericiooptions.IOStreams) *cobra. } o.addCommonFlags(cmd, f) cmd.Flags().StringVar(&o.ExposeType, "type", "", "Expose type, currently supported types are 'vpc', 'internet'") + cmd.Flags().StringVar(&o.ExposeSubType, "sub-type", "LoadBalancer", "Expose sub type, currently supported types are 'NodePort', 'LoadBalancer', only available if type is vpc") cmd.Flags().StringVar(&o.ExposeEnabled, "enable", "", "Enable or disable the expose, values can be true or false") cmd.Flags().BoolVar(&o.AutoApprove, "auto-approve", false, "Skip interactive approval before exposing the cluster") util.CheckErr(cmd.RegisterFlagCompletionFunc("type", func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { return []string{string(util.ExposeToVPC), string(util.ExposeToInternet)}, cobra.ShellCompDirectiveNoFileComp })) + util.CheckErr(cmd.RegisterFlagCompletionFunc("sub-type", func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { + return []string{util.NodePort, util.LoadBalancer}, cobra.ShellCompDirectiveNoFileComp + })) util.CheckErr(cmd.RegisterFlagCompletionFunc("enable", func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { return []string{"true", "false"}, cobra.ShellCompDirectiveNoFileComp })) @@ -1135,8 +1167,8 @@ func (o *CustomOperations) validateAndCompleteComponentName() error { } // check if the custom ops supports the component or complete the component for the cluster supportedComponentDefs := map[string]struct{}{} - for _, v := range opsDef.Spec.ComponentDefinitionRefs { - supportedComponentDefs[v.Name] = struct{}{} + for _, v := range opsDef.Spec.ComponentInfos { + supportedComponentDefs[v.ComponentDefinitionName] = struct{}{} } if len(supportedComponentDefs) > 0 { // check if the ops supports the input component @@ -1294,9 +1326,9 @@ func NewRebuildInstanceCmd(f cmdutil.Factory, streams genericiooptions.IOStreams ComponentOps: appsv1alpha1.ComponentOps{ ComponentName: compName, }, - Instances: instances, - BackupName: o.BackupName, - EnvForRestore: envVars, + Instances: instances, + BackupName: o.BackupName, + RestoreEnv: envVars, }, } return nil @@ -1304,7 +1336,7 @@ func NewRebuildInstanceCmd(f cmdutil.Factory, streams genericiooptions.IOStreams cmd := &cobra.Command{ Use: "rebuild-instance NAME", Short: "Rebuild the specified instances in the cluster.", - Example: restartExample, + Example: rebuildExample, ValidArgsFunction: util.ResourceNameCompletionFunc(f, types.ClusterGVR()), Run: func(cmd *cobra.Command, args []string) { o.Args = args diff --git a/pkg/cmd/cluster/operations_test.go b/pkg/cmd/cluster/operations_test.go index f886b293d..78069b9e1 100644 --- a/pkg/cmd/cluster/operations_test.go +++ b/pkg/cmd/cluster/operations_test.go @@ -37,7 +37,6 @@ import ( appsv1alpha1 "github.com/apecloud/kubeblocks/apis/apps/v1alpha1" "github.com/apecloud/kubeblocks/pkg/constant" - testapps "github.com/apecloud/kubeblocks/pkg/testutil/apps" "github.com/apecloud/kbcli/pkg/testing" ) @@ -67,22 +66,6 @@ var _ = Describe("operations", func() { clusterWithOneComp.Spec.ComponentSpecs = []appsv1alpha1.ClusterComponentSpec{ clusterWithOneComp.Spec.ComponentSpecs[0], } - clusterWithOneComp.Spec.ComponentSpecs[0].ClassDefRef = &appsv1alpha1.ClassDefRef{Class: testapps.Class1c1gName} - classDef := testapps.NewComponentClassDefinitionFactory("custom", clusterWithOneComp.Spec.ClusterDefRef, testing.ComponentDefName). - AddClasses([]appsv1alpha1.ComponentClass{testapps.Class1c1g}). - GetObject() - resourceConstraint := testapps.NewComponentResourceConstraintFactory(testapps.DefaultResourceConstraintName). - AddConstraints(testapps.ProductionResourceConstraint). - AddSelector(appsv1alpha1.ClusterResourceConstraintSelector{ - ClusterDefRef: testing.ClusterDefName, - Components: []appsv1alpha1.ComponentResourceConstraintSelector{ - { - ComponentDefRef: testing.ComponentDefName, - Rules: []string{"c1"}, - }, - }, - }). - GetObject() // init cluster with one component and componentDefinition clusterWithCompDef := clusterWithOneComp.DeepCopy() @@ -96,8 +79,8 @@ var _ = Describe("operations", func() { opsDef := &appsv1alpha1.OpsDefinition{ ObjectMeta: metav1.ObjectMeta{Name: opsDefName}, Spec: appsv1alpha1.OpsDefinitionSpec{ - ComponentDefinitionRefs: []appsv1alpha1.ComponentDefinitionRef{ - {Name: testing.CompDefName}, + ComponentInfos: []appsv1alpha1.ComponentInfo{ + {ComponentDefinitionName: testing.CompDefName}, }, ParametersSchema: &appsv1alpha1.ParametersSchema{ OpenAPIV3Schema: &apiextensionsv1.JSONSchemaProps{ @@ -115,7 +98,7 @@ var _ = Describe("operations", func() { tf.Client = &clientfake.RESTClient{} tf.FakeDynamicClient = testing.FakeDynamicClient(testing.FakeClusterDef(), testing.FakeClusterVersion(), testing.FakeCompDef(), clusterWithTwoComps, clusterWithOneComp, clusterWithCompDef, - classDef, &pods.Items[0], &pods.Items[1], &podsWithCompDef.Items[0], &podsWithCompDef.Items[1], resourceConstraint, opsDef) + &pods.Items[0], &pods.Items[1], &podsWithCompDef.Items[0], &podsWithCompDef.Items[1], opsDef) }) AfterEach(func() { @@ -142,8 +125,8 @@ var _ = Describe("operations", func() { Namespace: testing.Namespace, }, Spec: appsv1alpha1.OpsRequestSpec{ - ClusterRef: "test-cluster", - Type: opsType, + ClusterName: "test-cluster", + Type: opsType, }, Status: appsv1alpha1.OpsRequestStatus{ Phase: phase, @@ -163,7 +146,7 @@ var _ = Describe("operations", func() { o.Namespace = testing.Namespace o.Name = clusterName o.OpsType = appsv1alpha1.UpgradeType - Expect(o.Validate()).To(MatchError("missing cluster-version")) + Expect(o.Validate()).To(MatchError("missing cluster-version or components")) By("expect to validate success") o.ClusterVersionRef = "test-cluster-version" @@ -202,7 +185,7 @@ var _ = Describe("operations", func() { } o := initCommonOperationOps(appsv1alpha1.VolumeExpansionType, clusterName, true, persistentVolumeClaim) By("validate volumeExpansion when components is null") - Expect(o.Validate()).To(MatchError(`missing components, please specify the "--components" flag for multi-components cluster`)) + Expect(o.Validate()).To(MatchError(`missing components, please specify the "--components" flag for the cluster`)) By("validate volumeExpansion when vct-names is null") o.ComponentNames = []string{compName} @@ -231,43 +214,17 @@ var _ = Describe("operations", func() { Expect(o.CompleteComponentsFlag()).Should(Succeed()) Expect(o.ComponentNames[0]).Should(Equal(testing.ComponentName)) - By("validate invalid class") - o.Class = "class-not-exists" - in.Write([]byte(o.Name + "\n")) - Expect(o.Validate()).Should(HaveOccurred()) - - By("expect to validate success with class") - o.Class = testapps.Class1c1gName - in.Write([]byte(o.Name + "\n")) - Expect(o.Validate()).ShouldNot(HaveOccurred()) - By("validate invalid resource") - o.Class = "" - o.CPU = "100" - o.Memory = "100Gi" - in.Write([]byte(o.Name + "\n")) - Expect(o.Validate()).Should(HaveOccurred()) - - By("validate invalid resource") - o.Class = "" o.CPU = "1g" o.Memory = "100Gi" in.Write([]byte(o.Name + "\n")) Expect(o.Validate()).Should(HaveOccurred()) By("validate invalid resource") - o.Class = "" o.CPU = "1" o.Memory = "100MB" in.Write([]byte(o.Name + "\n")) Expect(o.Validate()).Should(HaveOccurred()) - - By("expect to validate success with resource") - o.Class = "" - o.CPU = "1" - o.Memory = "1Gi" - in.Write([]byte(o.Name + "\n")) - Expect(o.Validate()).ShouldNot(HaveOccurred()) }) It("Hscale Ops", func() { diff --git a/pkg/cmd/cluster/update.go b/pkg/cmd/cluster/update.go index 8c71109c6..8c0c81b0a 100644 --- a/pkg/cmd/cluster/update.go +++ b/pkg/cmd/cluster/update.go @@ -44,8 +44,10 @@ import ( "k8s.io/kubectl/pkg/util/templates" appsv1alpha1 "github.com/apecloud/kubeblocks/apis/apps/v1alpha1" + appsv1beta1 "github.com/apecloud/kubeblocks/apis/apps/v1beta1" dpv1alpha1 "github.com/apecloud/kubeblocks/apis/dataprotection/v1alpha1" cfgcore "github.com/apecloud/kubeblocks/pkg/configuration/core" + cfgutil "github.com/apecloud/kubeblocks/pkg/configuration/util" "github.com/apecloud/kubeblocks/pkg/constant" "github.com/apecloud/kubeblocks/pkg/controller/configuration" "github.com/apecloud/kubeblocks/pkg/dataprotection/utils" @@ -282,8 +284,8 @@ func (o *UpdateOptions) buildPatch() error { "tolerations": {field: "tolerations", obj: spec, fn: buildTolObj}, // monitor and logs - "monitoring-interval": {field: "monitor", obj: nil, fn: buildComps}, - "enable-all-logs": {field: "enable-all-logs", obj: nil, fn: buildComps}, + "disable-exporter": {field: "disableExporter", obj: nil, fn: buildComps}, + "enable-all-logs": {field: "enable-all-logs", obj: nil, fn: buildComps}, // backup config "backup-enabled": {field: "enabled", obj: nil, fn: buildBackup}, @@ -372,7 +374,7 @@ func (o *UpdateOptions) buildComponents(field string, val string) error { } switch field { - case "monitor": + case "disableExporter": return o.updateMonitor(val) case "enable-all-logs": return o.updateEnabledLog(val) @@ -458,7 +460,7 @@ func (o *UpdateOptions) reconfigureLogVariables(c *appsv1alpha1.Cluster, cd *app buf bytes.Buffer keyName string configTemplate *corev1.ConfigMap - formatter *appsv1alpha1.FormatterConfig + formatter *appsv1beta1.FileFormatConfig logTPL *template.Template logVariables map[string]string unstructuredObj *unstructured.Unstructured @@ -477,7 +479,7 @@ func (o *UpdateOptions) reconfigureLogVariables(c *appsv1alpha1.Cluster, cd *app return err } // TODO: very hack logic for ini config file - formatter.FormatterOptions = appsv1alpha1.FormatterOptions{IniConfig: &appsv1alpha1.IniConfig{SectionName: defaultSectionName}} + formatter.FormatterAction = appsv1beta1.FormatterAction{IniConfig: &appsv1beta1.IniConfig{SectionName: defaultSectionName}} if logVariables, err = cfgcore.TransformConfigFileToKeyValueMap(keyName, formatter, buf.Bytes()); err != nil { return err } @@ -517,7 +519,7 @@ func findFirstConfigSpec( return &configSpecs[0], nil } -func findConfigTemplateInfo(dynamic dynamic.Interface, configSpec *appsv1alpha1.ComponentConfigSpec) (*corev1.ConfigMap, *appsv1alpha1.FormatterConfig, error) { +func findConfigTemplateInfo(dynamic dynamic.Interface, configSpec *appsv1alpha1.ComponentConfigSpec) (*corev1.ConfigMap, *appsv1beta1.FileFormatConfig, error) { if configSpec == nil { return nil, nil, errors.New("configTemplateSpec is nil") } @@ -529,7 +531,7 @@ func findConfigTemplateInfo(dynamic dynamic.Interface, configSpec *appsv1alpha1. if err != nil { return nil, nil, err } - return configTemplate, configConstraint.Spec.FormatterConfig, nil + return configTemplate, configConstraint.Spec.FileFormatConfig, nil } func newConfigTemplateEngine() *template.Template { @@ -602,13 +604,13 @@ func buildLogsReconfiguringOps(clusterName, namespace, compName, configName, key } func (o *UpdateOptions) updateMonitor(val string) error { - intVal, err := strconv.ParseInt(val, 10, 32) + disableExporter, err := strconv.ParseBool(val) if err != nil { return err } for i := range o.cluster.Spec.ComponentSpecs { - o.cluster.Spec.ComponentSpecs[i].Monitor = intVal != 0 + o.cluster.Spec.ComponentSpecs[i].DisableExporter = cfgutil.ToPointer(disableExporter) } return nil } diff --git a/pkg/cmd/cluster/update_test.go b/pkg/cmd/cluster/update_test.go index d54b53c28..477ed84e1 100644 --- a/pkg/cmd/cluster/update_test.go +++ b/pkg/cmd/cluster/update_test.go @@ -88,11 +88,12 @@ var _ = Describe("cluster update", func() { It("set monitoring interval", func() { fakeCluster := testing.FakeCluster("c1", "default") - tf.FakeDynamicClient = testing.FakeDynamicClient(fakeCluster) - Expect(cmd.Flags().Set("monitoring-interval", "15")).Should(Succeed()) + fakeClusterDef := testing.FakeClusterDef() + tf.FakeDynamicClient = testing.FakeDynamicClient(fakeCluster, fakeClusterDef) + Expect(cmd.Flags().Set("disable-exporter", "false")).Should(Succeed()) Expect(o.CmdComplete(cmd, args)).Should(Succeed()) Expect(o.Complete()).Should(Succeed()) - Expect(o.Patch).Should(ContainSubstring("\"monitor\":true")) + Expect(o.Patch).Should(ContainSubstring("\"disableExporter\":false")) }) It("set enable-all-logs", func() { diff --git a/pkg/cmd/clusterversion/clusterversion.go b/pkg/cmd/clusterversion/clusterversion.go index e3aff3d32..904645f1e 100644 --- a/pkg/cmd/clusterversion/clusterversion.go +++ b/pkg/cmd/clusterversion/clusterversion.go @@ -119,8 +119,8 @@ func isDefault(cv *v1alpha1.ClusterVersion) string { if cv.Annotations == nil { return "false" } - if _, ok := cv.Annotations[constant.DefaultClusterVersionAnnotationKey]; !ok { + if _, ok := cv.Annotations[types.KBDefaultClusterVersionAnnotationKey]; !ok { return "false" } - return cv.Annotations[constant.DefaultClusterVersionAnnotationKey] + return cv.Annotations[types.KBDefaultClusterVersionAnnotationKey] } diff --git a/pkg/cmd/clusterversion/set_default.go b/pkg/cmd/clusterversion/set_default.go index 0fb340865..a153c82ed 100644 --- a/pkg/cmd/clusterversion/set_default.go +++ b/pkg/cmd/clusterversion/set_default.go @@ -159,7 +159,7 @@ func patchDefaultClusterVersionAnnotations(client dynamic.Interface, cvName stri patchData := map[string]interface{}{ "metadata": map[string]interface{}{ "annotations": map[string]interface{}{ - constant.DefaultClusterVersionAnnotationKey: value, + types.KBDefaultClusterVersionAnnotationKey: value, }, }, } @@ -189,7 +189,7 @@ func getMapsBetweenCvAndCd(client dynamic.Interface) (map[string]string, map[str if annotations == nil { continue } - if annotations[constant.DefaultClusterVersionAnnotationKey] == annotationTrueValue { + if annotations[types.KBDefaultClusterVersionAnnotationKey] == annotationTrueValue { cdToDefaultCv[labels[constant.ClusterDefLabelKey]] = name } } diff --git a/pkg/cmd/clusterversion/set_default_test.go b/pkg/cmd/clusterversion/set_default_test.go index 9c3bb65d8..44165f3c4 100644 --- a/pkg/cmd/clusterversion/set_default_test.go +++ b/pkg/cmd/clusterversion/set_default_test.go @@ -37,6 +37,7 @@ import ( "github.com/apecloud/kubeblocks/pkg/constant" "github.com/apecloud/kbcli/pkg/testing" + "github.com/apecloud/kbcli/pkg/types" ) var _ = Describe("set-default", func() { @@ -116,10 +117,10 @@ var _ = Describe("set-default", func() { cv := testing.FakeClusterVersion() Expect(isDefault(cv)).Should(Equal(annotationFalseValue)) cv.SetAnnotations(map[string]string{ - constant.DefaultClusterVersionAnnotationKey: annotationFalseValue, + types.KBDefaultClusterVersionAnnotationKey: annotationFalseValue, }) Expect(isDefault(cv)).Should(Equal(annotationFalseValue)) - cv.Annotations[constant.DefaultClusterVersionAnnotationKey] = annotationTrueValue + cv.Annotations[types.KBDefaultClusterVersionAnnotationKey] = annotationTrueValue Expect(isDefault(cv)).Should(Equal(annotationTrueValue)) }) diff --git a/pkg/cmd/context/cloud_context.go b/pkg/cmd/context/cloud_context.go deleted file mode 100644 index cbd73af91..000000000 --- a/pkg/cmd/context/cloud_context.go +++ /dev/null @@ -1,409 +0,0 @@ -/* -Copyright (C) 2022-2024 ApeCloud Co., Ltd - -This file is part of KubeBlocks project - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU Affero General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU Affero General Public License for more details. - -You should have received a copy of the GNU Affero General Public License -along with this program. If not, see . -*/ - -package context - -import ( - "encoding/json" - "fmt" - "net/http" - "os" - "strings" - "time" - - "github.com/google/uuid" - "github.com/jedib0t/go-pretty/v6/table" - "github.com/pkg/errors" - "gopkg.in/yaml.v2" - "k8s.io/cli-runtime/pkg/genericiooptions" - - "github.com/apecloud/kbcli/pkg/cmd/organization" - "github.com/apecloud/kbcli/pkg/printer" -) - -const contextAPIName = "contexts" - -type CloudContext struct { - ContextName string - Token string - OrgName string - APIURL string - APIPath string - OutputFormat string - - genericiooptions.IOStreams -} - -type Metadata struct { - Name string `json:"name"` - Description string `json:"description"` - Project string `json:"project"` - Organization string `json:"organization"` - Partner string `json:"partner"` - ID string `json:"id"` - CreatedAt struct { - Seconds int `json:"seconds"` - Nanos int `json:"nanos"` - } `json:"createdAt"` - ModifiedAt struct { - Seconds int `json:"seconds"` - Nanos int `json:"nanos"` - } `json:"modifiedAt"` -} - -type Params struct { - KubernetesProvider string `json:"kubernetesProvider"` - ProvisionEnvironment string `json:"provisionEnvironment"` - ProvisionType string `json:"provisionType"` - State string `json:"state"` -} - -type ClusterStatus struct { - Conditions []struct { - Type string `json:"type"` - LastUpdated struct { - Seconds int `json:"seconds"` - Nanos int `json:"nanos"` - } `json:"lastUpdated"` - Reason string `json:"reason"` - } `json:"conditions"` - Token string `json:"token"` - PublishedBlueprint string `json:"publishedBlueprint"` -} - -type ClusterData struct { - ClusterBlueprint string `json:"cluster_blueprint"` - Projects []struct { - ProjectID string `json:"projectID"` - ClusterID string `json:"clusterID"` - } `json:"projects"` - ClusterStatus ClusterStatus `json:"cluster_status"` -} - -type ClusterSpec struct { - ClusterType string `json:"clusterType"` - Metro struct{} `json:"metro"` - OverrideSelector string `json:"overrideSelector"` - Params Params `json:"params"` - ProxyConfig struct{} `json:"proxyConfig"` - ClusterData ClusterData `json:"clusterData"` -} - -type ClusterItem struct { - Metadata Metadata `json:"metadata"` - Spec ClusterSpec `json:"spec"` -} - -type CloudContextsResponse struct { - APIVersion string `json:"apiVersion"` - Kind string `json:"kind"` - Metadata struct { - Count int `json:"count"` - Limit int `json:"limit"` - } `json:"metadata"` - Items []ClusterItem `json:"items"` -} - -type Status struct { - ConditionStatus int `json:"conditionStatus"` -} - -type CloudContextResponse struct { - ID uuid.UUID `json:"id"` - Name string `json:"name"` - OrgName string `json:"orgName"` - Description string `json:"description,omitempty"` - DisplayName string `json:"displayName,omitempty"` - State string `json:"state"` - CreatedAt time.Time `json:"createdAt"` - UpdatedAt time.Time `json:"updatedAt"` -} - -func (c *CloudContext) showContext() error { - cloudContext, err := c.GetContext() - if err != nil { - return errors.Wrapf(err, "Failed to get environment %s", c.ContextName) - } - - switch strings.ToLower(c.OutputFormat) { - case "yaml": - return c.printYAML(cloudContext) - case "json": - return c.printJSON(cloudContext) - case "human": - fallthrough - default: - return c.printTable(cloudContext) - } -} - -func (c *CloudContext) printYAML(ctxRes *CloudContextResponse) error { - yamlData, err := yaml.Marshal(ctxRes) - if err != nil { - return err - } - - fmt.Fprintf(c.Out, "%s", string(yamlData)) - return nil -} - -func (c *CloudContext) printJSON(ctxRes *CloudContextResponse) error { - jsonData, err := json.MarshalIndent(ctxRes, "", " ") - if err != nil { - return err - } - - fmt.Fprintf(c.Out, "%s", string(jsonData)) - return nil -} - -func (c *CloudContext) printTable(ctxRes *CloudContextResponse) error { - tbl := printer.NewTablePrinter(c.Out) - tbl.Tbl.SetColumnConfigs([]table.ColumnConfig{ - {Number: 8, WidthMax: 120}, - }) - tbl.SetHeader( - "NAME", - "Description", - "Project", - "Organization", - "Partner", - "ID", - "CreatedAt", - "UpdatedAt", - ) - - createAt := convertTimestampToHumanReadable( - ctxRes.CreatedAt, - ) - modifiedAt := convertTimestampToHumanReadable( - ctxRes.UpdatedAt, - ) - tbl.AddRow( - ctxRes.Name, - ctxRes.Description, - "", - ctxRes.OrgName, - "", - ctxRes.ID, - createAt, - modifiedAt, - ) - tbl.Print() - - return nil -} - -func (c *CloudContext) showContexts() error { - cloudContexts, err := c.GetContexts() - if err != nil { - return errors.Wrapf(err, "Failed to get environments, please check your organization name") - } - - tbl := printer.NewTablePrinter(c.Out) - tbl.Tbl.SetColumnConfigs([]table.ColumnConfig{ - {Number: 8, WidthMax: 120}, - }) - tbl.SetHeader( - "NAME", - "Description", - "Project", - "Organization", - "Partner", - "ID", - "CreatedAt", - "ModifiedAt", - ) - - for _, orgItem := range cloudContexts { - createAt := convertTimestampToHumanReadable( - orgItem.CreatedAt, - ) - modifiedAt := convertTimestampToHumanReadable( - orgItem.UpdatedAt, - ) - tbl.AddRow( - orgItem.Name, - orgItem.Description, - "", - orgItem.OrgName, - "", - orgItem.ID, - createAt, - modifiedAt, - ) - } - tbl.Print() - - if ok := writeContexts(cloudContexts); ok != nil { - return errors.Wrapf(err, "Failed to write environments.") - } - return nil -} - -func (c *CloudContext) showCurrentContext() error { - currentContext, err := c.getCurrentContext() - if err != nil { - return errors.Wrapf(err, "Failed to get current environment.") - } - - fmt.Fprintf(c.Out, "Current environment: %s\n", currentContext) - return nil -} - -func (c *CloudContext) showUseContext() error { - oldContextName, err := c.useContext(c.ContextName) - if err != nil { - return errors.Wrapf(err, "Failed to switch environment to %s.", c.ContextName) - } - - fmt.Fprintf(c.Out, "Successfully switched from %s to environment %s.\n", oldContextName, c.ContextName) - return nil -} - -func (c *CloudContext) showRemoveContext() error { - if err := c.removeContext(); err != nil { - return errors.Wrapf(err, "Failed to remove environment %s.", c.ContextName) - } - - fmt.Fprintf(c.Out, "Environment %s removed.\n", c.ContextName) - return nil -} - -func (c *CloudContext) GetContext() (*CloudContextResponse, error) { - path := strings.Join([]string{c.APIURL, c.APIPath, organization.OrgAPIName, c.OrgName, contextAPIName, c.ContextName}, "/") - response, err := organization.NewRequest(http.MethodGet, path, c.Token, nil) - if err != nil { - return nil, err - } - - var context CloudContextResponse - err = json.Unmarshal(response, &context) - if err != nil { - return nil, errors.Wrapf(err, "Failed to unmarshal environment %s.", c.ContextName) - } - - return &context, nil -} - -func (c *CloudContext) GetContexts() ([]CloudContextResponse, error) { - path := strings.Join([]string{c.APIURL, c.APIPath, organization.OrgAPIName, c.OrgName, contextAPIName}, "/") - response, err := organization.NewRequest(http.MethodGet, path, c.Token, nil) - if err != nil { - return nil, err - } - - var contexts []CloudContextResponse - err = json.Unmarshal(response, &contexts) - if err != nil { - return nil, errors.Wrap(err, "Failed to unmarshal environments.") - } - - return contexts, nil -} - -func (c *CloudContext) getCurrentContext() (string, error) { - currentOrgAndContext, err := organization.GetCurrentOrgAndContext() - if err != nil { - return "", errors.Wrap(err, "Failed to get current environment.") - } - - if ok, err := c.isValidContext(currentOrgAndContext.CurrentContext); !ok { - return "", err - } - - return currentOrgAndContext.CurrentContext, nil -} - -func (c *CloudContext) useContext(contextName string) (string, error) { - if ok, err := c.isValidContext(contextName); !ok { - return "", err - } - - currentOrgAndContext, err := organization.GetCurrentOrgAndContext() - if err != nil { - return "", errors.Wrap(err, "Failed to get current environment.") - } - - oldContextName := currentOrgAndContext.CurrentContext - currentOrgAndContext.CurrentContext = contextName - if err = organization.SetCurrentOrgAndContext(currentOrgAndContext); err != nil { - return "", errors.Wrapf(err, "Failed to switch environment to %s.", contextName) - } - - return oldContextName, nil -} - -// RemoveContext TODO: By the way, delete the context stored locally. -func (c *CloudContext) removeContext() error { - path := strings.Join([]string{c.APIURL, c.APIPath, organization.OrgAPIName, c.OrgName, contextAPIName, c.ContextName}, "/") - _, err := organization.NewRequest(http.MethodDelete, path, c.Token, nil) - if err != nil { - return err - } - - return nil -} - -func (c *CloudContext) isValidContext(contextName string) (bool, error) { - cloudContexts, err := c.GetContexts() - if err != nil { - return false, errors.Wrap(err, "Failed to get environments.") - } - - if len(cloudContexts) == 0 { - return false, errors.Wrap(err, "No environment found, please create a environment on cloud.") - } - - for _, item := range cloudContexts { - if item.Name == contextName { - return true, nil - } - } - - return false, errors.Errorf("Environment %s does not exist.", contextName) -} - -func writeContexts(contexts []CloudContextResponse) error { - jsonData, err := json.MarshalIndent(contexts, "", " ") - if err != nil { - return err - } - - filePath, err := organization.GetContextFilePath() - if err != nil { - return err - } - file, err := os.Create(filePath) - if err != nil { - return err - } - defer file.Close() - - _, err = file.Write(jsonData) - if err != nil { - return err - } - return nil -} - -func convertTimestampToHumanReadable(t time.Time) string { - // Format the time to a human-readable layout - return t.Format("2006-01-02 15:04:05") -} diff --git a/pkg/cmd/context/cloud_context_test.go b/pkg/cmd/context/cloud_context_test.go deleted file mode 100644 index b0b14b916..000000000 --- a/pkg/cmd/context/cloud_context_test.go +++ /dev/null @@ -1,136 +0,0 @@ -/* -Copyright (C) 2022-2024 ApeCloud Co., Ltd - -This file is part of KubeBlocks project - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU Affero General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU Affero General Public License for more details. - -You should have received a copy of the GNU Affero General Public License -along with this program. If not, see . -*/ - -package context - -import ( - ginkgo_context "github.com/onsi/ginkgo/v2" - . "github.com/onsi/gomega" - - "encoding/json" - "net/http" - "net/http/httptest" - - "github.com/apecloud/kbcli/pkg/cmd/auth/utils" - "github.com/apecloud/kbcli/pkg/cmd/organization" -) - -func mockServer() *httptest.Server { - return httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - switch r.URL.Path { - case "/api/v1/organizations/test_org/contexts/test_context": - switch r.Method { - case http.MethodGet: - cloudContextResponse := CloudContextResponse{ - Name: "test_context", - } - jsonData, err := json.Marshal(cloudContextResponse) - if err != nil { - w.WriteHeader(http.StatusInternalServerError) - return - } - w.Header().Set("Content-Type", "application/json") - w.WriteHeader(http.StatusOK) - _, _ = w.Write(jsonData) - case http.MethodDelete: - w.WriteHeader(http.StatusOK) - case http.MethodPost: - w.WriteHeader(http.StatusCreated) - default: - w.WriteHeader(http.StatusNotFound) - } - - case "/api/v1/organizations/test_org/contexts": - cloudContextsResponse := []CloudContextResponse{ - { - Name: "test_context", - }, - } - jsonData, err := json.Marshal(cloudContextsResponse) - if err != nil { - w.WriteHeader(http.StatusInternalServerError) - return - } - - w.Header().Set("Content-Type", "application/json") - w.WriteHeader(http.StatusOK) - _, _ = w.Write(jsonData) - } - })) -} - -var _ = ginkgo_context.Describe("Test Cloud Context", func() { - var ( - o *CloudContext - ) - ginkgo_context.BeforeEach(func() { - server := mockServer() - o = &CloudContext{ - ContextName: "test_context", - OrgName: "test_org", - APIURL: server.URL, - APIPath: utils.APIPathV1, - } - }) - - ginkgo_context.AfterEach(func() { - }) - - ginkgo_context.Context("test cloud context", func() { - Expect(organization.SetCurrentOrgAndContext(&organization.CurrentOrgAndContext{ - CurrentOrganization: "test_org", - CurrentContext: "test_context", - })).Should(BeNil()) - - ginkgo_context.It("test GetContext ", func() { - ExpectWithOffset(1, func() error { - _, err := o.GetContext() - return err - }()).To(BeNil()) - }) - - ginkgo_context.It("test GetContexts ", func() { - ExpectWithOffset(1, func() error { - _, err := o.GetContexts() - return err - }()).To(BeNil()) - }) - - ginkgo_context.It("test getCurrentContext ", func() { - ExpectWithOffset(1, func() error { - _, err := o.getCurrentContext() - return err - }()).To(BeNil()) - }) - - ginkgo_context.It("test useContext ", func() { - ExpectWithOffset(1, func() error { - _, err := o.useContext("test_context") - return err - }()).To(BeNil()) - }) - - ginkgo_context.It("test deleteOrganization ", func() { - ExpectWithOffset(1, func() error { - err := o.removeContext() - return err - }()).To(BeNil()) - }) - }) -}) diff --git a/pkg/cmd/context/context.go b/pkg/cmd/context/context.go deleted file mode 100644 index c094b7b73..000000000 --- a/pkg/cmd/context/context.go +++ /dev/null @@ -1,202 +0,0 @@ -/* -Copyright (C) 2022-2024 ApeCloud Co., Ltd - -This file is part of KubeBlocks project - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU Affero General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU Affero General Public License for more details. - -You should have received a copy of the GNU Affero General Public License -along with this program. If not, see . -*/ - -package context - -import ( - viper "github.com/apecloud/kubeblocks/pkg/viperx" - "github.com/pkg/errors" - "github.com/spf13/cobra" - "k8s.io/cli-runtime/pkg/genericiooptions" - cmdutil "k8s.io/kubectl/pkg/cmd/util" - "k8s.io/kubectl/pkg/util/templates" - - "github.com/apecloud/kbcli/pkg/cmd/auth/utils" - "github.com/apecloud/kbcli/pkg/cmd/organization" - "github.com/apecloud/kbcli/pkg/types" -) - -var contextExample = templates.Examples(` - // Get the environment name currently used by the user. - kbcli environment current - // List all environments created by the current user. - kbcli environment list - // Get the description information of environment environment1. - kbcli environment describe environment1 - // Switch to environment environment2. - kbcli environment use environment2 -`) - -const ( - localContext = "local" -) - -type Context interface { - showContext() error - showContexts() error - showCurrentContext() error - showUseContext() error - showRemoveContext() error -} - -type ContextOptions struct { - ContextName string - Context Context - OutputFormat string - - genericiooptions.IOStreams -} - -func NewContextCmd(streams genericiooptions.IOStreams) *cobra.Command { - cmd := &cobra.Command{ - Use: "environment", - Aliases: []string{"env"}, - Short: "kbcli environment allows you to manage cloud environment. This command is currently only applicable to cloud," + - " and currently does not support switching the environment of the local k8s cluster.", - Example: contextExample, - } - cmd.AddCommand( - newContextListCmd(streams), - newContextUseCmd(streams), - newContextCurrentCmd(streams), - newContextDescribeCmd(streams), - ) - return cmd -} - -func newContextListCmd(streams genericiooptions.IOStreams) *cobra.Command { - o := &ContextOptions{IOStreams: streams} - - cmd := &cobra.Command{ - Use: "list", - Short: "List all created environments.", - Run: func(cmd *cobra.Command, args []string) { - cmdutil.CheckErr(o.complete(args)) - cmdutil.CheckErr(o.validate(cmd)) - cmdutil.CheckErr(o.runList()) - }, - } - return cmd -} - -func newContextCurrentCmd(streams genericiooptions.IOStreams) *cobra.Command { - o := &ContextOptions{IOStreams: streams} - - cmd := &cobra.Command{ - Use: "current", - Short: "Get the currently used environment.", - Run: func(cmd *cobra.Command, args []string) { - cmdutil.CheckErr(o.complete(args)) - cmdutil.CheckErr(o.validate(cmd)) - cmdutil.CheckErr(o.runCurrent()) - }, - } - return cmd -} - -func newContextDescribeCmd(streams genericiooptions.IOStreams) *cobra.Command { - o := &ContextOptions{IOStreams: streams} - - cmd := &cobra.Command{ - Use: "describe", - Short: "Get the description information of a environment.", - Run: func(cmd *cobra.Command, args []string) { - cmdutil.CheckErr(o.complete(args)) - cmdutil.CheckErr(o.validate(cmd)) - cmdutil.CheckErr(o.runDescribe()) - }, - } - - cmd.Flags().StringVarP(&o.OutputFormat, "output", "o", "human", "Output format (table|yaml|json)") - - return cmd -} - -func newContextUseCmd(streams genericiooptions.IOStreams) *cobra.Command { - o := &ContextOptions{IOStreams: streams} - - cmd := &cobra.Command{ - Use: "use", - Short: "Use another environment that you have already created.", - Run: func(cmd *cobra.Command, args []string) { - cmdutil.CheckErr(o.complete(args)) - cmdutil.CheckErr(o.validate(cmd)) - cmdutil.CheckErr(o.runUse()) - }, - } - - return cmd -} - -func (o *ContextOptions) validate(cmd *cobra.Command) error { - if cmd.Name() == "describe" || cmd.Name() == "use" { - if o.ContextName == "" { - return errors.New("environment name is required") - } - } - - return nil -} - -func (o *ContextOptions) complete(args []string) error { - if len(args) > 0 { - o.ContextName = args[0] - } - - currentOrgAndContext, err := organization.GetCurrentOrgAndContext() - if err != nil { - return err - } - - if o.Context == nil { - if currentOrgAndContext.CurrentContext != localContext { - token, err := organization.GetToken() - if err != nil { - return err - } - o.Context = &CloudContext{ - ContextName: o.ContextName, - Token: token, - OrgName: currentOrgAndContext.CurrentOrganization, - IOStreams: o.IOStreams, - APIURL: viper.GetString(types.CfgKeyOpenAPIServer), - APIPath: utils.APIPathV1, - OutputFormat: o.OutputFormat, - } - } - } - - return nil -} - -func (o *ContextOptions) runList() error { - return o.Context.showContexts() -} - -func (o *ContextOptions) runCurrent() error { - return o.Context.showCurrentContext() -} - -func (o *ContextOptions) runDescribe() error { - return o.Context.showContext() -} - -func (o *ContextOptions) runUse() error { - return o.Context.showUseContext() -} diff --git a/pkg/cmd/context/context_text.go b/pkg/cmd/context/context_text.go deleted file mode 100644 index 7d5174dac..000000000 --- a/pkg/cmd/context/context_text.go +++ /dev/null @@ -1,109 +0,0 @@ -/* -Copyright (C) 2022-2024 ApeCloud Co., Ltd - -This file is part of KubeBlocks project - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU Affero General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU Affero General Public License for more details. - -You should have received a copy of the GNU Affero General Public License -along with this program. If not, see . -*/ - -package context - -import ( - ginkgo_context "github.com/onsi/ginkgo/v2" - . "github.com/onsi/gomega" - - "k8s.io/cli-runtime/pkg/genericiooptions" - - "github.com/apecloud/kbcli/pkg/cmd/organization" -) - -type MockContext struct { - genericiooptions.IOStreams -} - -func (m *MockContext) showContext() error { - return nil -} - -func (m *MockContext) showContexts() error { - return nil -} - -func (m *MockContext) showCurrentContext() error { - return nil -} - -func (m *MockContext) showUseContext() error { - return nil -} - -func (m *MockContext) showRemoveContext() error { - return nil -} - -var _ = ginkgo_context.Describe("Test Cloud Context", func() { - var ( - streams genericiooptions.IOStreams - o *ContextOptions - ) - ginkgo_context.BeforeEach(func() { - streams, _, _, _ = genericiooptions.NewTestIOStreams() - o = &ContextOptions{ - ContextName: "test_context", - Context: &MockContext{ - IOStreams: streams, - }, - IOStreams: streams, - } - }) - - ginkgo_context.AfterEach(func() { - }) - - ginkgo_context.Context("test context", func() { - Expect(organization.SetCurrentOrgAndContext(&organization.CurrentOrgAndContext{ - CurrentOrganization: "test_org", - CurrentContext: "test_context", - })).Should(BeNil()) - - args := []string{"test_context"} - ginkgo_context.It("test context list ", func() { - cmd := newContextListCmd(streams) - Expect(o.complete(args)).Should(Succeed()) - Expect(o.validate(cmd)).Should(Succeed()) - Expect(o.runList()).Should(Succeed()) - }) - - ginkgo_context.It("test context current ", func() { - cmd := newContextCurrentCmd(streams) - Expect(o.complete(args)).Should(Succeed()) - Expect(o.validate(cmd)).Should(Succeed()) - Expect(o.runCurrent()).Should(Succeed()) - }) - - ginkgo_context.It("test context describe ", func() { - cmd := newContextDescribeCmd(streams) - Expect(o.complete(args)).Should(Succeed()) - Expect(o.validate(cmd)).Should(Succeed()) - Expect(o.runDescribe()).Should(Succeed()) - }) - - ginkgo_context.It("test context use ", func() { - cmd := newContextUseCmd(streams) - Expect(o.complete(args)).Should(Succeed()) - Expect(o.validate(cmd)).Should(Succeed()) - Expect(o.runUse()).Should(Succeed()) - }) - }) -}) diff --git a/pkg/cmd/context/suite_test.go b/pkg/cmd/context/suite_test.go deleted file mode 100644 index eaca32af4..000000000 --- a/pkg/cmd/context/suite_test.go +++ /dev/null @@ -1,33 +0,0 @@ -/* -Copyright (C) 2022-2024 ApeCloud Co., Ltd - -This file is part of KubeBlocks project - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU Affero General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU Affero General Public License for more details. - -You should have received a copy of the GNU Affero General Public License -along with this program. If not, see . -*/ - -package context - -import ( - "testing" - - ginkgo_context "github.com/onsi/ginkgo/v2" - - . "github.com/onsi/gomega" -) - -func TestDashboard(t *testing.T) { - RegisterFailHandler(ginkgo_context.Fail) - ginkgo_context.RunSpecs(t, "Context Suite") -} diff --git a/pkg/cmd/dataprotection/backuppolicy.go b/pkg/cmd/dataprotection/backuppolicy.go index c1f867ef6..f4ffde679 100644 --- a/pkg/cmd/dataprotection/backuppolicy.go +++ b/pkg/cmd/dataprotection/backuppolicy.go @@ -37,19 +37,16 @@ var ( # list all backup policies kbcli cluster list-backup-policy - # list backup policies with specified name - kbcli cluster list-backup-policy mypolicy - - # list backup policies of the specified cluster - kbcli cluster list-backup-policy --cluster mycluster + # using short cmd to list backup policy of the specified cluster + kbcli cluster list-bp mycluster `) describeBackupPolicyExample = templates.Examples(` - # describe a backup policy - kbcli cluster describe-backup-policy mypolicy + # describe the default backup policy of the cluster + kbcli cluster describe-backup-policy cluster-name - # describe the default backup policy of the specified cluster - kbcli cluster describe-backup-policy --cluster mycluster + # describe the backup policy of the cluster with specified name + kbcli cluster describe-backup-policy cluster-name --name backup-policy-name `) ) diff --git a/pkg/cmd/dataprotection/restore.go b/pkg/cmd/dataprotection/restore.go index dfbca0f5e..fe5d2c579 100644 --- a/pkg/cmd/dataprotection/restore.go +++ b/pkg/cmd/dataprotection/restore.go @@ -78,8 +78,7 @@ func newRestoreCommand(f cmdutil.Factory, streams genericiooptions.IOStreams) *c } cmd.Flags().StringVar(&clusterName, "cluster", "", "The cluster to restore") - cmd.Flags().StringVar(&o.RestoreSpec.RestoreTimeStr, "restore-to-time", "", "point in time recovery(PITR)") - cmd.Flags().BoolVar(&o.RestoreSpec.EffectiveCommonComponentDef, "effective-common-component-def", false, "this backup will be restored for all components which refer to common ComponentDefinition.") + cmd.Flags().StringVar(&o.RestoreSpec.RestorePointInTime, "restore-to-time", "", "point in time recovery(PITR)") cmd.Flags().StringVar(&o.RestoreSpec.VolumeRestorePolicy, "volume-restore-policy", "Parallel", "the volume claim restore policy, supported values: [Serial, Parallel]") return cmd } diff --git a/pkg/cmd/fault/fault.go b/pkg/cmd/fault/fault.go deleted file mode 100644 index bbf857ea1..000000000 --- a/pkg/cmd/fault/fault.go +++ /dev/null @@ -1,202 +0,0 @@ -/* -Copyright (C) 2022-2024 ApeCloud Co., Ltd - -This file is part of KubeBlocks project - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU Affero General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU Affero General Public License for more details. - -You should have received a copy of the GNU Affero General Public License -along with this program. If not, see . -*/ - -package fault - -import ( - "context" - "fmt" - "regexp" - "strconv" - "strings" - - "github.com/spf13/cobra" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/runtime/schema" - "k8s.io/cli-runtime/pkg/genericiooptions" - "k8s.io/client-go/kubernetes" - "k8s.io/klog/v2" - cmdutil "k8s.io/kubectl/pkg/cmd/util" - - "github.com/apecloud/kbcli/pkg/action" - "github.com/apecloud/kbcli/pkg/printer" - "github.com/apecloud/kbcli/pkg/util" -) - -type Selector struct { - PodNameSelectors map[string][]string `json:"pods"` - - NamespaceSelectors []string `json:"namespaces"` - - LabelSelectors map[string]string `json:"labelSelectors"` - - PodPhaseSelectors []string `json:"podPhaseSelectors"` - - NodeLabelSelectors map[string]string `json:"nodeSelectors"` - - AnnotationSelectors map[string]string `json:"annotationSelectors"` - - NodeNameSelectors []string `json:"nodes"` -} - -type FaultBaseOptions struct { - Action string `json:"action"` - - Mode string `json:"mode"` - - Value string `json:"value"` - - Duration string `json:"duration"` - - Selector `json:"selector"` - - action.CreateOptions `json:"-"` -} - -func NewFaultCmd(f cmdutil.Factory, streams genericiooptions.IOStreams) *cobra.Command { - cmd := &cobra.Command{ - Use: "fault", - Short: "Inject faults to pod.", - } - cmd.AddCommand( - NewPodChaosCmd(f, streams), - NewNetworkChaosCmd(f, streams), - NewTimeChaosCmd(f, streams), - NewIOChaosCmd(f, streams), - NewStressChaosCmd(f, streams), - NewNodeChaosCmd(f, streams), - NewListCmd(f, streams), - NewDeleteCmd(f, streams), - ) - return cmd -} - -func registerFlagCompletionFunc(cmd *cobra.Command, f cmdutil.Factory) { - var formatsWithDesc = map[string]string{ - "JSON": "Output result in JSON format", - "YAML": "Output result in YAML format", - } - util.CheckErr(cmd.RegisterFlagCompletionFunc("output", - func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { - var names []string - for format, desc := range formatsWithDesc { - if strings.HasPrefix(format, toComplete) { - names = append(names, fmt.Sprintf("%s\t%s", format, desc)) - } - } - return names, cobra.ShellCompDirectiveNoFileComp - })) -} - -func (o *FaultBaseOptions) AddCommonFlag(cmd *cobra.Command) { - cmd.Flags().StringVar(&o.Mode, "mode", "all", `You can select "one", "all", "fixed", "fixed-percent", "random-max-percent", Specify the experimental mode, that is, which Pods to experiment with.`) - cmd.Flags().StringVar(&o.Value, "value", "", `If you choose mode=fixed or fixed-percent or random-max-percent, you can enter a value to specify the number or percentage of pods you want to inject.`) - cmd.Flags().StringVar(&o.Duration, "duration", "10s", "Supported formats of the duration are: ms / s / m / h.") - cmd.Flags().StringToStringVar(&o.LabelSelectors, "label", map[string]string{}, `label for pod, such as '"app.kubernetes.io/component=mysql, statefulset.kubernetes.io/pod-name=mycluster-mysql-0.`) - cmd.Flags().StringArrayVar(&o.NamespaceSelectors, "ns-fault", []string{"default"}, `Specifies the namespace into which you want to inject faults.`) - cmd.Flags().StringArrayVar(&o.PodPhaseSelectors, "phase", []string{}, `Specify the pod that injects the fault by the state of the pod.`) - cmd.Flags().StringToStringVar(&o.NodeLabelSelectors, "node-label", map[string]string{}, `label for node, such as '"kubernetes.io/arch=arm64,kubernetes.io/hostname=minikube-m03,kubernetes.io/os=linux.`) - cmd.Flags().StringArrayVar(&o.NodeNameSelectors, "node", []string{}, `Inject faults into pods in the specified node.`) - cmd.Flags().StringToStringVar(&o.AnnotationSelectors, "annotation", map[string]string{}, `Select the pod to inject the fault according to Annotation.`) - cmd.Flags().StringVar(&o.DryRun, "dry-run", "none", `Must be "client", or "server". If with client strategy, only print the object that would be sent, and no data is actually sent. If with server strategy, submit the server-side request, but no data is persistent.`) - cmd.Flags().Lookup("dry-run").NoOptDefVal = Unchanged - - printer.AddOutputFlagForCreate(cmd, &o.Format, false) -} - -func (o *FaultBaseOptions) BaseValidate() error { - if o.DryRun == "none" { - enable, err := o.checkChaosMeshEnable() - if err != nil { - return err - } - if !enable { - return fmt.Errorf("chaos-mesh is not enabled, use `kbcli addon enable fault-chaos-mesh` to enable chaos-mesh first") - } - } - - if ok, err := IsRegularMatch(o.Duration); !ok { - return err - } - - if o.Value == "" && (o.Mode == "fixed" || o.Mode == "fixed-percent" || o.Mode == "random-max-percent") { - return fmt.Errorf("you must use --value to specify an integer") - } - - if ok, err := IsInteger(o.Value); !ok { - return err - } - - return nil -} - -func (o *FaultBaseOptions) BaseComplete() error { - if len(o.Args) > 0 { - o.PodNameSelectors = make(map[string][]string, len(o.NamespaceSelectors)) - for _, ns := range o.NamespaceSelectors { - o.PodNameSelectors[ns] = o.Args - } - } - return nil -} - -func IsRegularMatch(str string) (bool, error) { - pattern := regexp.MustCompile(`^\d+(ms|s|m|h)$`) - if str != "" && !pattern.MatchString(str) { - return false, fmt.Errorf("invalid duration:%s; input format must be in the form of number + time unit, like 10s, 10m", str) - } else { - return true, nil - } -} - -func IsInteger(str string) (bool, error) { - if _, err := strconv.Atoi(str); str != "" && err != nil { - return false, fmt.Errorf("invalid value:%s; must be an integer", str) - } else { - return true, nil - } -} - -func GetGVR(group, version, resourceName string) schema.GroupVersionResource { - return schema.GroupVersionResource{Group: group, Version: version, Resource: resourceName} -} - -func (o *FaultBaseOptions) checkChaosMeshEnable() (bool, error) { - config, err := o.Factory.ToRESTConfig() - if err != nil { - return false, err - } - - clientSet, err := kubernetes.NewForConfig(config) - if err != nil { - return false, err - } - podList, err := clientSet.CoreV1().Pods("").List(context.TODO(), metav1.ListOptions{ - LabelSelector: "app.kubernetes.io/part-of=chaos-mesh", - }) - if err != nil { - klog.V(1).Info(err) - return false, err - } - - if len(podList.Items) > 0 { - return true, nil - } - return false, nil -} diff --git a/pkg/cmd/fault/fault_constant.go b/pkg/cmd/fault/fault_constant.go deleted file mode 100644 index 13ee17fe7..000000000 --- a/pkg/cmd/fault/fault_constant.go +++ /dev/null @@ -1,144 +0,0 @@ -/* -Copyright (C) 2022-2024 ApeCloud Co., Ltd - -This file is part of KubeBlocks project - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU Affero General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU Affero General Public License for more details. - -You should have received a copy of the GNU Affero General Public License -along with this program. If not, see . -*/ - -package fault - -import cp "github.com/apecloud/kbcli/pkg/cloudprovider" - -// Unchanged DryRun flag -const ( - Unchanged = "unchanged" -) - -// GVR -const ( - Group = "chaos-mesh.org" - Version = "v1alpha1" - GroupVersion = Group + "/" + Version - - ResourcePodChaos = "podchaos" - ResourceNetworkChaos = "networkchaos" - ResourceDNSChaos = "dnschaos" - ResourceHTTPChaos = "httpchaos" - ResourceIOChaos = "iochaos" - ResourceStressChaos = "stresschaos" - ResourceTimeChaos = "timechaos" - ResourceAWSChaos = "awschaos" - ResourceGCPChaos = "gcpchaos" - - KindAWSChaos = "AWSChaos" - KindGCPChaos = "GCPChaos" -) - -// Cue Template Name -const ( - CueTemplatePodChaos = "pod_chaos_template.cue" - CueTemplateNetworkChaos = "network_chaos_template.cue" - CueTemplateDNSChaos = "dns_chaos_template.cue" - CueTemplateHTTPChaos = "http_chaos_template.cue" - CueTemplateIOChaos = "io_chaos_template.cue" - CueTemplateStressChaos = "stress_chaos_template.cue" - CueTemplateTimeChaos = "time_chaos_template.cue" - CueTemplateNodeChaos = "node_chaos_template.cue" -) - -// Pod Chaos Command -const ( - Kill = "kill" - KillShort = "kill pod" - Failure = "failure" - FailureShort = "failure pod" - KillContainer = "kill-container" - KillContainerShort = "kill containers" -) - -// NetWork Chaos Command -const ( - Partition = "partition" - PartitionShort = "Make a pod network partitioned from other objects." - Loss = "loss" - LossShort = "Cause pods to communicate with other objects to drop packets." - Delay = "delay" - DelayShort = "Make pods communicate with other objects lazily." - Duplicate = "duplicate" - DuplicateShort = "Make pods communicate with other objects to pick up duplicate packets." - Corrupt = "corrupt" - CorruptShort = "Distorts the messages a pod communicates with other objects." - Bandwidth = "bandwidth" - BandwidthShort = "Limit the bandwidth that pods use to communicate with other objects." -) - -// DNS Chaos Command -const ( - Random = "random" - RandomShort = "Make DNS return any IP when resolving external domain names." - Error = "error" - ErrorShort = "Make DNS return an error when resolving external domain names." -) - -// HTTP Chaos Command -const ( - Abort = "abort" - AbortShort = "Abort the HTTP request and response." - HTTPDelay = "delay" - HTTPDelayShort = "Delay the HTTP request and response." - Replace = "replace" - ReplaceShort = "Replace the HTTP request and response." - Patch = "patch" - PatchShort = "Patch the HTTP request and response." -) - -// IO Chaos Command -const ( - Latency = "latency" - LatencyShort = "Delayed IO operations." - Errno = "errno" - ErrnoShort = "Causes IO operations to return specific errors." - Attribute = "attribute" - AttributeShort = "Override the attributes of the file." - Mistake = "mistake" - MistakeShort = "Alters the contents of the file, distorting the contents of the file." -) - -// Stress Chaos Command -const ( - Stress = "stress" - StressShort = "Add memory pressure or CPU load to the system." -) - -// Time Chaos Command -const ( - Time = "time" - TimeShort = "Clock skew failure." -) - -// Node Chaos Command -const ( - Stop = "stop" - StopShort = "Stop instance" - Restart = "restart" - RestartShort = "Restart instance" - DetachVolume = "detach-volume" - DetachVolumeShort = "Detach volume" - - AWSSecretName = "cloud-key-secret-aws" - GCPSecretName = "cloud-key-secret-gcp" -) - -var supportedCloudProviders = []string{cp.AWS, cp.GCP} diff --git a/pkg/cmd/fault/fault_dns.go b/pkg/cmd/fault/fault_dns.go deleted file mode 100644 index c51866f89..000000000 --- a/pkg/cmd/fault/fault_dns.go +++ /dev/null @@ -1,142 +0,0 @@ -/* -Copyright (C) 2022-2024 ApeCloud Co., Ltd - -This file is part of KubeBlocks project - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU Affero General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU Affero General Public License for more details. - -You should have received a copy of the GNU Affero General Public License -along with this program. If not, see . -*/ - -package fault - -import ( - "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" - "github.com/spf13/cobra" - "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" - "k8s.io/apimachinery/pkg/runtime" - "k8s.io/cli-runtime/pkg/genericiooptions" - cmdutil "k8s.io/kubectl/pkg/cmd/util" - "k8s.io/kubectl/pkg/util/templates" - - "github.com/apecloud/kbcli/pkg/action" - "github.com/apecloud/kbcli/pkg/util" -) - -var faultDNSExample = templates.Examples(` - // Inject DNS faults into all pods under the default namespace, so that any IP is returned when accessing the bing.com domain name. - kbcli fault dns random --patterns=bing.com --duration=1m - - // Inject DNS faults into all pods under the default namespace, so that error is returned when accessing the bing.com domain name. - kbcli fault dns error --patterns=bing.com --duration=1m -`) - -type DNSChaosOptions struct { - Patterns []string `json:"patterns"` - - FaultBaseOptions -} - -func NewDNSChaosOptions(f cmdutil.Factory, streams genericiooptions.IOStreams, act string) *DNSChaosOptions { - o := &DNSChaosOptions{ - FaultBaseOptions: FaultBaseOptions{ - CreateOptions: action.CreateOptions{ - Factory: f, - IOStreams: streams, - CueTemplateName: CueTemplateDNSChaos, - GVR: GetGVR(Group, Version, ResourceDNSChaos), - }, - Action: act, - }, - } - o.CreateOptions.PreCreate = o.PreCreate - o.CreateOptions.Options = o - return o -} - -func NewDNSChaosCmd(f cmdutil.Factory, streams genericiooptions.IOStreams) *cobra.Command { - cmd := &cobra.Command{ - Use: "dns", - Short: "Inject faults into DNS server.", - } - cmd.AddCommand( - NewRandomCmd(f, streams), - NewErrorCmd(f, streams), - ) - return cmd -} - -func NewRandomCmd(f cmdutil.Factory, streams genericiooptions.IOStreams) *cobra.Command { - o := NewDNSChaosOptions(f, streams, string(v1alpha1.RandomAction)) - cmd := o.NewCobraCommand(Random, RandomShort) - - o.AddCommonFlag(cmd) - util.CheckErr(cmd.MarkFlagRequired("patterns")) - - return cmd -} - -func NewErrorCmd(f cmdutil.Factory, streams genericiooptions.IOStreams) *cobra.Command { - o := NewDNSChaosOptions(f, streams, string(v1alpha1.ErrorAction)) - cmd := o.NewCobraCommand(Error, ErrorShort) - - o.AddCommonFlag(cmd) - util.CheckErr(cmd.MarkFlagRequired("patterns")) - - return cmd -} - -func (o *DNSChaosOptions) NewCobraCommand(use, short string) *cobra.Command { - return &cobra.Command{ - Use: use, - Short: short, - Example: faultDNSExample, - Run: func(cmd *cobra.Command, args []string) { - o.Args = args - cmdutil.CheckErr(o.CreateOptions.Complete()) - cmdutil.CheckErr(o.Validate()) - cmdutil.CheckErr(o.Complete()) - cmdutil.CheckErr(o.Run()) - }, - } -} - -func (o *DNSChaosOptions) AddCommonFlag(cmd *cobra.Command) { - o.FaultBaseOptions.AddCommonFlag(cmd) - - cmd.Flags().StringArrayVar(&o.Patterns, "patterns", nil, `Select the domain name template that matching the failure behavior & supporting placeholders ? and wildcards *.`) - - // register flag completion func - registerFlagCompletionFunc(cmd, o.Factory) -} - -func (o *DNSChaosOptions) Validate() error { - return o.BaseValidate() -} - -func (o *DNSChaosOptions) Complete() error { - return o.BaseComplete() -} - -func (o *DNSChaosOptions) PreCreate(obj *unstructured.Unstructured) error { - c := &v1alpha1.DNSChaos{} - if err := runtime.DefaultUnstructuredConverter.FromUnstructured(obj.Object, c); err != nil { - return err - } - - data, e := runtime.DefaultUnstructuredConverter.ToUnstructured(c) - if e != nil { - return e - } - obj.SetUnstructuredContent(data) - return nil -} diff --git a/pkg/cmd/fault/fault_dns_test.go b/pkg/cmd/fault/fault_dns_test.go deleted file mode 100644 index 8b4d7c3a8..000000000 --- a/pkg/cmd/fault/fault_dns_test.go +++ /dev/null @@ -1,93 +0,0 @@ -/* -Copyright (C) 2022-2024 ApeCloud Co., Ltd - -This file is part of KubeBlocks project - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU Affero General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU Affero General Public License for more details. - -You should have received a copy of the GNU Affero General Public License -along with this program. If not, see . -*/ - -package fault - -import ( - . "github.com/onsi/ginkgo/v2" - . "github.com/onsi/gomega" - - "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" - "k8s.io/cli-runtime/pkg/genericiooptions" - clientfake "k8s.io/client-go/rest/fake" - cmdtesting "k8s.io/kubectl/pkg/cmd/testing" - - "github.com/apecloud/kbcli/pkg/testing" -) - -var _ = Describe("Fault Network DNS", func() { - var ( - tf *cmdtesting.TestFactory - streams genericiooptions.IOStreams - ) - BeforeEach(func() { - streams, _, _, _ = genericiooptions.NewTestIOStreams() - tf = cmdtesting.NewTestFactory().WithNamespace(testing.Namespace) - tf.Client = &clientfake.RESTClient{} - }) - - AfterEach(func() { - tf.Cleanup() - }) - Context("test fault network dns", func() { - - It("fault network dns random", func() { - inputs := [][]string{ - {"--dry-run=client", "--patterns=kubeblocks.io"}, - {"--mode=one", "--patterns=kubeblocks.io", "--dry-run=client"}, - {"--mode=fixed", "--value=2", "--patterns=kubeblocks.io", "--dry-run=client"}, - {"--mode=fixed-percent", "--value=50", "--patterns=kubeblocks.io", "--dry-run=client"}, - {"--mode=random-max-percent", "--value=50", "--patterns=kubeblocks.io", "--dry-run=client"}, - {"--ns-fault=kb-system", "--patterns=kubeblocks.io", "--dry-run=client"}, - {"--node=minikube-m02", "--patterns=kubeblocks.io", "--dry-run=client"}, - {"--label=app.kubernetes.io/component=mysql", "--patterns=kubeblocks.io", "--dry-run=client"}, - {"--node-label=kubernetes.io/arch=arm64", "--patterns=kubeblocks.io", "--dry-run=client"}, - {"--annotation=example-annotation=group-a", "--patterns=kubeblocks.io", "--dry-run=client"}, - } - o := NewDNSChaosOptions(tf, streams, string(v1alpha1.RandomAction)) - cmd := o.NewCobraCommand(Random, RandomShort) - o.AddCommonFlag(cmd) - - for _, input := range inputs { - Expect(cmd.Flags().Parse(input)).Should(Succeed()) - Expect(o.CreateOptions.Complete()) - Expect(o.Complete()).Should(Succeed()) - Expect(o.Validate()).Should(Succeed()) - Expect(o.Run()).Should(Succeed()) - } - }) - - It("fault network dns error", func() { - inputs := [][]string{ - {"--patterns=kubeblocks.io", "--dry-run=client"}, - } - o := NewDNSChaosOptions(tf, streams, string(v1alpha1.ErrorAction)) - cmd := o.NewCobraCommand(Error, ErrorShort) - o.AddCommonFlag(cmd) - - for _, input := range inputs { - Expect(cmd.Flags().Parse(input)).Should(Succeed()) - Expect(o.CreateOptions.Complete()) - Expect(o.Complete()).Should(Succeed()) - Expect(o.Validate()).Should(Succeed()) - Expect(o.Run()).Should(Succeed()) - } - }) - }) -}) diff --git a/pkg/cmd/fault/fault_http.go b/pkg/cmd/fault/fault_http.go deleted file mode 100644 index b95a5819e..000000000 --- a/pkg/cmd/fault/fault_http.go +++ /dev/null @@ -1,243 +0,0 @@ -/* -Copyright (C) 2022-2024 ApeCloud Co., Ltd - -This file is part of KubeBlocks project - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU Affero General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU Affero General Public License for more details. - -You should have received a copy of the GNU Affero General Public License -along with this program. If not, see . -*/ - -package fault - -import ( - "fmt" - - "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" - "github.com/spf13/cobra" - "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" - "k8s.io/apimachinery/pkg/runtime" - "k8s.io/apimachinery/pkg/util/json" - "k8s.io/cli-runtime/pkg/genericiooptions" - cmdutil "k8s.io/kubectl/pkg/cmd/util" - "k8s.io/kubectl/pkg/util/templates" - - "github.com/apecloud/kbcli/pkg/action" -) - -var faultHTTPExample = templates.Examples(` - # By default, the method of GET from port 80 is blocked. - kbcli fault network http abort --duration=1m - - # Block the method of GET from port 4399. - kbcli fault network http abort --port=4399 --duration=1m - - # Block the method of POST from port 4399. - kbcli fault network http abort --port=4399 --method=POST --duration=1m - - # Delays post requests from port 4399. - kbcli fault network http delay --port=4399 --method=POST --delay=15s - - # Replace the GET method sent from port 80 with the PUT method. - kbcli fault network http replace --replace-method=PUT --duration=1m - - # Replace the GET method sent from port 80 with the PUT method, and replace the request body. - kbcli fault network http replace --body="you are good luck" --replace-method=PUT --duration=2m - - # Replace the response content "you" from port 80. - kbcli fault network http replace --target=Response --body=you --duration=30s - - # Append content to the body of the post request sent from port 4399, in JSON format. - kbcli fault network http patch --method=POST --port=4399 --body="you are good luck" --type=JSON --duration=30s -`) - -type HTTPReplace struct { - ReplaceBody []byte `json:"body,omitempty"` - InputReplaceBody string `json:"-"` - ReplacePath string `json:"path,omitempty"` - ReplaceMethod string `json:"method,omitempty"` -} - -type HTTPPatch struct { - HTTPPatchBody `json:"body,omitempty"` -} - -type HTTPPatchBody struct { - PatchBodyValue string `json:"value,omitempty"` - PatchBodyType string `json:"type,omitempty"` -} - -type HTTPChaosOptions struct { - Target string `json:"target"` - Port int32 `json:"port"` - Path string `json:"path"` - Method string `json:"method"` - Code int32 `json:"code,omitempty"` - - // abort command - Abort bool `json:"abort,omitempty"` - // delay command - Delay string `json:"delay,omitempty"` - // replace command - HTTPReplace `json:"replace,omitempty"` - // patch command - HTTPPatch `json:"patch,omitempty"` - - FaultBaseOptions -} - -func NewHTTPChaosOptions(f cmdutil.Factory, streams genericiooptions.IOStreams, act string) *HTTPChaosOptions { - o := &HTTPChaosOptions{ - FaultBaseOptions: FaultBaseOptions{ - CreateOptions: action.CreateOptions{ - Factory: f, - IOStreams: streams, - CueTemplateName: CueTemplateHTTPChaos, - GVR: GetGVR(Group, Version, ResourceHTTPChaos), - }, - Action: act, - }, - } - o.CreateOptions.PreCreate = o.PreCreate - o.CreateOptions.Options = o - return o -} - -func NewHTTPChaosCmd(f cmdutil.Factory, streams genericiooptions.IOStreams) *cobra.Command { - cmd := &cobra.Command{ - Use: "http", - Short: "Intercept HTTP requests and responses.", - } - cmd.AddCommand( - NewAbortCmd(f, streams), - NewHTTPDelayCmd(f, streams), - NewReplaceCmd(f, streams), - NewPatchCmd(f, streams), - ) - return cmd -} - -func NewAbortCmd(f cmdutil.Factory, streams genericiooptions.IOStreams) *cobra.Command { - o := NewHTTPChaosOptions(f, streams, "") - cmd := o.NewCobraCommand(Abort, AbortShort) - - o.AddCommonFlag(cmd) - cmd.Flags().BoolVar(&o.Abort, "abort", true, `Indicates whether to inject the fault that interrupts the connection.`) - - return cmd -} - -func NewHTTPDelayCmd(f cmdutil.Factory, streams genericiooptions.IOStreams) *cobra.Command { - o := NewHTTPChaosOptions(f, streams, "") - cmd := o.NewCobraCommand(HTTPDelay, HTTPDelayShort) - - o.AddCommonFlag(cmd) - cmd.Flags().StringVar(&o.Delay, "delay", "10s", `The time for delay.`) - - return cmd -} - -func NewReplaceCmd(f cmdutil.Factory, streams genericiooptions.IOStreams) *cobra.Command { - o := NewHTTPChaosOptions(f, streams, "") - cmd := o.NewCobraCommand(Replace, ReplaceShort) - - o.AddCommonFlag(cmd) - cmd.Flags().StringVar(&o.InputReplaceBody, "body", "", `The content of the request body or response body to replace the failure.`) - cmd.Flags().StringVar(&o.ReplacePath, "replace-path", "", `The URI path used to replace content.`) - cmd.Flags().StringVar(&o.ReplaceMethod, "replace-method", "", `The replaced content of the HTTP request method.`) - - return cmd -} - -func NewPatchCmd(f cmdutil.Factory, streams genericiooptions.IOStreams) *cobra.Command { - o := NewHTTPChaosOptions(f, streams, "") - cmd := o.NewCobraCommand(Patch, PatchShort) - - o.AddCommonFlag(cmd) - cmd.Flags().StringVar(&o.PatchBodyValue, "body", "", `The fault of the request body or response body with patch faults.`) - cmd.Flags().StringVar(&o.PatchBodyType, "type", "", `The type of patch faults of the request body or response body. Currently, it only supports JSON.`) - - return cmd -} - -func (o *HTTPChaosOptions) NewCobraCommand(use, short string) *cobra.Command { - return &cobra.Command{ - Use: use, - Short: short, - Example: faultHTTPExample, - Run: func(cmd *cobra.Command, args []string) { - o.Args = args - cmdutil.CheckErr(o.CreateOptions.Complete()) - cmdutil.CheckErr(o.Validate()) - cmdutil.CheckErr(o.Complete()) - cmdutil.CheckErr(o.Run()) - }, - } -} - -func (o *HTTPChaosOptions) AddCommonFlag(cmd *cobra.Command) { - o.FaultBaseOptions.AddCommonFlag(cmd) - - cmd.Flags().StringVar(&o.Target, "target", "Request", `Specifies whether the target of fault injection is Request or Response. The target-related fields should be configured at the same time.`) - cmd.Flags().Int32Var(&o.Port, "port", 80, `The TCP port that the target service listens on.`) - cmd.Flags().StringVar(&o.Path, "path", "*", `The URI path of the target request. Supports Matching wildcards.`) - cmd.Flags().StringVar(&o.Method, "method", "GET", `The HTTP method of the target request method. For example: GET, POST, PUT, DELETE, HEAD, OPTIONS, PATCH.`) - cmd.Flags().Int32Var(&o.Code, "code", 0, `The status code responded by target.`) - - // register flag completion func - registerFlagCompletionFunc(cmd, o.Factory) -} - -func (o *HTTPChaosOptions) Validate() error { - if o.PatchBodyType != "" && o.PatchBodyType != "JSON" { - return fmt.Errorf("--type only supports JSON") - } - if o.PatchBodyValue != "" && o.PatchBodyType == "" { - return fmt.Errorf("--type is required when --body is specified") - } - if o.PatchBodyType != "" && o.PatchBodyValue == "" { - return fmt.Errorf("--body is required when --type is specified") - } - - var msg interface{} - if o.PatchBodyValue != "" && json.Unmarshal([]byte(o.PatchBodyValue), &msg) != nil { - return fmt.Errorf("--body is not a valid JSON") - } - - if o.Target == "Request" && o.Code != 0 { - return fmt.Errorf("--code is only supported when --target=Response") - } - - if ok, err := IsRegularMatch(o.Delay); !ok { - return err - } - return o.BaseValidate() -} - -func (o *HTTPChaosOptions) Complete() error { - o.ReplaceBody = []byte(o.InputReplaceBody) - return o.BaseComplete() -} - -func (o *HTTPChaosOptions) PreCreate(obj *unstructured.Unstructured) error { - c := &v1alpha1.HTTPChaos{} - if err := runtime.DefaultUnstructuredConverter.FromUnstructured(obj.Object, c); err != nil { - return err - } - - data, e := runtime.DefaultUnstructuredConverter.ToUnstructured(c) - if e != nil { - return e - } - obj.SetUnstructuredContent(data) - return nil -} diff --git a/pkg/cmd/fault/fault_http_test.go b/pkg/cmd/fault/fault_http_test.go deleted file mode 100644 index d2960c253..000000000 --- a/pkg/cmd/fault/fault_http_test.go +++ /dev/null @@ -1,139 +0,0 @@ -/* -Copyright (C) 2022-2024 ApeCloud Co., Ltd - -This file is part of KubeBlocks project - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU Affero General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU Affero General Public License for more details. - -You should have received a copy of the GNU Affero General Public License -along with this program. If not, see . -*/ - -package fault - -import ( - . "github.com/onsi/ginkgo/v2" - . "github.com/onsi/gomega" - - "k8s.io/cli-runtime/pkg/genericiooptions" - clientfake "k8s.io/client-go/rest/fake" - cmdtesting "k8s.io/kubectl/pkg/cmd/testing" - - "github.com/apecloud/kbcli/pkg/testing" -) - -var _ = Describe("Fault Network HTPP", func() { - var ( - tf *cmdtesting.TestFactory - streams genericiooptions.IOStreams - ) - BeforeEach(func() { - streams, _, _, _ = genericiooptions.NewTestIOStreams() - tf = cmdtesting.NewTestFactory().WithNamespace(testing.Namespace) - tf.Client = &clientfake.RESTClient{} - }) - - AfterEach(func() { - tf.Cleanup() - }) - - Context("test fault network http", func() { - It("fault network http abort", func() { - inputs := [][]string{ - {"--dry-run=client"}, - {"--mode=one", "--dry-run=client"}, - {"--mode=fixed", "--value=2", "--dry-run=client"}, - {"--mode=fixed-percent", "--value=50", "--dry-run=client"}, - {"--mode=random-max-percent", "--value=50", "--dry-run=client"}, - {"--ns-fault=kb-system", "--dry-run=client"}, - {"--node=minikube-m02", "--dry-run=client"}, - {"--label=app.kubernetes.io/component=mysql", "--dry-run=client"}, - {"--node-label=kubernetes.io/arch=arm64", "--dry-run=client"}, - {"--annotation=example-annotation=group-a", "--dry-run=client"}, - {"--abort=true", "--dry-run=client"}, - } - o := NewHTTPChaosOptions(tf, streams, "") - cmd := o.NewCobraCommand(Abort, AbortShort) - o.AddCommonFlag(cmd) - cmd.Flags().BoolVar(&o.Abort, "abort", true, `Indicates whether to inject the fault that interrupts the connection.`) - - for _, input := range inputs { - Expect(cmd.Flags().Parse(input)).Should(Succeed()) - Expect(o.CreateOptions.Complete()) - Expect(o.Complete()).Should(Succeed()) - Expect(o.Validate()).Should(Succeed()) - Expect(o.Run()).Should(Succeed()) - } - }) - - It("fault network http delay", func() { - inputs := [][]string{ - {"--dry-run=client"}, - {"--delay=50s", "--dry-run=client"}, - } - o := NewHTTPChaosOptions(tf, streams, "") - cmd := o.NewCobraCommand(Delay, DelayShort) - o.AddCommonFlag(cmd) - cmd.Flags().StringVar(&o.Delay, "delay", "10s", `The time for delay.`) - - for _, input := range inputs { - Expect(cmd.Flags().Parse(input)).Should(Succeed()) - Expect(o.CreateOptions.Complete()) - Expect(o.Complete()).Should(Succeed()) - Expect(o.Validate()).Should(Succeed()) - Expect(o.Run()).Should(Succeed()) - } - }) - - It("fault network http replace", func() { - inputs := [][]string{ - {"--dry-run=client"}, - {"--replace-method=PUT", "--body=\"you are good luck\"", "--replace-path=/local/", "--duration=1m", "--dry-run=client"}, - {"--target=Response", "--replace-method=PUT", "--body=you", "--replace-path=/local/", "--duration=1m", "--dry-run=client"}, - } - o := NewHTTPChaosOptions(tf, streams, "") - cmd := o.NewCobraCommand(Replace, ReplaceShort) - o.AddCommonFlag(cmd) - cmd.Flags().StringVar(&o.InputReplaceBody, "body", "", `The content of the request body or response body to replace the failure.`) - cmd.Flags().StringVar(&o.ReplacePath, "replace-path", "", `The URI path used to replace content.`) - cmd.Flags().StringVar(&o.ReplaceMethod, "replace-method", "", `The replaced content of the HTTP request method.`) - - for _, input := range inputs { - Expect(cmd.Flags().Parse(input)).Should(Succeed()) - Expect(o.CreateOptions.Complete()) - Expect(o.Complete()).Should(Succeed()) - Expect(o.Validate()).Should(Succeed()) - Expect(o.Run()).Should(Succeed()) - } - }) - - It("fault network http patch", func() { - inputs := [][]string{ - {"--dry-run=client"}, - {"--body=\"you are good luck\"", "--type=JSON", "--duration=1m", "--dry-run=client"}, - {"--target=Response", "--body=\"you are good luck\"", "--type=JSON", "--duration=1m", "--dry-run=client"}, - } - o := NewHTTPChaosOptions(tf, streams, "") - cmd := o.NewCobraCommand(Patch, PatchShort) - o.AddCommonFlag(cmd) - cmd.Flags().StringVar(&o.PatchBodyValue, "body", "", `The fault of the request body or response body with patch faults.`) - cmd.Flags().StringVar(&o.PatchBodyType, "type", "", `The type of patch faults of the request body or response body. Currently, it only supports JSON.`) - - for _, input := range inputs { - Expect(cmd.Flags().Parse(input)).Should(Succeed()) - Expect(o.CreateOptions.Complete()) - Expect(o.Complete()).Should(Succeed()) - Expect(o.Validate()).Should(Succeed()) - Expect(o.Run()).Should(Succeed()) - } - }) - }) -}) diff --git a/pkg/cmd/fault/fault_io.go b/pkg/cmd/fault/fault_io.go deleted file mode 100644 index 726f3faa1..000000000 --- a/pkg/cmd/fault/fault_io.go +++ /dev/null @@ -1,231 +0,0 @@ -/* -Copyright (C) 2022-2024 ApeCloud Co., Ltd - -This file is part of KubeBlocks project - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU Affero General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU Affero General Public License for more details. - -You should have received a copy of the GNU Affero General Public License -along with this program. If not, see . -*/ - -package fault - -import ( - "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" - "github.com/spf13/cobra" - "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" - "k8s.io/apimachinery/pkg/runtime" - "k8s.io/cli-runtime/pkg/genericiooptions" - cmdutil "k8s.io/kubectl/pkg/cmd/util" - "k8s.io/kubectl/pkg/util/templates" - - "github.com/apecloud/kbcli/pkg/action" - "github.com/apecloud/kbcli/pkg/util" -) - -var faultIOExample = templates.Examples(` - # Affects the first container in default namespace's all pods. Delay all IO operations under the /data path by 10s. - kbcli fault io latency --delay=10s --volume-path=/data - - # Affects the first container in mycluster-mysql-0 pod. - kbcli fault io latency mycluster-mysql-0 --delay=10s --volume-path=/data - - # Affects the mysql container in mycluster-mysql-0 pod. - kbcli fault io latency mycluster-mysql-0 --delay=10s --volume-path=/data -c=mysql - - # There is a 50% probability of affecting the read IO operation of the test.txt file under the /data path. - kbcli fault io latency mycluster-mysql-0 --delay=10s --volume-path=/data --path=test.txt --percent=50 --method=READ -c=mysql - - # Same as above.Make all IO operations under the /data path return the specified error number 22 (Invalid argument). - kbcli fault io errno --volume-path=/data --errno=22 - - # Same as above.Modify the IO operation permission attribute of the files under the /data path to 72.(110 in octal). - kbcli fault io attribute --volume-path=/data --perm=72 - - # Modify all files so that random positions of 1's with a maximum length of 10 bytes will be replaced with 0's. - kbcli fault io mistake --volume-path=/data --filling=zero --max-occurrences=10 --max-length=1 -`) - -type IOAttribute struct { - Ino uint64 `json:"ino,omitempty"` - Size uint64 `json:"size,omitempty"` - Blocks uint64 `json:"blocks,omitempty"` - Perm uint16 `json:"perm,omitempty"` - Nlink uint32 `json:"nlink,omitempty"` - UID uint32 `json:"uid,omitempty"` - GID uint32 `json:"gid,omitempty"` -} - -type IOMistake struct { - Filling string `json:"filling,omitempty"` - MaxOccurrences int `json:"maxOccurrences,omitempty"` - MaxLength int `json:"maxLength,omitempty"` -} - -type IOChaosOptions struct { - // Parameters required by the `latency` command. - Delay string `json:"delay"` - - // Parameters required by the `fault` command. - Errno int `json:"errno"` - - // Parameters required by the `attribute` command. - IOAttribute `json:"attr,omitempty"` - - // Parameters required by the `mistake` command. - IOMistake `json:"mistake,omitempty"` - - VolumePath string `json:"volumePath"` - Path string `json:"path"` - Percent int `json:"percent"` - Methods []string `json:"methods,omitempty"` - ContainerNames []string `json:"containerNames,omitempty"` - - FaultBaseOptions -} - -func NewIOChaosCmd(f cmdutil.Factory, streams genericiooptions.IOStreams) *cobra.Command { - cmd := &cobra.Command{ - Use: "io", - Short: "IO chaos.", - } - cmd.AddCommand( - NewIOLatencyCmd(f, streams), - NewIOFaultCmd(f, streams), - NewIOAttributeOverrideCmd(f, streams), - NewIOMistakeCmd(f, streams), - ) - return cmd -} - -func NewIOChaosOptions(f cmdutil.Factory, streams genericiooptions.IOStreams, act string) *IOChaosOptions { - o := &IOChaosOptions{ - FaultBaseOptions: FaultBaseOptions{ - CreateOptions: action.CreateOptions{ - Factory: f, - IOStreams: streams, - CueTemplateName: CueTemplateIOChaos, - GVR: GetGVR(Group, Version, ResourceIOChaos), - }, - Action: act, - }, - } - o.CreateOptions.PreCreate = o.PreCreate - o.CreateOptions.Options = o - return o -} - -func NewIOLatencyCmd(f cmdutil.Factory, streams genericiooptions.IOStreams) *cobra.Command { - o := NewIOChaosOptions(f, streams, string(v1alpha1.IoLatency)) - cmd := o.NewCobraCommand(Latency, LatencyShort) - - o.AddCommonFlag(cmd, f) - cmd.Flags().StringVar(&o.Delay, "delay", "", `Specific delay time.`) - - util.CheckErr(cmd.MarkFlagRequired("delay")) - return cmd -} - -func NewIOFaultCmd(f cmdutil.Factory, streams genericiooptions.IOStreams) *cobra.Command { - o := NewIOChaosOptions(f, streams, string(v1alpha1.IoFaults)) - cmd := o.NewCobraCommand(Errno, ErrnoShort) - - o.AddCommonFlag(cmd, f) - cmd.Flags().IntVar(&o.Errno, "errno", 0, `The returned error number.`) - - util.CheckErr(cmd.MarkFlagRequired("errno")) - return cmd -} - -func NewIOAttributeOverrideCmd(f cmdutil.Factory, streams genericiooptions.IOStreams) *cobra.Command { - o := NewIOChaosOptions(f, streams, string(v1alpha1.IoAttrOverride)) - cmd := o.NewCobraCommand(Attribute, AttributeShort) - - o.AddCommonFlag(cmd, f) - cmd.Flags().Uint64Var(&o.Ino, "ino", 0, `ino number.`) - cmd.Flags().Uint64Var(&o.Size, "size", 0, `File size.`) - cmd.Flags().Uint64Var(&o.Blocks, "blocks", 0, `The number of blocks the file occupies.`) - cmd.Flags().Uint16Var(&o.Perm, "perm", 0, `Decimal representation of file permissions.`) - cmd.Flags().Uint32Var(&o.Nlink, "nlink", 0, `The number of hard links.`) - cmd.Flags().Uint32Var(&o.UID, "uid", 0, `Owner's user ID.`) - cmd.Flags().Uint32Var(&o.GID, "gid", 0, `The owner's group ID.`) - - return cmd -} - -func NewIOMistakeCmd(f cmdutil.Factory, streams genericiooptions.IOStreams) *cobra.Command { - o := NewIOChaosOptions(f, streams, string(v1alpha1.IoMistake)) - cmd := o.NewCobraCommand(Mistake, MistakeShort) - - o.AddCommonFlag(cmd, f) - cmd.Flags().StringVar(&o.Filling, "filling", "", `The filling content of the error data can only be zero (filling with 0) or random (filling with random bytes).`) - cmd.Flags().IntVar(&o.MaxOccurrences, "max-occurrences", 1, `The maximum number of times an error can occur per operation.`) - cmd.Flags().IntVar(&o.MaxLength, "max-length", 1, `The maximum length (in bytes) of each error.`) - - util.CheckErr(cmd.MarkFlagRequired("filling")) - util.CheckErr(cmd.MarkFlagRequired("max-occurrences")) - util.CheckErr(cmd.MarkFlagRequired("max-length")) - - return cmd -} - -func (o *IOChaosOptions) NewCobraCommand(use, short string) *cobra.Command { - return &cobra.Command{ - Use: use, - Short: short, - Example: faultIOExample, - Run: func(cmd *cobra.Command, args []string) { - o.Args = args - cmdutil.CheckErr(o.CreateOptions.Complete()) - cmdutil.CheckErr(o.Validate()) - cmdutil.CheckErr(o.Complete()) - cmdutil.CheckErr(o.Run()) - }, - } -} - -func (o *IOChaosOptions) AddCommonFlag(cmd *cobra.Command, f cmdutil.Factory) { - o.FaultBaseOptions.AddCommonFlag(cmd) - - cmd.Flags().StringVar(&o.VolumePath, "volume-path", "", `The mount point of the volume in the target container must be the root directory of the mount.`) - cmd.Flags().StringVar(&o.Path, "path", "", `The effective scope of the injection error can be a wildcard or a single file.`) - cmd.Flags().IntVar(&o.Percent, "percent", 100, `Probability of failure per operation, in %.`) - cmd.Flags().StringArrayVar(&o.Methods, "method", nil, "The file system calls that need to inject faults. For example: WRITE READ") - cmd.Flags().StringArrayVarP(&o.ContainerNames, "container", "c", nil, "The name of the container, such as mysql, prometheus.If it's empty, the first container will be injected.") - - util.CheckErr(cmd.MarkFlagRequired("volume-path")) - - // register flag completion func - registerFlagCompletionFunc(cmd, f) -} - -func (o *IOChaosOptions) Validate() error { - return o.BaseValidate() -} - -func (o *IOChaosOptions) Complete() error { - return o.BaseComplete() -} - -func (o *IOChaosOptions) PreCreate(obj *unstructured.Unstructured) error { - c := &v1alpha1.IOChaos{} - if err := runtime.DefaultUnstructuredConverter.FromUnstructured(obj.Object, c); err != nil { - return err - } - - data, e := runtime.DefaultUnstructuredConverter.ToUnstructured(c) - if e != nil { - return e - } - obj.SetUnstructuredContent(data) - return nil -} diff --git a/pkg/cmd/fault/fault_io_test.go b/pkg/cmd/fault/fault_io_test.go deleted file mode 100644 index 624228e2b..000000000 --- a/pkg/cmd/fault/fault_io_test.go +++ /dev/null @@ -1,146 +0,0 @@ -/* -Copyright (C) 2022-2024 ApeCloud Co., Ltd - -This file is part of KubeBlocks project - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU Affero General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU Affero General Public License for more details. - -You should have received a copy of the GNU Affero General Public License -along with this program. If not, see . -*/ - -package fault - -import ( - . "github.com/onsi/ginkgo/v2" - . "github.com/onsi/gomega" - - "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" - "k8s.io/cli-runtime/pkg/genericiooptions" - clientfake "k8s.io/client-go/rest/fake" - cmdtesting "k8s.io/kubectl/pkg/cmd/testing" - - "github.com/apecloud/kbcli/pkg/testing" -) - -var _ = Describe("Fault IO", func() { - var ( - tf *cmdtesting.TestFactory - streams genericiooptions.IOStreams - ) - BeforeEach(func() { - streams, _, _, _ = genericiooptions.NewTestIOStreams() - tf = cmdtesting.NewTestFactory().WithNamespace(testing.Namespace) - tf.Client = &clientfake.RESTClient{} - }) - - AfterEach(func() { - tf.Cleanup() - }) - - Context("test fault io", func() { - - It("fault io latency", func() { - inputs := [][]string{ - {"--mode=one", "--delay=10s", "--volume-path=/data", "--dry-run=client"}, - {"--mode=fixed", "--value=2", "--delay=10s", "--volume-path=/data", "--dry-run=client"}, - {"--mode=fixed-percent", "--value=50", "--delay=10s", "--volume-path=/data", "--dry-run=client"}, - {"--mode=random-max-percent", "--value=50", "--delay=10s", "--volume-path=/data", "--dry-run=client"}, - {"--ns-fault=kb-system", "--delay=10s", "--volume-path=/data", "--dry-run=client"}, - {"--node=minikube-m02", "--delay=10s", "--volume-path=/data", "--dry-run=client"}, - {"--label=app.kubernetes.io/component=mysql", "--delay=10s", "--volume-path=/data", "--dry-run=client"}, - {"--node-label=kubernetes.io/arch=arm64", "--delay=10s", "--volume-path=/data", "--dry-run=client"}, - {"--annotation=example-annotation=group-a", "--delay=10s", "--volume-path=/data", "--dry-run=client"}, - {"--delay=10s", "--volume-path=/data", "--dry-run=client"}, - {"--delay=10s", "--volume-path=/data", "--path=test.txt", "--percent=50", "--method=READ", "-c=mysql", "--dry-run=client"}, - } - o := NewIOChaosOptions(tf, streams, string(v1alpha1.IoLatency)) - cmd := o.NewCobraCommand(Latency, LatencyShort) - o.AddCommonFlag(cmd, tf) - cmd.Flags().StringVar(&o.Delay, "delay", "", `Specific delay time.`) - - for _, input := range inputs { - Expect(cmd.Flags().Parse(input)).Should(Succeed()) - Expect(o.CreateOptions.Complete()) - Expect(o.Complete()).Should(Succeed()) - Expect(o.Validate()).Should(Succeed()) - Expect(o.Run()).Should(Succeed()) - } - }) - - It("fault io errno", func() { - inputs := [][]string{ - {"--errno=22", "--volume-path=/data", "--dry-run=client"}, - {"--errno=22", "--volume-path=/data", "--path=test.txt", "--percent=50", "--method=READ", "--dry-run=client"}, - } - o := NewIOChaosOptions(tf, streams, string(v1alpha1.IoFaults)) - cmd := o.NewCobraCommand(Errno, ErrnoShort) - o.AddCommonFlag(cmd, tf) - cmd.Flags().IntVar(&o.Errno, "errno", 0, `The returned error number.`) - - for _, input := range inputs { - Expect(cmd.Flags().Parse(input)).Should(Succeed()) - Expect(o.CreateOptions.Complete()) - Expect(o.Complete()).Should(Succeed()) - Expect(o.Validate()).Should(Succeed()) - Expect(o.Run()).Should(Succeed()) - } - }) - - It("fault io attribute", func() { - inputs := [][]string{ - {"--perm=72", "--size=72", "--blocks=72", "--nlink=72", "--ino=72", - "--uid=72", "--gid=72", "--volume-path=/data", "--dry-run=client"}, - } - o := NewIOChaosOptions(tf, streams, string(v1alpha1.IoAttrOverride)) - cmd := o.NewCobraCommand(Attribute, AttributeShort) - o.AddCommonFlag(cmd, tf) - cmd.Flags().Uint64Var(&o.Ino, "ino", 0, `ino number.`) - cmd.Flags().Uint64Var(&o.Size, "size", 0, `File size.`) - cmd.Flags().Uint64Var(&o.Blocks, "blocks", 0, `The number of blocks the file occupies.`) - cmd.Flags().Uint16Var(&o.Perm, "perm", 0, `Decimal representation of file permissions.`) - cmd.Flags().Uint32Var(&o.Nlink, "nlink", 0, `The number of hard links.`) - cmd.Flags().Uint32Var(&o.UID, "uid", 0, `Owner's user ID.`) - cmd.Flags().Uint32Var(&o.GID, "gid", 0, `The owner's group ID.`) - - for _, input := range inputs { - Expect(cmd.Flags().Parse(input)).Should(Succeed()) - Expect(o.CreateOptions.Complete()) - Expect(o.Complete()).Should(Succeed()) - Expect(o.Validate()).Should(Succeed()) - Expect(o.Run()).Should(Succeed()) - } - }) - - It("fault io mistake", func() { - inputs := [][]string{ - {"--volume-path=/data", "--filling=zero", "--max-occurrences=10", "--max-length=1", "--dry-run=client"}, - {"--volume-path=/data", "--filling=random", "--max-occurrences=10", "--max-length=1", "--dry-run=client"}, - {"--volume-path=/data", "--filling=zero", "--max-occurrences=10", "--max-length=1", "--path=test.txt", "--percent=50", "--method=READ", "--dry-run=client"}, - } - o := NewIOChaosOptions(tf, streams, string(v1alpha1.IoMistake)) - cmd := o.NewCobraCommand(Mistake, MistakeShort) - o.AddCommonFlag(cmd, tf) - cmd.Flags().StringVar(&o.Filling, "filling", "", `The filling content of the error data can only be zero (filling with 0) or random (filling with random bytes).`) - cmd.Flags().IntVar(&o.MaxOccurrences, "max-occurrences", 1, `The maximum number of times an error can occur per operation.`) - cmd.Flags().IntVar(&o.MaxLength, "max-length", 1, `The maximum length (in bytes) of each error.`) - - for _, input := range inputs { - Expect(cmd.Flags().Parse(input)).Should(Succeed()) - Expect(o.CreateOptions.Complete()) - Expect(o.Complete()).Should(Succeed()) - Expect(o.Validate()).Should(Succeed()) - Expect(o.Run()).Should(Succeed()) - } - }) - - }) -}) diff --git a/pkg/cmd/fault/fault_network.go b/pkg/cmd/fault/fault_network.go deleted file mode 100644 index 7f7c27386..000000000 --- a/pkg/cmd/fault/fault_network.go +++ /dev/null @@ -1,355 +0,0 @@ -/* -Copyright (C) 2022-2024 ApeCloud Co., Ltd - -This file is part of KubeBlocks project - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU Affero General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU Affero General Public License for more details. - -You should have received a copy of the GNU Affero General Public License -along with this program. If not, see . -*/ - -package fault - -import ( - "fmt" - - "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" - "github.com/spf13/cobra" - "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" - "k8s.io/apimachinery/pkg/runtime" - "k8s.io/cli-runtime/pkg/genericiooptions" - cmdutil "k8s.io/kubectl/pkg/cmd/util" - "k8s.io/kubectl/pkg/util/templates" - - "github.com/apecloud/kbcli/pkg/action" - "github.com/apecloud/kbcli/pkg/util" -) - -var faultNetWorkExample = templates.Examples(` - # Isolate all pods network under the default namespace from the outside world, including the k8s internal network. - kbcli fault network partition - - # The specified pod is isolated from the k8s external network "kubeblocks.io". - kbcli fault network partition mycluster-mysql-1 --external-targets=kubeblocks.io - - # Isolate the network between two pods. - kbcli fault network partition mycluster-mysql-1 --target-label=statefulset.kubernetes.io/pod-name=mycluster-mysql-2 - - // Like the partition command, the target can be specified through --target-label or --external-targets. The pod only has obstacles in communicating with this target. If the target is not specified, all communication will be blocked. - # Block all pod communication under the default namespace, resulting in a 50% packet loss rate. - kbcli fault network loss --loss=50 - - # Block the specified pod communication, so that the packet loss rate is 50%. - kbcli fault network loss mysql-cluster-mysql-2 --loss=50 - - kbcli fault network corrupt --corrupt=50 - - # Blocks specified pod communication with a 50% packet corruption rate. - kbcli fault network corrupt mysql-cluster-mysql-2 --corrupt=50 - - kbcli fault network duplicate --duplicate=50 - - # Block specified pod communication so that the packet repetition rate is 50%. - kbcli fault network duplicate mysql-cluster-mysql-2 --duplicate=50 - - kbcli fault network delay --latency=10s - - # Block the communication of the specified pod, causing its network delay for 10s. - kbcli fault network delay mysql-cluster-mysql-2 --latency=10s - - # Limit the communication bandwidth between mysql-cluster-mysql-2 and the outside. - kbcli fault network bandwidth mysql-cluster-mysql-2 --rate=1kbps --duration=1m -`) - -type Target struct { - TargetMode string `json:"mode,omitempty"` - TargetValue string `json:"value,omitempty"` - TargetSelector `json:"selector,omitempty"` -} - -type TargetSelector struct { - // Specifies the labels that target Pods come with. - TargetLabelSelectors map[string]string `json:"labelSelectors,omitempty"` - // Specifies the namespaces to which target Pods belong. - TargetNamespaceSelectors []string `json:"namespaces,omitempty"` -} - -// NetworkLoss Loss command -type NetworkLoss struct { - // The percentage of packet loss - Loss string `json:"loss,omitempty"` - // The correlation of loss or corruption or duplication or delay - Correlation string `json:"correlation,omitempty"` -} - -// NetworkDelay Delay command -type NetworkDelay struct { - // The latency of delay - Latency string `json:"latency,omitempty"` - // The jitter of delay - Jitter string `json:"jitter,omitempty"` - // The correlation of loss or corruption or duplication or delay - Correlation string `json:"correlation,omitempty"` -} - -// NetworkDuplicate Duplicate command -type NetworkDuplicate struct { - // The percentage of packet duplication - Duplicate string `json:"duplicate,omitempty"` - // The correlation of loss or corruption or duplication or delay - Correlation string `json:"correlation,omitempty"` -} - -// NetworkCorrupt Corrupt command -type NetworkCorrupt struct { - // The percentage of packet corruption - Corrupt string `json:"corrupt,omitempty"` - // The correlation of loss or corruption or duplication or delay - Correlation string `json:"correlation,omitempty"` -} - -// NetworkBandwidth Bandwidth command -type NetworkBandwidth struct { - // the rate at which the bandwidth is limited. - Rate string `json:"rate,omitempty"` - // the number of bytes waiting in the queue. - Limit uint32 `json:"limit,omitempty"` - // the maximum number of bytes that can be sent instantaneously. - Buffer uint32 `json:"buffer,omitempty"` - // the bucket's maximum consumption rate. Reference: https://man7.org/linux/man-pages/man8/tc-tbf.8.html. - Peakrate uint64 `json:"peakrate,omitempty"` - // the size of the peakrate bucket. Reference: https://man7.org/linux/man-pages/man8/tc-tbf.8.html. - Minburst uint32 `json:"minburst,omitempty"` -} - -type NetworkChaosOptions struct { - // Specify the network direction - Direction string `json:"direction"` - - // A network target outside of Kubernetes, which can be an IPv4 address or a domain name, - // such as "kubeblocks.io". Only works with direction: to. - ExternalTargets []string `json:"externalTargets,omitempty"` - - // A collection of target pods. Pods can be selected by namespace and label. - Target `json:"target,omitempty"` - - NetworkLoss `json:"loss,omitempty"` - - NetworkDelay `json:"delay,omitempty"` - - NetworkDuplicate `json:"duplicate,omitempty"` - - NetworkCorrupt `json:"corrupt,omitempty"` - - NetworkBandwidth `json:"bandwidth,omitempty"` - - FaultBaseOptions -} - -func NewNetworkChaosOptions(f cmdutil.Factory, streams genericiooptions.IOStreams, act string) *NetworkChaosOptions { - o := &NetworkChaosOptions{ - FaultBaseOptions: FaultBaseOptions{CreateOptions: action.CreateOptions{ - Factory: f, - IOStreams: streams, - CueTemplateName: CueTemplateNetworkChaos, - GVR: GetGVR(Group, Version, ResourceNetworkChaos), - }, - Action: act, - }, - } - o.CreateOptions.PreCreate = o.PreCreate - o.CreateOptions.Options = o - return o -} - -func NewNetworkChaosCmd(f cmdutil.Factory, streams genericiooptions.IOStreams) *cobra.Command { - cmd := &cobra.Command{ - Use: "network", - Short: "Network chaos.", - } - cmd.AddCommand( - NewPartitionCmd(f, streams), - NewLossCmd(f, streams), - NewDelayCmd(f, streams), - NewDuplicateCmd(f, streams), - NewCorruptCmd(f, streams), - NewBandwidthCmd(f, streams), - NewDNSChaosCmd(f, streams), - NewHTTPChaosCmd(f, streams), - ) - return cmd -} - -func NewPartitionCmd(f cmdutil.Factory, streams genericiooptions.IOStreams) *cobra.Command { - o := NewNetworkChaosOptions(f, streams, string(v1alpha1.PartitionAction)) - cmd := o.NewCobraCommand(Partition, PartitionShort) - - o.AddCommonFlag(cmd) - - return cmd -} - -func NewLossCmd(f cmdutil.Factory, streams genericiooptions.IOStreams) *cobra.Command { - o := NewNetworkChaosOptions(f, streams, string(v1alpha1.LossAction)) - cmd := o.NewCobraCommand(Loss, LossShort) - - o.AddCommonFlag(cmd) - cmd.Flags().StringVar(&o.Loss, "loss", "", `Indicates the probability of a packet error occurring. Value range: [0, 100].`) - cmd.Flags().StringVarP(&o.NetworkLoss.Correlation, "correlation", "c", "", `Indicates the correlation between the probability of a packet error occurring and whether it occurred the previous time. Value range: [0, 100].`) - - util.CheckErr(cmd.MarkFlagRequired("loss")) - - return cmd -} - -func NewDelayCmd(f cmdutil.Factory, streams genericiooptions.IOStreams) *cobra.Command { - o := NewNetworkChaosOptions(f, streams, string(v1alpha1.DelayAction)) - cmd := o.NewCobraCommand(Delay, DelayShort) - - o.AddCommonFlag(cmd) - cmd.Flags().StringVar(&o.Latency, "latency", "", `the length of time to delay.`) - cmd.Flags().StringVar(&o.Jitter, "jitter", "", `the variation range of the delay time.`) - cmd.Flags().StringVarP(&o.NetworkDelay.Correlation, "correlation", "c", "", `Indicates the probability of a packet error occurring. Value range: [0, 100].`) - - util.CheckErr(cmd.MarkFlagRequired("latency")) - - return cmd -} - -func NewDuplicateCmd(f cmdutil.Factory, streams genericiooptions.IOStreams) *cobra.Command { - o := NewNetworkChaosOptions(f, streams, string(v1alpha1.DuplicateAction)) - cmd := o.NewCobraCommand(Duplicate, DuplicateShort) - - o.AddCommonFlag(cmd) - cmd.Flags().StringVar(&o.Duplicate, "duplicate", "", `the probability of a packet being repeated. Value range: [0, 100].`) - cmd.Flags().StringVarP(&o.NetworkDuplicate.Correlation, "correlation", "c", "", `Indicates the correlation between the probability of a packet error occurring and whether it occurred the previous time. Value range: [0, 100].`) - - util.CheckErr(cmd.MarkFlagRequired("duplicate")) - - return cmd -} - -func NewCorruptCmd(f cmdutil.Factory, streams genericiooptions.IOStreams) *cobra.Command { - o := NewNetworkChaosOptions(f, streams, string(v1alpha1.CorruptAction)) - cmd := o.NewCobraCommand(Corrupt, CorruptShort) - - o.AddCommonFlag(cmd) - cmd.Flags().StringVar(&o.Corrupt, "corrupt", "", `Indicates the probability of a packet error occurring. Value range: [0, 100].`) - cmd.Flags().StringVarP(&o.NetworkCorrupt.Correlation, "correlation", "c", "", `Indicates the correlation between the probability of a packet error occurring and whether it occurred the previous time. Value range: [0, 100].`) - - util.CheckErr(cmd.MarkFlagRequired("corrupt")) - - return cmd -} - -func NewBandwidthCmd(f cmdutil.Factory, streams genericiooptions.IOStreams) *cobra.Command { - o := NewNetworkChaosOptions(f, streams, string(v1alpha1.BandwidthAction)) - cmd := o.NewCobraCommand(Bandwidth, BandwidthShort) - - o.AddCommonFlag(cmd) - cmd.Flags().StringVar(&o.Rate, "rate", "", `the rate at which the bandwidth is limited. For example : 10 bps/kbps/mbps/gbps.`) - cmd.Flags().Uint32Var(&o.Limit, "limit", 1, `the number of bytes waiting in the queue.`) - cmd.Flags().Uint32Var(&o.Buffer, "buffer", 1, `the maximum number of bytes that can be sent instantaneously.`) - cmd.Flags().Uint64Var(&o.Peakrate, "peakrate", 0, `the maximum consumption rate of the bucket.`) - cmd.Flags().Uint32Var(&o.Minburst, "minburst", 0, `the size of the peakrate bucket.`) - - util.CheckErr(cmd.MarkFlagRequired("rate")) - - return cmd -} - -func (o *NetworkChaosOptions) NewCobraCommand(use, short string) *cobra.Command { - return &cobra.Command{ - Use: use, - Short: short, - Example: faultNetWorkExample, - Run: func(cmd *cobra.Command, args []string) { - o.Args = args - cmdutil.CheckErr(o.CreateOptions.Complete()) - cmdutil.CheckErr(o.Validate()) - cmdutil.CheckErr(o.Complete()) - cmdutil.CheckErr(o.Run()) - }, - } -} - -func (o *NetworkChaosOptions) AddCommonFlag(cmd *cobra.Command) { - o.FaultBaseOptions.AddCommonFlag(cmd) - - cmd.Flags().StringVar(&o.Direction, "direction", "to", `You can select "to"" or "from"" or "both"".`) - cmd.Flags().StringArrayVarP(&o.ExternalTargets, "external-target", "e", nil, "a network target outside of Kubernetes, which can be an IPv4 address or a domain name,\n\t such as \"www.baidu.com\". Only works with direction: to.") - cmd.Flags().StringVar(&o.TargetMode, "target-mode", "", `You can select "one", "all", "fixed", "fixed-percent", "random-max-percent", Specify the experimental mode, that is, which Pods to experiment with.`) - cmd.Flags().StringVar(&o.TargetValue, "target-value", "", `If you choose mode=fixed or fixed-percent or random-max-percent, you can enter a value to specify the number or percentage of pods you want to inject.`) - cmd.Flags().StringToStringVar(&o.TargetLabelSelectors, "target-label", nil, `label for pod, such as '"app.kubernetes.io/component=mysql, statefulset.kubernetes.io/pod-name=mycluster-mysql-0"'`) - cmd.Flags().StringArrayVar(&o.TargetNamespaceSelectors, "target-ns-fault", nil, `Specifies the namespace into which you want to inject faults.`) - - // register flag completion func - registerFlagCompletionFunc(cmd, o.Factory) -} - -func (o *NetworkChaosOptions) Validate() error { - if o.TargetValue == "" && (o.TargetMode == "fixed" || o.TargetMode == "fixed-percent" || o.TargetMode == "random-max-percent") { - return fmt.Errorf("--value is required to specify pod nums or percentage") - } - - if (o.TargetNamespaceSelectors != nil || o.TargetLabelSelectors != nil) && o.TargetMode == "" { - return fmt.Errorf("--target-mode is required to specify a target mode") - } - - if o.ExternalTargets != nil && o.Direction != "to" { - return fmt.Errorf("--direction=to is required when specifying external targets") - } - - if ok, err := IsInteger(o.TargetValue); !ok { - return err - } - - if ok, err := IsInteger(o.Loss); !ok { - return err - } - - if ok, err := IsInteger(o.Corrupt); !ok { - return err - } - - if ok, err := IsInteger(o.Duplicate); !ok { - return err - } - - if ok, err := IsRegularMatch(o.Latency); !ok { - return err - } - - if ok, err := IsRegularMatch(o.Jitter); !ok { - return err - } - - return o.BaseValidate() -} - -func (o *NetworkChaosOptions) Complete() error { - return o.BaseComplete() -} - -func (o *NetworkChaosOptions) PreCreate(obj *unstructured.Unstructured) error { - c := &v1alpha1.NetworkChaos{} - if err := runtime.DefaultUnstructuredConverter.FromUnstructured(obj.Object, c); err != nil { - return err - } - - data, e := runtime.DefaultUnstructuredConverter.ToUnstructured(c) - if e != nil { - return e - } - obj.SetUnstructuredContent(data) - return nil -} diff --git a/pkg/cmd/fault/fault_network_test.go b/pkg/cmd/fault/fault_network_test.go deleted file mode 100644 index 8cec2a972..000000000 --- a/pkg/cmd/fault/fault_network_test.go +++ /dev/null @@ -1,184 +0,0 @@ -/* -Copyright (C) 2022-2024 ApeCloud Co., Ltd - -This file is part of KubeBlocks project - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU Affero General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU Affero General Public License for more details. - -You should have received a copy of the GNU Affero General Public License -along with this program. If not, see . -*/ - -package fault - -import ( - . "github.com/onsi/ginkgo/v2" - . "github.com/onsi/gomega" - - "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" - "k8s.io/cli-runtime/pkg/genericiooptions" - clientfake "k8s.io/client-go/rest/fake" - cmdtesting "k8s.io/kubectl/pkg/cmd/testing" - - "github.com/apecloud/kbcli/pkg/testing" -) - -var _ = Describe("Fault Network", func() { - var ( - tf *cmdtesting.TestFactory - streams genericiooptions.IOStreams - ) - BeforeEach(func() { - streams, _, _, _ = genericiooptions.NewTestIOStreams() - tf = cmdtesting.NewTestFactory().WithNamespace(testing.Namespace) - tf.Client = &clientfake.RESTClient{} - }) - - AfterEach(func() { - tf.Cleanup() - }) - - Context("test fault network", func() { - It("fault network partition", func() { - inputs := [][]string{ - {"--dry-run=client"}, - {"--mode=one", "--dry-run=client"}, - {"--mode=fixed", "--value=2", "--dry-run=client"}, - {"--mode=fixed-percent", "--value=50", "--dry-run=client"}, - {"--mode=random-max-percent", "--value=50", "--dry-run=client"}, - {"--ns-fault=kb-system", "--dry-run=client"}, - {"--node=minikube-m02", "--dry-run=client"}, - {"--label=app.kubernetes.io/component=mysql", "--dry-run=client"}, - {"--node-label=kubernetes.io/arch=arm64", "--dry-run=client"}, - {"--annotation=example-annotation=group-a", "--dry-run=client"}, - {"--external-target=kubeblocks.io", "--dry-run=client"}, - {"--target-mode=one", "--target-label=statefulset.kubernetes.io/pod-name=mycluster-mysql-2", "--target-ns-fault=default", "--dry-run=client"}, - } - o := NewNetworkChaosOptions(tf, streams, string(v1alpha1.PartitionAction)) - cmd := o.NewCobraCommand(Partition, PartitionShort) - o.AddCommonFlag(cmd) - - for _, input := range inputs { - Expect(cmd.Flags().Parse(input)).Should(Succeed()) - Expect(o.CreateOptions.Complete()) - Expect(o.Complete()).Should(Succeed()) - Expect(o.Validate()).Should(Succeed()) - Expect(o.Run()).Should(Succeed()) - } - }) - - It("fault network loss", func() { - inputs := [][]string{ - {"--loss=50", "--dry-run=client"}, - {"--loss=50", "--correlation=100", "--dry-run=client"}, - } - o := NewNetworkChaosOptions(tf, streams, string(v1alpha1.LossAction)) - cmd := o.NewCobraCommand(Loss, LossShort) - o.AddCommonFlag(cmd) - cmd.Flags().StringVar(&o.Loss, "loss", "", `Indicates the probability of a packet error occurring. Value range: [0, 100].`) - cmd.Flags().StringVarP(&o.NetworkLoss.Correlation, "correlation", "c", "0", `Indicates the correlation between the probability of a packet error occurring and whether it occurred the previous time. Value range: [0, 100].`) - - for _, input := range inputs { - Expect(cmd.Flags().Parse(input)).Should(Succeed()) - Expect(o.CreateOptions.Complete()) - Expect(o.Complete()).Should(Succeed()) - Expect(o.Validate()).Should(Succeed()) - Expect(o.Run()).Should(Succeed()) - } - }) - - It("fault network delay", func() { - inputs := [][]string{ - {"--latency=50s", "--dry-run=client"}, - {"--latency=50s", "--jitter=10s", "--dry-run=client"}, - {"--latency=50s", "--correlation=100", "--dry-run=client"}, - {"--latency=50s", "--jitter=10s", "--correlation=100", "--dry-run=client"}, - } - o := NewNetworkChaosOptions(tf, streams, string(v1alpha1.DelayAction)) - cmd := o.NewCobraCommand(Delay, DelayShort) - o.AddCommonFlag(cmd) - cmd.Flags().StringVar(&o.Latency, "latency", "", `the length of time to delay.`) - cmd.Flags().StringVar(&o.Jitter, "jitter", "0ms", `the variation range of the delay time.`) - cmd.Flags().StringVarP(&o.NetworkDelay.Correlation, "correlation", "c", "0", `Indicates the probability of a packet error occurring. Value range: [0, 100].`) - - for _, input := range inputs { - Expect(cmd.Flags().Parse(input)).Should(Succeed()) - Expect(o.CreateOptions.Complete()) - Expect(o.Complete()).Should(Succeed()) - Expect(o.Validate()).Should(Succeed()) - Expect(o.Run()).Should(Succeed()) - } - }) - - It("fault network duplicate", func() { - inputs := [][]string{ - {"--duplicate=50", "--dry-run=client"}, - {"--duplicate=50", "--correlation=100", "--dry-run=client"}, - } - o := NewNetworkChaosOptions(tf, streams, string(v1alpha1.DuplicateAction)) - cmd := o.NewCobraCommand(Duplicate, DuplicateShort) - o.AddCommonFlag(cmd) - cmd.Flags().StringVar(&o.Duplicate, "duplicate", "", `the probability of a packet being repeated. Value range: [0, 100].`) - cmd.Flags().StringVarP(&o.NetworkDuplicate.Correlation, "correlation", "c", "0", `Indicates the correlation between the probability of a packet error occurring and whether it occurred the previous time. Value range: [0, 100].`) - - for _, input := range inputs { - Expect(cmd.Flags().Parse(input)).Should(Succeed()) - Expect(o.CreateOptions.Complete()) - Expect(o.Complete()).Should(Succeed()) - Expect(o.Validate()).Should(Succeed()) - Expect(o.Run()).Should(Succeed()) - } - }) - - It("fault network corrupt", func() { - inputs := [][]string{ - {"--corrupt=50", "--dry-run=client"}, - {"--corrupt=50", "--correlation=100", "--dry-run=client"}, - } - o := NewNetworkChaosOptions(tf, streams, string(v1alpha1.CorruptAction)) - cmd := o.NewCobraCommand(Corrupt, CorruptShort) - o.AddCommonFlag(cmd) - cmd.Flags().StringVar(&o.Corrupt, "corrupt", "", `Indicates the probability of a packet error occurring. Value range: [0, 100].`) - cmd.Flags().StringVarP(&o.NetworkCorrupt.Correlation, "correlation", "c", "0", `Indicates the correlation between the probability of a packet error occurring and whether it occurred the previous time. Value range: [0, 100].`) - - for _, input := range inputs { - Expect(cmd.Flags().Parse(input)).Should(Succeed()) - Expect(o.CreateOptions.Complete()) - Expect(o.Complete()).Should(Succeed()) - Expect(o.Validate()).Should(Succeed()) - Expect(o.Run()).Should(Succeed()) - } - }) - - It("fault network bandwidth", func() { - inputs := [][]string{ - {"--rate=10kbps", "--dry-run=client"}, - {"--rate=10kbps", "--limit=1000", "--buffer=100", "--peakrate=10", "--minburst=5", "--dry-run=client"}, - } - o := NewNetworkChaosOptions(tf, streams, string(v1alpha1.BandwidthAction)) - cmd := o.NewCobraCommand(Bandwidth, BandwidthShort) - o.AddCommonFlag(cmd) - cmd.Flags().StringVar(&o.Rate, "rate", "", `the rate at which the bandwidth is limited. For example : 10 bps/kbps/mbps/gbps.`) - cmd.Flags().Uint32Var(&o.Limit, "limit", 1, `the number of bytes waiting in the queue.`) - cmd.Flags().Uint32Var(&o.Buffer, "buffer", 1, `the maximum number of bytes that can be sent instantaneously.`) - cmd.Flags().Uint64Var(&o.Peakrate, "peakrate", 0, `the maximum consumption rate of the bucket.`) - cmd.Flags().Uint32Var(&o.Minburst, "minburst", 0, `the size of the peakrate bucket.`) - - for _, input := range inputs { - Expect(cmd.Flags().Parse(input)).Should(Succeed()) - Expect(o.CreateOptions.Complete()) - Expect(o.Complete()).Should(Succeed()) - Expect(o.Validate()).Should(Succeed()) - Expect(o.Run()).Should(Succeed()) - } - }) - }) -}) diff --git a/pkg/cmd/fault/fault_node.go b/pkg/cmd/fault/fault_node.go deleted file mode 100644 index 9ad2606aa..000000000 --- a/pkg/cmd/fault/fault_node.go +++ /dev/null @@ -1,471 +0,0 @@ -/* -Copyright (C) 2022-2024 ApeCloud Co., Ltd - -This file is part of KubeBlocks project - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU Affero General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU Affero General Public License for more details. - -You should have received a copy of the GNU Affero General Public License -along with this program. If not, see . -*/ - -package fault - -import ( - "bufio" - "context" - "encoding/base64" - "fmt" - "io/ioutil" - "os" - "path/filepath" - "strings" - - "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" - "github.com/spf13/cobra" - corev1 "k8s.io/api/core/v1" - k8serrors "k8s.io/apimachinery/pkg/api/errors" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" - "k8s.io/apimachinery/pkg/runtime" - "k8s.io/cli-runtime/pkg/genericiooptions" - "k8s.io/client-go/kubernetes" - cmdutil "k8s.io/kubectl/pkg/cmd/util" - "k8s.io/kubectl/pkg/util/templates" - - "github.com/apecloud/kbcli/pkg/action" - cp "github.com/apecloud/kbcli/pkg/cloudprovider" - "github.com/apecloud/kbcli/pkg/printer" - "github.com/apecloud/kbcli/pkg/util" - "github.com/apecloud/kbcli/pkg/util/prompt" -) - -var faultNodeExample = templates.Examples(` - # Stop a specified EC2 instance. - kbcli fault node stop node1 -c=aws --region=cn-northwest-1 --duration=3m - - # Stop two specified EC2 instances. - kbcli fault node stop node1 node2 -c=aws --region=cn-northwest-1 --duration=3m - - # Restart two specified EC2 instances. - kbcli fault node restart node1 node2 -c=aws --region=cn-northwest-1 --duration=3m - - # Detach two specified volume from two specified EC2 instances. - kbcli fault node detach-volume node1 node2 -c=aws --region=cn-northwest-1 --duration=1m --volume-id=v1,v2 --device-name=/d1,/d2 - - # Stop two specified GCK instances. - kbcli fault node stop node1 node2 -c=gcp --region=us-central1-c --project=apecloud-platform-engineering - - # Restart two specified GCK instances. - kbcli fault node restart node1 node2 -c=gcp --region=us-central1-c --project=apecloud-platform-engineering - - # Detach two specified volume from two specified GCK instances. - kbcli fault node detach-volume node1 node2 -c=gcp --region=us-central1-c --project=apecloud-platform-engineering --device-name=/d1,/d2 -`) - -type NodeChaoOptions struct { - Kind string `json:"kind"` - - Action string `json:"action"` - - CloudProvider string `json:"-"` - - SecretName string `json:"secretName"` - - Region string `json:"region"` - - Instance string `json:"instance"` - - VolumeID string `json:"volumeID"` - VolumeIDs []string `json:"-"` - - DeviceName string `json:"deviceName,omitempty"` - DeviceNames []string `json:"-"` - - Project string `json:"project"` - - Duration string `json:"duration"` - - AutoApprove bool `json:"-"` - - action.CreateOptions `json:"-"` -} - -func NewNodeOptions(f cmdutil.Factory, streams genericiooptions.IOStreams) *NodeChaoOptions { - o := &NodeChaoOptions{ - CreateOptions: action.CreateOptions{ - Factory: f, - IOStreams: streams, - CueTemplateName: CueTemplateNodeChaos, - }, - } - o.CreateOptions.PreCreate = o.PreCreate - o.CreateOptions.Options = o - return o -} - -func NewNodeChaosCmd(f cmdutil.Factory, streams genericiooptions.IOStreams) *cobra.Command { - cmd := &cobra.Command{ - Use: "node", - Short: "Node chaos.", - } - - cmd.AddCommand( - NewStopCmd(f, streams), - NewRestartCmd(f, streams), - NewDetachVolumeCmd(f, streams), - ) - return cmd -} - -func NewStopCmd(f cmdutil.Factory, streams genericiooptions.IOStreams) *cobra.Command { - o := NewNodeOptions(f, streams) - cmd := o.NewCobraCommand(Stop, StopShort) - - o.AddCommonFlag(cmd) - return cmd -} - -func NewRestartCmd(f cmdutil.Factory, streams genericiooptions.IOStreams) *cobra.Command { - o := NewNodeOptions(f, streams) - cmd := o.NewCobraCommand(Restart, RestartShort) - - o.AddCommonFlag(cmd) - return cmd -} - -func NewDetachVolumeCmd(f cmdutil.Factory, streams genericiooptions.IOStreams) *cobra.Command { - o := NewNodeOptions(f, streams) - cmd := o.NewCobraCommand(DetachVolume, DetachVolumeShort) - - o.AddCommonFlag(cmd) - cmd.Flags().StringSliceVar(&o.VolumeIDs, "volume-id", nil, "The volume ids of the ec2. Only available when cloud-provider=aws.") - cmd.Flags().StringSliceVar(&o.DeviceNames, "device-name", nil, "The device name of the volume.") - - util.CheckErr(cmd.MarkFlagRequired("device-name")) - return cmd -} - -func (o *NodeChaoOptions) NewCobraCommand(use, short string) *cobra.Command { - return &cobra.Command{ - Use: use, - Short: short, - Example: faultNodeExample, - Run: func(cmd *cobra.Command, args []string) { - cmdutil.CheckErr(o.Execute(use, args, false)) - }, - } -} - -func (o *NodeChaoOptions) Execute(action string, args []string, testEnv bool) error { - o.Args = args - if err := o.CreateOptions.Complete(); err != nil { - return err - } - if err := o.Complete(action); err != nil { - return err - } - if err := o.Validate(); err != nil { - return err - } - - for idx, arg := range o.Args { - o.Instance = arg - if o.DeviceNames != nil { - o.DeviceName = o.DeviceNames[idx] - } - if o.VolumeIDs != nil { - o.VolumeID = o.VolumeIDs[idx] - } - if err := o.CreateSecret(testEnv); err != nil { - return err - } - if err := o.Run(); err != nil { - return err - } - } - return nil -} - -func (o *NodeChaoOptions) AddCommonFlag(cmd *cobra.Command) { - cmd.Flags().StringVarP(&o.CloudProvider, "cloud-provider", "c", "", fmt.Sprintf("Cloud provider type, one of %v", supportedCloudProviders)) - cmd.Flags().StringVar(&o.Region, "region", "", "The region of the node.") - cmd.Flags().StringVar(&o.Project, "project", "", "The name of the GCP project. Only available when cloud-provider=gcp.") - cmd.Flags().StringVar(&o.SecretName, "secret", "", "The name of the secret containing cloud provider specific credentials.") - cmd.Flags().StringVar(&o.Duration, "duration", "30s", "Supported formats of the duration are: ms / s / m / h.") - - cmd.Flags().BoolVar(&o.AutoApprove, "auto-approve", false, "Skip interactive approval before create secret.") - cmd.Flags().StringVar(&o.DryRun, "dry-run", "none", `Must be "client", or "server". If with client strategy, only print the object that would be sent, and no data is actually sent. If with server strategy, submit the server-side request, but no data is persistent.`) - cmd.Flags().Lookup("dry-run").NoOptDefVal = Unchanged - printer.AddOutputFlagForCreate(cmd, &o.Format, false) - - util.CheckErr(cmd.MarkFlagRequired("cloud-provider")) - util.CheckErr(cmd.MarkFlagRequired("region")) - - // register flag completion func - registerFlagCompletionFunc(cmd, o.Factory) -} - -func (o *NodeChaoOptions) Validate() error { - if ok, err := IsRegularMatch(o.Duration); !ok { - return err - } - - if len(o.Args) == 0 { - return fmt.Errorf("node instance is required") - } - - switch o.CloudProvider { - case cp.AWS: - if o.Project != "" { - return fmt.Errorf("--project is not supported when cloud provider is aws") - } - if o.Action == DetachVolume && o.VolumeIDs == nil { - return fmt.Errorf("--volume-id is required when cloud provider is aws") - } - if o.Action == DetachVolume && len(o.DeviceNames) != len(o.VolumeIDs) { - return fmt.Errorf("the number of volume-id must be equal to the number of device-name") - } - case cp.GCP: - if o.Project == "" { - return fmt.Errorf("--project is required when cloud provider is gcp") - } - if o.VolumeIDs != nil { - return fmt.Errorf(" --volume-id is not supported when cloud provider is gcp") - } - default: - return fmt.Errorf("cloud provider type, one of %v", supportedCloudProviders) - } - - if o.DeviceNames != nil && len(o.Args) != len(o.DeviceNames) { - return fmt.Errorf("the number of device-name must be equal to the number of node") - } - return nil -} - -func (o *NodeChaoOptions) Complete(action string) error { - if o.CloudProvider == cp.AWS { - o.GVR = GetGVR(Group, Version, ResourceAWSChaos) - o.Kind = KindAWSChaos - if o.SecretName == "" { - o.SecretName = AWSSecretName - } - switch action { - case Stop: - o.Action = string(v1alpha1.Ec2Stop) - case Restart: - o.Action = string(v1alpha1.Ec2Restart) - case DetachVolume: - o.Action = string(v1alpha1.DetachVolume) - } - } else if o.CloudProvider == cp.GCP { - o.GVR = GetGVR(Group, Version, ResourceGCPChaos) - o.Kind = KindGCPChaos - if o.SecretName == "" { - o.SecretName = GCPSecretName - } - switch action { - case Stop: - o.Action = string(v1alpha1.NodeStop) - case Restart: - o.Action = string(v1alpha1.NodeReset) - case DetachVolume: - o.Action = string(v1alpha1.DiskLoss) - } - } - return nil -} - -func (o *NodeChaoOptions) PreCreate(obj *unstructured.Unstructured) error { - var c v1alpha1.InnerObject - - if o.CloudProvider == cp.AWS { - c = &v1alpha1.AWSChaos{} - } else if o.CloudProvider == cp.GCP { - c = &v1alpha1.GCPChaos{} - } - - if err := runtime.DefaultUnstructuredConverter.FromUnstructured(obj.Object, c); err != nil { - return err - } - - data, e := runtime.DefaultUnstructuredConverter.ToUnstructured(c) - if e != nil { - return e - } - obj.SetUnstructuredContent(data) - return nil -} - -func (o *NodeChaoOptions) CreateSecret(testEnv bool) error { - if testEnv { - return nil - } - - if o.DryRun != "none" { - return nil - } - - config, err := o.Factory.ToRESTConfig() - if err != nil { - return err - } - - clientSet, err := kubernetes.NewForConfig(config) - if err != nil { - return err - } - - // Check if Secret already exists - secretClient := clientSet.CoreV1().Secrets(o.Namespace) - _, err = secretClient.Get(context.TODO(), o.SecretName, metav1.GetOptions{}) - if err == nil { - fmt.Printf("Secret %s exists under %s namespace.\n", o.SecretName, o.Namespace) - return nil - } else if !k8serrors.IsNotFound(err) { - return err - } - - if err := o.confirmToContinue(); err != nil { - return err - } - - switch o.CloudProvider { - case "aws": - if err := handleAWS(clientSet, o.Namespace, o.SecretName); err != nil { - return err - } - case "gcp": - if err := handleGCP(clientSet, o.Namespace, o.SecretName); err != nil { - return err - } - default: - return fmt.Errorf("unknown cloud provider:%s", o.CloudProvider) - } - return nil -} - -func (o *NodeChaoOptions) confirmToContinue() error { - if !o.AutoApprove { - printer.Warning(o.Out, "A secret will be created for the cloud account to access %s, do you want to continue to create this secret: %s ?\n Only 'yes' will be accepted to confirm.\n\n", o.CloudProvider, o.SecretName) - entered, _ := prompt.NewPrompt("Enter a value:", nil, o.In).Run() - if entered != "yes" { - fmt.Fprintf(o.Out, "\nCancel automatic secert creation. You will not be able to access the nodes on the cluster.\n") - return cmdutil.ErrExit - } - } - fmt.Fprintf(o.Out, "Continue to create secret: %s\n", o.SecretName) - return nil -} - -func handleAWS(clientSet *kubernetes.Clientset, namespace, secretName string) error { - accessKeyID, secretAccessKey, err := readAWSCredentials() - if err != nil { - return err - } - - secret := &corev1.Secret{ - ObjectMeta: metav1.ObjectMeta{ - Name: secretName, - Namespace: namespace, - }, - Type: corev1.SecretTypeOpaque, - StringData: map[string]string{ - "aws_access_key_id": accessKeyID, - "aws_secret_access_key": secretAccessKey, - }, - } - - createdSecret, err := clientSet.CoreV1().Secrets(namespace).Create(context.TODO(), secret, metav1.CreateOptions{}) - if err != nil { - return err - } - - fmt.Printf("Secret %s created successfully\n", createdSecret.Name) - return nil -} - -func handleGCP(clientSet *kubernetes.Clientset, namespace, secretName string) error { - home, err := os.UserHomeDir() - if err != nil { - return err - } - - filePath := filepath.Join(home, ".config", "gcloud", "application_default_credentials.json") - data, err := ioutil.ReadFile(filePath) - jsonData := string(data) - fmt.Println(jsonData) - if err != nil { - return err - } - encodedData := base64.StdEncoding.EncodeToString([]byte(jsonData)) - - secret := &corev1.Secret{ - ObjectMeta: metav1.ObjectMeta{ - Name: secretName, - Namespace: namespace, - }, - Type: corev1.SecretTypeOpaque, - StringData: map[string]string{ - "service_account": encodedData, - }, - } - - createdSecret, err := clientSet.CoreV1().Secrets(namespace).Create(context.TODO(), secret, metav1.CreateOptions{}) - if err != nil { - return err - } - - fmt.Printf("Secret %s created successfully\n", createdSecret.Name) - return nil -} - -func readAWSCredentials() (string, string, error) { - home, err := os.UserHomeDir() - if err != nil { - return "", "", err - } - filePath := filepath.Join(home, ".aws", "credentials") - file, err := os.Open(filePath) - if err != nil { - return "", "", err - } - defer func(file *os.File) { - err := file.Close() - if err != nil { - fmt.Printf("unable to close file: %s", err) - } - }(file) - - // Read file content line by line using bufio.Scanner - scanner := bufio.NewScanner(file) - accessKeyID := "" - secretAccessKey := "" - - for scanner.Scan() { - line := scanner.Text() - if strings.HasPrefix(line, "aws_access_key_id") { - accessKeyID = strings.TrimSpace(strings.SplitN(line, "=", 2)[1]) - } else if strings.HasPrefix(line, "aws_secret_access_key") { - secretAccessKey = strings.TrimSpace(strings.SplitN(line, "=", 2)[1]) - } - } - - if scanner.Err() != nil { - return "", "", scanner.Err() - } - - if accessKeyID == "" || secretAccessKey == "" { - return "", "", fmt.Errorf("unable to find valid AWS access key information") - } - - return accessKeyID, secretAccessKey, nil -} diff --git a/pkg/cmd/fault/fault_node_test.go b/pkg/cmd/fault/fault_node_test.go deleted file mode 100644 index c07b16c2a..000000000 --- a/pkg/cmd/fault/fault_node_test.go +++ /dev/null @@ -1,104 +0,0 @@ -/* -Copyright (C) 2022-2024 ApeCloud Co., Ltd - -This file is part of KubeBlocks project - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU Affero General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU Affero General Public License for more details. - -You should have received a copy of the GNU Affero General Public License -along with this program. If not, see . -*/ - -package fault - -import ( - . "github.com/onsi/ginkgo/v2" - . "github.com/onsi/gomega" - - "k8s.io/cli-runtime/pkg/genericiooptions" - clientfake "k8s.io/client-go/rest/fake" - cmdtesting "k8s.io/kubectl/pkg/cmd/testing" - - "github.com/apecloud/kbcli/pkg/testing" -) - -var _ = Describe("Fault Node", func() { - var ( - tf *cmdtesting.TestFactory - streams genericiooptions.IOStreams - ) - BeforeEach(func() { - streams, _, _, _ = genericiooptions.NewTestIOStreams() - tf = cmdtesting.NewTestFactory().WithNamespace(testing.Namespace) - tf.Client = &clientfake.RESTClient{} - }) - - AfterEach(func() { - tf.Cleanup() - }) - - Context("test fault node", func() { - It("fault node stop", func() { - inputs := [][]string{ - {"-c=aws", "--region=cn-northwest-1", "--dry-run=client"}, - {"-c=aws", "--region=cn-northwest-1", "--secret=test-secret", "--dry-run=client"}, - {"-c=gcp", "--region=us-central1-c", "--project=apecloud-platform-engineering", "--dry-run=client"}, - } - o := NewNodeOptions(tf, streams) - cmd := o.NewCobraCommand(Stop, StopShort) - o.AddCommonFlag(cmd) - - o.Args = []string{"node1", "node2"} - for _, input := range inputs { - Expect(cmd.Flags().Parse(input)).Should(Succeed()) - Expect(o.Execute(Stop, o.Args, true)).Should(Succeed()) - } - }) - - It("fault node restart", func() { - inputs := [][]string{ - {"-c=aws", "--region=cn-northwest-1", "--dry-run=client"}, - {"-c=aws", "--region=cn-northwest-1", "--secret=test-secret", "--dry-run=client"}, - {"-c=gcp", "--region=us-central1-c", "--project=apecloud-platform-engineering", "--dry-run=client"}, - } - o := NewNodeOptions(tf, streams) - cmd := o.NewCobraCommand(Restart, RestartShort) - o.AddCommonFlag(cmd) - - o.Args = []string{"node1", "node2"} - for _, input := range inputs { - Expect(cmd.Flags().Parse(input)).Should(Succeed()) - Expect(o.Execute(Restart, o.Args, true)).Should(Succeed()) - } - }) - - It("fault node detach-volume", func() { - inputs := [][]string{ - {"-c=aws", "--region=cn-northwest-1", "--volume-id=v1,v2", "--device-name=/d1,/d2", "--dry-run=client"}, - {"-c=aws", "--region=cn-northwest-1", "--volume-id=v1,v2", "--device-name=/d1,/d2", "--secret=test-secret", "--dry-run=client"}, - {"-c=gcp", "--region=us-central1-c", "--project=apecloud-platform-engineering", "--device-name=/d1,/d2", "--dry-run=client"}, - } - o := NewNodeOptions(tf, streams) - cmd := o.NewCobraCommand(DetachVolume, DetachVolumeShort) - o.AddCommonFlag(cmd) - cmd.Flags().StringSliceVar(&o.VolumeIDs, "volume-id", nil, "The volume id of the ec2.") - cmd.Flags().StringSliceVar(&o.DeviceNames, "device-name", nil, "The device name of the volume.") - - o.Args = []string{"node1", "node2"} - for _, input := range inputs { - Expect(cmd.Flags().Parse(input)).Should(Succeed()) - Expect(o.Execute(DetachVolume, o.Args, true)).Should(Succeed()) - o.VolumeIDs = nil - o.DeviceNames = nil - } - }) - }) -}) diff --git a/pkg/cmd/fault/fault_pod.go b/pkg/cmd/fault/fault_pod.go deleted file mode 100644 index 3bad917a3..000000000 --- a/pkg/cmd/fault/fault_pod.go +++ /dev/null @@ -1,186 +0,0 @@ -/* -Copyright (C) 2022-2024 ApeCloud Co., Ltd - -This file is part of KubeBlocks project - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU Affero General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU Affero General Public License for more details. - -You should have received a copy of the GNU Affero General Public License -along with this program. If not, see . -*/ - -package fault - -import ( - "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" - "github.com/spf13/cobra" - "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" - "k8s.io/apimachinery/pkg/runtime" - "k8s.io/cli-runtime/pkg/genericiooptions" - cmdutil "k8s.io/kubectl/pkg/cmd/util" - "k8s.io/kubectl/pkg/util/templates" - - "github.com/apecloud/kbcli/pkg/action" - "github.com/apecloud/kbcli/pkg/util" -) - -var faultPodExample = templates.Examples(` - # kill all pods in default namespace - kbcli fault pod kill - - # kill any pod in default namespace - kbcli fault pod kill --mode=one - - # kill two pods in default namespace - kbcli fault pod kill --mode=fixed --value=2 - - # kill 50% pods in default namespace - kbcli fault pod kill --mode=percentage --value=50 - - # kill mysql-cluster-mysql-0 pod in default namespace - kbcli fault pod kill mysql-cluster-mysql-0 - - # kill all pods in default namespace - kbcli fault pod kill --ns-fault="default" - - # --label is required to specify the pods that need to be killed. - kbcli fault pod kill --label statefulset.kubernetes.io/pod-name=mysql-cluster-mysql-2 - - # kill pod under the specified node. - kbcli fault pod kill --node=minikube-m02 - - # kill pod under the specified node-label. - kbcli fault pod kill --node-label=kubernetes.io/arch=arm64 - - # Allow the experiment to last for one minute. - kbcli fault pod failure --duration=1m - - # kill container in pod - kbcli fault pod kill-container mysql-cluster-mysql-0 --container=mysql -`) - -type PodChaosOptions struct { - // GracePeriod waiting time, after which fault injection is performed - GracePeriod int64 `json:"gracePeriod"` - ContainerNames []string `json:"containerNames,omitempty"` - - FaultBaseOptions -} - -func NewPodChaosOptions(f cmdutil.Factory, streams genericiooptions.IOStreams, act string) *PodChaosOptions { - o := &PodChaosOptions{ - FaultBaseOptions: FaultBaseOptions{ - CreateOptions: action.CreateOptions{ - Factory: f, - IOStreams: streams, - CueTemplateName: CueTemplatePodChaos, - GVR: GetGVR(Group, Version, ResourcePodChaos), - }, - Action: act, - }, - } - o.CreateOptions.PreCreate = o.PreCreate - o.CreateOptions.Options = o - return o -} - -func NewPodChaosCmd(f cmdutil.Factory, streams genericiooptions.IOStreams) *cobra.Command { - cmd := &cobra.Command{ - Use: "pod", - Short: "Pod chaos.", - } - cmd.AddCommand( - NewPodKillCmd(f, streams), - NewPodFailureCmd(f, streams), - NewContainerKillCmd(f, streams), - ) - return cmd -} - -func NewPodKillCmd(f cmdutil.Factory, streams genericiooptions.IOStreams) *cobra.Command { - o := NewPodChaosOptions(f, streams, string(v1alpha1.PodKillAction)) - cmd := o.NewCobraCommand(Kill, KillShort) - - o.AddCommonFlag(cmd) - cmd.Flags().Int64VarP(&o.GracePeriod, "grace-period", "g", 0, "Grace period represents the duration in seconds before the pod should be killed") - - // register flag completion func - registerFlagCompletionFunc(cmd, f) - - return cmd -} - -func NewPodFailureCmd(f cmdutil.Factory, streams genericiooptions.IOStreams) *cobra.Command { - o := NewPodChaosOptions(f, streams, string(v1alpha1.PodFailureAction)) - cmd := o.NewCobraCommand(Failure, FailureShort) - - o.AddCommonFlag(cmd) - // register flag completion func - registerFlagCompletionFunc(cmd, f) - - return cmd -} - -func NewContainerKillCmd(f cmdutil.Factory, streams genericiooptions.IOStreams) *cobra.Command { - o := NewPodChaosOptions(f, streams, string(v1alpha1.ContainerKillAction)) - cmd := o.NewCobraCommand(KillContainer, KillContainerShort) - - o.AddCommonFlag(cmd) - cmd.Flags().StringArrayVarP(&o.ContainerNames, "container", "c", nil, "the name of the container you want to kill, such as mysql, prometheus.") - - util.CheckErr(cmd.MarkFlagRequired("container")) - - // register flag completion func - registerFlagCompletionFunc(cmd, f) - - return cmd -} - -func (o *PodChaosOptions) NewCobraCommand(use, short string) *cobra.Command { - return &cobra.Command{ - Use: use, - Short: short, - Example: faultPodExample, - Run: func(cmd *cobra.Command, args []string) { - o.Args = args - cmdutil.CheckErr(o.CreateOptions.Complete()) - cmdutil.CheckErr(o.Validate()) - cmdutil.CheckErr(o.Complete()) - cmdutil.CheckErr(o.Run()) - }, - } -} - -func (o *PodChaosOptions) AddCommonFlag(cmd *cobra.Command) { - o.FaultBaseOptions.AddCommonFlag(cmd) -} - -func (o *PodChaosOptions) Validate() error { - return o.BaseValidate() -} - -func (o *PodChaosOptions) Complete() error { - return o.BaseComplete() -} - -func (o *PodChaosOptions) PreCreate(obj *unstructured.Unstructured) error { - c := &v1alpha1.PodChaos{} - if err := runtime.DefaultUnstructuredConverter.FromUnstructured(obj.Object, c); err != nil { - return err - } - - data, e := runtime.DefaultUnstructuredConverter.ToUnstructured(c) - if e != nil { - return e - } - obj.SetUnstructuredContent(data) - return nil -} diff --git a/pkg/cmd/fault/fault_pod_test.go b/pkg/cmd/fault/fault_pod_test.go deleted file mode 100644 index a4f2de569..000000000 --- a/pkg/cmd/fault/fault_pod_test.go +++ /dev/null @@ -1,96 +0,0 @@ -/* -Copyright (C) 2022-2024 ApeCloud Co., Ltd - -This file is part of KubeBlocks project - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU Affero General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU Affero General Public License for more details. - -You should have received a copy of the GNU Affero General Public License -along with this program. If not, see . -*/ - -package fault - -import ( - . "github.com/onsi/ginkgo/v2" - . "github.com/onsi/gomega" - - "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" - "k8s.io/cli-runtime/pkg/genericiooptions" - clientfake "k8s.io/client-go/rest/fake" - cmdtesting "k8s.io/kubectl/pkg/cmd/testing" - - "github.com/apecloud/kbcli/pkg/testing" -) - -var _ = Describe("Fault POD", func() { - var ( - tf *cmdtesting.TestFactory - streams genericiooptions.IOStreams - ) - BeforeEach(func() { - streams, _, _, _ = genericiooptions.NewTestIOStreams() - tf = cmdtesting.NewTestFactory().WithNamespace(testing.Namespace) - tf.Client = &clientfake.RESTClient{} - }) - - AfterEach(func() { - tf.Cleanup() - }) - - Context("test fault pod", func() { - It("fault pod kill", func() { - inputs := [][]string{ - {"--dry-run=client"}, - {"--mode=one", "--dry-run=client"}, - {"--mode=fixed", "--value=2", "--dry-run=client"}, - {"--mode=fixed-percent", "--value=50", "--dry-run=client"}, - {"--mode=random-max-percent", "--value=50", "--dry-run=client"}, - {"--grace-period=5", "--dry-run=client"}, - {"--ns-fault=kb-system", "--dry-run=client"}, - {"--node=minikube-m02", "--dry-run=client"}, - {"--label=app.kubernetes.io/component=mysql", "--dry-run=client"}, - {"--node-label=kubernetes.io/arch=arm64", "--dry-run=client"}, - {"--annotation=example-annotation=group-a", "--dry-run=client"}, - } - o := NewPodChaosOptions(tf, streams, string(v1alpha1.PodKillAction)) - cmd := o.NewCobraCommand(Kill, KillShort) - o.AddCommonFlag(cmd) - cmd.Flags().Int64VarP(&o.GracePeriod, "grace-period", "g", 0, "Grace period represents the duration in seconds before the pod should be killed") - - for _, input := range inputs { - Expect(cmd.Flags().Parse(input)).Should(Succeed()) - Expect(o.CreateOptions.Complete()) - Expect(o.Complete()).Should(Succeed()) - Expect(o.Validate()).Should(Succeed()) - Expect(o.Run()).Should(Succeed()) - } - }) - - It("fault pod kill-container", func() { - inputs := [][]string{ - {"--container=mysql", "--container=config-manager", "--dry-run=client"}, - } - o := NewPodChaosOptions(tf, streams, string(v1alpha1.ContainerKillAction)) - cmd := o.NewCobraCommand(KillContainer, KillContainerShort) - o.AddCommonFlag(cmd) - cmd.Flags().StringArrayVarP(&o.ContainerNames, "container", "c", nil, "the name of the container you want to kill, such as mysql, prometheus.") - - for _, input := range inputs { - Expect(cmd.Flags().Parse(input)).Should(Succeed()) - Expect(o.CreateOptions.Complete()) - Expect(o.Complete()).Should(Succeed()) - Expect(o.Validate()).Should(Succeed()) - Expect(o.Run()).Should(Succeed()) - } - }) - }) -}) diff --git a/pkg/cmd/fault/fault_stress.go b/pkg/cmd/fault/fault_stress.go deleted file mode 100644 index 252b71303..000000000 --- a/pkg/cmd/fault/fault_stress.go +++ /dev/null @@ -1,146 +0,0 @@ -/* -Copyright (C) 2022-2024 ApeCloud Co., Ltd - -This file is part of KubeBlocks project - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU Affero General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU Affero General Public License for more details. - -You should have received a copy of the GNU Affero General Public License -along with this program. If not, see . -*/ - -package fault - -import ( - "fmt" - - "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" - "github.com/spf13/cobra" - "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" - "k8s.io/apimachinery/pkg/runtime" - "k8s.io/cli-runtime/pkg/genericiooptions" - cmdutil "k8s.io/kubectl/pkg/cmd/util" - "k8s.io/kubectl/pkg/util/templates" - - "github.com/apecloud/kbcli/pkg/action" -) - -var faultStressExample = templates.Examples(` - # Affects the first container in default namespace's all pods.Making CPU load up to 50%, and the memory up to 100MB. - kbcli fault stress --cpu-worker=2 --cpu-load=50 --memory-worker=1 --memory-size=100Mi - - # Affects the first container in mycluster-mysql-0 pod. Making the CPU load up to 50%, and the memory up to 500MB. - kbcli fault stress mycluster-mysql-0 --cpu-worker=2 --cpu-load=50 - - # Affects the mysql container in mycluster-mysql-0 pod. Making the memory up to 500MB. - kbcli fault stress mycluster-mysql-0 --memory-worker=2 --memory-size=500Mi -c=mysql -`) - -type CPU struct { - Workers int `json:"workers"` - Load int `json:"load"` -} - -type Memory struct { - Workers int `json:"workers"` - Size string `json:"size"` -} - -type Stressors struct { - CPU `json:"cpu"` - Memory `json:"memory"` -} - -type StressChaosOptions struct { - Stressors `json:"stressors"` - ContainerNames []string `json:"containerNames,omitempty"` - - FaultBaseOptions -} - -func NewStressChaosOptions(f cmdutil.Factory, streams genericiooptions.IOStreams, act string) *StressChaosOptions { - o := &StressChaosOptions{ - FaultBaseOptions: FaultBaseOptions{ - CreateOptions: action.CreateOptions{ - Factory: f, - IOStreams: streams, - CueTemplateName: CueTemplateStressChaos, - GVR: GetGVR(Group, Version, ResourceStressChaos), - }, - Action: act, - }, - } - o.CreateOptions.PreCreate = o.PreCreate - o.CreateOptions.Options = o - return o -} - -func NewStressChaosCmd(f cmdutil.Factory, streams genericiooptions.IOStreams) *cobra.Command { - o := NewStressChaosOptions(f, streams, "") - cmd := o.NewCobraCommand(Stress, StressShort) - - o.AddCommonFlag(cmd, f) - return cmd -} - -func (o *StressChaosOptions) NewCobraCommand(use, short string) *cobra.Command { - return &cobra.Command{ - Use: use, - Short: short, - Example: faultStressExample, - Run: func(cmd *cobra.Command, args []string) { - o.Args = args - cmdutil.CheckErr(o.CreateOptions.Complete()) - cmdutil.CheckErr(o.Validate()) - cmdutil.CheckErr(o.Complete()) - cmdutil.CheckErr(o.Run()) - }, - } -} - -func (o *StressChaosOptions) AddCommonFlag(cmd *cobra.Command, f cmdutil.Factory) { - o.FaultBaseOptions.AddCommonFlag(cmd) - - cmd.Flags().IntVar(&o.CPU.Workers, "cpu-worker", 0, `Specifies the number of threads that exert CPU pressure.`) - cmd.Flags().IntVar(&o.CPU.Load, "cpu-load", 0, `Specifies the percentage of CPU occupied. 0 means no extra load added, 100 means full load. The total load is workers * load.`) - cmd.Flags().IntVar(&o.Memory.Workers, "memory-worker", 0, `Specifies the number of threads that apply memory pressure.`) - cmd.Flags().StringVar(&o.Memory.Size, "memory-size", "", `Specify the size of the allocated memory or the percentage of the total memory, and the sum of the allocated memory is size. For example:256MB or 25%`) - cmd.Flags().StringArrayVarP(&o.ContainerNames, "container", "c", nil, "The name of the container, such as mysql, prometheus.If it's empty, the first container will be injected.") - - // register flag completion func - registerFlagCompletionFunc(cmd, f) -} - -func (o *StressChaosOptions) Validate() error { - if o.Memory.Workers == 0 && o.CPU.Workers == 0 { - return fmt.Errorf("the CPU or Memory workers must have at least one greater than 0, Use --cpu-workers or --memory-workers to specify") - } - - return o.BaseValidate() -} - -func (o *StressChaosOptions) Complete() error { - return o.BaseComplete() -} - -func (o *StressChaosOptions) PreCreate(obj *unstructured.Unstructured) error { - c := &v1alpha1.StressChaos{} - if err := runtime.DefaultUnstructuredConverter.FromUnstructured(obj.Object, c); err != nil { - return err - } - - data, e := runtime.DefaultUnstructuredConverter.ToUnstructured(c) - if e != nil { - return e - } - obj.SetUnstructuredContent(data) - return nil -} diff --git a/pkg/cmd/fault/fault_stress_test.go b/pkg/cmd/fault/fault_stress_test.go deleted file mode 100644 index 05aa44267..000000000 --- a/pkg/cmd/fault/fault_stress_test.go +++ /dev/null @@ -1,78 +0,0 @@ -/* -Copyright (C) 2022-2024 ApeCloud Co., Ltd - -This file is part of KubeBlocks project - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU Affero General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU Affero General Public License for more details. - -You should have received a copy of the GNU Affero General Public License -along with this program. If not, see . -*/ - -package fault - -import ( - . "github.com/onsi/ginkgo/v2" - . "github.com/onsi/gomega" - - "k8s.io/cli-runtime/pkg/genericiooptions" - clientfake "k8s.io/client-go/rest/fake" - cmdtesting "k8s.io/kubectl/pkg/cmd/testing" - - "github.com/apecloud/kbcli/pkg/testing" -) - -var _ = Describe("Fault Stress", func() { - var ( - tf *cmdtesting.TestFactory - streams genericiooptions.IOStreams - ) - BeforeEach(func() { - streams, _, _, _ = genericiooptions.NewTestIOStreams() - tf = cmdtesting.NewTestFactory().WithNamespace(testing.Namespace) - tf.Client = &clientfake.RESTClient{} - }) - - AfterEach(func() { - tf.Cleanup() - }) - Context("test fault stress", func() { - - It("fault stress", func() { - inputs := [][]string{ - {"--mode=one", "--cpu-worker=2", "--cpu-load=50", "--dry-run=client"}, - {"--mode=fixed", "--value=2", "--cpu-worker=2", "--cpu-load=50", "--dry-run=client"}, - {"--mode=fixed-percent", "--value=50", "--cpu-worker=2", "--cpu-load=50", "--dry-run=client"}, - {"--mode=random-max-percent", "--value=50", "--cpu-worker=2", "--cpu-load=50", "--dry-run=client"}, - {"--ns-fault=kb-system", "--cpu-worker=2", "--cpu-load=50", "--dry-run=client"}, - {"--node=minikube-m02", "--cpu-worker=2", "--cpu-load=50", "--dry-run=client"}, - {"--label=app.kubernetes.io/component=mysql", "--cpu-worker=2", "--cpu-load=50", "--dry-run=client"}, - {"--node-label=kubernetes.io/arch=arm64", "--cpu-worker=2", "--cpu-load=50", "--dry-run=client"}, - {"--annotation=example-annotation=group-a", "--cpu-worker=2", "--cpu-load=50", "--dry-run=client"}, - {"--cpu-worker=2", "--cpu-load=50", "--dry-run=client"}, - {"--memory-worker=2", "--memory-size=500Mi", "-c=mysql", "--dry-run=client"}, - {"--cpu-worker=2", "--cpu-load=50", "--memory-worker=1", "--memory-size=100Mi", "--dry-run=client"}, - {"--cpu-worker=2", "--cpu-load=50", "--memory-worker=1", "--memory-size=100Mi", "--dry-run=client", "--container=mysql"}, - } - o := NewStressChaosOptions(tf, streams, "") - cmd := o.NewCobraCommand(Stress, StressShort) - o.AddCommonFlag(cmd, tf) - - for _, input := range inputs { - Expect(cmd.Flags().Parse(input)).Should(Succeed()) - Expect(o.CreateOptions.Complete()) - Expect(o.Complete()).Should(Succeed()) - Expect(o.Validate()).Should(Succeed()) - Expect(o.Run()).Should(Succeed()) - } - }) - }) -}) diff --git a/pkg/cmd/fault/fault_time.go b/pkg/cmd/fault/fault_time.go deleted file mode 100644 index 9d0de070d..000000000 --- a/pkg/cmd/fault/fault_time.go +++ /dev/null @@ -1,135 +0,0 @@ -/* -Copyright (C) 2022-2024 ApeCloud Co., Ltd - -This file is part of KubeBlocks project - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU Affero General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU Affero General Public License for more details. - -You should have received a copy of the GNU Affero General Public License -along with this program. If not, see . -*/ - -package fault - -import ( - "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" - "github.com/spf13/cobra" - "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" - "k8s.io/apimachinery/pkg/runtime" - "k8s.io/cli-runtime/pkg/genericiooptions" - cmdutil "k8s.io/kubectl/pkg/cmd/util" - "k8s.io/kubectl/pkg/util/templates" - - "github.com/apecloud/kbcli/pkg/action" - "github.com/apecloud/kbcli/pkg/util" -) - -var faultTimeExample = templates.Examples(` - # Affects the first container in default namespace's all pods.Shifts the clock back five seconds. - kbcli fault time --time-offset=-5s - - # Affects the first container in default namespace's all pods. - kbcli fault time --time-offset=-5m5s - - # Affects the first container in mycluster-mysql-0 pod. Shifts the clock forward five seconds. - kbcli fault time mycluster-mysql-0 --time-offset=+5s50ms - - # Affects the mysql container in mycluster-mysql-0 pod. Shifts the clock forward five seconds. - kbcli fault time mycluster-mysql-0 --time-offset=+5s -c=mysql - - # The clock that specifies the effect of time offset is CLOCK_REALTIME. - kbcli fault time mycluster-mysql-0 --time-offset=+5s --clock-id=CLOCK_REALTIME -c=mysql -`) - -type TimeChaosOptions struct { - TimeOffset string `json:"timeOffset"` - - ClockIds []string `json:"clockIds,omitempty"` - - ContainerNames []string `json:"containerNames,omitempty"` - - FaultBaseOptions -} - -func NewTimeChaosOptions(f cmdutil.Factory, streams genericiooptions.IOStreams, act string) *TimeChaosOptions { - o := &TimeChaosOptions{ - FaultBaseOptions: FaultBaseOptions{ - CreateOptions: action.CreateOptions{ - Factory: f, - IOStreams: streams, - CueTemplateName: CueTemplateTimeChaos, - GVR: GetGVR(Group, Version, ResourceTimeChaos), - }, - Action: act, - }, - } - o.CreateOptions.PreCreate = o.PreCreate - o.CreateOptions.Options = o - return o -} - -func NewTimeChaosCmd(f cmdutil.Factory, streams genericiooptions.IOStreams) *cobra.Command { - o := NewTimeChaosOptions(f, streams, "") - cmd := o.NewCobraCommand(Time, TimeShort) - - o.AddCommonFlag(cmd, f) - return cmd -} - -func (o *TimeChaosOptions) NewCobraCommand(use, short string) *cobra.Command { - return &cobra.Command{ - Use: use, - Short: short, - Example: faultTimeExample, - Run: func(cmd *cobra.Command, args []string) { - o.Args = args - cmdutil.CheckErr(o.CreateOptions.Complete()) - cmdutil.CheckErr(o.Validate()) - cmdutil.CheckErr(o.Complete()) - cmdutil.CheckErr(o.Run()) - }, - } -} - -func (o *TimeChaosOptions) AddCommonFlag(cmd *cobra.Command, f cmdutil.Factory) { - o.FaultBaseOptions.AddCommonFlag(cmd) - - cmd.Flags().StringVar(&o.TimeOffset, "time-offset", "", "Specifies the length of the time offset. For example: -5s, -10m100ns.") - cmd.Flags().StringArrayVar(&o.ClockIds, "clock-id", nil, `Specifies the clock on which the time offset acts.If it's empty, it will be set to ['CLOCK_REALTIME'].See clock_gettime [https://man7.org/linux/man-pages/man2/clock_gettime.2.html] document for details.`) - cmd.Flags().StringArrayVarP(&o.ContainerNames, "container", "c", nil, `Specifies the injected container name. For example: mysql. If it's empty, the first container will be injected.`) - - util.CheckErr(cmd.MarkFlagRequired("time-offset")) - - // register flag completion func - registerFlagCompletionFunc(cmd, f) -} - -func (o *TimeChaosOptions) Validate() error { - return o.BaseValidate() -} - -func (o *TimeChaosOptions) Complete() error { - return o.BaseComplete() -} - -func (o *TimeChaosOptions) PreCreate(obj *unstructured.Unstructured) error { - c := &v1alpha1.TimeChaos{} - if err := runtime.DefaultUnstructuredConverter.FromUnstructured(obj.Object, c); err != nil { - return err - } - - data, e := runtime.DefaultUnstructuredConverter.ToUnstructured(c) - if e != nil { - return e - } - obj.SetUnstructuredContent(data) - return nil -} diff --git a/pkg/cmd/fault/fault_time_test.go b/pkg/cmd/fault/fault_time_test.go deleted file mode 100644 index e8449abb2..000000000 --- a/pkg/cmd/fault/fault_time_test.go +++ /dev/null @@ -1,76 +0,0 @@ -/* -Copyright (C) 2022-2024 ApeCloud Co., Ltd - -This file is part of KubeBlocks project - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU Affero General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU Affero General Public License for more details. - -You should have received a copy of the GNU Affero General Public License -along with this program. If not, see . -*/ - -package fault - -import ( - . "github.com/onsi/ginkgo/v2" - . "github.com/onsi/gomega" - - "k8s.io/cli-runtime/pkg/genericiooptions" - clientfake "k8s.io/client-go/rest/fake" - cmdtesting "k8s.io/kubectl/pkg/cmd/testing" - - "github.com/apecloud/kbcli/pkg/testing" -) - -var _ = Describe("Fault Time", func() { - var ( - tf *cmdtesting.TestFactory - streams genericiooptions.IOStreams - ) - BeforeEach(func() { - streams, _, _, _ = genericiooptions.NewTestIOStreams() - tf = cmdtesting.NewTestFactory().WithNamespace(testing.Namespace) - tf.Client = &clientfake.RESTClient{} - }) - - AfterEach(func() { - tf.Cleanup() - }) - Context("test fault time", func() { - - It("fault time", func() { - inputs := [][]string{ - {"--mode=one", "--time-offset=-5s", "--dry-run=client"}, - {"--mode=fixed", "--value=2", "--time-offset=-5s", "--dry-run=client"}, - {"--mode=fixed-percent", "--value=50", "--time-offset=-5s", "--dry-run=client"}, - {"--mode=random-max-percent", "--value=50", "--time-offset=-5s", "--dry-run=client"}, - {"--ns-fault=kb-system", "--time-offset=-5s", "--dry-run=client"}, - {"--node=minikube-m02", "--time-offset=-5s", "--dry-run=client"}, - {"--label=app.kubernetes.io/component=mysql", "--time-offset=-5s", "--dry-run=client"}, - {"--node-label=kubernetes.io/arch=arm64", "--time-offset=-5s", "--dry-run=client"}, - {"--annotation=example-annotation=group-a", "--time-offset=-5s", "--dry-run=client"}, - {"--time-offset=-5s", "--dry-run=client"}, - {"--time-offset=+5s", "--clock-id=CLOCK_REALTIME", "-c=mysql", "--dry-run=client"}, - } - o := NewTimeChaosOptions(tf, streams, "") - cmd := o.NewCobraCommand(Time, TimeShort) - o.AddCommonFlag(cmd, tf) - - for _, input := range inputs { - Expect(cmd.Flags().Parse(input)).Should(Succeed()) - Expect(o.CreateOptions.Complete()) - Expect(o.Complete()).Should(Succeed()) - Expect(o.Validate()).Should(Succeed()) - Expect(o.Run()).Should(Succeed()) - } - }) - }) -}) diff --git a/pkg/cmd/fault/list_and_delete.go b/pkg/cmd/fault/list_and_delete.go deleted file mode 100644 index 9fafc8490..000000000 --- a/pkg/cmd/fault/list_and_delete.go +++ /dev/null @@ -1,244 +0,0 @@ -/* -Copyright (C) 2022-2024 ApeCloud Co., Ltd - -This file is part of KubeBlocks project - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU Affero General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU Affero General Public License for more details. - -You should have received a copy of the GNU Affero General Public License -along with this program. If not, see . -*/ - -package fault - -import ( - "context" - "fmt" - "sort" - "strings" - "time" - - "github.com/jedib0t/go-pretty/v6/table" - "github.com/pkg/errors" - "github.com/spf13/cobra" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/cli-runtime/pkg/genericiooptions" - "k8s.io/client-go/dynamic" - cmdutil "k8s.io/kubectl/pkg/cmd/util" - "k8s.io/kubectl/pkg/util/templates" - - "github.com/apecloud/kbcli/pkg/printer" - "github.com/apecloud/kbcli/pkg/util" -) - -var listExample = templates.Examples(` - # List all chaos resources - kbcli fault list - - # List all chaos kind - kbcli fault list --kind - - # List specific chaos resources. Use 'kbcli fault list --kind' to get chaos kind. - kbcli fault list podchaos -`) - -var deleteExample = templates.Examples(` - # Delete all chaos resources - kbcli fault delete - - # Delete specific chaos resources - kbcli fault delete podchaos -`) - -type ListAndDeleteOptions struct { - Factory cmdutil.Factory - Dynamic dynamic.Interface - - ResourceKinds []string - AllResourceKinds []string - Kind bool - - genericiooptions.IOStreams -} - -func NewListCmd(f cmdutil.Factory, streams genericiooptions.IOStreams) *cobra.Command { - o := &ListAndDeleteOptions{Factory: f, IOStreams: streams} - cmd := cobra.Command{ - Use: "list", - Short: "List chaos resources.", - Example: listExample, - Run: func(cmd *cobra.Command, args []string) { - util.CheckErr(o.Validate(args)) - util.CheckErr(o.Complete(args)) - util.CheckErr(o.RunList()) - }, - } - cmd.Flags().BoolVar(&o.Kind, "kind", false, "Print chaos resource kind.") - return &cmd -} - -func NewDeleteCmd(f cmdutil.Factory, streams genericiooptions.IOStreams) *cobra.Command { - o := &ListAndDeleteOptions{Factory: f, IOStreams: streams} - return &cobra.Command{ - Use: "delete", - Short: "Delete chaos resources.", - Example: deleteExample, - Run: func(cmd *cobra.Command, args []string) { - util.CheckErr(o.Validate(args)) - util.CheckErr(o.Complete(args)) - util.CheckErr(o.RunDelete()) - }, - } -} - -func (o *ListAndDeleteOptions) Validate(args []string) error { - var err error - o.AllResourceKinds, err = getAllChaosResourceKinds(o.Factory, GroupVersion) - if err != nil { - return fmt.Errorf("failed to get all chaos resource kinds: %v", err) - } - kindMap := make(map[string]bool) - for _, kind := range o.AllResourceKinds { - kindMap[kind] = true - } - for _, kind := range args { - if _, ok := kindMap[kind]; !ok { - return fmt.Errorf("invalid chaos resource kind: %s\nUse 'kbcli fault list --kind' to list all chaos resource kinds", kind) - } - } - - return nil -} - -func (o *ListAndDeleteOptions) Complete(args []string) error { - if o.Kind { - for _, resourceKind := range o.AllResourceKinds { - fmt.Fprintf(o.Out, "%s\n", resourceKind) - } - return nil - } - - if len(args) > 0 { - o.ResourceKinds = args - } else { - o.ResourceKinds = o.AllResourceKinds - } - - var err error - o.Dynamic, err = o.Factory.DynamicClient() - if err != nil { - return fmt.Errorf("failed to create dynamic client: %v", err) - } - - return nil -} - -func (o *ListAndDeleteOptions) RunList() error { - if o.Kind { - return nil - } - - tbl := printer.NewTablePrinter(o.Out) - tbl.Tbl.SetColumnConfigs([]table.ColumnConfig{ - {Number: 2, WidthMax: 120}, - }) - tbl.SetHeader("NAME", "AGE") - - for _, resourceKind := range o.ResourceKinds { - if err := o.listResources(resourceKind, tbl); err != nil { - return err - } - } - - tbl.Print() - return nil -} - -func (o *ListAndDeleteOptions) RunDelete() error { - for _, resourceKind := range o.ResourceKinds { - if err := o.deleteResources(resourceKind); err != nil { - return err - } - } - return nil -} - -func (o *ListAndDeleteOptions) listResources(resourceKind string, tbl *printer.TablePrinter) error { - gvr := GetGVR(Group, Version, resourceKind) - resourceList, err := o.Dynamic.Resource(gvr).List(context.TODO(), metav1.ListOptions{}) - if err != nil { - return errors.Wrapf(err, "failed to list %s", gvr) - } - - if len(resourceList.Items) == 0 { - return nil - } - - // sort by creation time from old to new - sort.Slice(resourceList.Items, func(i, j int) bool { - t1, _ := time.Parse(time.RFC3339, resourceList.Items[i].GetCreationTimestamp().String()) - t2, _ := time.Parse(time.RFC3339, resourceList.Items[j].GetCreationTimestamp().String()) - return t1.Before(t2) - }) - - for _, obj := range resourceList.Items { - creationTime := obj.GetCreationTimestamp().Time - age := time.Since(creationTime).Round(time.Second).String() - tbl.AddRow(obj.GetName(), age) - } - return nil -} - -func (o *ListAndDeleteOptions) deleteResources(resourceKind string) error { - gvr := GetGVR(Group, Version, resourceKind) - resourceList, err := o.Dynamic.Resource(gvr).List(context.TODO(), metav1.ListOptions{}) - if err != nil { - return errors.Wrapf(err, "failed to list %s", gvr) - } - - if len(resourceList.Items) == 0 { - return nil - } - - for _, obj := range resourceList.Items { - err = o.Dynamic.Resource(gvr).Namespace(obj.GetNamespace()).Delete(context.TODO(), obj.GetName(), metav1.DeleteOptions{}) - if err != nil { - return errors.Wrapf(err, "failed to delete %s", gvr) - } - fmt.Fprintf(o.Out, "delete resource %s/%s\n", obj.GetNamespace(), obj.GetName()) - } - return nil -} - -func getAllChaosResourceKinds(f cmdutil.Factory, groupVersion string) ([]string, error) { - discoveryClient, err := f.ToDiscoveryClient() - if err != nil { - return nil, errors.Wrap(err, "failed to create discovery client") - } - chaosResources, err := discoveryClient.ServerResourcesForGroupVersion(groupVersion) - if err != nil { - return nil, errors.Wrapf(err, "failed to get server resources for %s", groupVersion) - } - - resourceKinds := make([]string, 0) - for _, resourceKind := range chaosResources.APIResources { - // skip subresources - if len(strings.Split(resourceKind.Name, "/")) > 1 { - continue - } - // skip podhttpchaos and podnetworkchaos etc. - if resourceKind.Name != "podchaos" && strings.HasPrefix(resourceKind.Name, "pod") { - continue - } - resourceKinds = append(resourceKinds, resourceKind.Name) - } - return resourceKinds, nil -} diff --git a/pkg/cmd/fault/list_and_delete_test.go b/pkg/cmd/fault/list_and_delete_test.go deleted file mode 100644 index 8f49ad4c3..000000000 --- a/pkg/cmd/fault/list_and_delete_test.go +++ /dev/null @@ -1,93 +0,0 @@ -/* -Copyright (C) 2022-2024 ApeCloud Co., Ltd - -This file is part of KubeBlocks project - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU Affero General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU Affero General Public License for more details. - -You should have received a copy of the GNU Affero General Public License -along with this program. If not, see . -*/ - -package fault - -import ( - "net/http" - - . "github.com/onsi/ginkgo/v2" - . "github.com/onsi/gomega" - - "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" - "k8s.io/apimachinery/pkg/runtime" - "k8s.io/apimachinery/pkg/runtime/schema" - "k8s.io/cli-runtime/pkg/genericiooptions" - "k8s.io/cli-runtime/pkg/resource" - "k8s.io/client-go/dynamic/fake" - "k8s.io/client-go/kubernetes/scheme" - clientfake "k8s.io/client-go/rest/fake" - cmdtesting "k8s.io/kubectl/pkg/cmd/testing" - - "github.com/apecloud/kbcli/pkg/testing" -) - -var _ = Describe("Chaos resources list and delete", func() { - var ( - tf *cmdtesting.TestFactory - streams genericiooptions.IOStreams - namespace = "test" - podChaosName = "testPodChaos" - podChaos = testing.FakePodChaos(podChaosName, namespace) - ) - - BeforeEach(func() { - streams, _, _, _ = genericiooptions.NewTestIOStreams() - tf = testing.NewTestFactory(namespace) - codec := scheme.Codecs.LegacyCodec(scheme.Scheme.PrioritizedVersionsAllGroups()...) - httpResp := func(obj runtime.Object) *http.Response { - return &http.Response{StatusCode: http.StatusOK, Header: cmdtesting.DefaultHeader(), Body: cmdtesting.ObjBody(codec, obj)} - } - tf.UnstructuredClient = &clientfake.RESTClient{ - GroupVersion: schema.GroupVersion{Group: Group, Version: Version}, - NegotiatedSerializer: resource.UnstructuredPlusDefaultContentConfig().NegotiatedSerializer, - Client: clientfake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { - urlPrefix := "/apis/" + GroupVersion + "/namespaces/" + namespace - mapping := map[string]*http.Response{ - urlPrefix + "/podchaos/" + podChaos.Name: httpResp(podChaos), - } - return mapping[req.URL.Path], nil - }), - } - - tf.Client = tf.UnstructuredClient - _ = v1alpha1.AddToScheme(scheme.Scheme) - tf.FakeDynamicClient = fake.NewSimpleDynamicClient(scheme.Scheme, podChaos) - }) - - AfterEach(func() { - tf.Cleanup() - }) - - Context("test list and delete chaos resources", func() { - It("test fault list", func() { - args := []string{"podchaoses"} - o := &ListAndDeleteOptions{Factory: tf, IOStreams: streams} - Expect(o.Complete(args)).Should(Succeed()) - Expect(o.RunList()).Should(Succeed()) - }) - - It("test fault delete", func() { - args := []string{"podchaoses"} - o := &ListAndDeleteOptions{Factory: tf, IOStreams: streams} - Expect(o.Complete(args)).Should(Succeed()) - Expect(o.RunDelete()).Should(Succeed()) - }) - }) -}) diff --git a/pkg/cmd/fault/suite_test.go b/pkg/cmd/fault/suite_test.go deleted file mode 100644 index e2fbd82fc..000000000 --- a/pkg/cmd/fault/suite_test.go +++ /dev/null @@ -1,32 +0,0 @@ -/* -Copyright (C) 2022-2024 ApeCloud Co., Ltd - -This file is part of KubeBlocks project - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU Affero General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU Affero General Public License for more details. - -You should have received a copy of the GNU Affero General Public License -along with this program. If not, see . -*/ - -package fault - -import ( - "testing" - - . "github.com/onsi/ginkgo/v2" - . "github.com/onsi/gomega" -) - -func TestDashboard(t *testing.T) { - RegisterFailHandler(Fail) - RunSpecs(t, "Fault Suite") -} diff --git a/pkg/cmd/kubeblocks/install.go b/pkg/cmd/kubeblocks/install.go index 50a18f2e7..a3262b05d 100644 --- a/pkg/cmd/kubeblocks/install.go +++ b/pkg/cmd/kubeblocks/install.go @@ -71,11 +71,12 @@ type Options struct { HelmCfg *helm.Config // Namespace is the current namespace the command running in - Namespace string - Client kubernetes.Interface - Dynamic dynamic.Interface - Timeout time.Duration - Wait bool + Namespace string + Client kubernetes.Interface + Dynamic dynamic.Interface + Timeout time.Duration + Wait bool + WaitAddons bool } type InstallOptions struct { @@ -157,8 +158,9 @@ func newInstallCmd(f cmdutil.Factory, streams genericiooptions.IOStreams) *cobra cmd.Flags().StringVar(&o.Version, "version", version.DefaultKubeBlocksVersion, "KubeBlocks version") cmd.Flags().BoolVar(&o.CreateNamespace, "create-namespace", false, "Create the namespace if not present") cmd.Flags().BoolVar(&o.Check, "check", true, "Check kubernetes environment before installation") - cmd.Flags().DurationVar(&o.Timeout, "timeout", 300*time.Second, "Time to wait for installing KubeBlocks, such as --timeout=10m") + cmd.Flags().DurationVar(&o.Timeout, "timeout", 600*time.Second, "Time to wait for installing KubeBlocks, such as --timeout=10m") cmd.Flags().BoolVar(&o.Wait, "wait", true, "Wait for KubeBlocks to be ready, including all the auto installed add-ons. It will wait for a --timeout period") + cmd.Flags().BoolVar(&o.WaitAddons, "wait-addons", true, "Wait for auto installed add-ons. It will wait for a --timeout period") cmd.Flags().BoolVar(&p.force, flagForce, p.force, "If present, just print fail item and continue with the following steps") cmd.Flags().StringVar(&o.PodAntiAffinity, "pod-anti-affinity", "", "Pod anti-affinity type, one of: (Preferred, Required)") cmd.Flags().StringArrayVar(&o.TopologyKeys, "topology-keys", nil, "Topology keys for affinity") @@ -295,9 +297,41 @@ func (o *InstallOptions) Install() error { // install KubeBlocks s = spinner.New(o.Out, spinnerMsg("Install KubeBlocks "+o.Version)) defer s.Fail() + + getImageRegistry := func() string { + registry := viperx.GetString(types.CfgKeyImageRegistry) + if registry != "" { + return registry + } + + // get from values options + for _, s := range o.ValueOpts.Values { + if split := strings.Split(s, "="); split[0] == types.ImageRegistryKey && len(split) == 2 { + registry = split[1] + break + } + } + + // user do not specify image registry, get default image registry based on K8s provider and region + if registry == "" { + registry, err = util.GetImageRegistryByProvider(o.Client) + if err != nil { + fmt.Fprintf(o.ErrOut, "Failed to get image registry by provider: %v\n", err) + return "" + } + } + return registry + } + imageRegistry := getImageRegistry() + if imageRegistry != "" { + klog.V(1).Infof("Use image registry %s", imageRegistry) + o.ValueOpts.Values = append(o.ValueOpts.Values, fmt.Sprintf("%s=%s", types.ImageRegistryKey, imageRegistry)) + } + if err = o.installChart(); err != nil { return err } + // save KB image.registry config writeImageRegistryKey := func(registry string) error { viperx.Set(types.CfgKeyImageRegistry, registry) @@ -313,14 +347,12 @@ func (o *InstallOptions) Install() error { return err } - for _, s := range o.ValueOpts.Values { - if split := strings.Split(s, "="); split[0] == types.ImageRegistryKey && len(split) == 2 { - if err := writeImageRegistryKey(split[1]); err != nil { - return err - } + // if imageRegistry is not empty, save it to config file and used by addon + if imageRegistry != "" { + if err := writeImageRegistryKey(imageRegistry); err != nil { + return err } } - s.Success() // wait for auto-install addons to be ready @@ -345,7 +377,7 @@ You can check the KubeBlocks status by running "kbcli kubeblocks status" // waitAddonsEnabled waits for auto-install addons status to be enabled func (o *InstallOptions) waitAddonsEnabled() error { - if !o.Wait { + if !o.Wait || !o.WaitAddons { return nil } @@ -563,6 +595,11 @@ func (o *InstallOptions) buildChart() *helm.InstallOpts { } } +func (o *InstallOptions) disableHelmPreHookJob() { + // disable kubeblocks helm pre hook job + o.ValueOpts.Values = append(o.ValueOpts.Values, "crd.enabled=false") +} + func versionExists(version string) (bool, error) { if version == "" { return true, nil diff --git a/pkg/cmd/kubeblocks/kubeblocks_objects.go b/pkg/cmd/kubeblocks/kubeblocks_objects.go index 6e9925558..b1f70b252 100644 --- a/pkg/cmd/kubeblocks/kubeblocks_objects.go +++ b/pkg/cmd/kubeblocks/kubeblocks_objects.go @@ -21,6 +21,7 @@ package kubeblocks import ( "context" + "encoding/json" "strings" corev1 "k8s.io/api/core/v1" @@ -34,6 +35,7 @@ import ( "k8s.io/client-go/dynamic" "k8s.io/client-go/kubernetes" "k8s.io/klog/v2" + "sigs.k8s.io/controller-runtime/pkg/client" extensionsv1alpha1 "github.com/apecloud/kubeblocks/apis/extensions/v1alpha1" "github.com/apecloud/kubeblocks/pkg/constant" @@ -233,6 +235,14 @@ func deleteObjects(dynamic dynamic.Interface, gvr schema.GroupVersionResource, o continue } + // hack delete configconstraint cr + if gvr == types.ConfigConstraintGVR() { + klog.V(1).Infof("process configconstraints v1beta1 cr: %s", s.GetName()) + if err := checkAndPatchCCRequiredFields(dynamic, &s); err != nil { + return err + } + } + klog.V(1).Infof("remove finalizers of %s %s", gvr.String(), s.GetName()) if _, err := dynamic.Resource(gvr).Namespace(s.GetNamespace()).Patch(context.TODO(), s.GetName(), k8sapitypes.JSONPatchType, []byte("[{\"op\": \"remove\", \"path\": \"/metadata/finalizers\"}]"), metav1.PatchOptions{}); err != nil && !apierrors.IsNotFound(err) { @@ -242,6 +252,30 @@ func deleteObjects(dynamic dynamic.Interface, gvr schema.GroupVersionResource, o return nil } +func checkAndPatchCCRequiredFields(dynamic dynamic.Interface, object *unstructured.Unstructured) error { + patchData := map[string]interface{}{ + "spec": map[string]interface{}{ + "fileFormatConfig": map[string]interface{}{ + "format": "yaml", + }, + }, + } + + _, found, err := unstructured.NestedString(object.Object, "spec", "fileFormatConfig", "format") + if err != nil || found { + return err + } + + patchBytes, _ := json.Marshal(patchData) + _, err = dynamic.Resource(types.ConfigConstraintGVR()).Patch(context.TODO(), + object.GetName(), + k8sapitypes.MergePatchType, + patchBytes, + metav1.PatchOptions{}, + ) + return client.IgnoreNotFound(err) +} + func getRemainedResource(objs kbObjects) map[string][]string { res := map[string][]string{} appendItems := func(key string, l *unstructured.UnstructuredList) { diff --git a/pkg/cmd/kubeblocks/status.go b/pkg/cmd/kubeblocks/status.go index 6cedfe14e..f2af19e46 100644 --- a/pkg/cmd/kubeblocks/status.go +++ b/pkg/cmd/kubeblocks/status.go @@ -248,7 +248,7 @@ func (o *statusOptions) showAddons() { for _, addon := range o.addons { if addon.Labels == nil { provider = notAvailable - } else if provider, ok = addon.Labels[constant.AddonProviderLabelKey]; !ok { + } else if provider, ok = addon.Labels[types.KBAddonProviderLabelKey]; !ok { provider = notAvailable } tbl.AddRow(addon.Name, addon.Status.Phase, addon.Spec.Type, provider) @@ -497,7 +497,7 @@ func computeMetricByWorkloads(ctx context.Context, ns string, workloads []*unstr computeMetrics := func(namespace, name string, matchLabels string) { if pods, err := mc.MetricsV1beta1().PodMetricses(namespace).List(ctx, metav1.ListOptions{LabelSelector: matchLabels}); err != nil { if klog.V(1).Enabled() { - klog.Errorf("failed to get pod metrics for %s/%s, selector: , error: %v", namespace, name, matchLabels, err) + klog.Errorf("failed to get pod metrics for %s/%s, selector: %v, error: %v", namespace, name, matchLabels, err) } } else { cpuUsage, memUsage := int64(0), int64(0) diff --git a/pkg/cmd/kubeblocks/uninstall.go b/pkg/cmd/kubeblocks/uninstall.go index 3559834b3..6bb61c3ce 100644 --- a/pkg/cmd/kubeblocks/uninstall.go +++ b/pkg/cmd/kubeblocks/uninstall.go @@ -97,7 +97,7 @@ func newUninstallCmd(f cmdutil.Factory, streams genericiooptions.IOStreams) *cob cmd.Flags().BoolVar(&o.removePVs, "remove-pvs", false, "Remove PersistentVolume or not") cmd.Flags().BoolVar(&o.removePVCs, "remove-pvcs", false, "Remove PersistentVolumeClaim or not") cmd.Flags().BoolVar(&o.RemoveNamespace, "remove-namespace", false, "Remove default created \"kb-system\" namespace or not") - cmd.Flags().DurationVar(&o.Timeout, "timeout", 300*time.Second, "Time to wait for uninstalling KubeBlocks, such as --timeout=5m") + cmd.Flags().DurationVar(&o.Timeout, "timeout", 600*time.Second, "Time to wait for uninstalling KubeBlocks, such as --timeout=5m") cmd.Flags().BoolVar(&o.Wait, "wait", true, "Wait for KubeBlocks to be uninstalled, including all the add-ons. It will wait for a --timeout period") return cmd } diff --git a/pkg/cmd/kubeblocks/upgrade.go b/pkg/cmd/kubeblocks/upgrade.go index d49d52b89..07418b631 100644 --- a/pkg/cmd/kubeblocks/upgrade.go +++ b/pkg/cmd/kubeblocks/upgrade.go @@ -31,6 +31,7 @@ import ( appsv1 "k8s.io/api/apps/v1" apierrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" apitypes "k8s.io/apimachinery/pkg/types" "k8s.io/apimachinery/pkg/util/wait" "k8s.io/cli-runtime/pkg/genericiooptions" @@ -44,6 +45,7 @@ import ( "github.com/apecloud/kbcli/pkg/types" "github.com/apecloud/kbcli/pkg/util" "github.com/apecloud/kbcli/pkg/util/breakingchange" + "github.com/apecloud/kbcli/pkg/util/conversion" "github.com/apecloud/kbcli/pkg/util/helm" "github.com/apecloud/kbcli/pkg/util/prompt" ) @@ -79,7 +81,7 @@ func newUpgradeCmd(f cmdutil.Factory, streams genericiooptions.IOStreams) *cobra cmd.Flags().StringVar(&o.Version, "version", "", "Set KubeBlocks version") cmd.Flags().BoolVar(&o.Check, "check", true, "Check kubernetes environment before upgrade") - cmd.Flags().DurationVar(&o.Timeout, "timeout", 300*time.Second, "Time to wait for upgrading KubeBlocks, such as --timeout=10m") + cmd.Flags().DurationVar(&o.Timeout, "timeout", 600*time.Second, "Time to wait for upgrading KubeBlocks, such as --timeout=10m") cmd.Flags().BoolVar(&o.Wait, "wait", true, "Wait for KubeBlocks to be ready. It will wait for a --timeout period") cmd.Flags().BoolVar(&o.autoApprove, "auto-approve", false, "Skip interactive approval before upgrading KubeBlocks") helm.AddValueOptionsFlags(cmd.Flags(), &o.ValueOpts) @@ -205,6 +207,18 @@ func (o *InstallOptions) Upgrade() error { return err } + // save old version crs + var unstructuredObjects []unstructured.Unstructured + conversionMeta := conversion.NewVersionConversion(o.Dynamic, o.OldVersion, o.Version) + if conversionMeta.NeedConversion() { + s = spinner.New(o.Out, spinnerMsg("Conversion old version[%s] CRs to new version[%s]", o.OldVersion, o.Version)) + defer s.Fail() + if unstructuredObjects, err = conversion.FetchAndConversionResources(conversionMeta); err != nil { + return fmt.Errorf("conversion crs failed: %s", err.Error()) + } + s.Success() + } + // create or update crds s = spinner.New(o.Out, spinnerMsg("Upgrade CRDs")) defer s.Fail() @@ -213,8 +227,19 @@ func (o *InstallOptions) Upgrade() error { } s.Success() + // conversion new version crs + if conversionMeta.NeedConversion() { + s = spinner.New(o.Out, spinnerMsg("update new version CRs")) + defer s.Fail() + if err = conversion.UpdateNewVersionResources(conversionMeta, unstructuredObjects); err != nil { + return fmt.Errorf("update new crs failed: %s", err.Error()) + } + s.Success() + } + s = spinner.New(o.Out, spinnerMsg("Upgrading KubeBlocks "+msg)) defer s.Fail() + o.disableHelmPreHookJob() // upgrade KubeBlocks chart if err = o.upgradeChart(); err != nil { return err diff --git a/pkg/cmd/kubeblocks/util.go b/pkg/cmd/kubeblocks/util.go index 8972c0da3..4d983547d 100644 --- a/pkg/cmd/kubeblocks/util.go +++ b/pkg/cmd/kubeblocks/util.go @@ -60,11 +60,42 @@ func getGVRByCRD(crd *unstructured.Unstructured) (*schema.GroupVersionResource, } return &schema.GroupVersionResource{ Group: group, - Version: types.AppsAPIVersion, + Version: getVersionFromCRD(crd), Resource: strings.Split(crd.GetName(), ".")[0], }, nil } +func getVersionFromCRD(crd *unstructured.Unstructured) string { + versions, found, err := unstructured.NestedFieldNoCopy(crd.Object, "spec", "versions") + if err != nil || !found || versions == nil { + return types.AppsAPIVersion + } + if _, ok := versions.([]interface{}); !ok { + return types.AppsAPIVersion + } + + isStorageVersion := func(version map[string]interface{}) bool { + storage, found, err := unstructured.NestedBool(version, "storage") + return found && err == nil && storage + } + + var ver string + var ok bool + var mapValue map[string]interface{} + for _, version := range versions.([]interface{}) { + if mapValue, ok = version.(map[string]interface{}); !ok { + continue + } + if !isStorageVersion(mapValue) { + continue + } + if ver, found, err = unstructured.NestedString(mapValue, "name"); found && err == nil { + return ver + } + } + return types.AppsAPIVersion +} + // check if KubeBlocks has been installed func checkIfKubeBlocksInstalled(client kubernetes.Interface) (bool, string, error) { kbDeploys, err := client.AppsV1().Deployments(metav1.NamespaceAll).List(context.TODO(), @@ -296,6 +327,7 @@ func createOrUpdateCRDS(dynamic dynamic.Interface, kbVersion string) error { return err } if resp.StatusCode == http.StatusNotFound { + fmt.Printf("not found CRDs from %s, please specify the right version", crdsURL) return nil } else if resp.StatusCode != http.StatusOK { return fmt.Errorf("failed to download CRDs from %s", crdsURL) diff --git a/pkg/cmd/migration/base.go b/pkg/cmd/migration/base.go deleted file mode 100644 index e5f04f4e0..000000000 --- a/pkg/cmd/migration/base.go +++ /dev/null @@ -1,261 +0,0 @@ -/* -Copyright (C) 2022-2024 ApeCloud Co., Ltd - -This file is part of KubeBlocks project - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU Affero General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU Affero General Public License for more details. - -You should have received a copy of the GNU Affero General Public License -along with this program. If not, see . -*/ - -package migration - -import ( - "context" - "fmt" - "os" - "strings" - - "k8s.io/apimachinery/pkg/api/errors" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/runtime" - "k8s.io/apimachinery/pkg/runtime/schema" - "k8s.io/client-go/dynamic" - cmdutil "k8s.io/kubectl/pkg/cmd/util" - - "github.com/apecloud/kbcli/pkg/types" - migrationv1 "github.com/apecloud/kbcli/pkg/types/migrationapi" - "github.com/apecloud/kbcli/pkg/util" -) - -const ( - MigrationTaskLabel = "datamigration.apecloud.io/migrationtask" - MigrationTaskStepAnnotation = "datamigration.apecloud.io/step" - SerialJobOrderAnnotation = "common.apecloud.io/serial_job_order" -) - -const ( - invalidMigrationCrdAdvice = "to use migration-related functions, please ensure that the addon of migration is enabled, use: 'kbcli addon enable migration' to enable the addon" -) - -// Endpoint -// Todo: For the source or target is cluster in KubeBlocks. A better way is to get secret from {$clustername}-conn-credential, so the username, password, addresses can be omitted - -type EndpointModel struct { - UserName string `json:"userName"` - Password string `json:"password"` - Address string `json:"address"` - // +optional - Database string `json:"databaseName,omitempty"` -} - -func (e *EndpointModel) BuildFromStr(msgArr *[]string, endpointStr string) error { - if endpointStr == "" { - BuildErrorMsg(msgArr, "endpoint string cannot be empty") - return nil - } - e.clear() - endpointStr = strings.TrimSpace(endpointStr) - accountURLPair := strings.Split(endpointStr, "@") - if len(accountURLPair) != 2 { - BuildErrorMsg(msgArr, "endpoint may not contain account info") - return nil - } - accountPair := strings.Split(accountURLPair[0], ":") - if len(accountPair) != 2 { - BuildErrorMsg(msgArr, "the account info in endpoint is invalid, should be like \"user:123456\"") - return nil - } - e.UserName = accountPair[0] - e.Password = accountPair[1] - if strings.LastIndex(accountURLPair[1], "/") != -1 { - addressDatabasePair := strings.Split(accountURLPair[1], "/") - e.Address = strings.Join(addressDatabasePair[:len(addressDatabasePair)-1], "/") - e.Database = addressDatabasePair[len(addressDatabasePair)-1] - } else { - e.Address = accountURLPair[1] - } - return nil -} - -func (e *EndpointModel) clear() { - e.Address = "" - e.Password = "" - e.UserName = "" - e.Database = "" -} - -// Migration Object - -type MigrationObjectModel struct { - WhiteList []DBObjectExpress `json:"whiteList"` -} - -type DBObjectExpress struct { - SchemaName string `json:"schemaName"` - // +optional - IsAll bool `json:"isAll"` - // +optional - TableList []TableObjectExpress `json:"tableList"` -} - -type TableObjectExpress struct { - TableName string `json:"tableName"` - // +optional - IsAll bool `json:"isAll"` -} - -func (m *MigrationObjectModel) BuildFromStrs(errMsgArr *[]string, objStrs []string) error { - if len(objStrs) == 0 { - BuildErrorMsg(errMsgArr, "migration object cannot be empty") - return nil - } - for _, str := range objStrs { - msg := "" - if str == "" { - msg = "the database or database.table in migration object cannot be empty" - } - dbTablePair := strings.Split(str, ".") - if len(dbTablePair) > 2 { - msg = fmt.Sprintf("[%s] is not a valid database or database.table", str) - } - if msg != "" { - BuildErrorMsg(errMsgArr, msg) - return nil - } - if len(dbTablePair) == 1 { - m.WhiteList = append(m.WhiteList, DBObjectExpress{ - SchemaName: str, - IsAll: true, - }) - } else { - dbObjPoint, err := m.ContainSchema(dbTablePair[0]) - if err != nil { - return err - } - if dbObjPoint != nil { - dbObjPoint.TableList = append(dbObjPoint.TableList, TableObjectExpress{ - TableName: dbTablePair[1], - IsAll: true, - }) - } else { - m.WhiteList = append(m.WhiteList, DBObjectExpress{ - SchemaName: dbTablePair[0], - TableList: []TableObjectExpress{{ - TableName: dbTablePair[1], - IsAll: true, - }}, - }) - } - } - } - return nil -} - -func (m *MigrationObjectModel) ContainSchema(schemaName string) (*DBObjectExpress, error) { - for i := 0; i < len(m.WhiteList); i++ { - if m.WhiteList[i].SchemaName == schemaName { - return &m.WhiteList[i], nil - } - } - return nil, nil -} - -func CliStepChangeToStructure() (map[string]string, []string) { - validStepMap := map[string]string{ - migrationv1.CliStepPreCheck.String(): migrationv1.CliStepPreCheck.String(), - migrationv1.CliStepInitStruct.String(): migrationv1.CliStepInitStruct.String(), - migrationv1.CliStepInitData.String(): migrationv1.CliStepInitData.String(), - migrationv1.CliStepCdc.String(): migrationv1.CliStepCdc.String(), - } - validStepKey := make([]string, 0) - for k := range validStepMap { - validStepKey = append(validStepKey, k) - } - return validStepMap, validStepKey -} - -type TaskTypeEnum string - -const ( - Initialization TaskTypeEnum = "initialization" - InitializationAndCdc TaskTypeEnum = "initialization-and-cdc" // default value -) - -func (s TaskTypeEnum) String() string { - return string(s) -} - -func IsMigrationCrdValidWithDynamic(dynamic *dynamic.Interface) (bool, error) { - resource := types.CustomResourceDefinitionGVR() - if err := APIResource(dynamic, &resource, "migrationtasks.datamigration.apecloud.io", "", nil); err != nil { - return false, err - } - if err := APIResource(dynamic, &resource, "migrationtemplates.datamigration.apecloud.io", "", nil); err != nil { - return false, err - } - if err := APIResource(dynamic, &resource, "serialjobs.common.apecloud.io", "", nil); err != nil { - return false, err - } - return true, nil -} - -func PrintCrdInvalidError(err error) { - if err == nil { - return - } - if !errors.IsNotFound(err) { - util.CheckErr(err) - } - fmt.Fprintf(os.Stderr, "hint: %s\n", invalidMigrationCrdAdvice) - os.Exit(cmdutil.DefaultErrorExitCode) -} - -func IsMigrationCrdValidWithFactory(factory cmdutil.Factory) (bool, error) { - dynamic, err := factory.DynamicClient() - if err != nil { - return false, err - } - return IsMigrationCrdValidWithDynamic(&dynamic) -} - -func APIResource(dynamic *dynamic.Interface, resource *schema.GroupVersionResource, name string, namespace string, res interface{}) error { - obj, err := (*dynamic).Resource(*resource).Namespace(namespace).Get(context.Background(), name, metav1.GetOptions{}, "") - if err != nil { - return err - } - if res != nil { - return runtime.DefaultUnstructuredConverter.FromUnstructured(obj.Object, res) - } - return nil -} - -func BuildErrorMsg(msgArr *[]string, msg string) { - if *msgArr == nil { - *msgArr = make([]string, 1) - } - *msgArr = append(*msgArr, msg) -} - -func BuildInitializationStepsOrder(task *migrationv1.MigrationTask, template *migrationv1.MigrationTemplate) []string { - stepMap := make(map[string]string) - for _, taskStep := range task.Spec.Initialization.Steps { - stepMap[taskStep.String()] = taskStep.String() - } - resultArr := make([]string, 0) - for _, stepModel := range template.Spec.Initialization.Steps { - if stepMap[stepModel.Step.String()] != "" { - resultArr = append(resultArr, stepModel.Step.CliString()) - } - } - return resultArr -} diff --git a/pkg/cmd/migration/base_test.go b/pkg/cmd/migration/base_test.go deleted file mode 100644 index 5cc0b172f..000000000 --- a/pkg/cmd/migration/base_test.go +++ /dev/null @@ -1,67 +0,0 @@ -/* -Copyright (C) 2022-2024 ApeCloud Co., Ltd - -This file is part of KubeBlocks project - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU Affero General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU Affero General Public License for more details. - -You should have received a copy of the GNU Affero General Public License -along with this program. If not, see . -*/ - -package migration - -import ( - . "github.com/onsi/ginkgo/v2" - . "github.com/onsi/gomega" - - v1alpha1 "github.com/apecloud/kbcli/pkg/types/migrationapi" -) - -var _ = Describe("base", func() { - - Context("Basic function validate", func() { - - It("CliStepChangeToStructure", func() { - resultMap, resultKeyArr := CliStepChangeToStructure() - Expect(len(resultMap)).Should(Equal(4)) - Expect(len(resultKeyArr)).Should(Equal(4)) - }) - - It("BuildInitializationStepsOrder", func() { - task := &v1alpha1.MigrationTask{ - Spec: v1alpha1.MigrationTaskSpec{ - Initialization: v1alpha1.InitializationConfig{ - Steps: []v1alpha1.StepEnum{ - v1alpha1.StepFullLoad, - v1alpha1.StepStructPreFullLoad, - }, - }, - }, - } - template := &v1alpha1.MigrationTemplate{ - Spec: v1alpha1.MigrationTemplateSpec{ - Initialization: v1alpha1.InitializationModel{ - Steps: []v1alpha1.StepModel{ - {Step: v1alpha1.StepStructPreFullLoad}, - {Step: v1alpha1.StepFullLoad}, - }, - }, - }, - } - arr := BuildInitializationStepsOrder(task, template) - Expect(len(arr)).Should(Equal(2)) - Expect(arr[0]).Should(Equal(v1alpha1.StepStructPreFullLoad.CliString())) - Expect(arr[1]).Should(Equal(v1alpha1.StepFullLoad.CliString())) - }) - }) - -}) diff --git a/pkg/cmd/migration/cmd_builder.go b/pkg/cmd/migration/cmd_builder.go deleted file mode 100644 index 56e947c9e..000000000 --- a/pkg/cmd/migration/cmd_builder.go +++ /dev/null @@ -1,60 +0,0 @@ -/* -Copyright (C) 2022-2024 ApeCloud Co., Ltd - -This file is part of KubeBlocks project - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU Affero General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU Affero General Public License for more details. - -You should have received a copy of the GNU Affero General Public License -along with this program. If not, see . -*/ - -package migration - -import ( - "github.com/spf13/cobra" - "k8s.io/cli-runtime/pkg/genericiooptions" - cmdutil "k8s.io/kubectl/pkg/cmd/util" - "k8s.io/kubectl/pkg/util/templates" -) - -// NewMigrationCmd creates the cluster command -func NewMigrationCmd(f cmdutil.Factory, streams genericiooptions.IOStreams) *cobra.Command { - cmd := &cobra.Command{ - Use: "migration", - Short: "Data migration between two data sources.", - } - - groups := templates.CommandGroups{ - { - Message: "Basic Migration Commands:", - Commands: []*cobra.Command{ - NewMigrationCreateCmd(f, streams), - NewMigrationTemplatesCmd(f, streams), - NewMigrationListCmd(f, streams), - NewMigrationTerminateCmd(f, streams), - }, - }, - { - Message: "Migration Operation Commands:", - Commands: []*cobra.Command{ - NewMigrationDescribeCmd(f, streams), - NewMigrationLogsCmd(f, streams), - }, - }, - } - - // add subcommands - groups.Add(cmd) - templates.ActsAsRootCommand(cmd, nil, groups...) - - return cmd -} diff --git a/pkg/cmd/migration/cmd_builder_test.go b/pkg/cmd/migration/cmd_builder_test.go deleted file mode 100644 index ccb35767d..000000000 --- a/pkg/cmd/migration/cmd_builder_test.go +++ /dev/null @@ -1,41 +0,0 @@ -/* -Copyright (C) 2022-2024 ApeCloud Co., Ltd - -This file is part of KubeBlocks project - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU Affero General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU Affero General Public License for more details. - -You should have received a copy of the GNU Affero General Public License -along with this program. If not, see . -*/ - -package migration - -import ( - . "github.com/onsi/ginkgo/v2" - . "github.com/onsi/gomega" - - "k8s.io/cli-runtime/pkg/genericiooptions" - cmdtesting "k8s.io/kubectl/pkg/cmd/testing" -) - -var _ = Describe("cmd_builder", func() { - var ( - streams genericiooptions.IOStreams - tf *cmdtesting.TestFactory - ) - - It("command build", func() { - cmd := NewMigrationCmd(tf, streams) - Expect(cmd).ShouldNot(BeNil()) - }) - -}) diff --git a/pkg/cmd/migration/create.go b/pkg/cmd/migration/create.go deleted file mode 100644 index 11ed84a6b..000000000 --- a/pkg/cmd/migration/create.go +++ /dev/null @@ -1,293 +0,0 @@ -/* -Copyright (C) 2022-2024 ApeCloud Co., Ltd - -This file is part of KubeBlocks project - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU Affero General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU Affero General Public License for more details. - -You should have received a copy of the GNU Affero General Public License -along with this program. If not, see . -*/ - -package migration - -import ( - "fmt" - "strings" - "time" - - "github.com/spf13/cobra" - v1 "k8s.io/api/core/v1" - "k8s.io/apimachinery/pkg/util/rand" - "k8s.io/cli-runtime/pkg/genericiooptions" - cmdutil "k8s.io/kubectl/pkg/cmd/util" - - "github.com/apecloud/kbcli/pkg/action" - "github.com/apecloud/kbcli/pkg/types" - migrationv1 "github.com/apecloud/kbcli/pkg/types/migrationapi" - "github.com/apecloud/kbcli/pkg/util" -) - -var ( - AllStepsArr = []string{ - migrationv1.CliStepGlobal.String(), - migrationv1.CliStepPreCheck.String(), - migrationv1.CliStepCdc.String(), - migrationv1.CliStepInitStruct.String(), - migrationv1.CliStepInitData.String(), - } -) - -const ( - StringBoolTrue = "true" - StringBoolFalse = "false" -) - -type CreateMigrationOptions struct { - Template string `json:"template"` - TaskType string `json:"taskType,omitempty"` - Source string `json:"source"` - SourceEndpointModel EndpointModel `json:"sourceEndpointModel,omitempty"` - Sink string `json:"sink"` - SinkEndpointModel EndpointModel `json:"sinkEndpointModel,omitempty"` - MigrationObject []string `json:"migrationObject"` - MigrationObjectModel MigrationObjectModel `json:"migrationObjectModel,omitempty"` - Steps []string `json:"steps,omitempty"` - StepsModel []string `json:"stepsModel,omitempty"` - Tolerations []string `json:"tolerations,omitempty"` - TolerationModel map[string][]interface{} `json:"tolerationModel,omitempty"` - Resources []string `json:"resources,omitempty"` - ResourceModel map[string]interface{} `json:"resourceModel,omitempty"` - ServerID uint32 `json:"serverId,omitempty"` - action.CreateOptions `json:"-"` -} - -func NewMigrationCreateCmd(f cmdutil.Factory, streams genericiooptions.IOStreams) *cobra.Command { - o := &CreateMigrationOptions{ - CreateOptions: action.CreateOptions{ - Factory: f, - IOStreams: streams, - CueTemplateName: "migration_template.cue", - GVR: types.MigrationTaskGVR(), - }} - o.CreateOptions.Options = o - - cmd := &cobra.Command{ - Use: "create NAME", - Short: "Create a migration task.", - Example: CreateTemplate, - ValidArgsFunction: util.ResourceNameCompletionFunc(f, types.MigrationTaskGVR()), - Run: func(cmd *cobra.Command, args []string) { - o.Args = args - cmdutil.CheckErr(o.Complete()) - cmdutil.CheckErr(o.Validate()) - cmdutil.CheckErr(o.Run()) - }, - } - - cmd.Flags().StringVar(&o.Template, "template", "", "Specify migration template, run \"kbcli migration templates\" to show all available migration templates") - cmd.Flags().StringVar(&o.Source, "source", "", "Set the source database information for migration.such as '{username}:{password}@{connection_address}:{connection_port}/[{database}]'") - cmd.Flags().StringVar(&o.Sink, "sink", "", "Set the sink database information for migration.such as '{username}:{password}@{connection_address}:{connection_port}/[{database}]") - cmd.Flags().StringSliceVar(&o.MigrationObject, "migration-object", []string{}, "Set the data objects that need to be migrated,such as '\"db1.table1\",\"db2\"'") - cmd.Flags().StringSliceVar(&o.Steps, "steps", []string{}, "Set up migration steps,such as: precheck=true,init-struct=true,init-data=true,cdc=true") - cmd.Flags().StringSliceVar(&o.Tolerations, "tolerations", []string{}, "Tolerations for migration, such as '\"key=engineType,value=pg,operator=Equal,effect=NoSchedule\"'") - cmd.Flags().StringSliceVar(&o.Resources, "resources", []string{}, "Resources limit for migration, such as '\"cpu=3000m,memory=3Gi\"'") - - util.CheckErr(cmd.MarkFlagRequired("template")) - util.CheckErr(cmd.MarkFlagRequired("source")) - util.CheckErr(cmd.MarkFlagRequired("sink")) - util.CheckErr(cmd.MarkFlagRequired("migration-object")) - return cmd -} - -func (o *CreateMigrationOptions) Validate() error { - var err error - - if _, err = IsMigrationCrdValidWithDynamic(&o.Dynamic); err != nil { - PrintCrdInvalidError(err) - } - - if o.Template == "" { - return fmt.Errorf("migration template is needed, use \"kbcli migration templates\" to check and special one") - } - - errMsgArr := make([]string, 0) - // Source - o.SourceEndpointModel = EndpointModel{} - if err = o.SourceEndpointModel.BuildFromStr(&errMsgArr, o.Source); err != nil { - return err - } - // Sink - o.SinkEndpointModel = EndpointModel{} - if err = o.SinkEndpointModel.BuildFromStr(&errMsgArr, o.Sink); err != nil { - return err - } - - // MigrationObject - if err = o.MigrationObjectModel.BuildFromStrs(&errMsgArr, o.MigrationObject); err != nil { - return err - } - - // Steps & taskType - if err = o.BuildWithSteps(&errMsgArr); err != nil { - return err - } - - // Tolerations - if err = o.BuildWithTolerations(); err != nil { - return err - } - - // Resources - if err = o.BuildWithResources(); err != nil { - return err - } - - // RuntimeParams - if err = o.BuildWithRuntimeParams(); err != nil { - return err - } - - // Log errors if necessary - if len(errMsgArr) > 0 { - return fmt.Errorf(strings.Join(errMsgArr, ";\n")) - } - return nil -} - -func (o *CreateMigrationOptions) BuildWithSteps(errMsgArr *[]string) error { - taskType := InitializationAndCdc.String() - validStepMap, validStepKey := CliStepChangeToStructure() - enableCdc, enablePreCheck, enableInitStruct, enableInitData := StringBoolTrue, StringBoolTrue, StringBoolTrue, StringBoolTrue - if len(o.Steps) > 0 { - for _, step := range o.Steps { - stepArr := strings.Split(step, "=") - if len(stepArr) != 2 { - BuildErrorMsg(errMsgArr, fmt.Sprintf("[%s] in steps setting is invalid", step)) - return nil - } - stepName := strings.ToLower(strings.TrimSpace(stepArr[0])) - enable := strings.ToLower(strings.TrimSpace(stepArr[1])) - if validStepMap[stepName] == "" { - BuildErrorMsg(errMsgArr, fmt.Sprintf("[%s] in steps settings is invalid, the name should be one of: (%s)", step, validStepKey)) - return nil - } - if enable != StringBoolTrue && enable != StringBoolFalse { - BuildErrorMsg(errMsgArr, fmt.Sprintf("[%s] in steps settings is invalid, the value should be one of: (true false)", step)) - return nil - } - switch stepName { - case migrationv1.CliStepCdc.String(): - enableCdc = enable - case migrationv1.CliStepPreCheck.String(): - enablePreCheck = enable - case migrationv1.CliStepInitStruct.String(): - enableInitStruct = enable - case migrationv1.CliStepInitData.String(): - enableInitData = enable - } - } - - if enableInitData != StringBoolTrue { - BuildErrorMsg(errMsgArr, "step init-data is needed") - return nil - } - if enableCdc == StringBoolTrue { - taskType = InitializationAndCdc.String() - } else { - taskType = Initialization.String() - } - } - o.TaskType = taskType - o.StepsModel = []string{} - if enablePreCheck == StringBoolTrue { - o.StepsModel = append(o.StepsModel, migrationv1.StepPreCheck.String()) - } - if enableInitStruct == StringBoolTrue { - o.StepsModel = append(o.StepsModel, migrationv1.StepStructPreFullLoad.String()) - } - if enableInitData == StringBoolTrue { - o.StepsModel = append(o.StepsModel, migrationv1.StepFullLoad.String()) - } - return nil -} - -func (o *CreateMigrationOptions) BuildWithTolerations() error { - o.TolerationModel = o.buildTolerationOrResources(o.Tolerations) - tmp := make([]interface{}, 0) - for _, step := range AllStepsArr { - if o.TolerationModel[step] == nil { - o.TolerationModel[step] = tmp - } - } - return nil -} - -func (o *CreateMigrationOptions) BuildWithResources() error { - o.ResourceModel = make(map[string]interface{}) - for k, v := range o.buildTolerationOrResources(o.Resources) { - if len(v) >= 1 { - o.ResourceModel[k] = v[0] - } - } - for _, step := range AllStepsArr { - if o.ResourceModel[step] == nil { - o.ResourceModel[step] = v1.ResourceList{} - } - } - return nil -} - -func (o *CreateMigrationOptions) BuildWithRuntimeParams() error { - template := migrationv1.MigrationTemplate{} - templateGvr := types.MigrationTemplateGVR() - if err := APIResource(&o.CreateOptions.Dynamic, &templateGvr, o.Template, "", &template); err != nil { - return err - } - - // Generate random serverId for MySQL type database. Possible values are between 10001 and 2^32-10001 - if template.Spec.Source.DBType == migrationv1.MigrationDBTypeMySQL { - o.ServerID = o.generateRandomMySQLServerID() - } else { - o.ServerID = 10001 - } - - return nil -} - -func (o *CreateMigrationOptions) buildTolerationOrResources(raws []string) map[string][]interface{} { - results := make(map[string][]interface{}) - for _, raw := range raws { - step := migrationv1.CliStepGlobal.String() - tmpMap := map[string]interface{}{} - rawLoop: - for _, entries := range strings.Split(raw, ",") { - parts := strings.SplitN(entries, "=", 2) - k := strings.TrimSpace(parts[0]) - v := strings.TrimSpace(parts[1]) - if k == "step" { - switch v { - case migrationv1.CliStepPreCheck.String(), migrationv1.CliStepCdc.String(), migrationv1.CliStepInitStruct.String(), migrationv1.CliStepInitData.String(): - step = v - } - continue rawLoop - } - tmpMap[k] = v - } - results[step] = append(results[step], tmpMap) - } - return results -} - -func (o *CreateMigrationOptions) generateRandomMySQLServerID() uint32 { - rand.Seed(time.Now().UnixNano()) - return uint32(rand.Int63nRange(10001, 1<<32-10001)) -} diff --git a/pkg/cmd/migration/create_test.go b/pkg/cmd/migration/create_test.go deleted file mode 100644 index e4cbfc7dc..000000000 --- a/pkg/cmd/migration/create_test.go +++ /dev/null @@ -1,183 +0,0 @@ -/* -Copyright (C) 2022-2024 ApeCloud Co., Ltd - -This file is part of KubeBlocks project - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU Affero General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU Affero General Public License for more details. - -You should have received a copy of the GNU Affero General Public License -along with this program. If not, see . -*/ - -package migration - -import ( - "bytes" - - . "github.com/onsi/ginkgo/v2" - . "github.com/onsi/gomega" - - "k8s.io/cli-runtime/pkg/genericiooptions" - "k8s.io/client-go/kubernetes/scheme" - cmdTest "k8s.io/kubectl/pkg/cmd/testing" - - app "github.com/apecloud/kubeblocks/apis/apps/v1alpha1" - - "github.com/apecloud/kbcli/pkg/testing" - v1alpha1 "github.com/apecloud/kbcli/pkg/types/migrationapi" -) - -var ( - streams genericiooptions.IOStreams - out *bytes.Buffer - tf *cmdTest.TestFactory -) - -const ( - namespace = "test" -) - -var _ = Describe("create", func() { - o := &CreateMigrationOptions{} - - BeforeEach(func() { - streams, _, out, _ = genericiooptions.NewTestIOStreams() - tf = testing.NewTestFactory(namespace) - - _ = app.AddToScheme(scheme.Scheme) - - tf.Client = tf.UnstructuredClient - }) - - Context("Input params validate", func() { - var err error - errMsgArr := make([]string, 0, 3) - It("Endpoint with database", func() { - o.Source = "user:123456@127.0.0.1:5432/database" - err = o.SourceEndpointModel.BuildFromStr(&errMsgArr, o.Source) - Expect(err).ShouldNot(HaveOccurred()) - Expect(o.SourceEndpointModel.UserName).Should(Equal("user")) - Expect(o.SourceEndpointModel.Password).Should(Equal("123456")) - Expect(o.SourceEndpointModel.Address).Should(Equal("127.0.0.1:5432")) - Expect(o.SourceEndpointModel.Database).Should(Equal("database")) - Expect(len(errMsgArr)).Should(Equal(0)) - - o.Sink = "user:123456127.0.0.1:5432/database" - err = o.SinkEndpointModel.BuildFromStr(&errMsgArr, o.Sink) - Expect(err).ShouldNot(HaveOccurred()) - Expect(len(errMsgArr)).Should(Equal(1)) - }) - - It("Endpoint with no database", func() { - o.Source = "user:123456@127.0.0.1:3306" - errMsgArr := make([]string, 0, 3) - err = o.SourceEndpointModel.BuildFromStr(&errMsgArr, o.Source) - Expect(err).ShouldNot(HaveOccurred()) - Expect(o.SourceEndpointModel.UserName).Should(Equal("user")) - Expect(o.SourceEndpointModel.Password).Should(Equal("123456")) - Expect(o.SourceEndpointModel.Address).Should(Equal("127.0.0.1:3306")) - Expect(o.SourceEndpointModel.Database).Should(BeEmpty()) - Expect(len(errMsgArr)).Should(Equal(0)) - - o.Sink = "user:123456127.0.0.1:3306" - err = o.SinkEndpointModel.BuildFromStr(&errMsgArr, o.Sink) - Expect(err).ShouldNot(HaveOccurred()) - Expect(len(errMsgArr)).Should(Equal(1)) - }) - - It("MigrationObject", func() { - o.MigrationObject = []string{"schema_public.table1", "schema2.table2_1", "schema2.table2_2", "schema3"} - err = o.MigrationObjectModel.BuildFromStrs(&errMsgArr, o.MigrationObject) - Expect(err).ShouldNot(HaveOccurred()) - for _, obj := range o.MigrationObjectModel.WhiteList { - Expect(obj.SchemaName).Should(BeElementOf("schema_public", "schema2", "schema3")) - switch obj.SchemaName { - case "schema_public": - Expect(len(obj.TableList)).Should(Equal(1)) - Expect(obj.TableList[0].TableName).Should(Equal("table1")) - Expect(obj.TableList[0].IsAll).Should(BeTrue()) - case "schema2": - Expect(len(obj.TableList)).Should(Equal(2)) - for _, tb := range obj.TableList { - Expect(tb.TableName).Should(BeElementOf("table2_1", "table2_2")) - Expect(tb.IsAll).Should(BeTrue()) - } - case "schema3": - Expect(obj.IsAll).Should(BeTrue()) - } - } - }) - - It("Steps", func() { - o.Steps = make([]string, 0) - err = o.BuildWithSteps(&errMsgArr) - Expect(err).ShouldNot(HaveOccurred()) - Expect(o.TaskType).Should(Equal(InitializationAndCdc.String())) - Expect(o.StepsModel).Should(ContainElements(v1alpha1.StepPreCheck.String(), v1alpha1.StepStructPreFullLoad.String(), v1alpha1.StepFullLoad.String())) - o.Steps = []string{"precheck=true", "init-struct=false", "cdc=false"} - err = o.BuildWithSteps(&errMsgArr) - Expect(err).ShouldNot(HaveOccurred()) - Expect(o.TaskType).Should(Equal(Initialization.String())) - Expect(o.StepsModel).Should(ContainElements(v1alpha1.StepPreCheck.String(), v1alpha1.StepFullLoad.String())) - }) - - It("Tolerations", func() { - o.Tolerations = []string{ - "step=global,key=engineType,value=pg,operator=Equal,effect=NoSchedule", - "step=init-data,key=engineType,value=pg1,operator=Equal,effect=NoSchedule", - "key=engineType,value=pg2,operator=Equal,effect=NoSchedule", - } - err = o.BuildWithTolerations() - Expect(err).ShouldNot(HaveOccurred()) - Expect(o.TolerationModel[v1alpha1.CliStepGlobal.String()]).ShouldNot(BeEmpty()) - Expect(o.TolerationModel[v1alpha1.CliStepInitData.String()]).ShouldNot(BeEmpty()) - Expect(len(o.TolerationModel[v1alpha1.CliStepInitData.String()])).Should(Equal(1)) - Expect(len(o.TolerationModel[v1alpha1.CliStepGlobal.String()])).Should(Equal(2)) - Expect(len(o.TolerationModel[v1alpha1.CliStepPreCheck.String()])).Should(Equal(0)) - }) - - It("Resources", func() { - o.Resources = []string{ - "step=global,cpu=1000m,memory=1Gi", - "step=init-data,cpu=2000m,memory=2Gi", - "cpu=3000m,memory=3Gi", - } - err = o.BuildWithResources() - Expect(err).ShouldNot(HaveOccurred()) - Expect(o.ResourceModel[v1alpha1.CliStepGlobal.String()]).ShouldNot(BeEmpty()) - Expect(o.ResourceModel[v1alpha1.CliStepInitData.String()]).ShouldNot(BeEmpty()) - Expect(o.ResourceModel[v1alpha1.CliStepPreCheck.String()]).Should(BeEmpty()) - }) - - It("RuntimeParams", func() { - type void struct{} - var setValue void - serverIDSet := make(map[uint32]void) - - loopCount := 0 - for loopCount < 1000 { - newServerID := o.generateRandomMySQLServerID() - Expect(newServerID >= 10001 && newServerID <= 1<<32-10001).Should(BeTrue()) - serverIDSet[newServerID] = setValue - - loopCount += 1 - } - Expect(len(serverIDSet) > 500).Should(BeTrue()) - }) - }) - - Context("Mock run", func() { - It("test", func() { - cmd := NewMigrationCreateCmd(tf, streams) - Expect(cmd).ShouldNot(BeNil()) - }) - }) -}) diff --git a/pkg/cmd/migration/describe.go b/pkg/cmd/migration/describe.go deleted file mode 100644 index 2fabd732f..000000000 --- a/pkg/cmd/migration/describe.go +++ /dev/null @@ -1,304 +0,0 @@ -/* -Copyright (C) 2022-2024 ApeCloud Co., Ltd - -This file is part of KubeBlocks project - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU Affero General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU Affero General Public License for more details. - -You should have received a copy of the GNU Affero General Public License -along with this program. If not, see . -*/ - -package migration - -import ( - "context" - "fmt" - "io" - "sort" - "strconv" - "strings" - "time" - - "github.com/spf13/cobra" - appv1 "k8s.io/api/apps/v1" - batchv1 "k8s.io/api/batch/v1" - v1 "k8s.io/api/core/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/runtime/schema" - "k8s.io/cli-runtime/pkg/genericiooptions" - "k8s.io/client-go/dynamic" - clientset "k8s.io/client-go/kubernetes" - cmdutil "k8s.io/kubectl/pkg/cmd/util" - - "github.com/apecloud/kbcli/pkg/printer" - "github.com/apecloud/kbcli/pkg/types" - v1alpha1 "github.com/apecloud/kbcli/pkg/types/migrationapi" - "github.com/apecloud/kbcli/pkg/util" -) - -var ( - newTbl = func(out io.Writer, title string, header ...interface{}) *printer.TablePrinter { - fmt.Fprintln(out, title) - tbl := printer.NewTablePrinter(out) - tbl.SetHeader(header...) - return tbl - } -) - -type describeOptions struct { - factory cmdutil.Factory - client clientset.Interface - dynamic dynamic.Interface - namespace string - - // resource type and names - gvr schema.GroupVersionResource - names []string - - *v1alpha1.MigrationObjects - genericiooptions.IOStreams -} - -func newOptions(f cmdutil.Factory, streams genericiooptions.IOStreams) *describeOptions { - return &describeOptions{ - factory: f, - IOStreams: streams, - gvr: types.MigrationTaskGVR(), - } -} - -func NewMigrationDescribeCmd(f cmdutil.Factory, streams genericiooptions.IOStreams) *cobra.Command { - o := newOptions(f, streams) - cmd := &cobra.Command{ - Use: "describe NAME", - Short: "Show details of a specific migration task.", - Example: DescribeExample, - ValidArgsFunction: util.ResourceNameCompletionFunc(f, types.MigrationTaskGVR()), - Run: func(cmd *cobra.Command, args []string) { - util.CheckErr(o.complete(args)) - util.CheckErr(o.run()) - }, - } - return cmd -} - -func (o *describeOptions) complete(args []string) error { - var err error - - if o.client, err = o.factory.KubernetesClientSet(); err != nil { - return err - } - - if o.dynamic, err = o.factory.DynamicClient(); err != nil { - return err - } - - if o.namespace, _, err = o.factory.ToRawKubeConfigLoader().Namespace(); err != nil { - return err - } - - if _, err = IsMigrationCrdValidWithDynamic(&o.dynamic); err != nil { - PrintCrdInvalidError(err) - } - - if len(args) == 0 { - return fmt.Errorf("migration task name should be specified") - } - o.names = args - return nil -} - -func (o *describeOptions) run() error { - for _, name := range o.names { - if err := o.describeMigration(name); err != nil { - return err - } - } - return nil -} - -func (o *describeOptions) describeMigration(name string) error { - var err error - if o.MigrationObjects, err = getMigrationObjects(o, name); err != nil { - return err - } - - // MigrationTask Summary - showTaskSummary(o.Task, o.Out) - - // MigrationTask Config - showTaskConfig(o.Task, o.Out) - - // MigrationTemplate Summary - showTemplateSummary(o.Template, o.Out) - - // Initialization Detail - showInitialization(o.Task, o.Template, o.Jobs, o.Out) - - switch o.Task.Spec.TaskType { - case v1alpha1.InitializationAndCdc, v1alpha1.CDC: - // Cdc Detail - showCdc(o.StatefulSets, o.Pods, o.Out) - - // Cdc Metrics - showCdcMetrics(o.Task, o.Out) - } - - fmt.Fprintln(o.Out) - - return nil -} - -func getMigrationObjects(o *describeOptions, taskName string) (*v1alpha1.MigrationObjects, error) { - obj := &v1alpha1.MigrationObjects{ - Task: &v1alpha1.MigrationTask{}, - Template: &v1alpha1.MigrationTemplate{}, - } - var err error - taskGvr := types.MigrationTaskGVR() - if err = APIResource(&o.dynamic, &taskGvr, taskName, o.namespace, obj.Task); err != nil { - return nil, err - } - templateGvr := types.MigrationTemplateGVR() - if err = APIResource(&o.dynamic, &templateGvr, obj.Task.Spec.Template, "", obj.Template); err != nil { - return nil, err - } - listOpts := func() metav1.ListOptions { - return metav1.ListOptions{ - LabelSelector: fmt.Sprintf("%s=%s", MigrationTaskLabel, taskName), - } - } - if obj.Jobs, err = o.client.BatchV1().Jobs(o.namespace).List(context.Background(), listOpts()); err != nil { - return nil, err - } - if obj.Pods, err = o.client.CoreV1().Pods(o.namespace).List(context.Background(), listOpts()); err != nil { - return nil, err - } - if obj.StatefulSets, err = o.client.AppsV1().StatefulSets(o.namespace).List(context.Background(), listOpts()); err != nil { - return nil, err - } - return obj, nil -} - -func showTaskSummary(task *v1alpha1.MigrationTask, out io.Writer) { - if task == nil { - return - } - title := fmt.Sprintf("Name: %s\t Status: %s", task.Name, task.Status.TaskStatus) - tbl := newTbl(out, title, "NAMESPACE", "CREATED-TIME", "START-TIME", "FINISHED-TIME") - tbl.AddRow(task.Namespace, util.TimeFormatWithDuration(&task.CreationTimestamp, time.Second), util.TimeFormatWithDuration(task.Status.StartTime, time.Second), util.TimeFormatWithDuration(task.Status.FinishTime, time.Second)) - tbl.Print() -} - -func showTaskConfig(task *v1alpha1.MigrationTask, out io.Writer) { - if task == nil { - return - } - tbl := newTbl(out, "\nMigration Config:") - tbl.AddRow("source", fmt.Sprintf("%s:%s@%s/%s", - task.Spec.SourceEndpoint.UserName, - task.Spec.SourceEndpoint.Password, - task.Spec.SourceEndpoint.Address, - task.Spec.SourceEndpoint.DatabaseName, - )) - tbl.AddRow("sink", fmt.Sprintf("%s:%s@%s/%s", - task.Spec.SinkEndpoint.UserName, - task.Spec.SinkEndpoint.Password, - task.Spec.SinkEndpoint.Address, - task.Spec.SinkEndpoint.DatabaseName, - )) - tbl.AddRow("migration objects", task.Spec.MigrationObj.String(true)) - tbl.Print() -} - -func showTemplateSummary(template *v1alpha1.MigrationTemplate, out io.Writer) { - if template == nil { - return - } - title := fmt.Sprintf("\nTemplate: %s\t", template.Name) - tbl := newTbl(out, title, "DATABASE-MAPPING", "STATUS") - tbl.AddRow(template.Spec.Description, template.Status.Phase) - tbl.Print() -} - -func showInitialization(task *v1alpha1.MigrationTask, template *v1alpha1.MigrationTemplate, jobList *batchv1.JobList, out io.Writer) { - if len(jobList.Items) == 0 { - return - } - sort.SliceStable(jobList.Items, func(i, j int) bool { - jobName1 := jobList.Items[i].Name - jobName2 := jobList.Items[j].Name - order1, _ := strconv.ParseInt(string([]byte(jobName1)[strings.LastIndex(jobName1, "-")+1:]), 10, 8) - order2, _ := strconv.ParseInt(string([]byte(jobName2)[strings.LastIndex(jobName2, "-")+1:]), 10, 8) - return order1 < order2 - }) - cliStepOrder := BuildInitializationStepsOrder(task, template) - tbl := newTbl(out, "\nInitialization:", "STEP", "NAMESPACE", "STATUS", "CREATED_TIME", "START-TIME", "FINISHED-TIME") - if len(cliStepOrder) != len(jobList.Items) { - return - } - for i, job := range jobList.Items { - tbl.AddRow(cliStepOrder[i], job.Namespace, getJobStatus(job.Status.Conditions), util.TimeFormatWithDuration(&job.CreationTimestamp, time.Second), util.TimeFormatWithDuration(job.Status.StartTime, time.Second), util.TimeFormatWithDuration(job.Status.CompletionTime, time.Second)) - } - tbl.Print() -} - -func showCdc(statefulSets *appv1.StatefulSetList, pods *v1.PodList, out io.Writer) { - if len(pods.Items) == 0 || len(statefulSets.Items) == 0 { - return - } - tbl := newTbl(out, "\nCdc:", "NAMESPACE", "STATUS", "CREATED_TIME", "START-TIME") - for _, pod := range pods.Items { - if pod.Annotations[MigrationTaskStepAnnotation] != v1alpha1.StepCdc.String() { - continue - } - tbl.AddRow(pod.Namespace, getCdcStatus(&statefulSets.Items[0], &pod), util.TimeFormatWithDuration(&pod.CreationTimestamp, time.Second), util.TimeFormatWithDuration(pod.Status.StartTime, time.Second)) - } - tbl.Print() -} - -func showCdcMetrics(task *v1alpha1.MigrationTask, out io.Writer) { - if task.Status.Cdc.Metrics == nil || len(task.Status.Cdc.Metrics) == 0 { - return - } - arr := make([]string, 0) - for mKey := range task.Status.Cdc.Metrics { - arr = append(arr, mKey) - } - sort.Strings(arr) - tbl := newTbl(out, "\nCdc Metrics:") - for _, k := range arr { - tbl.AddRow(k, task.Status.Cdc.Metrics[k]) - } - tbl.Print() -} - -func getJobStatus(conditions []batchv1.JobCondition) string { - if len(conditions) == 0 { - return "-" - } else { - return string(conditions[len(conditions)-1].Type) - } -} - -func getCdcStatus(statefulSet *appv1.StatefulSet, cdcPod *v1.Pod) v1.PodPhase { - if cdcPod.Status.Phase == v1.PodRunning && - statefulSet.Status.Replicas > statefulSet.Status.AvailableReplicas { - if time.Now().Unix()-statefulSet.CreationTimestamp.Time.Unix() < 10*60 { - return v1.PodPending - } else { - return v1.PodFailed - } - } else { - return cdcPod.Status.Phase - } -} diff --git a/pkg/cmd/migration/describe_test.go b/pkg/cmd/migration/describe_test.go deleted file mode 100644 index a92299af7..000000000 --- a/pkg/cmd/migration/describe_test.go +++ /dev/null @@ -1,79 +0,0 @@ -/* -Copyright (C) 2022-2024 ApeCloud Co., Ltd - -This file is part of KubeBlocks project - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU Affero General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU Affero General Public License for more details. - -You should have received a copy of the GNU Affero General Public License -along with this program. If not, see . -*/ - -package migration - -import ( - "time" - - . "github.com/onsi/ginkgo/v2" - . "github.com/onsi/gomega" - - appv1 "k8s.io/api/apps/v1" - corev1 "k8s.io/api/core/v1" - v1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/cli-runtime/pkg/genericiooptions" - cmdtesting "k8s.io/kubectl/pkg/cmd/testing" -) - -var _ = Describe("describe", func() { - - var ( - streams genericiooptions.IOStreams - tf *cmdtesting.TestFactory - ) - - It("command build", func() { - cmd := NewMigrationDescribeCmd(tf, streams) - Expect(cmd).ShouldNot(BeNil()) - }) - - It("func test", func() { - sts := appv1.StatefulSet{ - Status: appv1.StatefulSetStatus{ - Replicas: 1, - }, - } - pod := corev1.Pod{} - - sts.Status.AvailableReplicas = 0 - pod.Status.Phase = corev1.PodFailed - Expect(getCdcStatus(&sts, &pod)).Should(Equal(corev1.PodFailed)) - - sts.Status.AvailableReplicas = 1 - pod.Status.Phase = corev1.PodPending - Expect(getCdcStatus(&sts, &pod)).Should(Equal(corev1.PodPending)) - - sts.Status.AvailableReplicas = 1 - pod.Status.Phase = corev1.PodRunning - Expect(getCdcStatus(&sts, &pod)).Should(Equal(corev1.PodRunning)) - - sts.Status.AvailableReplicas = 0 - t1, _ := time.ParseDuration("-30m") - sts.CreationTimestamp = v1.NewTime(time.Now().Add(t1)) - pod.Status.Phase = corev1.PodRunning - Expect(getCdcStatus(&sts, &pod)).Should(Equal(corev1.PodFailed)) - - sts.Status.AvailableReplicas = 0 - sts.CreationTimestamp = v1.NewTime(time.Now()) - pod.Status.Phase = corev1.PodRunning - Expect(getCdcStatus(&sts, &pod)).Should(Equal(corev1.PodPending)) - }) - -}) diff --git a/pkg/cmd/migration/examples.go b/pkg/cmd/migration/examples.go deleted file mode 100644 index c7a6d1640..000000000 --- a/pkg/cmd/migration/examples.go +++ /dev/null @@ -1,107 +0,0 @@ -/* -Copyright (C) 2022-2024 ApeCloud Co., Ltd - -This file is part of KubeBlocks project - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU Affero General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU Affero General Public License for more details. - -You should have received a copy of the GNU Affero General Public License -along with this program. If not, see . -*/ - -package migration - -import "k8s.io/kubectl/pkg/util/templates" - -// Cli Migration Command Examples -var ( - CreateTemplate = templates.Examples(` - # Create a migration task to migrate the entire database under mysql: mydb1 and mytable1 under database: mydb2 to the target mysql - kbcli migration create mytask --template apecloud-mysql2mysql - --source user:123456@127.0.0.1:3306 - --sink user:123456@127.0.0.1:3305 - --migration-object '"mydb1","mydb2.mytable1"' - - # Create a migration task to migrate the schema: myschema under database: mydb1 under PostgreSQL to the target PostgreSQL - kbcli migration create mytask --template apecloud-pg2pg - --source user:123456@127.0.0.1:3306/mydb1 - --sink user:123456@127.0.0.1:3305/mydb1 - --migration-object '"myschema"' - - # Use prechecks, data initialization, CDC, but do not perform structure initialization - kbcli migration create mytask --template apecloud-pg2pg - --source user:123456@127.0.0.1:3306/mydb1 - --sink user:123456@127.0.0.1:3305/mydb1 - --migration-object '"myschema"' - --steps precheck=true,init-struct=false,init-data=true,cdc=true - - # Create a migration task with two tolerations - kbcli migration create mytask --template apecloud-pg2pg - --source user:123456@127.0.0.1:3306/mydb1 - --sink user:123456@127.0.0.1:3305/mydb1 - --migration-object '"myschema"' - --tolerations '"step=global,key=engineType,value=pg,operator=Equal,effect=NoSchedule","step=init-data,key=diskType,value=ssd,operator=Equal,effect=NoSchedule"' - - # Limit resource usage when performing data initialization - kbcli migration create mytask --template apecloud-pg2pg - --source user:123456@127.0.0.1:3306/mydb1 - --sink user:123456@127.0.0.1:3305/mydb1 - --migration-object '"myschema"' - --resources '"step=init-data,cpu=1000m,memory=1Gi"' - `) - DescribeExample = templates.Examples(` - # describe a specified migration task - kbcli migration describe mytask - `) - ListExample = templates.Examples(` - # list all migration tasks - kbcli migration list - - # list a single migration task with specified NAME - kbcli migration list mytask - - # list a single migration task in YAML output format - kbcli migration list mytask -o yaml - - # list a single migration task in JSON output format - kbcli migration list mytask -o json - - # list a single migration task in wide output format - kbcli migration list mytask -o wide - `) - TemplateExample = templates.Examples(` - # list all migration templates - kbcli migration templates - - # list a single migration template with specified NAME - kbcli migration templates mytemplate - - # list a single migration template in YAML output format - kbcli migration templates mytemplate -o yaml - - # list a single migration template in JSON output format - kbcli migration templates mytemplate -o json - - # list a single migration template in wide output format - kbcli migration templates mytemplate -o wide - `) - DeleteExample = templates.Examples(` - # terminate a migration task named mytask and delete resources in k8s without affecting source and target data in database - kbcli migration terminate mytask - `) - LogsExample = templates.Examples(` - # Logs when returning to the "init-struct" step from the migration task mytask - kbcli migration logs mytask --step init-struct - - # Logs only the most recent 20 lines when returning to the "cdc" step from the migration task mytask - kbcli migration logs mytask --step cdc --tail=20 - `) -) diff --git a/pkg/cmd/migration/list.go b/pkg/cmd/migration/list.go deleted file mode 100644 index b85fcb37f..000000000 --- a/pkg/cmd/migration/list.go +++ /dev/null @@ -1,50 +0,0 @@ -/* -Copyright (C) 2022-2024 ApeCloud Co., Ltd - -This file is part of KubeBlocks project - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU Affero General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU Affero General Public License for more details. - -You should have received a copy of the GNU Affero General Public License -along with this program. If not, see . -*/ - -package migration - -import ( - "github.com/spf13/cobra" - "k8s.io/cli-runtime/pkg/genericiooptions" - cmdutil "k8s.io/kubectl/pkg/cmd/util" - - "github.com/apecloud/kbcli/pkg/action" - "github.com/apecloud/kbcli/pkg/types" - "github.com/apecloud/kbcli/pkg/util" -) - -func NewMigrationListCmd(f cmdutil.Factory, streams genericiooptions.IOStreams) *cobra.Command { - o := action.NewListOptions(f, streams, types.MigrationTaskGVR()) - cmd := &cobra.Command{ - Use: "list [NAME]", - Short: "List migration tasks.", - Example: ListExample, - Aliases: []string{"ls"}, - ValidArgsFunction: util.ResourceNameCompletionFunc(f, o.GVR), - Run: func(cmd *cobra.Command, args []string) { - _, validErr := IsMigrationCrdValidWithFactory(o.Factory) - PrintCrdInvalidError(validErr) - o.Names = args - _, err := o.Run() - util.CheckErr(err) - }, - } - o.AddFlags(cmd) - return cmd -} diff --git a/pkg/cmd/migration/list_test.go b/pkg/cmd/migration/list_test.go deleted file mode 100644 index 343251213..000000000 --- a/pkg/cmd/migration/list_test.go +++ /dev/null @@ -1,42 +0,0 @@ -/* -Copyright (C) 2022-2024 ApeCloud Co., Ltd - -This file is part of KubeBlocks project - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU Affero General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU Affero General Public License for more details. - -You should have received a copy of the GNU Affero General Public License -along with this program. If not, see . -*/ - -package migration - -import ( - . "github.com/onsi/ginkgo/v2" - . "github.com/onsi/gomega" - - "k8s.io/cli-runtime/pkg/genericiooptions" - cmdtesting "k8s.io/kubectl/pkg/cmd/testing" -) - -var _ = Describe("list", func() { - - var ( - streams genericiooptions.IOStreams - tf *cmdtesting.TestFactory - ) - - It("command build", func() { - cmd := NewMigrationListCmd(tf, streams) - Expect(cmd).ShouldNot(BeNil()) - }) - -}) diff --git a/pkg/cmd/migration/logs.go b/pkg/cmd/migration/logs.go deleted file mode 100644 index 143f37aa8..000000000 --- a/pkg/cmd/migration/logs.go +++ /dev/null @@ -1,228 +0,0 @@ -/* -Copyright (C) 2022-2024 ApeCloud Co., Ltd - -This file is part of KubeBlocks project - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU Affero General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU Affero General Public License for more details. - -You should have received a copy of the GNU Affero General Public License -along with this program. If not, see . -*/ - -package migration - -import ( - "context" - "fmt" - "strconv" - "strings" - "time" - - "github.com/spf13/cobra" - corev1 "k8s.io/api/core/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/cli-runtime/pkg/genericiooptions" - "k8s.io/client-go/dynamic" - "k8s.io/client-go/kubernetes" - cmdlogs "k8s.io/kubectl/pkg/cmd/logs" - cmdutil "k8s.io/kubectl/pkg/cmd/util" - "k8s.io/kubectl/pkg/polymorphichelpers" - - "github.com/apecloud/kbcli/pkg/action" - "github.com/apecloud/kbcli/pkg/types" - migrationv1 "github.com/apecloud/kbcli/pkg/types/migrationapi" - "github.com/apecloud/kbcli/pkg/util" -) - -type LogsOptions struct { - taskName string - step string - Client *kubernetes.Clientset - Dynamic dynamic.Interface - *action.ExecOptions - logOptions cmdlogs.LogsOptions -} - -func NewMigrationLogsCmd(f cmdutil.Factory, streams genericiooptions.IOStreams) *cobra.Command { - l := &LogsOptions{ - ExecOptions: action.NewExecOptions(f, streams), - logOptions: cmdlogs.LogsOptions{ - Tail: -1, - IOStreams: streams, - }, - } - cmd := &cobra.Command{ - Use: "logs NAME", - Short: "Access migration task log file.", - Example: LogsExample, - ValidArgsFunction: util.ResourceNameCompletionFunc(f, types.MigrationTaskGVR()), - Run: func(cmd *cobra.Command, args []string) { - util.CheckErr(l.ExecOptions.Complete()) - util.CheckErr(l.complete(f, cmd, args)) - util.CheckErr(l.validate()) - util.CheckErr(l.runLogs()) - }, - } - l.addFlags(cmd) - return cmd -} - -func (o *LogsOptions) addFlags(cmd *cobra.Command) { - cmd.Flags().StringVar(&o.step, "step", "", "Specify the step. Allow values: precheck,init-struct,init-data,cdc") - - o.logOptions.AddFlags(cmd) -} - -// complete customs complete function for logs -func (o *LogsOptions) complete(f cmdutil.Factory, cmd *cobra.Command, args []string) error { - if len(args) == 0 { - return fmt.Errorf("migration task name should be specified") - } - if len(args) > 0 { - o.taskName = args[0] - } - if o.step == "" { - return fmt.Errorf("migration task step should be specified") - } - var err error - o.logOptions.Namespace, _, err = f.ToRawKubeConfigLoader().Namespace() - if err != nil { - return err - } - - o.Dynamic, err = f.DynamicClient() - if err != nil { - return err - } - - o.Client, err = f.KubernetesClientSet() - if err != nil { - return err - } - - if _, err = IsMigrationCrdValidWithDynamic(&o.Dynamic); err != nil { - PrintCrdInvalidError(err) - } - - taskObj, err := o.getMigrationObjects(o.taskName) - if err != nil { - return fmt.Errorf("failed to find the migrationtask") - } - pod := o.getPodByStep(taskObj, strings.TrimSpace(o.step)) - if pod == nil { - return fmt.Errorf("migrationtask[%s] step[%s] 's pod not found", taskObj.Task.Name, o.step) - } - o.logOptions.RESTClientGetter = f - o.logOptions.LogsForObject = polymorphichelpers.LogsForObjectFn - o.logOptions.Object = pod - o.logOptions.Options, _ = o.logOptions.ToLogOptions() - o.Pod = pod - - return nil -} - -func (o *LogsOptions) validate() error { - if len(o.taskName) == 0 { - return fmt.Errorf("migration task name must be specified") - } - - if o.logOptions.LimitBytes < 0 { - return fmt.Errorf("--limit-bytes must be greater than 0") - } - if o.logOptions.Tail < -1 { - return fmt.Errorf("--tail must be greater than or equal to -1") - } - if len(o.logOptions.SinceTime) > 0 && o.logOptions.SinceSeconds != 0 { - return fmt.Errorf("at most one of `sinceTime` or `sinceSeconds` may be specified") - } - logsOptions, ok := o.logOptions.Options.(*corev1.PodLogOptions) - if !ok { - return fmt.Errorf("unexpected logs options object") - } - if logsOptions.SinceSeconds != nil && *logsOptions.SinceSeconds < int64(0) { - return fmt.Errorf("--since must be greater than 0") - } - if logsOptions.TailLines != nil && *logsOptions.TailLines < -1 { - return fmt.Errorf("--tail must be greater than or equal to -1") - } - return nil -} - -func (o *LogsOptions) getMigrationObjects(taskName string) (*migrationv1.MigrationObjects, error) { - obj := &migrationv1.MigrationObjects{ - Task: &migrationv1.MigrationTask{}, - Template: &migrationv1.MigrationTemplate{}, - } - var err error - taskGvr := types.MigrationTaskGVR() - if err = APIResource(&o.Dynamic, &taskGvr, taskName, o.logOptions.Namespace, obj.Task); err != nil { - return nil, err - } - templateGvr := types.MigrationTemplateGVR() - if err = APIResource(&o.Dynamic, &templateGvr, obj.Task.Spec.Template, "", obj.Template); err != nil { - return nil, err - } - listOpts := func() metav1.ListOptions { - return metav1.ListOptions{ - LabelSelector: fmt.Sprintf("%s=%s", MigrationTaskLabel, taskName), - } - } - if obj.Pods, err = o.Client.CoreV1().Pods(o.logOptions.Namespace).List(context.Background(), listOpts()); err != nil { - return nil, err - } - return obj, nil -} - -func (o *LogsOptions) runLogs() error { - requests, err := o.logOptions.LogsForObject(o.logOptions.RESTClientGetter, o.logOptions.Object, o.logOptions.Options, 60*time.Second, false) - if err != nil { - return err - } - for _, request := range requests { - if err := cmdlogs.DefaultConsumeRequest(request, o.Out); err != nil { - if !o.logOptions.IgnoreLogErrors { - return err - } - fmt.Fprintf(o.Out, "error: %v\n", err) - } - } - return nil -} - -func (o *LogsOptions) getPodByStep(taskObj *migrationv1.MigrationObjects, step string) *corev1.Pod { - if taskObj == nil || len(taskObj.Pods.Items) == 0 { - return nil - } - switch step { - case migrationv1.CliStepCdc.String(): - for _, pod := range taskObj.Pods.Items { - if pod.Annotations[MigrationTaskStepAnnotation] == migrationv1.StepCdc.String() { - return &pod - } - } - case migrationv1.CliStepPreCheck.String(), migrationv1.CliStepInitStruct.String(), migrationv1.CliStepInitData.String(): - stepArr := BuildInitializationStepsOrder(taskObj.Task, taskObj.Template) - orderNo := "-1" - for index, stepByTemplate := range stepArr { - if step == stepByTemplate { - orderNo = strconv.Itoa(index) - break - } - } - for _, pod := range taskObj.Pods.Items { - if pod.Annotations[SerialJobOrderAnnotation] != "" && - pod.Annotations[SerialJobOrderAnnotation] == orderNo { - return &pod - } - } - } - return nil -} diff --git a/pkg/cmd/migration/logs_test.go b/pkg/cmd/migration/logs_test.go deleted file mode 100644 index a0c2502fa..000000000 --- a/pkg/cmd/migration/logs_test.go +++ /dev/null @@ -1,42 +0,0 @@ -/* -Copyright (C) 2022-2024 ApeCloud Co., Ltd - -This file is part of KubeBlocks project - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU Affero General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU Affero General Public License for more details. - -You should have received a copy of the GNU Affero General Public License -along with this program. If not, see . -*/ - -package migration - -import ( - . "github.com/onsi/ginkgo/v2" - . "github.com/onsi/gomega" - - "k8s.io/cli-runtime/pkg/genericiooptions" - cmdtesting "k8s.io/kubectl/pkg/cmd/testing" -) - -var _ = Describe("logs", func() { - - var ( - streams genericiooptions.IOStreams - tf *cmdtesting.TestFactory - ) - - It("command build", func() { - cmd := NewMigrationLogsCmd(tf, streams) - Expect(cmd).ShouldNot(BeNil()) - }) - -}) diff --git a/pkg/cmd/migration/suite_test.go b/pkg/cmd/migration/suite_test.go deleted file mode 100644 index b63674016..000000000 --- a/pkg/cmd/migration/suite_test.go +++ /dev/null @@ -1,32 +0,0 @@ -/* -Copyright (C) 2022-2024 ApeCloud Co., Ltd - -This file is part of KubeBlocks project - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU Affero General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU Affero General Public License for more details. - -You should have received a copy of the GNU Affero General Public License -along with this program. If not, see . -*/ - -package migration_test - -import ( - "testing" - - . "github.com/onsi/ginkgo/v2" - . "github.com/onsi/gomega" -) - -func TestMigration(t *testing.T) { - RegisterFailHandler(Fail) - RunSpecs(t, "Migration Suite") -} diff --git a/pkg/cmd/migration/templates.go b/pkg/cmd/migration/templates.go deleted file mode 100644 index 7b41a0762..000000000 --- a/pkg/cmd/migration/templates.go +++ /dev/null @@ -1,50 +0,0 @@ -/* -Copyright (C) 2022-2024 ApeCloud Co., Ltd - -This file is part of KubeBlocks project - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU Affero General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU Affero General Public License for more details. - -You should have received a copy of the GNU Affero General Public License -along with this program. If not, see . -*/ - -package migration - -import ( - "github.com/spf13/cobra" - "k8s.io/cli-runtime/pkg/genericiooptions" - cmdutil "k8s.io/kubectl/pkg/cmd/util" - - "github.com/apecloud/kbcli/pkg/action" - "github.com/apecloud/kbcli/pkg/types" - "github.com/apecloud/kbcli/pkg/util" -) - -func NewMigrationTemplatesCmd(f cmdutil.Factory, streams genericiooptions.IOStreams) *cobra.Command { - o := action.NewListOptions(f, streams, types.MigrationTemplateGVR()) - cmd := &cobra.Command{ - Use: "templates [NAME]", - Short: "List migration templates.", - Example: TemplateExample, - Aliases: []string{"tp", "template"}, - ValidArgsFunction: util.ResourceNameCompletionFunc(f, o.GVR), - Run: func(cmd *cobra.Command, args []string) { - _, validErr := IsMigrationCrdValidWithFactory(o.Factory) - PrintCrdInvalidError(validErr) - o.Names = args - _, err := o.Run() - util.CheckErr(err) - }, - } - o.AddFlags(cmd) - return cmd -} diff --git a/pkg/cmd/migration/templates_test.go b/pkg/cmd/migration/templates_test.go deleted file mode 100644 index b4e215696..000000000 --- a/pkg/cmd/migration/templates_test.go +++ /dev/null @@ -1,42 +0,0 @@ -/* -Copyright (C) 2022-2024 ApeCloud Co., Ltd - -This file is part of KubeBlocks project - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU Affero General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU Affero General Public License for more details. - -You should have received a copy of the GNU Affero General Public License -along with this program. If not, see . -*/ - -package migration - -import ( - . "github.com/onsi/ginkgo/v2" - . "github.com/onsi/gomega" - - "k8s.io/cli-runtime/pkg/genericiooptions" - cmdtesting "k8s.io/kubectl/pkg/cmd/testing" -) - -var _ = Describe("templates", func() { - - var ( - streams genericiooptions.IOStreams - tf *cmdtesting.TestFactory - ) - - It("command build", func() { - cmd := NewMigrationTemplatesCmd(tf, streams) - Expect(cmd).ShouldNot(BeNil()) - }) - -}) diff --git a/pkg/cmd/migration/terminate.go b/pkg/cmd/migration/terminate.go deleted file mode 100644 index 77a5bf650..000000000 --- a/pkg/cmd/migration/terminate.go +++ /dev/null @@ -1,57 +0,0 @@ -/* -Copyright (C) 2022-2024 ApeCloud Co., Ltd - -This file is part of KubeBlocks project - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU Affero General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU Affero General Public License for more details. - -You should have received a copy of the GNU Affero General Public License -along with this program. If not, see . -*/ - -package migration - -import ( - "fmt" - - "github.com/spf13/cobra" - "k8s.io/cli-runtime/pkg/genericiooptions" - cmdutil "k8s.io/kubectl/pkg/cmd/util" - - "github.com/apecloud/kbcli/pkg/action" - "github.com/apecloud/kbcli/pkg/types" - "github.com/apecloud/kbcli/pkg/util" -) - -func NewMigrationTerminateCmd(f cmdutil.Factory, streams genericiooptions.IOStreams) *cobra.Command { - o := action.NewDeleteOptions(f, streams, types.MigrationTaskGVR()) - cmd := &cobra.Command{ - Use: "terminate NAME", - Short: "Delete migration task.", - Example: DeleteExample, - ValidArgsFunction: util.ResourceNameCompletionFunc(f, types.MigrationTaskGVR()), - Run: func(cmd *cobra.Command, args []string) { - _, validErr := IsMigrationCrdValidWithFactory(o.Factory) - PrintCrdInvalidError(validErr) - util.CheckErr(deleteMigrationTask(o, args)) - }, - } - o.AddFlags(cmd) - return cmd -} - -func deleteMigrationTask(o *action.DeleteOptions, args []string) error { - if len(args) == 0 { - return fmt.Errorf("missing migration task name") - } - o.Names = args - return o.Run() -} diff --git a/pkg/cmd/migration/terminate_test.go b/pkg/cmd/migration/terminate_test.go deleted file mode 100644 index 125ff5983..000000000 --- a/pkg/cmd/migration/terminate_test.go +++ /dev/null @@ -1,42 +0,0 @@ -/* -Copyright (C) 2022-2024 ApeCloud Co., Ltd - -This file is part of KubeBlocks project - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU Affero General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU Affero General Public License for more details. - -You should have received a copy of the GNU Affero General Public License -along with this program. If not, see . -*/ - -package migration - -import ( - . "github.com/onsi/ginkgo/v2" - . "github.com/onsi/gomega" - - "k8s.io/cli-runtime/pkg/genericiooptions" - cmdtesting "k8s.io/kubectl/pkg/cmd/testing" -) - -var _ = Describe("terminate", func() { - - var ( - streams genericiooptions.IOStreams - tf *cmdtesting.TestFactory - ) - - It("command build", func() { - cmd := NewMigrationTerminateCmd(tf, streams) - Expect(cmd).ShouldNot(BeNil()) - }) - -}) diff --git a/pkg/cmd/organization/cloud_organization.go b/pkg/cmd/organization/cloud_organization.go deleted file mode 100644 index e1fab48ce..000000000 --- a/pkg/cmd/organization/cloud_organization.go +++ /dev/null @@ -1,175 +0,0 @@ -/* -Copyright (C) 2022-2024 ApeCloud Co., Ltd - -This file is part of KubeBlocks project - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU Affero General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU Affero General Public License for more details. - -You should have received a copy of the GNU Affero General Public License -along with this program. If not, see . -*/ - -package organization - -import ( - "encoding/json" - "net/http" - "os" - "path/filepath" - "strings" - - "github.com/pkg/errors" -) - -const OrgAPIName = "organizations" - -type CloudOrganization struct { - Token string - APIURL string - APIPath string -} - -func (o *CloudOrganization) getOrganization(name string) (*OrgItem, error) { - path := strings.Join([]string{o.APIURL, o.APIPath, OrgAPIName, name}, "/") - response, err := NewRequest(http.MethodGet, path, o.Token, nil) - if err != nil { - return nil, errors.Wrap(err, "Failed to get organization.") - } - - var orgItem OrgItem - err = json.Unmarshal(response, &orgItem) - if err != nil { - return nil, errors.Wrap(err, "Invalid organization format.") - } - - return &orgItem, nil -} - -func (o *CloudOrganization) GetOrganizations() (*Organizations, error) { - path := strings.Join([]string{o.APIURL, o.APIPath, OrgAPIName}, "/") - response, err := NewRequest(http.MethodGet, path, o.Token, nil) - if err != nil { - return nil, errors.Wrap(err, "Failed to get organizations.") - } - - var organizations Organizations - err = json.Unmarshal(response, &organizations) - if err != nil { - return nil, errors.Wrap(err, "Invalid organizations format.") - } - - return &organizations, nil -} - -func (o *CloudOrganization) switchOrganization(name string) (string, error) { - if ok, err := o.IsValidOrganization(name); !ok { - return "", err - } - - currentOrgAndContext, err := GetCurrentOrgAndContext() - if err != nil { - return "", errors.Wrap(err, "Failed to get current organization.") - } - oldOrganizationName := currentOrgAndContext.CurrentOrganization - currentOrgAndContext.CurrentOrganization = name - if err = SetCurrentOrgAndContext(currentOrgAndContext); err != nil { - return "", errors.Wrapf(err, "Failed to switch organization to %s.", name) - } - return oldOrganizationName, nil -} - -func (o *CloudOrganization) getCurrentOrganization() (string, error) { - currentOrg, err := getCurrentOrganization() - if err != nil { - return "", err - } - - if ok, err := o.IsValidOrganization(currentOrg); !ok { - return "", err - } - return currentOrg, nil -} - -func (o *CloudOrganization) IsValidOrganization(name string) (bool, error) { - organizations, err := o.GetOrganizations() - if err != nil { - return false, errors.Wrap(err, "Failed to get organizations.") - } - for _, item := range organizations.Items { - if item.Name == name { - return true, nil - } - } - return false, errors.Errorf("Organization %s not found.", name) -} - -func (o *CloudOrganization) addOrganization(body []byte) error { - path := strings.Join([]string{o.APIURL, o.APIPath, OrgAPIName}, "/") - _, err := NewRequest(http.MethodPost, path, o.Token, body) - if err != nil { - return errors.Wrap(err, "Failed to add organization.") - } - - return nil -} - -func (o *CloudOrganization) deleteOrganization(name string) error { - path := strings.Join([]string{o.APIURL, o.APIPath, OrgAPIName, name}, "/") - _, err := NewRequest(http.MethodDelete, path, o.Token, nil) - if err != nil { - return errors.Wrap(err, "Failed to delete organization.") - } - - return nil -} - -// SetCurrentOrgAndContext TODO:Check whether the newly set context and org exist. -func SetCurrentOrgAndContext(currentOrgAndContext *CurrentOrgAndContext) error { - data, err := json.MarshalIndent(currentOrgAndContext, "", " ") - if err != nil { - return errors.Wrap(err, "Failed to marshal current organization and context.") - } - - filePath, err := GetCurrentOrgAndContextFilePath() - if err != nil { - return errors.Wrap(err, "Failed to get current organization and context.") - } - - // Create the necessary folders and file if they don't exist - if err := os.MkdirAll(filepath.Dir(filePath), 0755); err != nil { - return errors.Wrap(err, "Failed to create necessary folders.") - } - - file, err := os.Create(filePath) - if err != nil { - return errors.Wrap(err, "Failed to create or open current organization and context file.") - } - - _, err = file.Write(data) - if err != nil { - return errors.Wrap(err, "Failed to write current organization and context.") - } - defer file.Close() - - return nil -} - -func getCurrentOrganization() (string, error) { - currentOrgAndContext, err := GetCurrentOrgAndContext() - if err != nil { - return "", err - } - - if currentOrgAndContext.CurrentOrganization == "" { - return "", errors.New("No organization available, please join an organization.") - } - return currentOrgAndContext.CurrentOrganization, nil -} diff --git a/pkg/cmd/organization/cloud_organization_test.go b/pkg/cmd/organization/cloud_organization_test.go deleted file mode 100644 index a52c61576..000000000 --- a/pkg/cmd/organization/cloud_organization_test.go +++ /dev/null @@ -1,158 +0,0 @@ -/* -Copyright (C) 2022-2024 ApeCloud Co., Ltd - -This file is part of KubeBlocks project - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU Affero General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU Affero General Public License for more details. - -You should have received a copy of the GNU Affero General Public License -along with this program. If not, see . -*/ - -package organization - -import ( - . "github.com/onsi/ginkgo/v2" - . "github.com/onsi/gomega" - - "encoding/json" - "net/http" - "net/http/httptest" - "os" - - "github.com/apecloud/kbcli/pkg/cmd/auth/utils" -) - -func mockServer() *httptest.Server { - return httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - switch r.URL.Path { - case "/api/v1/organizations/test_org": - switch r.Method { - case http.MethodGet: - org := OrgItem{ - ID: "test_id", - Name: "test_org", - Role: "test_role", - Description: "test_description", - DisplayName: "test_display_name", - CreatedAt: "test_created_at", - UpdatedAt: "test_updated_at", - } - - jsonData, err := json.Marshal(org) - if err != nil { - w.WriteHeader(http.StatusInternalServerError) - return - } - w.Header().Set("Content-Type", "application/json") - w.WriteHeader(http.StatusOK) - _, _ = w.Write(jsonData) - case http.MethodDelete: - w.WriteHeader(http.StatusOK) - case http.MethodPost: - w.WriteHeader(http.StatusCreated) - default: - w.WriteHeader(http.StatusNotFound) - } - - case "/api/v1/organizations": - orgs := &Organizations{ - Items: []OrgItem{ - { - ID: "test_id", - Name: "test_org", - Role: "test_role", - Description: "test_description", - DisplayName: "test_display_name", - }, - }, - } - jsonData, err := json.Marshal(orgs) - if err != nil { - w.WriteHeader(http.StatusInternalServerError) - return - } - - w.Header().Set("Content-Type", "application/json") - w.WriteHeader(http.StatusOK) - _, _ = w.Write(jsonData) - } - })) -} - -var _ = Describe("Test Cloud Organization", func() { - var ( - o *CloudOrganization - ) - BeforeEach(func() { - server := mockServer() - o = &CloudOrganization{Token: "test_token", APIURL: server.URL, APIPath: utils.APIPathV1} - os.Setenv("TEST_ENV", "true") - }) - - AfterEach(func() { - defer os.Unsetenv("TEST_ENV") - }) - - Context("test cloud organization", func() { - Expect(SetCurrentOrgAndContext(&CurrentOrgAndContext{ - CurrentOrganization: "test_org", - CurrentContext: "test_context", - })).Should(BeNil()) - - It("test getOrganization ", func() { - ExpectWithOffset(1, func() error { - _, err := o.getOrganization("test_org") - return err - }()).To(BeNil()) - }) - - It("test GetOrganizations ", func() { - ExpectWithOffset(1, func() error { - _, err := o.GetOrganizations() - return err - }()).To(BeNil()) - }) - - It("test GetCurrentOrgAndContext ", func() { - ExpectWithOffset(1, func() error { - _, err := GetCurrentOrgAndContext() - return err - }()).To(BeNil()) - }) - - It("test switchOrganization ", func() { - ExpectWithOffset(1, func() error { - _, err := o.switchOrganization("test_org") - return err - }()).To(BeNil()) - }) - - It("test addOrganization ", func() { - ExpectWithOffset(1, func() error { - org := &OrgItem{ - ID: "test_id", - } - body, err := json.Marshal(org) - Expect(err).To(BeNil()) - err = o.addOrganization(body) - return err - }()).To(BeNil()) - }) - - It("test deleteOrganization ", func() { - ExpectWithOffset(1, func() error { - err := o.deleteOrganization("test_org") - return err - }()).To(BeNil()) - }) - }) -}) diff --git a/pkg/cmd/organization/organization.go b/pkg/cmd/organization/organization.go deleted file mode 100644 index 4bb934e7d..000000000 --- a/pkg/cmd/organization/organization.go +++ /dev/null @@ -1,313 +0,0 @@ -/* -Copyright (C) 2022-2024 ApeCloud Co., Ltd - -This file is part of KubeBlocks project - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU Affero General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU Affero General Public License for more details. - -You should have received a copy of the GNU Affero General Public License -along with this program. If not, see . -*/ - -package organization - -import ( - "encoding/json" - "fmt" - "strings" - - viper "github.com/apecloud/kubeblocks/pkg/viperx" - "github.com/jedib0t/go-pretty/v6/table" - "github.com/pkg/errors" - "github.com/spf13/cobra" - "gopkg.in/yaml.v2" - "k8s.io/cli-runtime/pkg/genericiooptions" - cmdutil "k8s.io/kubectl/pkg/cmd/util" - "k8s.io/kubectl/pkg/util/templates" - - "github.com/apecloud/kbcli/pkg/cmd/auth/utils" - "github.com/apecloud/kbcli/pkg/printer" - "github.com/apecloud/kbcli/pkg/types" -) - -var organizationExample = templates.Examples(` - // Get the organization name currently used by the user. - kbcli org current - // List all organizations the current user has joined. - kbcli org list - // Get the description information of organization org1. - kbcli org describe org1 - // Switch to organization org2. - kbcli org switch org2 -`) - -type Organizations struct { - Items []OrgItem `json:"items"` -} - -type OrgItem struct { - ID string `json:"id"` - Name string `json:"name"` - Role string `json:"role"` - Description string `json:"description"` - DisplayName string `json:"displayName"` - CreatedAt string `json:"createdAt"` - UpdatedAt string `json:"updatedAt"` -} - -type CurrentOrgAndContext struct { - CurrentOrganization string `json:"currentOrganization"` - CurrentContext string `json:"currentContext"` -} - -type Organization interface { - getOrganization(name string) (*OrgItem, error) - GetOrganizations() (*Organizations, error) - switchOrganization(name string) (string, error) - getCurrentOrganization() (string, error) - addOrganization(body []byte) error - deleteOrganization(name string) error - IsValidOrganization(name string) (bool, error) -} - -type OrganizationOption struct { - Name string - OutputFormat string - Organization Organization - - genericiooptions.IOStreams -} - -func newOrganizationOption(streams genericiooptions.IOStreams) *OrganizationOption { - return &OrganizationOption{ - IOStreams: streams, - } -} - -func NewOrganizationCmd(streams genericiooptions.IOStreams) *cobra.Command { - cmd := &cobra.Command{ - Use: "org", - Short: "kbcli org is used to manage cloud organizations and is only suitable for interacting with cloud.", - Example: organizationExample, - } - cmd.AddCommand( - newOrgListCmd(streams), - newOrgSwitchCmd(streams), - newOrgCurrentCmd(streams), - newOrgDescribeCmd(streams), - ) - - return cmd -} - -func newOrgListCmd(streams genericiooptions.IOStreams) *cobra.Command { - o := newOrganizationOption(streams) - - cmd := &cobra.Command{ - Use: "list", - Short: "List all organizations you have joined.", - Run: func(cmd *cobra.Command, args []string) { - cmdutil.CheckErr(o.complete(args)) - cmdutil.CheckErr(o.validate(cmd)) - cmdutil.CheckErr(o.runList()) - }, - } - - return cmd -} - -func newOrgSwitchCmd(streams genericiooptions.IOStreams) *cobra.Command { - o := newOrganizationOption(streams) - - cmd := &cobra.Command{ - Use: "switch", - Short: "Switch to another organization you are already a member of.", - Run: func(cmd *cobra.Command, args []string) { - cmdutil.CheckErr(o.complete(args)) - cmdutil.CheckErr(o.validate(cmd)) - cmdutil.CheckErr(o.runSwitch()) - }, - } - - return cmd -} - -func newOrgCurrentCmd(streams genericiooptions.IOStreams) *cobra.Command { - o := newOrganizationOption(streams) - - cmd := &cobra.Command{ - Use: "current", - Short: "Get current organization.", - Run: func(cmd *cobra.Command, args []string) { - cmdutil.CheckErr(o.complete(args)) - cmdutil.CheckErr(o.validate(cmd)) - cmdutil.CheckErr(o.runCurrent()) - }, - } - - return cmd -} - -func newOrgDescribeCmd(streams genericiooptions.IOStreams) *cobra.Command { - o := newOrganizationOption(streams) - - cmd := &cobra.Command{ - Use: "describe", - Short: "Get the description information of an organization.", - Run: func(cmd *cobra.Command, args []string) { - cmdutil.CheckErr(o.complete(args)) - cmdutil.CheckErr(o.validate(cmd)) - cmdutil.CheckErr(o.runDescribe()) - }, - } - - cmd.Flags().StringVarP(&o.OutputFormat, "output", "o", "human", "Output format (human|yaml|json)") - - return cmd -} - -func (o *OrganizationOption) validate(cmd *cobra.Command) error { - if cmd.Name() == "switch" || cmd.Name() == "describe" { - if o.Name == "" { - return errors.New("Organization name is required.") - } - } - return nil -} - -func (o *OrganizationOption) complete(args []string) error { - if len(args) > 0 { - o.Name = args[0] - } - - token, err := GetToken() - if err != nil { - return err - } - - if o.Organization == nil { - o.Organization = &CloudOrganization{ - Token: token, - APIURL: viper.GetString(types.CfgKeyOpenAPIServer), - APIPath: utils.APIPathV1, - } - } - - return nil -} - -func (o *OrganizationOption) runList() error { - organizations, err := o.Organization.GetOrganizations() - if err != nil { - return err - } - - if len(organizations.Items) == 0 { - fmt.Fprintln(o.Out, "you are currently not join in any organization") - return nil - } - - tbl := printer.NewTablePrinter(o.Out) - tbl.Tbl.SetColumnConfigs([]table.ColumnConfig{ - {Number: 5, WidthMax: 120}, - }) - tbl.SetHeader("NAME", "DISPLAYNAME", "DESCRIPTION", "ROLE", "ORGID") - - for _, item := range organizations.Items { - tbl.AddRow(item.Name, item.DisplayName, item.Description, item.Role, item.ID) - } - - tbl.Print() - return nil -} - -func (o *OrganizationOption) runSwitch() error { - oldOrganizationName, err := o.Organization.switchOrganization(o.Name) - if err != nil { - return err - } - fmt.Fprintf(o.Out, "Successfully switched from %s to organization: %s\n", oldOrganizationName, o.Name) - return nil -} - -func (o *OrganizationOption) runCurrent() error { - currentOrg, err := o.Organization.getCurrentOrganization() - if err != nil { - return err - } - fmt.Fprintf(o.Out, "Current organization: %s\n", currentOrg) - return nil -} - -func (o *OrganizationOption) runDescribe() error { - orgItem, err := o.Organization.getOrganization(o.Name) - if err != nil { - return err - } - - switch strings.ToLower(o.OutputFormat) { - case "yaml": - return o.printYAML(orgItem) - case "json": - return o.printJSON(orgItem) - case "human": - fallthrough - default: - return o.printTable(orgItem) - } -} - -func (o *OrganizationOption) printYAML(orgItem *OrgItem) error { - body, err := yaml.Marshal(orgItem) - if err != nil { - return err - } - fmt.Fprintf(o.Out, "%s\n", body) - return nil -} - -func (o *OrganizationOption) printJSON(orgItem *OrgItem) error { - body, err := json.MarshalIndent(orgItem, "", " ") - if err != nil { - return err - } - fmt.Fprintf(o.Out, "%s\n", body) - return nil -} - -func (o *OrganizationOption) printTable(orgItem *OrgItem) error { - tbl := printer.NewTablePrinter(o.Out) - tbl.Tbl.SetColumnConfigs([]table.ColumnConfig{ - {Number: 5, WidthMax: 120}, - }) - tbl.SetHeader( - "NAME", - "DISPLAYNAME", - "CREATEDAT", - "UPDATEDAT", - "DESCRIPTION", - "ORGID", - "ROLE", - ) - - tbl.AddRow( - orgItem.Name, - orgItem.DisplayName, - orgItem.CreatedAt, - orgItem.UpdatedAt, - orgItem.Description, - orgItem.ID, - orgItem.Role, - ) - - tbl.Print() - return nil -} diff --git a/pkg/cmd/organization/organization_test.go b/pkg/cmd/organization/organization_test.go deleted file mode 100644 index a1fff5dd6..000000000 --- a/pkg/cmd/organization/organization_test.go +++ /dev/null @@ -1,133 +0,0 @@ -/* -Copyright (C) 2022-2024 ApeCloud Co., Ltd - -This file is part of KubeBlocks project - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU Affero General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU Affero General Public License for more details. - -You should have received a copy of the GNU Affero General Public License -along with this program. If not, see . -*/ - -package organization - -import ( - . "github.com/onsi/ginkgo/v2" - . "github.com/onsi/gomega" - - "fmt" - "os" - - "k8s.io/cli-runtime/pkg/genericiooptions" -) - -type MockOrganization struct { - genericiooptions.IOStreams -} - -func (m *MockOrganization) getOrganization(name string) (*OrgItem, error) { - return &OrgItem{ - ID: "test", - Name: "test", - Role: "test", - Description: "test", - DisplayName: "test", - CreatedAt: "test", - }, nil -} - -func (m *MockOrganization) GetOrganizations() (*Organizations, error) { - return &Organizations{ - Items: []OrgItem{ - { - ID: "test", - Name: "test", - Role: "test", - Description: "test", - DisplayName: "test", - CreatedAt: "test", - }, - }, - }, nil -} - -func (m *MockOrganization) switchOrganization(name string) (string, error) { - fmt.Printf("switch to %s\n", name) - return "", nil -} - -func (m *MockOrganization) getCurrentOrganization() (string, error) { - fmt.Printf("get current organization\n") - return "", nil -} - -func (m *MockOrganization) addOrganization(body []byte) error { - fmt.Printf("add organization %s\n", string(body)) - return nil -} - -func (m *MockOrganization) deleteOrganization(name string) error { - fmt.Printf("delete organization %s\n", name) - return nil -} - -func (m *MockOrganization) IsValidOrganization(name string) (bool, error) { - fmt.Printf("check organization %s\n", name) - return true, nil -} - -var _ = Describe("Test Organization", func() { - var ( - streams genericiooptions.IOStreams - o *OrganizationOption - ) - BeforeEach(func() { - streams, _, _, _ = genericiooptions.NewTestIOStreams() - o = &OrganizationOption{IOStreams: streams, Organization: &MockOrganization{}} - os.Setenv("TEST_ENV", "true") - }) - - AfterEach(func() { - defer os.Unsetenv("TEST_ENV") - }) - - Context("test organization", func() { - args := []string{"test", "test", "test"} - - It("test organization list ", func() { - cmd := newOrgListCmd(streams) - Expect(o.complete(args)).Should(Succeed()) - Expect(o.validate(cmd)).Should(Succeed()) - Expect(o.runList()).Should(Succeed()) - }) - - It("test organization switch ", func() { - cmd := newOrgListCmd(streams) - Expect(o.complete(args)).Should(Succeed()) - Expect(o.validate(cmd)).Should(Succeed()) - Expect(o.runSwitch()).Should(Succeed()) - }) - - It("test organization current ", func() { - cmd := newOrgListCmd(streams) - Expect(o.complete(args)).Should(Succeed()) - Expect(o.validate(cmd)).Should(Succeed()) - Expect(o.runCurrent()).Should(Succeed()) - }) - - It("test organization describe ", func() { - cmd := newOrgListCmd(streams) - Expect(o.complete(args)).Should(Succeed()) - Expect(o.validate(cmd)).Should(Succeed()) - Expect(o.runDescribe()).Should(Succeed()) - }) - }) -}) diff --git a/pkg/cmd/organization/request.go b/pkg/cmd/organization/request.go deleted file mode 100644 index cbab00b26..000000000 --- a/pkg/cmd/organization/request.go +++ /dev/null @@ -1,70 +0,0 @@ -/* -Copyright (C) 2022-2024 ApeCloud Co., Ltd - -This file is part of KubeBlocks project - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU Affero General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU Affero General Public License for more details. - -You should have received a copy of the GNU Affero General Public License -along with this program. If not, see . -*/ - -package organization - -import ( - "bytes" - "encoding/json" - "fmt" - "io" - "net/http" - - "github.com/hashicorp/go-cleanhttp" - "github.com/pkg/errors" -) - -type ErrorResponse struct { - Code int `json:"code"` - Message string `json:"message"` - Reason string `json:"reason"` -} - -func NewRequest(method, path, token string, requestBody []byte) ([]byte, error) { - client := cleanhttp.DefaultClient() - req, err := http.NewRequest(method, path, bytes.NewBuffer(requestBody)) - if err != nil { - return nil, errors.Wrapf(err, "failed to create request for %s", path) - } - - req.Header.Set("Accept", "application/json") - req.Header.Set("Authorization", "Bearer "+token) - - resp, err := client.Do(req) - if err != nil { - return nil, errors.Wrapf(err, "failed to perform request for %s", path) - } - defer resp.Body.Close() - - if resp.StatusCode >= 400 { - var errorResponse ErrorResponse - err = json.NewDecoder(resp.Body).Decode(&errorResponse) - if err != nil { - return nil, errors.Wrapf(err, "code: %d, failed to decode error response body for %s", resp.StatusCode, path) - } - return nil, fmt.Errorf("request failed with status code: %d for %s\nreason: %s %s", resp.StatusCode, path, errorResponse.Reason, errorResponse.Message) - } - - responseBody, err := io.ReadAll(resp.Body) - if err != nil { - return nil, errors.Wrapf(err, "failed to read response body for %s", path) - } - - return responseBody, nil -} diff --git a/pkg/cmd/organization/suite_test.go b/pkg/cmd/organization/suite_test.go deleted file mode 100644 index 7e9607c6d..000000000 --- a/pkg/cmd/organization/suite_test.go +++ /dev/null @@ -1,32 +0,0 @@ -/* -Copyright (C) 2022-2024 ApeCloud Co., Ltd - -This file is part of KubeBlocks project - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU Affero General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU Affero General Public License for more details. - -You should have received a copy of the GNU Affero General Public License -along with this program. If not, see . -*/ - -package organization - -import ( - "testing" - - . "github.com/onsi/ginkgo/v2" - . "github.com/onsi/gomega" -) - -func TestDashboard(t *testing.T) { - RegisterFailHandler(Fail) - RunSpecs(t, "Organization Suite") -} diff --git a/pkg/cmd/organization/utils.go b/pkg/cmd/organization/utils.go deleted file mode 100644 index 5aabd3a92..000000000 --- a/pkg/cmd/organization/utils.go +++ /dev/null @@ -1,94 +0,0 @@ -/* -Copyright (C) 2022-2024 ApeCloud Co., Ltd - -This file is part of KubeBlocks project - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU Affero General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU Affero General Public License for more details. - -You should have received a copy of the GNU Affero General Public License -along with this program. If not, see . -*/ - -package organization - -import ( - "encoding/json" - "os" - "path/filepath" - - "github.com/pkg/errors" - - "github.com/apecloud/kbcli/pkg/cmd/auth/authorize" - "github.com/apecloud/kbcli/pkg/util" -) - -const ( - CloudContextDir = "cloud_context" - CurrentOrgAndContextFile = "current.json" - ContextFile = "context.json" -) - -func GetCurrentOrgAndContextFilePath() (string, error) { - cliHomeDir, err := util.GetCliHomeDir() - if err != nil { - return "", err - } - if err != nil { - return "", err - } - filePath := filepath.Join(cliHomeDir, CloudContextDir, CurrentOrgAndContextFile) - return filePath, nil -} - -func GetContextFilePath() (string, error) { - cliHomeDir, err := util.GetCliHomeDir() - if err != nil { - return "", err - } - filePath := filepath.Join(cliHomeDir, CloudContextDir, ContextFile) - return filePath, nil -} - -func GetToken() (string, error) { - v := os.Getenv("TEST_ENV") - if v == "true" { - return "test_token", nil - } - - cached := authorize.NewKeyringCachedTokenProvider(nil) - tokenRes, err := cached.GetTokens() - if err != nil { - return "", err - } - if tokenRes != nil { - return tokenRes.IDToken, nil - } - return "", errors.New("Failed to get token") -} - -func GetCurrentOrgAndContext() (*CurrentOrgAndContext, error) { - filePath, err := GetCurrentOrgAndContextFilePath() - if err != nil { - return nil, errors.Wrapf(err, "Failed to get current organization and context file: %s", filePath) - } - data, err := os.ReadFile(filePath) - if err != nil { - return nil, errors.Wrapf(err, "Failed to read current organization and context file: %s", filePath) - } - - var currentOrgAndContext CurrentOrgAndContext - err = json.Unmarshal(data, ¤tOrgAndContext) - if err != nil { - return nil, errors.Wrap(err, "Invalid current organization and context format.") - } - - return ¤tOrgAndContext, nil -} diff --git a/pkg/cmd/playground/destroy.go b/pkg/cmd/playground/destroy.go index 3c58a858f..de5dda092 100644 --- a/pkg/cmd/playground/destroy.go +++ b/pkg/cmd/playground/destroy.go @@ -85,7 +85,7 @@ func newDestroyCmd(streams genericiooptions.IOStreams) *cobra.Command { } cmd.Flags().BoolVar(&o.purge, "purge", true, "Purge all resources before destroying kubernetes cluster, delete all clusters created by KubeBlocks and uninstall KubeBlocks.") - cmd.Flags().DurationVar(&o.timeout, "timeout", 300*time.Second, "Time to wait for destroying KubeBlocks, such as --timeout=10m") + cmd.Flags().DurationVar(&o.timeout, "timeout", 600*time.Second, "Time to wait for destroying KubeBlocks, such as --timeout=10m") cmd.Flags().BoolVar(&o.autoApprove, "auto-approve", false, "Skip interactive approval before destroying the playground") return cmd } diff --git a/pkg/cmd/playground/init.go b/pkg/cmd/playground/init.go index 4612c05c3..b5bb590c3 100644 --- a/pkg/cmd/playground/init.go +++ b/pkg/cmd/playground/init.go @@ -131,7 +131,7 @@ func newInitCmd(streams genericiooptions.IOStreams) *cobra.Command { cmd.Flags().StringVar(&o.kbVersion, "version", version.DefaultKubeBlocksVersion, "KubeBlocks version") cmd.Flags().StringVar(&o.cloudProvider, "cloud-provider", defaultCloudProvider, fmt.Sprintf("Cloud provider type, one of %v", supportedCloudProviders)) cmd.Flags().StringVar(&o.region, "region", "", "The region to create kubernetes cluster") - cmd.Flags().DurationVar(&o.Timeout, "timeout", 300*time.Second, "Time to wait for init playground, such as --timeout=10m") + cmd.Flags().DurationVar(&o.Timeout, "timeout", 600*time.Second, "Time to wait for init playground, such as --timeout=10m") cmd.Flags().BoolVar(&o.autoApprove, "auto-approve", false, "Skip interactive approval during the initialization of playground") util.CheckErr(cmd.RegisterFlagCompletionFunc( @@ -506,10 +506,10 @@ func (o *initOptions) createCluster() error { c.Namespace = defaultNamespace c.Name = kbClusterName c.UpdatableFlags = cmdcluster.UpdatableFlags{ - TerminationPolicy: "WipeOut", - MonitoringInterval: 15, - PodAntiAffinity: "Preferred", - Tenancy: "SharedNode", + TerminationPolicy: "WipeOut", + DisableExporter: false, + PodAntiAffinity: "Preferred", + Tenancy: "SharedNode", } // if we are running on local, create cluster with one replica diff --git a/pkg/cmd/plugin/plugin.go b/pkg/cmd/plugin/plugin.go index c44c0d92b..8e53fc200 100644 --- a/pkg/cmd/plugin/plugin.go +++ b/pkg/cmd/plugin/plugin.go @@ -164,7 +164,7 @@ func (o *PluginListOptions) ListPlugins() ([]string, []error) { files, err := os.ReadDir(dir) if err != nil { if _, ok := err.(*os.PathError); ok { - klog.V(1).Info("Unable to read directory %q from your PATH: %v. Skipping...\n", dir, err) + klog.V(1).Infof("Unable to read directory %q from your PATH: %v. Skipping...\n", dir, err) continue } diff --git a/pkg/cmd/report/report.go b/pkg/cmd/report/report.go index 93954102d..cec05bae0 100644 --- a/pkg/cmd/report/report.go +++ b/pkg/cmd/report/report.go @@ -106,7 +106,7 @@ var _ reportInterface = &reportClusterOptions{} func NewReportCmd(f cmdutil.Factory, streams genericiooptions.IOStreams) *cobra.Command { cmd := &cobra.Command{ Use: "report [kubeblocks | cluster]", - Short: "report kubeblocks or cluster info.", + Short: "Report kubeblocks or cluster info.", } cmd.AddCommand( newKubeblocksReportCmd(f, streams), diff --git a/pkg/scheme/install.go b/pkg/scheme/install.go index 812402068..31152cd91 100644 --- a/pkg/scheme/install.go +++ b/pkg/scheme/install.go @@ -28,6 +28,7 @@ import ( clientgoscheme "k8s.io/client-go/kubernetes/scheme" appsv1alpha1 "github.com/apecloud/kubeblocks/apis/apps/v1alpha1" + appsv1beta1 "github.com/apecloud/kubeblocks/apis/apps/v1beta1" dpv1alpha1 "github.com/apecloud/kubeblocks/apis/dataprotection/v1alpha1" extensionsv1alpha1 "github.com/apecloud/kubeblocks/apis/extensions/v1alpha1" workloadsv1alpha1 "github.com/apecloud/kubeblocks/apis/workloads/v1alpha1" @@ -37,6 +38,7 @@ func init() { utilruntime.Must(metav1.AddMetaToScheme(Scheme)) utilruntime.Must(clientgoscheme.AddToScheme(Scheme)) utilruntime.Must(appsv1alpha1.AddToScheme(Scheme)) + utilruntime.Must(appsv1beta1.AddToScheme(Scheme)) utilruntime.Must(dpv1alpha1.AddToScheme(Scheme)) utilruntime.Must(snapshotv1.AddToScheme(Scheme)) utilruntime.Must(snapshotv1beta1.AddToScheme(Scheme)) diff --git a/pkg/testing/client.go b/pkg/testing/client.go index 26fb727bb..db22f9f7f 100644 --- a/pkg/testing/client.go +++ b/pkg/testing/client.go @@ -28,6 +28,7 @@ import ( metricsfakeclient "k8s.io/metrics/pkg/client/clientset/versioned/fake" appsv1alpha1 "github.com/apecloud/kubeblocks/apis/apps/v1alpha1" + appsv1beta1 "github.com/apecloud/kubeblocks/apis/apps/v1beta1" dpv1alpha1 "github.com/apecloud/kubeblocks/apis/dataprotection/v1alpha1" extensionsv1alpha1 "github.com/apecloud/kubeblocks/apis/extensions/v1alpha1" kbfakeclient "github.com/apecloud/kubeblocks/pkg/client/clientset/versioned/fake" @@ -39,6 +40,7 @@ func FakeClientSet(objects ...runtime.Object) *kubefakeclient.Clientset { func FakeDynamicClient(objects ...runtime.Object) *dynamicfakeclient.FakeDynamicClient { _ = appsv1alpha1.AddToScheme(scheme.Scheme) + _ = appsv1beta1.AddToScheme(scheme.Scheme) _ = extensionsv1alpha1.AddToScheme(scheme.Scheme) _ = dpv1alpha1.AddToScheme(scheme.Scheme) return dynamicfakeclient.NewSimpleDynamicClient(scheme.Scheme, objects...) diff --git a/pkg/testing/fake.go b/pkg/testing/fake.go index 47d94f688..3b7400c37 100644 --- a/pkg/testing/fake.go +++ b/pkg/testing/fake.go @@ -39,9 +39,9 @@ import ( "k8s.io/utils/pointer" appsv1alpha1 "github.com/apecloud/kubeblocks/apis/apps/v1alpha1" + appsv1beta1 "github.com/apecloud/kubeblocks/apis/apps/v1beta1" dpv1alpha1 "github.com/apecloud/kubeblocks/apis/dataprotection/v1alpha1" extensionsv1alpha1 "github.com/apecloud/kubeblocks/apis/extensions/v1alpha1" - storagev1alpha1 "github.com/apecloud/kubeblocks/apis/storage/v1alpha1" workloadsv1alpha1 "github.com/apecloud/kubeblocks/apis/workloads/v1alpha1" "github.com/apecloud/kubeblocks/pkg/constant" dptypes "github.com/apecloud/kubeblocks/pkg/dataprotection/types" @@ -796,13 +796,13 @@ func FakeConfigMap(cmName string, namespace string, data map[string]string) *cor return cm } -func FakeConfigConstraint(ccName string) *appsv1alpha1.ConfigConstraint { - cm := &appsv1alpha1.ConfigConstraint{ +func FakeConfigConstraint(ccName string) *appsv1beta1.ConfigConstraint { + cm := &appsv1beta1.ConfigConstraint{ ObjectMeta: metav1.ObjectMeta{ Name: ccName, }, - Spec: appsv1alpha1.ConfigConstraintSpec{ - FormatterConfig: &appsv1alpha1.FormatterConfig{}, + Spec: appsv1beta1.ConfigConstraintSpec{ + FileFormatConfig: &appsv1beta1.FileFormatConfig{}, }, } return cm @@ -1119,16 +1119,16 @@ func FakeEventForObject(name string, namespace string, object string) *corev1.Ev } } -func FakeStorageProvider(name string, mutateFunc func(obj *storagev1alpha1.StorageProvider)) *storagev1alpha1.StorageProvider { - storageProvider := &storagev1alpha1.StorageProvider{ +func FakeStorageProvider(name string, mutateFunc func(obj *dpv1alpha1.StorageProvider)) *dpv1alpha1.StorageProvider { + storageProvider := &dpv1alpha1.StorageProvider{ TypeMeta: metav1.TypeMeta{ - APIVersion: fmt.Sprintf("%s/%s", types.StorageAPIGroup, types.StorageAPIVersion), + APIVersion: fmt.Sprintf("%s/%s", types.DPAPIGroup, types.DPAPIVersion), Kind: "StorageProvider", }, ObjectMeta: metav1.ObjectMeta{ Name: name, }, - Spec: storagev1alpha1.StorageProviderSpec{ + Spec: dpv1alpha1.StorageProviderSpec{ CSIDriverName: "fake-csi-s3", CSIDriverSecretTemplate: ` accessKeyId: {{ index .Parameters "accessKeyId" }} @@ -1140,7 +1140,7 @@ region: {{ index .Parameters "region" }} endpoint: {{ index .Parameters "endpoint" }} mountOptions: {{ index .Parameters "mountOptions" | default "" }} `, - ParametersSchema: &storagev1alpha1.ParametersSchema{ + ParametersSchema: &dpv1alpha1.ParametersSchema{ OpenAPIV3Schema: &apiextensionsv1.JSONSchemaProps{ Type: "object", Properties: map[string]apiextensionsv1.JSONSchemaProps{ diff --git a/pkg/testing/testdata/class.yaml b/pkg/testing/testdata/class.yaml deleted file mode 100644 index 882b18789..000000000 --- a/pkg/testing/testdata/class.yaml +++ /dev/null @@ -1,57 +0,0 @@ -apiVersion: apps.kubeblocks.io/v1alpha1 -kind: ComponentClassDefinition -metadata: - name: kb.classes.default.apecloud-mysql.mysql - labels: - class.kubeblocks.io/provider: kubeblocks - apps.kubeblocks.io/component-def-ref: mysql - clusterdefinition.kubeblocks.io/name: apecloud-mysql -spec: - groups: - - # class schema template, you can set default resource values here - template: | - cpu: "{{ .cpu }}" - memory: "{{ .memory }}Gi" - # class schema template variables - vars: [ cpu, memory] - series: - - # class name generator, you can reference variables in class schema template - # it's also ok to define static class name in following class definitions - namingTemplate: "general-{{ .cpu }}c{{ .memory }}g" - - # class definitions, we support two kinds of class definitions: - # 1. define arguments for class schema variables, class schema will be dynamically generated - # 2. statically define complete class schema - classes: - - args: [ "1", "1"] - - args: [ "2", "2"] - - args: [ "2", "4"] - - args: [ "2", "8"] - - args: [ "4", "16"] - - args: [ "8", "32"] - - args: [ "16", "64"] - - args: [ "32", "128"] - - args: [ "64", "256"] - - args: [ "128", "512"] - - - template: | - cpu: "{{ .cpu }}" - memory: "{{ .memory }}Gi" - vars: [ cpu, memory] - series: - - namingTemplate: "mo-{{ .cpu }}c{{ .memory }}g" - classes: - - args: [ "2", "16"] - - args: [ "4", "32"] - - args: [ "8", "64"] - - args: [ "12", "96"] - - args: [ "24", "192"] - - args: [ "48", "384"] - - args: [ "2", "32"] - - args: [ "4", "64"] - - args: [ "8", "128"] - - args: [ "16", "256"] - - args: [ "32", "512"] - - args: [ "48", "768"] - - args: [ "64", "1024"] - - args: [ "128", "2048"] \ No newline at end of file diff --git a/pkg/testing/testdata/component_with_class_1c1g.yaml b/pkg/testing/testdata/component_with_class_1c1g.yaml deleted file mode 100644 index a5adfde07..000000000 --- a/pkg/testing/testdata/component_with_class_1c1g.yaml +++ /dev/null @@ -1,16 +0,0 @@ -- name: test - componentDefRef: mysql - monitor: true - enabledLogs: [error, slow] - replicas: 1 - classDefRef: - class: general-1c1g - volumeClaimTemplates: - - name: data - spec: - accessModes: - - ReadWriteOnce - resources: - requests: - storage: 1Gi - volumeMode: Filesystem \ No newline at end of file diff --git a/pkg/testing/testdata/component_with_invalid_class.yaml b/pkg/testing/testdata/component_with_invalid_class.yaml deleted file mode 100644 index d9f359f45..000000000 --- a/pkg/testing/testdata/component_with_invalid_class.yaml +++ /dev/null @@ -1,16 +0,0 @@ -- name: test - componentDefRef: mysql - monitor: true - enabledLogs: [error, slow] - replicas: 1 - classDefRef: - class: class-not-exists - volumeClaimTemplates: - - name: data - spec: - accessModes: - - ReadWriteOnce - resources: - requests: - storage: 1Gi - volumeMode: Filesystem \ No newline at end of file diff --git a/pkg/testing/testdata/component_with_invalid_resource.yaml b/pkg/testing/testdata/component_with_invalid_resource.yaml deleted file mode 100644 index efdc476b1..000000000 --- a/pkg/testing/testdata/component_with_invalid_resource.yaml +++ /dev/null @@ -1,18 +0,0 @@ -- name: test - componentDefRef: mysql - monitor: true - enabledLogs: [error, slow] - replicas: 1 - resources: - requests: - cpu: 3 - memory: 7Gi - volumeClaimTemplates: - - name: data - spec: - accessModes: - - ReadWriteOnce - resources: - requests: - storage: 1Gi - volumeMode: Filesystem \ No newline at end of file diff --git a/pkg/testing/testdata/component_with_resource_1c1g.yaml b/pkg/testing/testdata/component_with_resource_1c1g.yaml deleted file mode 100644 index cfdf53ae8..000000000 --- a/pkg/testing/testdata/component_with_resource_1c1g.yaml +++ /dev/null @@ -1,18 +0,0 @@ -- name: test - componentDefRef: mysql - monitor: true - enabledLogs: [error, slow] - replicas: 1 - resources: - requests: - cpu: 1 - memory: 1Gi - volumeClaimTemplates: - - name: data - spec: - accessModes: - - ReadWriteOnce - resources: - requests: - storage: 1Gi - volumeMode: Filesystem \ No newline at end of file diff --git a/pkg/testing/testdata/custom_class.yaml b/pkg/testing/testdata/custom_class.yaml deleted file mode 100644 index 3173d4181..000000000 --- a/pkg/testing/testdata/custom_class.yaml +++ /dev/null @@ -1,21 +0,0 @@ - - template: | - cpu: "{{ or .cpu 1 }}" - memory: "{{ or .memory 4 }}Gi" - vars: [cpu, memory] - series: - - namingTemplate: "custom-{{ .cpu }}c{{ .memory }}g" - classes: - - args: ["1", "1"] - - name: custom-4c16g - cpu: 4 - memory: 16Gi - - - template: | - cpu: "{{ or .cpu 1 }}" - memory: "{{ or .memory 4 }}Gi" - vars: [cpu, memory] - series: - - namingTemplate: "custom-{{ .cpu }}c{{ .memory }}g" - classes: - - args: ["2", "16"] - - args: ["4", "64"] diff --git a/pkg/testing/testdata/resource-constraint-general-without-selector.yaml b/pkg/testing/testdata/resource-constraint-general-without-selector.yaml deleted file mode 100644 index e8c0d7dd8..000000000 --- a/pkg/testing/testdata/resource-constraint-general-without-selector.yaml +++ /dev/null @@ -1,26 +0,0 @@ -apiVersion: apps.kubeblocks.io/v1alpha1 -kind: ComponentResourceConstraint -metadata: - name: kb-resource-constraint-general-without-selector - labels: - resourceconstraint.kubeblocks.io/provider: kubeblocks -spec: - rules: - - name: c1 - cpu: - min: 0.5 - max: 2 - step: 0.5 - memory: - sizePerCPU: 1Gi - - name: c2 - cpu: - min: 2 - max: 2 - memory: - sizePerCPU: 2Gi - - name: c3 - cpu: - slots: [2, 4, 8, 16, 24, 32, 48, 64, 96, 128] - memory: - sizePerCPU: 4Gi diff --git a/pkg/testing/testdata/resource-constraint-general.yaml b/pkg/testing/testdata/resource-constraint-general.yaml deleted file mode 100644 index fadbc67b0..000000000 --- a/pkg/testing/testdata/resource-constraint-general.yaml +++ /dev/null @@ -1,34 +0,0 @@ -apiVersion: apps.kubeblocks.io/v1alpha1 -kind: ComponentResourceConstraint -metadata: - name: kb-resource-constraint-general - labels: - resourceconstraint.kubeblocks.io/provider: kubeblocks -spec: - rules: - - name: c1 - cpu: - min: 0.5 - max: 2 - step: 0.5 - memory: - sizePerCPU: 1Gi - - name: c2 - cpu: - min: 2 - max: 2 - memory: - sizePerCPU: 2Gi - - name: c3 - cpu: - slots: [2, 4, 8, 16, 24, 32, 48, 64, 96, 128] - memory: - sizePerCPU: 4Gi - selector: - - clusterDefRef: apecloud-mysql - components: - - componentDefRef: mysql - rules: - - "c1" - - "c2" - - "c3" diff --git a/pkg/testing/testdata/resource-constraint-memory-optimized.yaml b/pkg/testing/testdata/resource-constraint-memory-optimized.yaml deleted file mode 100644 index 89db7f021..000000000 --- a/pkg/testing/testdata/resource-constraint-memory-optimized.yaml +++ /dev/null @@ -1,27 +0,0 @@ -apiVersion: apps.kubeblocks.io/v1alpha1 -kind: ComponentResourceConstraint -metadata: - name: kb-resource-constraint-memory-optimized - labels: - resourceconstraint.kubeblocks.io/provider: kubeblocks -spec: - rules: - - name: c1 - cpu: - slots: [2, 4, 8, 12, 24, 48] - memory: - sizePerCPU: 8Gi - - name: c2 - cpu: - min: 2 - max: 128 - step: 2 - memory: - sizePerCPU: 16Gi - selector: - - clusterDefRef: apecloud-mysql - components: - - componentDefRef: mysql - rules: - - "c1" - - "c2" diff --git a/pkg/types/config.go b/pkg/types/config.go index f0f303438..048275db7 100644 --- a/pkg/types/config.go +++ b/pkg/types/config.go @@ -27,7 +27,4 @@ const ( CfgKeyClusterDefaultMemory = "CLUSTER_DEFAULT_MEMORY" CfgKeyHelmRepoURL = "HELM_REPO_URL" CfgKeyImageRegistry = "IMAGE_REGISTRY" - CfgKeyOpenAPIServer = "OPENAPI_SERVER" - CfgKeyAuthURL = "AUTH_URL" - CfgKeyClientID = "CLIENT_ID" ) diff --git a/pkg/types/migrationapi/migration_object_express.go b/pkg/types/migrationapi/migration_object_express.go deleted file mode 100644 index 2498cc755..000000000 --- a/pkg/types/migrationapi/migration_object_express.go +++ /dev/null @@ -1,96 +0,0 @@ -/* -Copyright (C) 2022-2024 ApeCloud Co., Ltd - -This file is part of KubeBlocks project - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU Affero General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU Affero General Public License for more details. - -You should have received a copy of the GNU Affero General Public License -along with this program. If not, see . -*/ - -package v1alpha1 - -import ( - "fmt" - "strings" -) - -type MigrationObjectExpress struct { - WhiteList []DBObjectExpress `json:"whiteList"` - // +optional - BlackList []DBObjectExpress `json:"blackList"` -} - -func (m *MigrationObjectExpress) String(isWhite bool) string { - expressArr := m.WhiteList - if !isWhite { - expressArr = m.BlackList - } - stringArr := make([]string, 0) - for _, db := range expressArr { - stringArr = append(stringArr, db.String()...) - } - return strings.Join(stringArr, ",") -} - -type DBObjectExpress struct { - SchemaName string `json:"schemaName"` - // +optional - SchemaMappingName string `json:"schemaMappingName"` - // +optional - IsAll bool `json:"isAll"` - // +optional - TableList []TableObjectExpress `json:"tableList"` - DxlOpConfig `json:""` -} - -func (d *DBObjectExpress) String() []string { - stringArr := make([]string, 0) - if d.IsAll { - stringArr = append(stringArr, d.SchemaName) - } else { - for _, tb := range d.TableList { - stringArr = append(stringArr, fmt.Sprintf("%s.%s", d.SchemaName, tb.TableName)) - } - } - return stringArr -} - -type TableObjectExpress struct { - TableName string `json:"tableName"` - // +optional - TableMappingName string `json:"tableMappingName"` - // +optional - IsAll bool `json:"isAll"` - // +optional - FieldList []FieldObjectExpress `json:"fieldList"` - DxlOpConfig `json:""` -} - -type FieldObjectExpress struct { - FieldName string `json:"fieldName"` - // +optional - FieldMappingName string `json:"fieldMappingName"` -} - -type DxlOpConfig struct { - // +optional - DmlOp []DMLOpEnum `json:"dmlOp"` - // +optional - DdlOp []DDLOpEnum `json:"ddlOp"` - // +optional - DclOp []DCLOpEnum `json:"dclOp"` -} - -func (op *DxlOpConfig) IsEmpty() bool { - return len(op.DmlOp) == 0 -} diff --git a/pkg/types/migrationapi/migrationtask_types.go b/pkg/types/migrationapi/migrationtask_types.go deleted file mode 100644 index eeb96babd..000000000 --- a/pkg/types/migrationapi/migrationtask_types.go +++ /dev/null @@ -1,156 +0,0 @@ -/* -Copyright (C) 2022-2024 ApeCloud Co., Ltd - -This file is part of KubeBlocks project - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU Affero General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU Affero General Public License for more details. - -You should have received a copy of the GNU Affero General Public License -along with this program. If not, see . -*/ - -package v1alpha1 - -import ( - v1 "k8s.io/api/core/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" -) - -// MigrationTaskSpec defines the desired state of MigrationTask -type MigrationTaskSpec struct { - TaskType TaskTypeEnum `json:"taskType,omitempty"` - Template string `json:"template"` - SourceEndpoint Endpoint `json:"sourceEndpoint,omitempty"` - SinkEndpoint Endpoint `json:"sinkEndpoint,omitempty"` - // +optional - Cdc CdcConfig `json:"cdc,omitempty"` - // +optional - Initialization InitializationConfig `json:"initialization,omitempty"` - MigrationObj MigrationObjectExpress `json:"migrationObj,omitempty"` - // +optional - IsForceDelete bool `json:"isForceDelete,omitempty"` - // +optional - GlobalTolerations []v1.Toleration `json:"globalTolerations,omitempty"` - // +optional - GlobalResources v1.ResourceRequirements `json:"globalResources,omitempty"` -} - -type Endpoint struct { - // +optional - EndpointType EndpointTypeEnum `json:"endpointType,omitempty"` - Address string `json:"address"` - // +optional - DatabaseName string `json:"databaseName,omitempty"` - // +optional - UserName string `json:"userName"` - // +optional - Password string `json:"password"` - // +optional - Secret UserPswSecret `json:"secret"` -} - -type UserPswSecret struct { - Name string `json:"name"` - // +optional - Namespace string `json:"namespace,omitempty"` - // +optional - UserKeyword string `json:"userKeyword,omitempty"` - // +optional - PasswordKeyword string `json:"passwordKeyword,omitempty"` -} - -type CdcConfig struct { - // +optional - Config BaseConfig `json:"config"` -} - -type InitializationConfig struct { - // +optional - Steps []StepEnum `json:"steps,omitempty"` - // +optional - Config map[StepEnum]BaseConfig `json:"config,omitempty"` -} - -type BaseConfig struct { - // +optional - Resource v1.ResourceRequirements `json:"resource,omitempty"` - // +optional - Tolerations []v1.Toleration `json:"tolerations,omitempty"` - // +optional - // +kubebuilder:pruning:PreserveUnknownFields - // +kubebuilder:validation:Schemaless - Param IntOrStringMap `json:"param"` - // +optional - PersistentVolumeClaimName string `json:"persistentVolumeClaimName"` - // +optional - Metrics Metrics `json:"metrics,omitempty"` -} - -// MigrationTaskStatus defines the observed state of MigrationTask -type MigrationTaskStatus struct { - // +optional - TaskStatus TaskStatus `json:"taskStatus"` - // +optional - StartTime *metav1.Time `json:"startTime"` - // +optional - FinishTime *metav1.Time `json:"finishTime"` - // +optional - Cdc RunTimeStatus `json:"cdc"` - // +optional - Initialization RunTimeStatus `json:"initialization"` -} - -type RunTimeStatus struct { - // +optional - StartTime *metav1.Time `json:"startTime"` - // +optional - FinishTime *metav1.Time `json:"finishTime"` - // +optional - // +kubebuilder:pruning:PreserveUnknownFields - // +kubebuilder:validation:Schemaless - RunTimeParam IntOrStringMap `json:"runTimeParam,omitempty"` - // +optional - // +kubebuilder:pruning:PreserveUnknownFields - // +kubebuilder:validation:Schemaless - Metrics IntOrStringMap `json:"metrics,omitempty"` - // +optional - FailedReason string `json:"failedReason,omitempty"` -} - -// +kubebuilder:object:root=true -// +kubebuilder:subresource:status -// +kubebuilder:resource:categories={dtplatform},scope=Cluster,shortName=mt -// +kubebuilder:printcolumn:name="TEMPLATE",type="string",JSONPath=".spec.template",description="spec migration template" -// +kubebuilder:printcolumn:name="STATUS",type="string",JSONPath=".status.taskStatus",description="status taskStatus" -// +kubebuilder:printcolumn:name="AGE",type="date",JSONPath=".metadata.creationTimestamp" - -// MigrationTask is the Schema for the migrationTasks API -type MigrationTask struct { - metav1.TypeMeta `json:",inline"` - metav1.ObjectMeta `json:"metadata,omitempty"` - - Spec MigrationTaskSpec `json:"spec,omitempty"` - Status MigrationTaskStatus `json:"status,omitempty"` -} - -// +kubebuilder:object:root=true - -// MigrationTaskList contains a list of MigrationTask -type MigrationTaskList struct { - metav1.TypeMeta `json:",inline"` - metav1.ListMeta `json:"metadata,omitempty"` - Items []MigrationTask `json:"items"` -} - -type Metrics struct { - IsDisable bool `json:"isDisable,omitempty"` - PeriodSeconds int32 `json:"periodSeconds,omitempty"` -} diff --git a/pkg/types/migrationapi/migrationtemplate_types.go b/pkg/types/migrationapi/migrationtemplate_types.go deleted file mode 100644 index d8567d491..000000000 --- a/pkg/types/migrationapi/migrationtemplate_types.go +++ /dev/null @@ -1,106 +0,0 @@ -/* -Copyright (C) 2022-2024 ApeCloud Co., Ltd - -This file is part of KubeBlocks project - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU Affero General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU Affero General Public License for more details. - -You should have received a copy of the GNU Affero General Public License -along with this program. If not, see . -*/ - -package v1alpha1 - -import ( - v1 "k8s.io/api/core/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" -) - -// MigrationTemplateSpec defines the desired state of MigrationTemplate -type MigrationTemplateSpec struct { - TaskType []TaskTypeEnum `json:"taskType,omitempty"` - Source DBTypeSupport `json:"source"` - Sink DBTypeSupport `json:"target"` - Initialization InitializationModel `json:"initialization,omitempty"` - Cdc CdcModel `json:"cdc,omitempty"` - // +optional - Description string `json:"description,omitempty"` - // +optional - Decorator string `json:"decorator,omitempty"` -} - -type DBTypeSupport struct { - DBType DBTypeEnum `json:"dbType"` - DBVersion string `json:"dbVersion"` -} - -type InitializationModel struct { - // +optional - IsPositionPreparation bool `json:"isPositionPreparation,omitempty"` - Steps []StepModel `json:"steps,omitempty"` -} - -type StepModel struct { - Step StepEnum `json:"step"` - Container BasicContainerTemplate `json:"container"` - // +optional - // +kubebuilder:pruning:PreserveUnknownFields - // +kubebuilder:validation:Schemaless - Param IntOrStringMap `json:"param"` -} - -type CdcModel struct { - Container BasicContainerTemplate `json:"container"` - // +optional - Replicas *int32 `json:"replicas,omitempty"` - // +optional - // +kubebuilder:pruning:PreserveUnknownFields - // +kubebuilder:validation:Schemaless - Param IntOrStringMap `json:"param"` -} - -type BasicContainerTemplate struct { - Image string `json:"image"` - // +optional - Command []string `json:"command,omitempty"` - // +optional - Env []v1.EnvVar `json:"env,omitempty"` -} - -// MigrationTemplateStatus defines the observed state of MigrationTemplate -type MigrationTemplateStatus struct { - Phase Phase `json:"phase,omitempty"` -} - -// +kubebuilder:object:root=true -// +kubebuilder:subresource:status -// +kubebuilder:resource:categories={dtplatform},scope=Cluster,shortName=mtp -// +kubebuilder:printcolumn:name="DATABASE-MAPPING",type="string",JSONPath=".spec.description",description="the database mapping that supported" -// +kubebuilder:printcolumn:name="STATUS",type="string",JSONPath=".status.phase",description="the template status" -// +kubebuilder:printcolumn:name="AGE",type="date",JSONPath=".metadata.creationTimestamp" - -// MigrationTemplate is the Schema for the migrationtemplates API -type MigrationTemplate struct { - metav1.TypeMeta `json:",inline"` - metav1.ObjectMeta `json:"metadata,omitempty"` - - Spec MigrationTemplateSpec `json:"spec,omitempty"` - Status MigrationTemplateStatus `json:"status,omitempty"` -} - -// +kubebuilder:object:root=true - -// MigrationTemplateList contains a list of MigrationTemplate -type MigrationTemplateList struct { - metav1.TypeMeta `json:",inline"` - metav1.ListMeta `json:"metadata,omitempty"` - Items []MigrationTemplate `json:"items"` -} diff --git a/pkg/types/migrationapi/type.go b/pkg/types/migrationapi/type.go deleted file mode 100644 index 32f8cca94..000000000 --- a/pkg/types/migrationapi/type.go +++ /dev/null @@ -1,213 +0,0 @@ -/* -Copyright (C) 2022-2024 ApeCloud Co., Ltd - -This file is part of KubeBlocks project - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU Affero General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU Affero General Public License for more details. - -You should have received a copy of the GNU Affero General Public License -along with this program. If not, see . -*/ - -package v1alpha1 - -import ( - "strings" - - appv1 "k8s.io/api/apps/v1" - batchv1 "k8s.io/api/batch/v1" - v1 "k8s.io/api/core/v1" - "k8s.io/apimachinery/pkg/runtime" -) - -// DBTypeEnum defines the MigrationTemplate CR .spec.Source.DbType or .spec.Sink.DbType -// +enum -// +kubebuilder:validation:Enum={MySQL, PostgreSQL} -type DBTypeEnum string - -const ( - MigrationDBTypeMySQL DBTypeEnum = "MySQL" // default value - MigrationDBTypePostgreSQL DBTypeEnum = "PostgreSQL" -) - -func (d DBTypeEnum) String() string { - return string(d) -} - -// TaskTypeEnum defines the MigrationTask CR .spec.taskType -// +enum -// +kubebuilder:validation:Enum={initialization,cdc,initialization-and-cdc,initialization-and-twoway-cdc} -type TaskTypeEnum string - -const ( - Initialization TaskTypeEnum = "initialization" - CDC TaskTypeEnum = "cdc" - InitializationAndCdc TaskTypeEnum = "initialization-and-cdc" // default value -) - -// EndpointTypeEnum defines the MigrationTask CR .spec.source.endpointType and .spec.sink.endpointType -// +enum -// +kubebuilder:validation:Enum={address} -type EndpointTypeEnum string - -const ( - AddressDirectConnect EndpointTypeEnum = "address" // default value -) - -// non-use yet - -type ConflictPolicyEnum string - -const ( - Ignore ConflictPolicyEnum = "ignore" // default in FullLoad - Override ConflictPolicyEnum = "override" // default in CDC -) - -// DMLOpEnum defines the MigrationTask CR .spec.migrationObj -// +enum -// +kubebuilder:validation:Enum={all,none,insert,update,delete} -type DMLOpEnum string - -const ( - AllDML DMLOpEnum = "all" - NoneDML DMLOpEnum = "none" - Insert DMLOpEnum = "insert" - Update DMLOpEnum = "update" - Delete DMLOpEnum = "delete" -) - -// DDLOpEnum defines the MigrationTask CR .spec.migrationObj -// +enum -// +kubebuilder:validation:Enum={all,none} -type DDLOpEnum string - -const ( - AllDDL DDLOpEnum = "all" - NoneDDL DDLOpEnum = "none" -) - -// DCLOpEnum defines the MigrationTask CR .spec.migrationObj -// +enum -// +kubebuilder:validation:Enum={all,none} -type DCLOpEnum string - -const ( - AllDCL DDLOpEnum = "all" - NoneDCL DDLOpEnum = "none" -) - -// TaskStatus defines the MigrationTask CR .status.taskStatus -// +enum -// +kubebuilder:validation:Enum={Prepare,InitPrepared,Init,InitFinished,Running,Cached,Pause,Done} -type TaskStatus string - -const ( - PrepareStatus TaskStatus = "Prepare" - InitPrepared TaskStatus = "InitPrepared" - InitStatus TaskStatus = "Init" - InitFinished TaskStatus = "InitFinished" - RunningStatus TaskStatus = "Running" - CachedStatus TaskStatus = "Cached" - PauseStatus TaskStatus = "Pause" - DoneStatus TaskStatus = "Done" -) - -// StepEnum defines the MigrationTask CR .spec.steps -// +enum -// +kubebuilder:validation:Enum={preCheck,initStruct,initData,initStructLater} -type StepEnum string - -const ( - StepPreCheck StepEnum = "preCheck" - StepStructPreFullLoad StepEnum = "initStruct" - StepFullLoad StepEnum = "initData" - StepStructAfterFullLoad StepEnum = "initStructLater" - StepInitialization StepEnum = "initialization" - StepPreDelete StepEnum = "preDelete" - StepCdc StepEnum = "cdc" -) - -func (s StepEnum) String() string { - return string(s) -} - -func (s StepEnum) LowerCaseString() string { - return strings.ToLower(s.String()) -} - -func (s StepEnum) CliString() string { - switch s { - case StepPreCheck: - return CliStepPreCheck.String() - case StepStructPreFullLoad: - return CliStepInitStruct.String() - case StepFullLoad: - return CliStepInitData.String() - case StepCdc: - return CliStepCdc.String() - default: - return "unknown" - } -} - -type CliStepEnum string - -const ( - CliStepGlobal CliStepEnum = "global" - CliStepPreCheck CliStepEnum = "precheck" - CliStepInitStruct CliStepEnum = "init-struct" - CliStepInitData CliStepEnum = "init-data" - CliStepCdc CliStepEnum = "cdc" -) - -func (s CliStepEnum) String() string { - return string(s) -} - -// Phase defines the MigrationTemplate CR .status.phase -// +enum -// +kubebuilder:validation:Enum={Available,Unavailable} -type Phase string - -const ( - AvailablePhase Phase = "Available" - UnavailablePhase Phase = "Unavailable" -) - -type MigrationObjects struct { - Task *MigrationTask - Template *MigrationTemplate - - Jobs *batchv1.JobList - Pods *v1.PodList - StatefulSets *appv1.StatefulSetList -} - -// +k8s:deepcopy-gen=false - -type IntOrStringMap map[string]interface{} - -func (in *IntOrStringMap) DeepCopyInto(out *IntOrStringMap) { - if in == nil { - *out = nil - } else { - *out = runtime.DeepCopyJSON(*in) - } -} - -func (in *IntOrStringMap) DeepCopy() *IntOrStringMap { - if in == nil { - return nil - } - out := new(IntOrStringMap) - in.DeepCopyInto(out) - return out -} diff --git a/pkg/types/types.go b/pkg/types/types.go index 958739cc7..0940c00c4 100644 --- a/pkg/types/types.go +++ b/pkg/types/types.go @@ -100,6 +100,7 @@ const ( const ( AppsAPIGroup = "apps.kubeblocks.io" AppsAPIVersion = "v1alpha1" + AppsAPIBetaVersion = "v1beta1" ResourcePods = "pods" ResourceClusters = "clusters" ResourceClusterDefs = "clusterdefinitions" @@ -154,8 +155,6 @@ const ( // Labels const ( - ClassProviderLabelKey = "class.kubeblocks.io/provider" - AddonProviderLabelKey = "addon.kubeblocks.io/provider" // ProviderLabelKey was used as the label for addon providers before version 0.8.0 ProviderLabelKey = "kubeblocks.io/provider" @@ -191,14 +190,6 @@ const ( ResourceStorageProviders = "storageproviders" ) -// Migration API group -const ( - MigrationAPIGroup = "datamigration.apecloud.io" - MigrationAPIVersion = "v1alpha1" - ResourceMigrationTasks = "migrationtasks" - ResourceMigrationTemplates = "migrationtemplates" -) - // Crd Api group const ( CustomResourceDefinitionAPIGroup = "apiextensions.k8s.io" @@ -215,6 +206,7 @@ const ( ResourceYcsb = "ycsbs" ResourceTpcc = "tpccs" ResourceTpch = "tpches" + ResourceTpcds = "tpcds" ResourceRedisBench = "redisbenches" ) @@ -235,6 +227,15 @@ const ( ImageRegistryKey = "image.registry" ) +// Migrate some const from kubeblocks to kbcli +const ( + // KBDefaultClusterVersionAnnotationKey specifies the default cluster version. + KBDefaultClusterVersionAnnotationKey = "kubeblocks.io/is-default-cluster-version" + + // KBAddonProviderLabelKey marks the addon provider + KBAddonProviderLabelKey = "kubeblocks.io/provider" +) + var ( // KubeBlocksRepoName helm repo name for kubeblocks KubeBlocksRepoName = "kubeblocks" @@ -345,6 +346,10 @@ func AddonGVR() schema.GroupVersionResource { } func StorageProviderGVR() schema.GroupVersionResource { + return schema.GroupVersionResource{Group: DPAPIGroup, Version: DPAPIVersion, Resource: ResourceStorageProviders} +} + +func LegacyStorageProviderGVR() schema.GroupVersionResource { return schema.GroupVersionResource{Group: StorageAPIGroup, Version: StorageAPIVersion, Resource: ResourceStorageProviders} } @@ -401,6 +406,10 @@ func PVGVR() schema.GroupVersionResource { } func ConfigConstraintGVR() schema.GroupVersionResource { + return schema.GroupVersionResource{Group: AppsAPIGroup, Version: AppsAPIBetaVersion, Resource: ResourceConfigConstraintVersions} +} + +func ConfigConstraintOldGVR() schema.GroupVersionResource { return schema.GroupVersionResource{Group: AppsAPIGroup, Version: AppsAPIVersion, Resource: ResourceConfigConstraintVersions} } @@ -455,22 +464,6 @@ func ServiceAccountGVR() schema.GroupVersionResource { return schema.GroupVersionResource{Group: corev1.GroupName, Version: K8sCoreAPIVersion, Resource: ServiceAccounts} } -func MigrationTaskGVR() schema.GroupVersionResource { - return schema.GroupVersionResource{ - Group: MigrationAPIGroup, - Version: MigrationAPIVersion, - Resource: ResourceMigrationTasks, - } -} - -func MigrationTemplateGVR() schema.GroupVersionResource { - return schema.GroupVersionResource{ - Group: MigrationAPIGroup, - Version: MigrationAPIVersion, - Resource: ResourceMigrationTemplates, - } -} - func CustomResourceDefinitionGVR() schema.GroupVersionResource { return schema.GroupVersionResource{ Group: CustomResourceDefinitionAPIGroup, @@ -506,6 +499,10 @@ func TpchGVR() schema.GroupVersionResource { return schema.GroupVersionResource{Group: KubebenchAPIGroup, Version: KubebenchAPIVersion, Resource: ResourceTpch} } +func TpcdsGVR() schema.GroupVersionResource { + return schema.GroupVersionResource{Group: KubebenchAPIGroup, Version: KubebenchAPIVersion, Resource: ResourceTpcds} +} + func RedisBenchGVR() schema.GroupVersionResource { return schema.GroupVersionResource{Group: KubebenchAPIGroup, Version: KubebenchAPIVersion, Resource: ResourceRedisBench} } diff --git a/pkg/util/breakingchange/upgradehandlerto0.7.go b/pkg/util/breakingchange/upgradehandlerto0.7.go index 6c3a88d42..0c3cdf003 100644 --- a/pkg/util/breakingchange/upgradehandlerto0.7.go +++ b/pkg/util/breakingchange/upgradehandlerto0.7.go @@ -462,7 +462,7 @@ func (u *upgradeHandlerTo7) transformStatefulSet(dynamic dynamic.Interface, obj return nil } // create a rsm - serviceName, _, _ := unstructured.NestedString(obj.Object, "spec", "serviceName") + // serviceName, _, _ := unstructured.NestedString(obj.Object, "spec", "serviceName") matchLabels, _, _ := unstructured.NestedStringMap(obj.Object, "spec", "selector", "matchLabels") replicas, _, _ := unstructured.NestedInt64(obj.Object, "spec", "replicas") podManagementPolicy, _, _ := unstructured.NestedString(obj.Object, "spec", "podManagementPolicy") @@ -482,10 +482,10 @@ func (u *upgradeHandlerTo7) transformStatefulSet(dynamic dynamic.Interface, obj return err } updateStrategy, _, _ := unstructured.NestedString(obj.Object, "spec", "updateStrategy") - rsm := builder.NewReplicatedStateMachineBuilder(obj.GetNamespace(), obj.GetName()). + rsm := builder.NewInstanceSetBuilder(obj.GetNamespace(), obj.GetName()). AddAnnotationsInMap(obj.GetAnnotations()). AddLabelsInMap(obj.GetLabels()). - SetServiceName(serviceName). + // SetServiceName(serviceName). AddMatchLabelsInMap(matchLabels). SetReplicas(int32(replicas)). SetPodManagementPolicy(v1.PodManagementPolicyType(podManagementPolicy)). diff --git a/pkg/util/breakingchange/upgrader.go b/pkg/util/breakingchange/upgrader.go index 9a51161fa..46f8b8046 100644 --- a/pkg/util/breakingchange/upgrader.go +++ b/pkg/util/breakingchange/upgrader.go @@ -61,14 +61,14 @@ func registerUpgradeHandler(fromVersions []string, toVersion string, upgradeHand var majorMinorFromVersions []string for _, v := range fromVersions { - majorMinorFromVersion := getMajorMinorVersion(v) + majorMinorFromVersion := GetMajorMinorVersion(v) if majorMinorFromVersion == "" { panic(formatErr(v)) } majorMinorFromVersions = append(majorMinorFromVersions, majorMinorFromVersion) } - majorMinorToVersion := getMajorMinorVersion(toVersion) + majorMinorToVersion := GetMajorMinorVersion(toVersion) if majorMinorToVersion == "" { panic(formatErr(toVersion)) } @@ -80,8 +80,8 @@ func registerUpgradeHandler(fromVersions []string, toVersion string, upgradeHand // getUpgradeHandler gets the upgrade handler according to fromVersion and toVersion from upgradeHandlerMapper. func getUpgradeHandler(fromVersion, toVersion string) upgradeHandler { - majorMinorFromVersion := getMajorMinorVersion(fromVersion) - majorMinorToVersion := getMajorMinorVersion(toVersion) + majorMinorFromVersion := GetMajorMinorVersion(fromVersion) + majorMinorToVersion := GetMajorMinorVersion(toVersion) handlerRecorder, ok := upgradeHandlerMapper[majorMinorToVersion] if !ok { return nil @@ -123,7 +123,7 @@ func ValidateUpgradeVersion(fromVersion, toVersion string) error { return nil } -func getMajorMinorVersion(version string) string { +func GetMajorMinorVersion(version string) string { vs := strings.Split(version, ".") if len(vs) < 2 { return "" diff --git a/pkg/util/conversion/conversion.go b/pkg/util/conversion/conversion.go new file mode 100644 index 000000000..69dbef29e --- /dev/null +++ b/pkg/util/conversion/conversion.go @@ -0,0 +1,133 @@ +/* +Copyright (C) 2022-2024 ApeCloud Co., Ltd + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package conversion + +import ( + "fmt" + + appsv1alpha1 "github.com/apecloud/kubeblocks/apis/apps/v1alpha1" + appsv1beta1 "github.com/apecloud/kubeblocks/apis/apps/v1beta1" + "github.com/apecloud/kubeblocks/pkg/constant" + apierrors "k8s.io/apimachinery/pkg/api/errors" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" + apiruntime "k8s.io/apimachinery/pkg/runtime" + "k8s.io/client-go/dynamic" + "k8s.io/klog/v2" + "sigs.k8s.io/controller-runtime/pkg/client" + + "github.com/apecloud/kbcli/pkg/types" + "github.com/apecloud/kbcli/pkg/util" +) + +const ( + OldVersion = "08" + NewVersion = "09" +) + +func FetchAndConversionResources(versionMeta *VersionConversionMeta) ([]unstructured.Unstructured, error) { + var resources []unstructured.Unstructured + + if versionMeta.FromVersion == versionMeta.ToVersion { + return nil, nil + } + + if versionMeta.FromVersion != OldVersion || versionMeta.ToVersion != NewVersion { + klog.V(1).Infof("not to convert configconstraint multiversion") + return nil, nil + } + + oldResources, err := ResourcesWithGVR(versionMeta, types.ConfigConstraintOldGVR(), metav1.ListOptions{}) + if err != nil { + return nil, err + } + for _, oldObj := range oldResources { + newObj := appsv1beta1.ConfigConstraint{ + TypeMeta: metav1.TypeMeta{ + Kind: types.KindConfigConstraint, + APIVersion: types.ConfigConstraintGVR().GroupVersion().String(), + }, + } + klog.V(1).Infof("convert configconstraint[%s] cr from v1alpha1 to v1beta1", oldObj.GetName()) + // If v1alpha1 is converted from v1beta1 version + if hasConversionVersion(&oldObj) { + klog.V(1).Infof("configconstraint[%s] v1alpha1 is converted from v1beta1 version and ignore.", + client.ObjectKeyFromObject(&oldObj).String()) + continue + } + // If the converted version v1beta1 already exists + if hasValidBetaVersion(&oldObj, versionMeta) { + klog.V(1).Infof("configconstraint[%s] v1beta1 already exist and ignore.", + client.ObjectKeyFromObject(&oldObj).String()) + continue + } + if err := oldObj.ConvertTo(&newObj); err != nil { + return nil, err + } + item, err := apiruntime.DefaultUnstructuredConverter.ToUnstructured(&newObj) + if err != nil { + return nil, err + } + resources = append(resources, unstructured.Unstructured{Object: item}) + } + return resources, nil +} + +func hasValidBetaVersion(obj *appsv1alpha1.ConfigConstraint, dynamic dynamic.Interface) bool { + newObj := appsv1beta1.ConfigConstraint{} + if err := util.GetResourceObjectFromGVR(types.ConfigConstraintGVR(), client.ObjectKeyFromObject(obj), dynamic, &newObj); err != nil { + return false + } + + return hasConversionVersion(&newObj) +} + +func hasConversionVersion(obj client.Object) bool { + annotations := obj.GetAnnotations() + if len(annotations) == 0 { + return false + } + return annotations[constant.KubeblocksAPIConversionTypeAnnotationName] == constant.MigratedAPIVersion +} + +func UpdateNewVersionResources(versionMeta *VersionConversionMeta, targetObjects []unstructured.Unstructured) error { + if len(targetObjects) == 0 { + return nil + } + if versionMeta.FromVersion == versionMeta.ToVersion { + return nil + } + + for _, unstructuredObj := range targetObjects { + klog.V(1).Infof("update CR %s", unstructuredObj.GetName()) + _, err := versionMeta.Resource(types.ConfigConstraintGVR()). + Update(versionMeta.Ctx, &unstructuredObj, metav1.UpdateOptions{}) + if err != nil { + if apierrors.IsNotFound(err) { + if _, err := versionMeta.Resource(types.ConfigConstraintGVR()). + Create(versionMeta.Ctx, &unstructuredObj, metav1.CreateOptions{}); err != nil { + klog.V(1).ErrorS(err, "failed to create configConstraint") + return err + } + continue + } + klog.V(1).ErrorS(err, fmt.Sprintf("failed to update configconstraint cr[%v]", unstructuredObj.GetName())) + return err + } + } + return nil +} diff --git a/pkg/util/conversion/types.go b/pkg/util/conversion/types.go new file mode 100644 index 000000000..a53e81a4e --- /dev/null +++ b/pkg/util/conversion/types.go @@ -0,0 +1,46 @@ +/* +Copyright (C) 2022-2024 ApeCloud Co., Ltd + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package conversion + +import ( + "context" + + "k8s.io/client-go/dynamic" + + "github.com/apecloud/kbcli/pkg/util/breakingchange" +) + +type VersionConversionMeta struct { + dynamic.Interface + Ctx context.Context + + FromVersion string + ToVersion string +} + +func (version VersionConversionMeta) NeedConversion() bool { + return version.FromVersion != version.ToVersion +} + +func NewVersionConversion(dynamic dynamic.Interface, fromVersion, toVersion string) *VersionConversionMeta { + return &VersionConversionMeta{ + Ctx: context.Background(), + Interface: dynamic, + FromVersion: breakingchange.GetMajorMinorVersion(fromVersion), + ToVersion: breakingchange.GetMajorMinorVersion(toVersion), + } +} diff --git a/pkg/util/conversion/utils.go b/pkg/util/conversion/utils.go new file mode 100644 index 000000000..3fbee5f92 --- /dev/null +++ b/pkg/util/conversion/utils.go @@ -0,0 +1,41 @@ +/* +Copyright (C) 2022-2024 ApeCloud Co., Ltd + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package conversion + +import ( + appsv1alpha1 "github.com/apecloud/kubeblocks/apis/apps/v1alpha1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + apiruntime "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" +) + +func ResourcesWithGVR(versionMeta *VersionConversionMeta, gvr schema.GroupVersionResource, listOptions metav1.ListOptions) ([]appsv1alpha1.ConfigConstraint, error) { + var resourcesList []appsv1alpha1.ConfigConstraint + + objList, err := versionMeta.Resource(gvr).List(versionMeta.Ctx, listOptions) + if err != nil { + return nil, err + } + for _, v := range objList.Items { + obj := appsv1alpha1.ConfigConstraint{} + if err := apiruntime.DefaultUnstructuredConverter.FromUnstructured(v.Object, &obj); err != nil { + return nil, err + } + resourcesList = append(resourcesList, obj) + } + return resourcesList, nil +} diff --git a/pkg/util/helm/diff.go b/pkg/util/helm/diff.go index 270053ec6..5a8f8100b 100644 --- a/pkg/util/helm/diff.go +++ b/pkg/util/helm/diff.go @@ -42,7 +42,6 @@ import ( const k8sCRD = "CustomResourceDefinition" const TYPE = "type" const PROPERTIES = "properties" -const ADDITIONALPROPERTIES = "additionalProperties" const REQUIRED = "required" // APIPath is the key name to record the API fullpath diff --git a/pkg/util/provider.go b/pkg/util/provider.go index 86d0c3aee..9dc64c442 100644 --- a/pkg/util/provider.go +++ b/pkg/util/provider.go @@ -26,7 +26,15 @@ import ( corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/util/sets" "k8s.io/client-go/kubernetes" + "k8s.io/klog/v2" +) + +const ( + topologyRegionLabel = "topology.kubernetes.io/region" + + dockerRegistry = "docker.io" ) type K8sProvider string @@ -160,3 +168,95 @@ func GetK8sSemVer(version string) string { } return removeFirstChart(strArr[0]) } + +// GetImageRegistryByProvider returns the image registry based on the k8s provider, +// for different providers, we will use different image registry. +// +// Now, KubeBlocks has two image registries: docker.io and infracreate-registry.cn-zhangjiakou.cr.aliyuncs.com. +// KubeBlocks default image registry is infracreate-registry.cn-zhangjiakou.cr.aliyuncs.com, +// for some providers, or some regions, we should use docker.io as the image registry. +func GetImageRegistryByProvider(client kubernetes.Interface) (string, error) { + v, err := GetK8sVersion(client.Discovery()) + if err != nil { + return "", err + } + + getImageRegistryByProvider := func(p K8sProvider) string { + switch p { + case GKEProvider: + return dockerRegistry + case UnknownProvider, KINDProvider, K3SProvider: + return "" + default: + return "" + } + } + + var nodes *corev1.NodeList + provider := GetK8sProviderFromVersion(v) + if provider == UnknownProvider { + nodes, err = client.CoreV1().Nodes().List(context.Background(), metav1.ListOptions{}) + if err != nil { + klog.Info("Failed to get nodes list", err) + return "", err + } + provider = GetK8sProviderFromNodes(nodes) + } + + // get image registry by kubernetes provider + registry := getImageRegistryByProvider(provider) + if registry != "" { + return registry, nil + } + + // can not get image registry by provider, get it by region + if nodes == nil { + nodes, err = client.CoreV1().Nodes().List(context.Background(), metav1.ListOptions{}) + if err != nil { + klog.Info("Failed to get nodes list", err) + return "", err + } + } + + getRegion := func() string { + for _, node := range nodes.Items { + region := node.Labels[topologyRegionLabel] + if region != "" { + return region + } + } + return "" + } + + region := getRegion() + if region == "" { + klog.Info("Failed to get region from nodes") + return "", nil + } + + // Region info: + // aws: https://docs.aws.amazon.com/zh_cn/AWSEC2/latest/UserGuide/using-regions-availability-zones.html + // there are two regions in China: cn-north-1, cn-northwest-1 + // aliyun: https://help.aliyun.com/document_detail/40654.html + // azure: https://azure.microsoft.com/en-us/explore/global-infrastructure/data-residency/#select-geography + // huawei: https://developer.huaweicloud.com/endpoint + // tencent: https://www.tencentcloud.com/zh/document/product/213/6091 + switch provider { + case GKEProvider: + registry = dockerRegistry + case EKSProvider, ACKProvider: + if !strings.HasPrefix(region, "cn-") { + registry = dockerRegistry + } + case AKSProvider: + if !strings.HasPrefix(region, "china") { + registry = dockerRegistry + } + case TKEProvider: + cnRegions := sets.New("ap-guangzhou", "ap-shanghai", "ap-nanjing", "ap-beijing", "ap-chengdu", "ap-chongqing") + if !cnRegions.Has(region) { + registry = dockerRegistry + } + } + return registry, nil +} diff --git a/pkg/util/provider_test.go b/pkg/util/provider_test.go index a7891cfb7..ae9bc733a 100644 --- a/pkg/util/provider_test.go +++ b/pkg/util/provider_test.go @@ -26,16 +26,20 @@ import ( . "github.com/onsi/gomega" corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "github.com/apecloud/kbcli/pkg/testing" ) var _ = Describe("provider util", func() { - buildNodes := func(provider string) *corev1.NodeList { + buildNodes := func(provider string, labels map[string]string) *corev1.NodeList { return &corev1.NodeList{ Items: []corev1.Node{ { + ObjectMeta: metav1.ObjectMeta{ + Labels: labels, + }, Spec: corev1.NodeSpec{ ProviderID: fmt.Sprintf("%s://blabla", provider), }, @@ -58,7 +62,7 @@ var _ = Describe("provider util", func() { "1.25.0", UnknownProvider, false, - buildNodes(""), + buildNodes("", nil), }, { "EKS with unique version identifier", @@ -66,7 +70,7 @@ var _ = Describe("provider util", func() { "1.25.0", EKSProvider, true, - buildNodes(""), + buildNodes("", nil), }, { "EKS with providerID", @@ -74,7 +78,7 @@ var _ = Describe("provider util", func() { "1.25.0", EKSProvider, true, - buildNodes("aws"), + buildNodes("aws", nil), }, { "GKE with unique version identifier", @@ -82,7 +86,7 @@ var _ = Describe("provider util", func() { "1.24.9", GKEProvider, true, - buildNodes(""), + buildNodes("", nil), }, { "GKE with providerID", @@ -90,7 +94,7 @@ var _ = Describe("provider util", func() { "1.24.9", GKEProvider, true, - buildNodes("gce"), + buildNodes("gce", nil), }, { "TKE with unique version identifier", @@ -98,7 +102,7 @@ var _ = Describe("provider util", func() { "1.24.4", TKEProvider, true, - buildNodes(""), + buildNodes("", nil), }, { "TKE with providerID", @@ -106,7 +110,7 @@ var _ = Describe("provider util", func() { "1.24.9", TKEProvider, true, - buildNodes("qcloud"), + buildNodes("qcloud", nil), }, { "ACK with unique version identifier, as ACK don't have providerID", @@ -114,7 +118,7 @@ var _ = Describe("provider util", func() { "1.24.6", ACKProvider, true, - buildNodes(""), + buildNodes("", nil), }, { "AKS with providerID, as AKS don't have unique version identifier", @@ -122,7 +126,7 @@ var _ = Describe("provider util", func() { "1.24.9", AKSProvider, true, - buildNodes("azure"), + buildNodes("azure", nil), }, } @@ -136,4 +140,67 @@ var _ = Describe("provider util", func() { Expect(p.IsCloud()).Should(Equal(c.isCloud)) } }) + + It("GetImageRegistry", func() { + buildNodeWithRegion := func(provider, region string) *corev1.NodeList { + labels := map[string]string{ + topologyRegionLabel: region, + } + return buildNodes(provider, labels) + } + + cases := []struct { + description string + version string + region string + expectedImageRegistry string + nodes *corev1.NodeList + }{ + { + "Unknown provider", + "v1.25.0", + "", + "", + buildNodes("", nil), + }, + { + "EKS with region us-west-2", + "v1.25.0-eks-123456", + "us-west-2", + "docker.io", + buildNodeWithRegion("aws", "us-west-2"), + }, + { + // GCP DOES NOT have region with 'cn-*' prefix, so it should always + // use 'docker.io' as the default registry. + "GKE with region cn-north-1", + "v1.24.9-gke.3200", + "cn-north-1", + "docker.io", + buildNodeWithRegion("gce", "cn-north-1"), + }, + { + "TKE with region ap-guangzhou", + "v1.24.4-tke.5", + "ap-guangzhou", + "", + buildNodeWithRegion("qcloud", "ap-guangzhou"), + }, + { + "ACK with region cn-zhangjiakou", + "v1.24.6-aliyun.1", + "cn-zhangjiakou", + "", + buildNodeWithRegion("", "cn-zhangjiakou"), + }, + } + + for _, c := range cases { + By(c.description) + client := testing.FakeClientSet(c.nodes) + registry, err := GetImageRegistryByProvider(client) + Expect(err).ShouldNot(HaveOccurred()) + Expect(registry).Should(Equal(c.expectedImageRegistry)) + } + }) }) diff --git a/pkg/util/util.go b/pkg/util/util.go index a0f52ad1b..136c4428a 100644 --- a/pkg/util/util.go +++ b/pkg/util/util.go @@ -71,6 +71,7 @@ import ( "sigs.k8s.io/kustomize/kyaml/yaml" appsv1alpha1 "github.com/apecloud/kubeblocks/apis/apps/v1alpha1" + appsv1beta1 "github.com/apecloud/kubeblocks/apis/apps/v1beta1" "github.com/apecloud/kubeblocks/pkg/configuration/core" "github.com/apecloud/kubeblocks/pkg/configuration/openapi" cfgutil "github.com/apecloud/kubeblocks/pkg/configuration/util" @@ -565,6 +566,81 @@ func GetResourceObjectFromGVR(gvr schema.GroupVersionResource, key client.Object return apiruntime.DefaultUnstructuredConverter.FromUnstructured(unstructuredObj.Object, k8sObj) } +func GetDefaultRoleSelector(cli dynamic.Interface, + cluster *appsv1alpha1.Cluster, + compDefName string, + clusterCompDefRefName string) (string, error) { + if len(compDefName) > 0 { + compDef, err := GetCompDefByName(cli, compDefName) + if err != nil { + return "", err + } + if len(compDef.Spec.Roles) == 0 { + return "", nil + } + for _, role := range compDef.Spec.Roles { + if role.Writable && role.Serviceable { + return role.Name, nil + } + } + return "", nil + } + if cluster.Spec.ClusterDefRef != "" && clusterCompDefRefName != "" { + clusterDef, err := GetClusterDefByName(cli, cluster.Spec.ClusterDefRef) + if err != nil { + return "", err + } + clusterCompDef := clusterDef.GetComponentDefByName(clusterCompDefRefName) + if clusterCompDef == nil { + return "", fmt.Errorf("referenced cluster component definition is not defined: %s", clusterCompDefRefName) + } + switch clusterCompDef.WorkloadType { + case appsv1alpha1.Replication: + return constant.Primary, nil + case appsv1alpha1.Consensus: + if clusterCompDef.ConsensusSpec != nil { + return clusterCompDef.ConsensusSpec.Leader.Name, nil + } + return constant.Leader, nil + case appsv1alpha1.Stateful: + if clusterCompDef.RSMSpec != nil { + for _, role := range clusterCompDef.RSMSpec.Roles { + if role.IsLeader { + return role.Name, nil + } + } + } + } + } + return "", nil +} + +// GetCompDefByName gets the ComponentDefinition object by the name. +func GetCompDefByName(cli dynamic.Interface, compDefName string) (*appsv1alpha1.ComponentDefinition, error) { + compDef := &appsv1alpha1.ComponentDefinition{} + compDefKey := client.ObjectKey{ + Namespace: "", + Name: compDefName, + } + if err := GetResourceObjectFromGVR(types.CompDefGVR(), compDefKey, cli, &compDef); err != nil { + return nil, err + } + return compDef, nil +} + +// GetClusterDefByName gets the ClusterDefinition object by the name. +func GetClusterDefByName(cli dynamic.Interface, clusterDefName string) (*appsv1alpha1.ClusterDefinition, error) { + clusterDef := &appsv1alpha1.ClusterDefinition{} + clusterDefKey := client.ObjectKey{ + Namespace: "", + Name: clusterDefName, + } + if err := GetResourceObjectFromGVR(types.ClusterDefGVR(), clusterDefKey, cli, &clusterDef); err != nil { + return nil, err + } + return clusterDef, nil +} + // GetComponentsFromResource returns name of component. func GetComponentsFromResource(namespace, clusterName string, componentSpecs []appsv1alpha1.ClusterComponentSpec, cli dynamic.Interface) ([]string, error) { componentNames := make([]string, 0, len(componentSpecs)) @@ -608,7 +684,7 @@ func enableReconfiguring(component *appsv1alpha1.ConfigurationSpec) bool { func IsSupportReconfigureParams(tpl appsv1alpha1.ComponentConfigSpec, values map[string]*string, cli dynamic.Interface) (bool, error) { var ( err error - configConstraint = appsv1alpha1.ConfigConstraint{} + configConstraint = appsv1beta1.ConfigConstraint{} ) if err := GetResourceObjectFromGVR(types.ConfigConstraintGVR(), client.ObjectKey{ @@ -618,22 +694,22 @@ func IsSupportReconfigureParams(tpl appsv1alpha1.ComponentConfigSpec, values map return false, err } - if configConstraint.Spec.ConfigurationSchema == nil { + if configConstraint.Spec.ParametersSchema == nil { return true, nil } - schema := configConstraint.Spec.ConfigurationSchema.DeepCopy() - if schema.Schema == nil { - schema.Schema, err = openapi.GenerateOpenAPISchema(schema.CUE, configConstraint.Spec.CfgSchemaTopLevelName) + schema := configConstraint.Spec.ParametersSchema.DeepCopy() + if schema.SchemaInJSON == nil { + schema.SchemaInJSON, err = openapi.GenerateOpenAPISchema(schema.CUE, schema.TopLevelKey) if err != nil { return false, err } - if schema.Schema == nil { + if schema.SchemaInJSON == nil { return true, nil } } - schemaSpec := schema.Schema.Properties["spec"] + schemaSpec := schema.SchemaInJSON.Properties["spec"] for key := range values { if _, ok := schemaSpec.Properties[key]; !ok { return false, nil @@ -643,7 +719,7 @@ func IsSupportReconfigureParams(tpl appsv1alpha1.ComponentConfigSpec, values map } func ValidateParametersModified(tpl *appsv1alpha1.ComponentConfigSpec, parameters sets.Set[string], cli dynamic.Interface) (err error) { - cc := appsv1alpha1.ConfigConstraint{} + cc := appsv1beta1.ConfigConstraint{} ccKey := client.ObjectKey{ Namespace: "", Name: tpl.ConfigConstraintRef, @@ -654,7 +730,7 @@ func ValidateParametersModified(tpl *appsv1alpha1.ComponentConfigSpec, parameter return ValidateParametersModified2(parameters, cc.Spec) } -func ValidateParametersModified2(parameters sets.Set[string], cc appsv1alpha1.ConfigConstraintSpec) error { +func ValidateParametersModified2(parameters sets.Set[string], cc appsv1beta1.ConfigConstraintSpec) error { if len(cc.ImmutableParameters) == 0 { return nil } @@ -748,6 +824,9 @@ const ( ExposeToVPC ExposeType = "vpc" ExposeToInternet ExposeType = "internet" + NodePort string = "NodePort" + LoadBalancer string = "LoadBalancer" + EnableValue string = "true" DisableValue string = "false" ) @@ -863,9 +942,11 @@ func NewOpsRequestForReconfiguring(opsName, namespace, clusterName string) *apps Namespace: namespace, }, Spec: appsv1alpha1.OpsRequestSpec{ - ClusterRef: clusterName, + ClusterName: clusterName, Type: appsv1alpha1.ReconfiguringType, - Reconfigure: &appsv1alpha1.Reconfigure{}, + SpecificOpsRequest: appsv1alpha1.SpecificOpsRequest{ + Reconfigure: &appsv1alpha1.Reconfigure{}, + }, }, } } diff --git a/pkg/util/util_test.go b/pkg/util/util_test.go index 85cc3d36f..a165fb3b1 100644 --- a/pkg/util/util_test.go +++ b/pkg/util/util_test.go @@ -40,6 +40,7 @@ import ( "sigs.k8s.io/controller-runtime/pkg/log" appsv1alpha1 "github.com/apecloud/kubeblocks/apis/apps/v1alpha1" + appsv1beta1 "github.com/apecloud/kubeblocks/apis/apps/v1beta1" cfgcore "github.com/apecloud/kubeblocks/pkg/configuration/core" "github.com/apecloud/kubeblocks/pkg/constant" testapps "github.com/apecloud/kubeblocks/pkg/testutil/apps" @@ -202,21 +203,24 @@ var _ = Describe("util", func() { ) configConstraintObj := testapps.NewCustomizedObj("resources/mysql-config-constraint.yaml", - &appsv1alpha1.ConfigConstraint{}, testapps.WithNamespacedName(ccName, ""), func(cc *appsv1alpha1.ConfigConstraint) { + &appsv1beta1.ConfigConstraint{}, testapps.WithNamespacedName(ccName, ""), func(cc *appsv1beta1.ConfigConstraint) { if ccContext, err := testdata.GetTestDataFileContent("/cue_testdata/mysql_for_cli.cue"); err == nil { - cc.Spec.ConfigurationSchema = &appsv1alpha1.CustomParametersValidation{ + cc.Spec.ParametersSchema = &appsv1beta1.ParametersSchema{ CUE: string(ccContext), } } }) badcaseCCObject := configConstraintObj.DeepCopy() - badcaseCCObject.Spec.CfgSchemaTopLevelName = "badcase" + if badcaseCCObject.Spec.ParametersSchema != nil { + badcaseCCObject.Spec.ParametersSchema.TopLevelKey = "badcase" + } badcaseCCObject.SetName("badcase") tf := cmdtesting.NewTestFactory().WithNamespace(testNS) defer tf.Cleanup() Expect(appsv1alpha1.AddToScheme(scheme.Scheme)).Should(Succeed()) + Expect(appsv1beta1.AddToScheme(scheme.Scheme)).Should(Succeed()) mockClient := dynamicfakeclient.NewSimpleDynamicClientWithCustomListKinds(scheme.Scheme, nil, configConstraintObj, badcaseCCObject) configSpec := appsv1alpha1.ComponentConfigSpec{ ComponentTemplateSpec: appsv1alpha1.ComponentTemplateSpec{