diff --git a/.all-contributorsrc b/.all-contributorsrc
index b1ecabf5e..ea9bf6fe9 100644
--- a/.all-contributorsrc
+++ b/.all-contributorsrc
@@ -769,6 +769,24 @@
"contributions": [
"code"
]
+ },
+ {
+ "login": "chilianyi",
+ "name": "chilianyi",
+ "avatar_url": "https://avatars.githubusercontent.com/u/5917832?v=4",
+ "profile": "https://github.com/chilianyi",
+ "contributions": [
+ "code"
+ ]
+ },
+ {
+ "login": "xrwang8",
+ "name": "Ronald Fletcher",
+ "avatar_url": "https://avatars.githubusercontent.com/u/68765051?v=4",
+ "profile": "https://github.com/xrwang8",
+ "contributions": [
+ "code"
+ ]
}
],
"contributorsPerLine": 7,
diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md
index 5b0ea4e1e..1a75af7e8 100644
--- a/CONTRIBUTORS.md
+++ b/CONTRIBUTORS.md
@@ -113,6 +113,10 @@ Contributions of any kind are welcome! Thanks goes to these wonderful contributo
![cui fliter](https://avatars.githubusercontent.com/u/15921519?v=4?s=100) cui fliter 📖 |
![刘æ—](https://avatars.githubusercontent.com/u/9653438?v=4?s=100) åˆ˜æ— ðŸ’» |
![yuyu](https://avatars.githubusercontent.com/u/13790023?v=4?s=100) yuyu 💻 |
+ ![chilianyi](https://avatars.githubusercontent.com/u/5917832?v=4?s=100) chilianyi 💻 |
+
+
+ ![Ronald Fletcher](https://avatars.githubusercontent.com/u/68765051?v=4?s=100) Ronald Fletcher 💻 |
diff --git a/README.md b/README.md
index fac0829d5..3a2c29d06 100644
--- a/README.md
+++ b/README.md
@@ -397,6 +397,10 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d
![cui fliter](https://avatars.githubusercontent.com/u/15921519?v=4?s=100) cui fliter 📖 |
![刘æ—](https://avatars.githubusercontent.com/u/9653438?v=4?s=100) åˆ˜æ— ðŸ’» |
![yuyu](https://avatars.githubusercontent.com/u/13790023?v=4?s=100) yuyu 💻 |
+ ![chilianyi](https://avatars.githubusercontent.com/u/5917832?v=4?s=100) chilianyi 💻 |
+
+
+ ![Ronald Fletcher](https://avatars.githubusercontent.com/u/68765051?v=4?s=100) Ronald Fletcher 💻 |
diff --git a/README_zh-CN.md b/README_zh-CN.md
index 4e16a4604..62c4844f2 100644
--- a/README_zh-CN.md
+++ b/README_zh-CN.md
@@ -414,6 +414,10 @@ kubectl completion bash >/etc/bash_completion.d/kubectl
![cui fliter](https://avatars.githubusercontent.com/u/15921519?v=4?s=100) cui fliter 📖 |
![刘æ—](https://avatars.githubusercontent.com/u/9653438?v=4?s=100) åˆ˜æ— ðŸ’» |
![yuyu](https://avatars.githubusercontent.com/u/13790023?v=4?s=100) yuyu 💻 |
+ ![chilianyi](https://avatars.githubusercontent.com/u/5917832?v=4?s=100) chilianyi 💻 |
+
+
+ ![Ronald Fletcher](https://avatars.githubusercontent.com/u/68765051?v=4?s=100) Ronald Fletcher 💻 |
diff --git a/cmd/kk/apis/kubekey/v1alpha2/default.go b/cmd/kk/apis/kubekey/v1alpha2/default.go
index eede3ac42..b29348836 100644
--- a/cmd/kk/apis/kubekey/v1alpha2/default.go
+++ b/cmd/kk/apis/kubekey/v1alpha2/default.go
@@ -22,6 +22,7 @@ import (
"strings"
"github.com/kubesphere/kubekey/v3/cmd/kk/pkg/core/util"
+ "github.com/kubesphere/kubekey/v3/cmd/kk/pkg/version/kubernetes"
)
const (
@@ -41,7 +42,8 @@ const (
DefaultSSHTimeout = 30
DefaultEtcdVersion = "v3.5.6"
DefaultEtcdPort = "2379"
- DefaultDockerVersion = "24.0.6"
+ DefaultDockerVersion = "24.0.9"
+ DefaultCriDockerdVersion = "0.3.9"
DefaultContainerdVersion = "1.7.12"
DefaultRuncVersion = "v1.1.11"
DefaultCrictlVersion = "v1.29.0"
@@ -68,6 +70,7 @@ const (
DefaultProxyMode = "ipvs"
DefaultCrioEndpoint = "unix:///var/run/crio/crio.sock"
DefaultContainerdEndpoint = "unix:///run/containerd/containerd.sock"
+ DefaultCriDockerdEndpoint = "unix:///var/run/cri-dockerd.sock"
DefaultIsulaEndpoint = "unix:///var/run/isulad.sock"
Etcd = "etcd"
Master = "master"
@@ -315,7 +318,11 @@ func SetDefaultClusterCfg(cfg *ClusterSpec) Kubernetes {
if cfg.Kubernetes.ContainerRuntimeEndpoint == "" {
switch cfg.Kubernetes.ContainerManager {
case Docker:
- cfg.Kubernetes.ContainerRuntimeEndpoint = ""
+ if kubernetes.IsAtLeastV124(cfg.Kubernetes.Version) {
+ cfg.Kubernetes.ContainerRuntimeEndpoint = DefaultCriDockerdEndpoint
+ } else {
+ cfg.Kubernetes.ContainerRuntimeEndpoint = ""
+ }
case Crio:
cfg.Kubernetes.ContainerRuntimeEndpoint = DefaultCrioEndpoint
case Containerd:
diff --git a/cmd/kk/apis/kubekey/v1alpha2/multicluster_types.go b/cmd/kk/apis/kubekey/v1alpha2/multicluster_types.go
new file mode 100644
index 000000000..c6028ee3f
--- /dev/null
+++ b/cmd/kk/apis/kubekey/v1alpha2/multicluster_types.go
@@ -0,0 +1,162 @@
+package v1alpha2
+
+import (
+ corev1 "k8s.io/api/core/v1"
+ metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+ "k8s.io/apimachinery/pkg/types"
+)
+
+type MultiClusterSpec struct {
+ // Join cluster as a kubefed cluster
+ JoinFederation bool `json:"joinFederation,omitempty"`
+
+ // Desired state of the cluster
+ Enable bool `json:"enable,omitempty"`
+
+ // Provider of the cluster, this field is just for description
+ Provider string `json:"provider,omitempty"`
+
+ // Connection holds info to connect to the member cluster
+ Connection Connection `json:"connection,omitempty"`
+
+ // ExternalKubeAPIEnabled export kubeapiserver to public use a lb type service if connection type is proxy
+ ExternalKubeAPIEnabled bool `json:"externalKubeAPIEnabled,omitempty"`
+}
+
+type ConnectionType string
+
+const (
+ ConnectionTypeDirect ConnectionType = "direct"
+ ConnectionTypeProxy ConnectionType = "proxy"
+)
+
+type Connection struct {
+
+ // type defines how host cluster will connect to host cluster
+ // ConnectionTypeDirect means direct connection, this requires
+ // kubeconfig and kubesphere apiserver endpoint provided
+ // ConnectionTypeProxy means using kubesphere proxy, no kubeconfig
+ // or kubesphere apiserver endpoint required
+ Type ConnectionType `json:"type,omitempty"`
+
+ // KubeSphere API Server endpoint. Example: http://10.10.0.11:8080
+ // Should provide this field explicitly if connection type is direct.
+ // Will be populated by ks-apiserver if connection type is proxy.
+ KubeSphereAPIEndpoint string `json:"kubesphereAPIEndpoint,omitempty"`
+
+ // Kubernetes API Server endpoint. Example: https://10.10.0.1:6443
+ // Should provide this field explicitly if connection type is direct.
+ // Will be populated by ks-apiserver if connection type is proxy.
+ KubernetesAPIEndpoint string `json:"kubernetesAPIEndpoint,omitempty"`
+
+ // External Kubernetes API Server endpoint
+ // Will be populated by ks-apiserver if connection type is proxy and ExternalKubeAPIEnabled is true.
+ ExternalKubernetesAPIEndpoint string `json:"externalKubernetesAPIEndpoint,omitempty"`
+
+ // KubeConfig content used to connect to cluster api server
+ // Should provide this field explicitly if connection type is direct.
+ // Will be populated by ks-proxy if connection type is proxy.
+ KubeConfig []byte `json:"kubeconfig,omitempty"`
+
+ // Token used by agents of member cluster to connect to host cluster proxy.
+ // This field is populated by apiserver only if connection type is proxy.
+ Token string `json:"token,omitempty"`
+
+ // KubeAPIServerPort is the port which listens for forwarding kube-apiserver traffic
+ // Only applicable when connection type is proxy.
+ KubernetesAPIServerPort uint16 `json:"kubernetesAPIServerPort,omitempty"`
+
+ // KubeSphereAPIServerPort is the port which listens for forwarding kubesphere apigateway traffic
+ // Only applicable when connection type is proxy.
+ KubeSphereAPIServerPort uint16 `json:"kubesphereAPIServerPort,omitempty"`
+}
+type MultiClusterStatus struct {
+
+ // Represents the latest available observations of a cluster's current state.
+ Conditions []ClusterCondition `json:"conditions,omitempty"`
+
+ // GitVersion of the kubernetes cluster, this field is populated by cluster controller
+ KubernetesVersion string `json:"kubernetesVersion,omitempty"`
+
+ // GitVersion of the /kapis/version api response, this field is populated by cluster controller
+ KubeSphereVersion string `json:"kubeSphereVersion,omitempty"`
+
+ // Count of the kubernetes cluster nodes
+ // This field may not reflect the instant status of the cluster.
+ NodeCount int `json:"nodeCount,omitempty"`
+
+ // Zones are the names of availability zones in which the nodes of the cluster exist, e.g. 'us-east1-a'.
+ // +optional
+ Zones []string `json:"zones,omitempty"`
+
+ // Region is the name of the region in which all of the nodes in the cluster exist. e.g. 'us-east1'.
+ // +optional
+ Region *string `json:"region,omitempty"`
+
+ // Configz is status of components enabled in the member cluster. This is synchronized with member cluster
+ // every amount of time, like 5 minutes.
+ // +optional
+ Configz map[string]bool `json:"configz,omitempty"`
+
+ // UID is the kube-system namespace UID of the cluster, which represents the unique ID of the cluster.
+ UID types.UID `json:"uid,omitempty"`
+}
+type ClusterConditionType string
+
+const (
+ // Cluster agent is initialized and waiting for connecting
+ ClusterInitialized ClusterConditionType = "Initialized"
+
+ // Cluster agent is available
+ ClusterAgentAvailable ClusterConditionType = "AgentAvailable"
+
+ // Cluster has been one of federated clusters
+ ClusterFederated ClusterConditionType = "Federated"
+
+ // Cluster external access ready
+ ClusterExternalAccessReady ClusterConditionType = "ExternalAccessReady"
+
+ // Cluster is all available for requests
+ ClusterReady ClusterConditionType = "Ready"
+
+ // Openpitrix runtime is created
+ ClusterOpenPitrixRuntimeReady ClusterConditionType = "OpenPitrixRuntimeReady"
+
+ // ClusterKubeConfigCertExpiresInSevenDays indicates that the cluster certificate is about to expire.
+ ClusterKubeConfigCertExpiresInSevenDays ClusterConditionType = "KubeConfigCertExpiresInSevenDays"
+)
+
+type ClusterCondition struct {
+ // Type of the condition
+ Type ClusterConditionType `json:"type"`
+ // Status of the condition, one of True, False, Unknown.
+ Status corev1.ConditionStatus `json:"status"`
+ // The last time this condition was updated.
+ LastUpdateTime metav1.Time `json:"lastUpdateTime,omitempty"`
+ // Last time the condition transitioned from one status to another.
+ LastTransitionTime metav1.Time `json:"lastTransitionTime,omitempty"`
+ // The reason for the condition's last transition.
+ Reason string `json:"reason,omitempty"`
+ // A human readable message indicating details about the transition.
+ Message string `json:"message,omitempty"`
+}
+type MultiCluster struct {
+ metav1.TypeMeta `json:",inline"`
+ metav1.ObjectMeta `json:"metadata,omitempty"`
+
+ Spec MultiClusterSpec `json:"spec,omitempty"`
+ Status MultiClusterStatus `json:"status,omitempty"`
+}
+
+type MultiClusterList struct {
+ metav1.TypeMeta `json:",inline"`
+ metav1.ListMeta `json:"metadata,omitempty"`
+ Items []MultiCluster `json:"items"`
+}
+
+const HostClusterLabel = "cluster-role.kubesphere.io/host"
+
+func (m MultiCluster) IsHostCluster() bool {
+ _, host := m.Labels[HostClusterLabel]
+ return host
+}
diff --git a/cmd/kk/cmd/clusterinfo/clusterinfo.go b/cmd/kk/cmd/clusterinfo/clusterinfo.go
new file mode 100644
index 000000000..c7e51db53
--- /dev/null
+++ b/cmd/kk/cmd/clusterinfo/clusterinfo.go
@@ -0,0 +1,18 @@
+package clusterinfo
+
+import (
+ "github.com/spf13/cobra"
+)
+
+// NewCmdClusterInfo creates a new clusterinfo command
+func NewCmdClusterInfo() *cobra.Command {
+
+ cmd := &cobra.Command{
+ Use: "cluster-info",
+ Short: "display cluster information",
+ }
+
+ cmd.AddCommand(NewCmdClusterInfoDump())
+
+ return cmd
+}
diff --git a/cmd/kk/cmd/clusterinfo/clusterinfo_dump.go b/cmd/kk/cmd/clusterinfo/clusterinfo_dump.go
new file mode 100644
index 000000000..d9322d7cf
--- /dev/null
+++ b/cmd/kk/cmd/clusterinfo/clusterinfo_dump.go
@@ -0,0 +1,60 @@
+package clusterinfo
+
+import (
+ "fmt"
+ "github.com/kubesphere/kubekey/v3/cmd/kk/cmd/util"
+ "github.com/kubesphere/kubekey/v3/cmd/kk/pkg/clusterinfo"
+ "github.com/spf13/cobra"
+)
+
+type ClusterInfoDumpOptions struct {
+ Options clusterinfo.DumpOption
+}
+
+func NewClusterInfoDumpOptions() *ClusterInfoDumpOptions {
+ return &ClusterInfoDumpOptions{}
+}
+
+func NewCmdClusterInfoDump() *cobra.Command {
+ o := NewClusterInfoDumpOptions()
+ cmd := &cobra.Command{
+ Use: "dump",
+ Short: "Dumping key cluster configurations and files",
+ Run: func(cmd *cobra.Command, args []string) {
+
+ util.CheckErr(o.Validate())
+ util.CheckErr(o.Run())
+
+ },
+ }
+
+ o.addFlag(cmd)
+ return cmd
+}
+
+func (o *ClusterInfoDumpOptions) Validate() error {
+ switch o.Options.Type {
+ case "yaml", "YAML", "json", "JSON":
+ default:
+ return fmt.Errorf("unsupport output content format [%s]", o.Options.Type)
+ }
+ return nil
+}
+
+func (o *ClusterInfoDumpOptions) addFlag(cmd *cobra.Command) {
+ DefaultDumpNamespaces := []string{"kubesphere-system", "kubesphere-logging-system", "kubesphere-monitoring-system", "openpitrix-system", "kube-system", "istio-system", "kubesphere-devops-system", "porter-system"}
+ cmd.Flags().StringArrayVar(&o.Options.Namespace, "namespaces", DefaultDumpNamespaces, "Namespaces to be dumped, separated by commas.")
+ cmd.Flags().StringVar(&o.Options.KubeConfig, "kube-config", "", "Path to the kube-config file")
+ cmd.Flags().BoolVarP(&o.Options.AllNamespaces, "all-namespaces", "A", false, "dump all namespaces.")
+ cmd.Flags().StringVar(&o.Options.OutputDir, "output-dir", "", "output the dump result to the specified directory directory.")
+ cmd.Flags().StringVarP(&o.Options.Type, "output", "o", "json", "output file content format. support in json,yaml")
+ cmd.Flags().BoolVarP(&o.Options.Tar, "tar", "t", false, "build the dump result into a tar")
+ cmd.Flags().IntVar(&o.Options.Queue, "queue", 5, "dump queue size")
+ cmd.Flags().BoolVar(&o.Options.Logger, "log", false, "output the dump result to the log console")
+}
+
+func (o *ClusterInfoDumpOptions) Run() error {
+ fmt.Println("dumping cluster info...")
+ return clusterinfo.Dump(o.Options)
+
+}
diff --git a/cmd/kk/cmd/root.go b/cmd/kk/cmd/root.go
index 3ca697a9b..003354c65 100755
--- a/cmd/kk/cmd/root.go
+++ b/cmd/kk/cmd/root.go
@@ -18,6 +18,7 @@ package cmd
import (
"fmt"
+ "github.com/kubesphere/kubekey/v3/cmd/kk/cmd/clusterinfo"
"os"
"os/exec"
"runtime"
@@ -120,7 +121,7 @@ func NewKubeKeyCommand(o KubeKeyOptions) *cobra.Command {
cmds.AddCommand(completion.NewCmdCompletion())
cmds.AddCommand(version.NewCmdVersion())
-
+ cmds.AddCommand(clusterinfo.NewCmdClusterInfo())
return cmds
}
diff --git a/cmd/kk/cmd/upgrade/upgrade.go b/cmd/kk/cmd/upgrade/upgrade.go
index 4e9f60381..22382d2e7 100644
--- a/cmd/kk/cmd/upgrade/upgrade.go
+++ b/cmd/kk/cmd/upgrade/upgrade.go
@@ -31,14 +31,15 @@ import (
)
type UpgradeOptions struct {
- CommonOptions *options.CommonOptions
- ClusterCfgFile string
- Kubernetes string
- EnableKubeSphere bool
- KubeSphere string
- SkipPullImages bool
- DownloadCmd string
- Artifact string
+ CommonOptions *options.CommonOptions
+ ClusterCfgFile string
+ Kubernetes string
+ EnableKubeSphere bool
+ KubeSphere string
+ SkipPullImages bool
+ SkipDependencyCheck bool
+ DownloadCmd string
+ Artifact string
}
func NewUpgradeOptions() *UpgradeOptions {
@@ -80,14 +81,15 @@ func (o *UpgradeOptions) Complete(cmd *cobra.Command, args []string) error {
func (o *UpgradeOptions) Run() error {
arg := common.Argument{
- FilePath: o.ClusterCfgFile,
- KubernetesVersion: o.Kubernetes,
- KsEnable: o.EnableKubeSphere,
- KsVersion: o.KubeSphere,
- SkipPullImages: o.SkipPullImages,
- Debug: o.CommonOptions.Verbose,
- SkipConfirmCheck: o.CommonOptions.SkipConfirmCheck,
- Artifact: o.Artifact,
+ FilePath: o.ClusterCfgFile,
+ KubernetesVersion: o.Kubernetes,
+ KsEnable: o.EnableKubeSphere,
+ KsVersion: o.KubeSphere,
+ SkipPullImages: o.SkipPullImages,
+ Debug: o.CommonOptions.Verbose,
+ SkipConfirmCheck: o.CommonOptions.SkipConfirmCheck,
+ Artifact: o.Artifact,
+ SkipDependencyCheck: o.SkipDependencyCheck,
}
return pipelines.UpgradeCluster(arg, o.DownloadCmd)
}
@@ -100,6 +102,7 @@ func (o *UpgradeOptions) AddFlags(cmd *cobra.Command) {
cmd.Flags().StringVarP(&o.DownloadCmd, "download-cmd", "", "curl -L -o %s %s",
`The user defined command to download the necessary binary files. The first param '%s' is output path, the second param '%s', is the URL`)
cmd.Flags().StringVarP(&o.Artifact, "artifact", "a", "", "Path to a KubeKey artifact")
+ cmd.Flags().BoolVarP(&o.SkipDependencyCheck, "skip-dependency-check", "", false, "Skip kubernetes and kubesphere dependency version check")
}
func completionSetting(cmd *cobra.Command) (err error) {
diff --git a/cmd/kk/pkg/binaries/kubernetes.go b/cmd/kk/pkg/binaries/kubernetes.go
index 4e381305a..df87b25a2 100644
--- a/cmd/kk/pkg/binaries/kubernetes.go
+++ b/cmd/kk/pkg/binaries/kubernetes.go
@@ -20,14 +20,14 @@ import (
"fmt"
"os/exec"
- "github.com/pkg/errors"
-
kubekeyapiv1alpha2 "github.com/kubesphere/kubekey/v3/cmd/kk/apis/kubekey/v1alpha2"
"github.com/kubesphere/kubekey/v3/cmd/kk/pkg/common"
"github.com/kubesphere/kubekey/v3/cmd/kk/pkg/core/cache"
"github.com/kubesphere/kubekey/v3/cmd/kk/pkg/core/logger"
"github.com/kubesphere/kubekey/v3/cmd/kk/pkg/core/util"
"github.com/kubesphere/kubekey/v3/cmd/kk/pkg/files"
+ "github.com/kubesphere/kubekey/v3/cmd/kk/pkg/version/kubernetes"
+ "github.com/pkg/errors"
)
// K8sFilesDownloadHTTP defines the kubernetes' binaries that need to be downloaded in advance and downloads them.
@@ -40,6 +40,7 @@ func K8sFilesDownloadHTTP(kubeConf *common.KubeConf, path, version, arch string,
kubecni := files.NewKubeBinary("kubecni", arch, kubekeyapiv1alpha2.DefaultCniVersion, path, kubeConf.Arg.DownloadCommand)
helm := files.NewKubeBinary("helm", arch, kubekeyapiv1alpha2.DefaultHelmVersion, path, kubeConf.Arg.DownloadCommand)
docker := files.NewKubeBinary("docker", arch, kubekeyapiv1alpha2.DefaultDockerVersion, path, kubeConf.Arg.DownloadCommand)
+ criDockerd := files.NewKubeBinary("cri-dockerd", arch, kubekeyapiv1alpha2.DefaultCriDockerdVersion, path, kubeConf.Arg.DownloadCommand)
crictl := files.NewKubeBinary("crictl", arch, kubekeyapiv1alpha2.DefaultCrictlVersion, path, kubeConf.Arg.DownloadCommand)
containerd := files.NewKubeBinary("containerd", arch, kubekeyapiv1alpha2.DefaultContainerdVersion, path, kubeConf.Arg.DownloadCommand)
runc := files.NewKubeBinary("runc", arch, kubekeyapiv1alpha2.DefaultRuncVersion, path, kubeConf.Arg.DownloadCommand)
@@ -49,6 +50,9 @@ func K8sFilesDownloadHTTP(kubeConf *common.KubeConf, path, version, arch string,
if kubeConf.Cluster.Kubernetes.ContainerManager == kubekeyapiv1alpha2.Docker {
binaries = append(binaries, docker)
+ if kubernetes.IsAtLeastV124(kubeConf.Cluster.Kubernetes.Version) && kubeConf.Cluster.Kubernetes.ContainerManager == common.Docker {
+ binaries = append(binaries, criDockerd)
+ }
} else if kubeConf.Cluster.Kubernetes.ContainerManager == kubekeyapiv1alpha2.Containerd {
binaries = append(binaries, containerd, runc)
}
diff --git a/cmd/kk/pkg/bootstrap/confirm/tasks.go b/cmd/kk/pkg/bootstrap/confirm/tasks.go
index 06926da07..59edc41f2 100644
--- a/cmd/kk/pkg/bootstrap/confirm/tasks.go
+++ b/cmd/kk/pkg/bootstrap/confirm/tasks.go
@@ -23,16 +23,16 @@ import (
"regexp"
"strings"
- "github.com/mitchellh/mapstructure"
- "github.com/modood/table"
- "github.com/pkg/errors"
- versionutil "k8s.io/apimachinery/pkg/util/version"
-
"github.com/kubesphere/kubekey/v3/cmd/kk/pkg/common"
"github.com/kubesphere/kubekey/v3/cmd/kk/pkg/core/action"
"github.com/kubesphere/kubekey/v3/cmd/kk/pkg/core/connector"
"github.com/kubesphere/kubekey/v3/cmd/kk/pkg/core/logger"
"github.com/kubesphere/kubekey/v3/cmd/kk/pkg/core/util"
+ "github.com/kubesphere/kubekey/v3/cmd/kk/pkg/version/kubernetes"
+ "github.com/mitchellh/mapstructure"
+ "github.com/modood/table"
+ "github.com/pkg/errors"
+ versionutil "k8s.io/apimachinery/pkg/util/version"
)
// PreCheckResults defines the items to be checked.
@@ -107,18 +107,17 @@ func (i *InstallationConfirm) Execute(runtime connector.Runtime) error {
fmt.Println("https://github.com/kubesphere/kubekey#requirements-and-recommendations")
fmt.Println("")
- if k8sVersion, err := versionutil.ParseGeneric(i.KubeConf.Cluster.Kubernetes.Version); err == nil {
- if k8sVersion.AtLeast(versionutil.MustParseSemantic("v1.24.0")) && i.KubeConf.Cluster.Kubernetes.ContainerManager == common.Docker {
- fmt.Println("[Notice]")
- fmt.Println("Incorrect runtime. Please specify a container runtime other than Docker to install Kubernetes v1.24 or later.")
- fmt.Println("You can set \"spec.kubernetes.containerManager\" in the configuration file to \"containerd\" or add \"--container-manager containerd\" to the \"./kk create cluster\" command.")
- fmt.Println("For more information, see:")
- fmt.Println("https://github.com/kubesphere/kubekey/blob/master/docs/commands/kk-create-cluster.md")
- fmt.Println("https://kubernetes.io/docs/setup/production-environment/container-runtimes/#container-runtimes")
- fmt.Println("https://kubernetes.io/blog/2022/02/17/dockershim-faq/")
- fmt.Println("")
- stopFlag = true
- }
+ if kubernetes.IsAtLeastV124(i.KubeConf.Cluster.Kubernetes.Version) && i.KubeConf.Cluster.Kubernetes.ContainerManager == common.Docker &&
+ i.KubeConf.Cluster.Kubernetes.Type != common.Kubernetes {
+ fmt.Println("[Notice]")
+ fmt.Println("Incorrect runtime. Please specify a container runtime other than Docker to install Kubernetes v1.24 or later.")
+ fmt.Println("You can set \"spec.kubernetes.containerManager\" in the configuration file to \"containerd\" or add \"--container-manager containerd\" to the \"./kk create cluster\" command.")
+ fmt.Println("For more information, see:")
+ fmt.Println("https://github.com/kubesphere/kubekey/blob/master/docs/commands/kk-create-cluster.md")
+ fmt.Println("https://kubernetes.io/docs/setup/production-environment/container-runtimes/#container-runtimes")
+ fmt.Println("https://kubernetes.io/blog/2022/02/17/dockershim-faq/")
+ fmt.Println("")
+ stopFlag = true
}
if stopFlag {
diff --git a/cmd/kk/pkg/bootstrap/os/tasks.go b/cmd/kk/pkg/bootstrap/os/tasks.go
index 1f3467610..7a0b83a09 100644
--- a/cmd/kk/pkg/bootstrap/os/tasks.go
+++ b/cmd/kk/pkg/bootstrap/os/tasks.go
@@ -258,6 +258,9 @@ func (r *RemoveFiles) Execute(runtime connector.Runtime) error {
for _, file := range clusterFiles {
_, _ = runtime.GetRunner().SudoCmd(fmt.Sprintf("rm -rf %s", file), true)
}
+ // remove pki/etcd Path if it exists, otherwise it will cause the etcd reinstallation to fail if ip change
+ pkiPath := fmt.Sprintf("%s/pki/etcd", runtime.GetWorkDir())
+ _, _ = runtime.GetRunner().SudoCmd(fmt.Sprintf("rm -rf %s", pkiPath), true)
return nil
}
@@ -504,15 +507,33 @@ func (n *NodeConfigureNtpServer) Execute(runtime connector.Runtime) error {
chronyService = "chrony.service"
}
+ clearOldServerCmd := fmt.Sprintf(`sed -i '/^server/d' %s`, chronyConfigFile)
+ if _, err := runtime.GetRunner().SudoCmd(clearOldServerCmd, false); err != nil {
+ return errors.Wrapf(err, "delete old servers failed, please check file %s", chronyConfigFile)
+ }
+
// if NtpServers was configured
for _, server := range n.KubeConf.Cluster.System.NtpServers {
serverAddr := strings.Trim(server, " \"")
+ fmt.Printf("ntpserver: %s, current host: %s\n", serverAddr, currentHost.GetName())
if serverAddr == currentHost.GetName() || serverAddr == currentHost.GetInternalAddress() {
- allowClientCmd := fmt.Sprintf(`sed -i '/#allow/ a\allow 0.0.0.0/0' %s`, chronyConfigFile)
+ deleteAllowCmd := fmt.Sprintf(`sed -i '/^allow/d' %s`, chronyConfigFile)
+ if _, err := runtime.GetRunner().SudoCmd(deleteAllowCmd, false); err != nil {
+ return errors.Wrapf(err, "delete allow failed, please check file %s", chronyConfigFile)
+ }
+ allowClientCmd := fmt.Sprintf(`echo 'allow 0.0.0.0/0' >> %s`, chronyConfigFile)
if _, err := runtime.GetRunner().SudoCmd(allowClientCmd, false); err != nil {
return errors.Wrapf(err, "change host:%s chronyd conf failed, please check file %s", serverAddr, chronyConfigFile)
}
+ deleteLocalCmd := fmt.Sprintf(`sed -i '/^local/d' %s`, chronyConfigFile)
+ if _, err := runtime.GetRunner().SudoCmd(deleteLocalCmd, false); err != nil {
+ return errors.Wrapf(err, "delete local stratum failed, please check file %s", chronyConfigFile)
+ }
+ AddLocalCmd := fmt.Sprintf(`echo 'local stratum 10' >> %s`, chronyConfigFile)
+ if _, err := runtime.GetRunner().SudoCmd(AddLocalCmd, false); err != nil {
+ return errors.Wrapf(err, "Add local stratum 10 conf failed, please check file %s", chronyConfigFile)
+ }
}
// use internal ip to client chronyd server
diff --git a/cmd/kk/pkg/bootstrap/precheck/module.go b/cmd/kk/pkg/bootstrap/precheck/module.go
index df6583cdd..d38a515d7 100644
--- a/cmd/kk/pkg/bootstrap/precheck/module.go
+++ b/cmd/kk/pkg/bootstrap/precheck/module.go
@@ -88,6 +88,7 @@ func (n *NodePreCheckModule) Init() {
type ClusterPreCheckModule struct {
common.KubeModule
+ SkipDependencyCheck bool
}
func (c *ClusterPreCheckModule) Init() {
@@ -159,13 +160,25 @@ func (c *ClusterPreCheckModule) Init() {
Parallel: true,
}
- c.Tasks = []task.Interface{
- getKubeConfig,
- getAllNodesK8sVersion,
- calculateMinK8sVersion,
- checkDesiredK8sVersion,
- ksVersionCheck,
- dependencyCheck,
- getKubernetesNodesStatus,
+ if !c.SkipDependencyCheck {
+ c.Tasks = []task.Interface{
+ getKubeConfig,
+ getAllNodesK8sVersion,
+ calculateMinK8sVersion,
+ checkDesiredK8sVersion,
+ ksVersionCheck,
+ dependencyCheck,
+ getKubernetesNodesStatus,
+ }
+ } else {
+ c.Tasks = []task.Interface{
+ getKubeConfig,
+ getAllNodesK8sVersion,
+ calculateMinK8sVersion,
+ checkDesiredK8sVersion,
+ ksVersionCheck,
+ getKubernetesNodesStatus,
+ }
}
+
}
diff --git a/cmd/kk/pkg/clusterinfo/clusterinfo_dump.go b/cmd/kk/pkg/clusterinfo/clusterinfo_dump.go
new file mode 100644
index 000000000..7cbac9146
--- /dev/null
+++ b/cmd/kk/pkg/clusterinfo/clusterinfo_dump.go
@@ -0,0 +1,121 @@
+package clusterinfo
+
+import (
+ "bytes"
+ "encoding/json"
+ "fmt"
+ "github.com/kubesphere/kubekey/v3/cmd/kk/apis/kubekey/v1alpha2"
+ "github.com/kubesphere/kubekey/v3/cmd/kk/pkg/utils"
+ "github.com/xuri/excelize/v2"
+)
+
+type DumpOption struct {
+ Namespace []string
+ KubeConfig string
+ AllNamespaces bool
+ OutputDir string
+ Type string
+ Tar bool
+ Queue int
+ Logger bool
+}
+
+func Dump(option DumpOption) error {
+ client, err := utils.NewClient(option.KubeConfig)
+ if err != nil {
+ return err
+ }
+ dump := NewDumpOption(client)
+
+ cluster, err := dump.GetMultiCluster()
+ if err != nil {
+ return err
+ }
+
+ fileChan := NewFileChan(option, excelize.NewFile())
+ queue := make(chan struct{}, option.Queue)
+ go func() {
+ err = fileChan.WriteFile()
+ if err != nil {
+ fmt.Printf("failed to write file %s", err.Error())
+ fileChan.WaitGroup.Done()
+ }
+ }()
+
+ for _, multiCluster := range cluster {
+ fileChan.WaitGroup.Add(1)
+ queue <- struct{}{}
+ go func(multiCluster v1alpha2.MultiCluster) {
+ defer func() {
+ <-queue
+ }()
+ if multiCluster.IsHostCluster() {
+ fileChan.ReadData(dump, multiCluster.Name)
+ } else {
+ clusterClient, err := utils.NewClientForCluster(multiCluster.Spec.Connection.KubeConfig)
+ if err != nil {
+ fmt.Printf("failed to create cluster %s", multiCluster.Name)
+ fileChan.WaitGroup.Done()
+ return
+ }
+ fileChan.ReadData(NewDumpOption(clusterClient), multiCluster.Name)
+ }
+ }(multiCluster)
+ }
+
+ defer func() {
+ if err := fileChan.Excel.Close(); err != nil {
+ fmt.Println(err)
+ }
+ close(fileChan.OutFileChan)
+ close(queue)
+ }()
+
+ fileChan.WaitGroup.Wait()
+
+ fileChan.Excel.DeleteSheet("Sheet1")
+ fileChan.Excel.SaveAs(fmt.Sprintf("%s/%s", option.GetOutputDir(), "cluster_dump.xlsx"))
+
+ if option.Tar {
+ err = NewTar(option).Run()
+ if err != nil {
+ fmt.Printf("failed to tar file %s", err.Error())
+ return err
+ }
+ }
+
+ return nil
+}
+
+func resourcesClassification(resources interface{}) map[string][]interface{} {
+
+ var resourcesMap []map[string]interface{}
+ if marshal, err := json.Marshal(resources); err != nil {
+ fmt.Println(err, "marshal resources error")
+ return nil
+ } else {
+ decoder := json.NewDecoder(bytes.NewReader(marshal))
+ if err = decoder.Decode(&resourcesMap); err != nil {
+ fmt.Println(err, "Decode resources error")
+ return nil
+ }
+ }
+
+ var completeMap = make(map[string][]interface{})
+ for _, m := range resourcesMap {
+ namespace, ok := m["metadata"].(map[string]interface{})["namespace"]
+ if ok {
+ completeMap[namespace.(string)] = append(completeMap[namespace.(string)], m)
+ } else {
+ completeMap[""] = append(completeMap[""], m)
+ }
+ }
+ return completeMap
+}
+
+func (c *DumpOption) GetOutputDir() string {
+ if c.OutputDir == "" {
+ return "cluster_dump"
+ }
+ return c.OutputDir
+}
diff --git a/cmd/kk/pkg/clusterinfo/dump_file.go b/cmd/kk/pkg/clusterinfo/dump_file.go
new file mode 100644
index 000000000..d1ae91d6a
--- /dev/null
+++ b/cmd/kk/pkg/clusterinfo/dump_file.go
@@ -0,0 +1,143 @@
+package clusterinfo
+
+import (
+ "encoding/json"
+ "fmt"
+ "github.com/xuri/excelize/v2"
+ corev1 "k8s.io/api/core/v1"
+ "k8s.io/utils/strings/slices"
+ "os"
+ "path/filepath"
+ "sigs.k8s.io/yaml"
+ "strings"
+ "sync"
+)
+
+type ChanData struct {
+ FilePath string
+ Data interface{}
+}
+type DumpFileChan struct {
+ DumpOption
+ OutFileChan chan ChanData
+ Excel *excelize.File
+ WaitGroup sync.WaitGroup
+}
+
+type DumpFile interface {
+ CreateFile(string) (*os.File, error)
+ GetWireData(ChanData) []byte
+ WriteFile() error
+ SendData(ChanData, bool)
+ ReadData(*ClientSet, string)
+}
+
+func NewFileChan(option DumpOption, excel *excelize.File) *DumpFileChan {
+ return &DumpFileChan{
+ OutFileChan: make(chan ChanData),
+ WaitGroup: sync.WaitGroup{},
+ DumpOption: option,
+ Excel: excel,
+ }
+}
+
+func (c *DumpFileChan) CreateFile(path string) (*os.File, error) {
+ if err := os.MkdirAll(filepath.Dir(path), 0775); err != nil {
+ return nil, err
+ }
+
+ file, err := os.OpenFile(path, os.O_CREATE|os.O_WRONLY, 0775)
+ if err != nil {
+ return nil, err
+ }
+ return file, nil
+}
+
+func (c *DumpFileChan) GetWireData(o ChanData) []byte {
+ switch strings.ToLower(c.Type) {
+ case "yaml":
+ marshal, err := yaml.Marshal(o.Data)
+ if err != nil {
+ fmt.Printf("marshal data error %s\n", err.Error())
+ return nil
+ }
+ return marshal
+ default:
+ marshal, err := json.Marshal(o.Data)
+ if err != nil {
+ fmt.Printf("marshal data error %s\n", err.Error())
+ return nil
+ }
+ return marshal
+ }
+}
+
+func (c *DumpFileChan) WriteFile() error {
+
+ for o := range c.OutFileChan {
+ file, err := c.CreateFile(o.FilePath)
+ if err != nil {
+ fmt.Println(err, "create file error")
+ c.WaitGroup.Done()
+ return err
+ }
+ data := c.GetWireData(o)
+ if _, err = file.Write(data); err != nil {
+ fmt.Println(err, "write file error")
+ c.WaitGroup.Done()
+ return err
+ }
+ if c.Logger {
+ fmt.Println(string(data))
+ }
+ }
+ return nil
+}
+
+func (c *DumpFileChan) SendData(data ChanData, isContinue bool) {
+ if isContinue || c.AllNamespaces {
+ c.OutFileChan <- data
+ }
+}
+
+func (c *DumpFileChan) ReadData(client *ClientSet, clusterName string) {
+
+ _, err := c.Excel.NewSheet(clusterName)
+ if err != nil {
+ fmt.Println(err, "create sheet error")
+ return
+ }
+
+ index, err := c.Excel.NewStyle(&excelize.Style{
+ Font: &excelize.Font{
+ Bold: true,
+ Size: 15,
+ },
+ })
+ resources := client.GetClusterResources(corev1.NamespaceAll)
+ cellTag := []string{"A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z"}
+ cellTagIndex := 0
+ for resourceKey, resource := range resources {
+ for kind, instance := range resource {
+ c.Excel.SetCellValue(clusterName, fmt.Sprintf("%s1", cellTag[cellTagIndex]), kind)
+ rowIndex := 2
+ for namespace, data := range instance {
+ for _, datum := range data {
+ name := datum.(map[string]interface{})["metadata"].(map[string]interface{})["name"]
+ c.Excel.SetCellValue(clusterName, fmt.Sprintf("%s%d", cellTag[cellTagIndex], rowIndex), name)
+ c.SendData(ChanData{
+ FilePath: filepath.Join(c.GetOutputDir(), clusterName, resourceKey, namespace, kind, fmt.Sprintf("%s.%s", name, strings.ToLower(c.Type))),
+ Data: datum,
+ }, slices.Contains(c.Namespace, namespace) || namespace == "")
+ rowIndex++
+ }
+ }
+ cellTagIndex++
+ }
+ }
+
+ c.Excel.SetCellStyle(clusterName, "A1", fmt.Sprintf("%s1", cellTag[cellTagIndex-1]), index)
+ c.Excel.SetColWidth(clusterName, "A", fmt.Sprintf("%s", cellTag[cellTagIndex-1]), 30)
+ c.WaitGroup.Done()
+
+}
diff --git a/cmd/kk/pkg/clusterinfo/dump_resources.go b/cmd/kk/pkg/clusterinfo/dump_resources.go
new file mode 100644
index 000000000..7222d0eee
--- /dev/null
+++ b/cmd/kk/pkg/clusterinfo/dump_resources.go
@@ -0,0 +1,210 @@
+package clusterinfo
+
+import (
+ "context"
+ "encoding/json"
+ "fmt"
+ "github.com/kubesphere/kubekey/v3/cmd/kk/apis/kubekey/v1alpha2"
+ appsv1 "k8s.io/api/apps/v1"
+ batchv1 "k8s.io/api/batch/v1"
+ corev1 "k8s.io/api/core/v1"
+ metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+ "k8s.io/client-go/kubernetes"
+)
+
+type ClientSet struct {
+ Client *kubernetes.Clientset
+}
+
+type DumpResources interface {
+ GetNodes() []corev1.Node
+ GetNamespaces() []corev1.Namespace
+ GetConfigMap(namespace string) []corev1.ConfigMap
+ GetServices(namespace string) []corev1.Service
+ GetSecrets(namespace string) []corev1.Secret
+ GetDeployment(namespace string) []appsv1.Deployment
+ GetStatefulSets(namespace string) []appsv1.StatefulSet
+ GetPods(namespace string) []corev1.Pod
+ GetPersistentVolumeClaims(namespace string) []corev1.PersistentVolumeClaim
+ GetPersistentVolumes() []corev1.PersistentVolume
+ GetStorageClasses() []interface{}
+ GetJobs(namespace string) []batchv1.Job
+ GetCronJobs(namespace string) []batchv1.CronJob
+ GetCRD() []interface{}
+ GetClusterResources(namespace string) map[string]map[string]map[string][]interface{}
+ GetMultiCluster() ([]v1alpha2.MultiCluster, error)
+}
+
+func NewDumpOption(client *kubernetes.Clientset) *ClientSet {
+ return &ClientSet{
+ Client: client,
+ }
+}
+
+func (c *ClientSet) GetClusterResources(namespace string) map[string]map[string]map[string][]interface{} {
+
+ clusterResources := map[string]map[string][]interface{}{}
+ clusterResources["nodes"] = resourcesClassification(c.GetNodes())
+ clusterResources["namespaces"] = resourcesClassification(c.GetNamespaces())
+ clusterResources["persistentvolumes"] = resourcesClassification(c.GetPersistentVolumes())
+ clusterResources["storageclasses"] = resourcesClassification(c.GetStorageClasses())
+ namespaceResources := map[string]map[string][]interface{}{}
+ namespaceResources["crds"] = resourcesClassification(c.GetCRD())
+ namespaceResources["deployments"] = resourcesClassification(c.GetDeployment(namespace))
+ namespaceResources["statefulsets"] = resourcesClassification(c.GetStatefulSets(namespace))
+ namespaceResources["pods"] = resourcesClassification(c.GetPods(namespace))
+ namespaceResources["services"] = resourcesClassification(c.GetServices(namespace))
+ namespaceResources["configmaps"] = resourcesClassification(c.GetConfigMap(namespace))
+ namespaceResources["secrets"] = resourcesClassification(c.GetSecrets(namespace))
+ namespaceResources["persistentvolumeclaims"] = resourcesClassification(c.GetPersistentVolumeClaims(namespace))
+ namespaceResources["jobs"] = resourcesClassification(c.GetJobs(namespace))
+ namespaceResources["cronjobs"] = resourcesClassification(c.GetCronJobs(namespace))
+
+ return map[string]map[string]map[string][]interface{}{"clusterResources": clusterResources, "namespaceResources": namespaceResources}
+
+}
+
+func (c *ClientSet) GetCRD() []interface{} {
+ raw, err := c.Client.CoreV1().RESTClient().Get().AbsPath("/apis/installer.kubesphere.io/v1alpha1/clusterconfigurations").DoRaw(context.Background())
+ if err != nil {
+ return nil
+ }
+ var crd map[string]interface{}
+ err = json.Unmarshal(raw, &crd)
+ if err != nil {
+ return nil
+ }
+ return crd["items"].([]interface{})
+}
+
+func (c *ClientSet) GetNodes() []corev1.Node {
+ list, err := c.Client.CoreV1().Nodes().List(context.TODO(), metav1.ListOptions{})
+ if err != nil {
+ return nil
+ }
+
+ return list.Items
+}
+
+func (c *ClientSet) GetNamespaces() []corev1.Namespace {
+
+ list, err := c.Client.CoreV1().Namespaces().List(context.TODO(), metav1.ListOptions{})
+ if err != nil {
+ return nil
+ }
+ return list.Items
+}
+
+func (c *ClientSet) GetConfigMap(namespace string) []corev1.ConfigMap {
+ list, err := c.Client.CoreV1().ConfigMaps(namespace).List(context.TODO(), metav1.ListOptions{})
+ if err != nil {
+ return nil
+ }
+ return list.Items
+}
+
+func (c *ClientSet) GetMultiCluster() ([]v1alpha2.MultiCluster, error) {
+ raw, err := c.Client.CoreV1().RESTClient().Get().AbsPath("/apis/cluster.kubesphere.io/v1alpha1/clusters").DoRaw(context.TODO())
+ if err != nil {
+ fmt.Println(err, "failed to get cluster config")
+ return nil, err
+ }
+ var cluster v1alpha2.MultiClusterList
+ err = json.Unmarshal(raw, &cluster)
+ if err != nil {
+ fmt.Println(err, "failed to unmarshal cluster config")
+ return nil, err
+ }
+
+ return cluster.Items, nil
+}
+func (c *ClientSet) GetDeployment(namespace string) []appsv1.Deployment {
+
+ list, err := c.Client.AppsV1().Deployments(namespace).List(context.TODO(), metav1.ListOptions{})
+ if err != nil {
+ return nil
+ }
+
+ return list.Items
+}
+
+func (c *ClientSet) GetStatefulSets(namespace string) []appsv1.StatefulSet {
+
+ list, err := c.Client.AppsV1().StatefulSets(namespace).List(context.TODO(), metav1.ListOptions{})
+ if err != nil {
+ return nil
+ }
+ return list.Items
+}
+
+func (c *ClientSet) GetPods(namespace string) []corev1.Pod {
+ list, err := c.Client.CoreV1().Pods(namespace).List(context.TODO(), metav1.ListOptions{})
+ if err != nil {
+ return nil
+ }
+ return list.Items
+}
+
+func (c *ClientSet) GetServices(namespace string) []corev1.Service {
+ list, err := c.Client.CoreV1().Services(namespace).List(context.TODO(), metav1.ListOptions{})
+ if err != nil {
+ return nil
+ }
+ return list.Items
+}
+
+func (c *ClientSet) GetSecrets(namespace string) []corev1.Secret {
+ list, err := c.Client.CoreV1().Secrets(namespace).List(context.TODO(), metav1.ListOptions{})
+ if err != nil {
+ return nil
+ }
+ return list.Items
+}
+
+func (c *ClientSet) GetPersistentVolumeClaims(namespace string) []corev1.PersistentVolumeClaim {
+
+ list, err := c.Client.CoreV1().PersistentVolumeClaims(namespace).List(context.TODO(), metav1.ListOptions{})
+ if err != nil {
+ return nil
+ }
+
+ return list.Items
+}
+
+func (c *ClientSet) GetPersistentVolumes() []corev1.PersistentVolume {
+ list, err := c.Client.CoreV1().PersistentVolumes().List(context.TODO(), metav1.ListOptions{})
+ if err != nil {
+ return nil
+ }
+ return list.Items
+}
+
+func (c *ClientSet) GetStorageClasses() []interface{} {
+
+ raw, err := c.Client.CoreV1().RESTClient().Get().AbsPath("/apis/storage.k8s.io/v1/storageclasses").DoRaw(context.Background())
+ if err != nil {
+ return nil
+ }
+ var storageClass map[string]interface{}
+ err = json.Unmarshal(raw, &storageClass)
+ if err != nil {
+ return nil
+ }
+ return storageClass["items"].([]interface{})
+}
+
+func (c *ClientSet) GetJobs(namespace string) []batchv1.Job {
+ list, err := c.Client.BatchV1().Jobs(namespace).List(context.Background(), metav1.ListOptions{})
+ if err != nil {
+ return nil
+ }
+ return list.Items
+}
+
+func (c *ClientSet) GetCronJobs(namespace string) []batchv1.CronJob {
+ list, err := c.Client.BatchV1().CronJobs(namespace).List(context.Background(), metav1.ListOptions{})
+ if err != nil {
+ return nil
+ }
+ return list.Items
+}
diff --git a/cmd/kk/pkg/clusterinfo/dump_tar.go b/cmd/kk/pkg/clusterinfo/dump_tar.go
new file mode 100644
index 000000000..fd4066404
--- /dev/null
+++ b/cmd/kk/pkg/clusterinfo/dump_tar.go
@@ -0,0 +1,34 @@
+package clusterinfo
+
+import (
+ "fmt"
+ "os/exec"
+)
+
+const tarFileName = "cluster_dump.tar"
+
+type TarOptions struct {
+ DumpOption
+}
+
+func NewTar(option DumpOption) *TarOptions {
+ return &TarOptions{
+ DumpOption: option,
+ }
+}
+
+func (t TarOptions) Run() error {
+
+ sourceDir := t.GetOutputDir()
+ cmd := exec.Command("/bin/sh", "-c", fmt.Sprintf("tar -czvf %s %s", tarFileName, sourceDir))
+ output, err := cmd.Output()
+ if err != nil {
+ return err
+ }
+
+ if t.Logger {
+ fmt.Println(string(output))
+ }
+
+ return nil
+}
diff --git a/cmd/kk/pkg/common/common.go b/cmd/kk/pkg/common/common.go
index 4b24d7a3e..aeaa69f9c 100644
--- a/cmd/kk/pkg/common/common.go
+++ b/cmd/kk/pkg/common/common.go
@@ -62,6 +62,7 @@ const (
Hybridnet = "hybridnet"
Docker = "docker"
+ CriDockerd = "cri-dockerd"
Crictl = "crictl"
Containerd = "containerd"
Crio = "crio"
diff --git a/cmd/kk/pkg/common/kube_runtime.go b/cmd/kk/pkg/common/kube_runtime.go
index 970e924e9..e983fe735 100644
--- a/cmd/kk/pkg/common/kube_runtime.go
+++ b/cmd/kk/pkg/common/kube_runtime.go
@@ -39,6 +39,7 @@ type Argument struct {
IgnoreErr bool
SkipPullImages bool
SkipPushImages bool
+ SkipDependencyCheck bool
SecurityEnhancement bool
DeployLocalStorage *bool
DownloadCommand func(path, url string) string
diff --git a/cmd/kk/pkg/container/docker.go b/cmd/kk/pkg/container/docker.go
index f32807d8e..8be4612a3 100644
--- a/cmd/kk/pkg/container/docker.go
+++ b/cmd/kk/pkg/container/docker.go
@@ -21,14 +21,14 @@ import (
"path/filepath"
"strings"
- "github.com/pkg/errors"
-
"github.com/kubesphere/kubekey/v3/cmd/kk/pkg/common"
"github.com/kubesphere/kubekey/v3/cmd/kk/pkg/container/templates"
"github.com/kubesphere/kubekey/v3/cmd/kk/pkg/core/connector"
"github.com/kubesphere/kubekey/v3/cmd/kk/pkg/files"
"github.com/kubesphere/kubekey/v3/cmd/kk/pkg/registry"
"github.com/kubesphere/kubekey/v3/cmd/kk/pkg/utils"
+ "github.com/kubesphere/kubekey/v3/cmd/kk/pkg/version/kubernetes"
+ "github.com/pkg/errors"
)
type SyncDockerBinaries struct {
@@ -64,6 +64,39 @@ func (s *SyncDockerBinaries) Execute(runtime connector.Runtime) error {
return nil
}
+type SyncCriDockerdBinaries struct {
+ common.KubeAction
+}
+
+func (s *SyncCriDockerdBinaries) Execute(runtime connector.Runtime) error {
+ if err := utils.ResetTmpDir(runtime); err != nil {
+ return err
+ }
+
+ binariesMapObj, ok := s.PipelineCache.Get(common.KubeBinaries + "-" + runtime.RemoteHost().GetArch())
+ if !ok {
+ return errors.New("get KubeBinary by pipeline cache failed")
+ }
+ binariesMap := binariesMapObj.(map[string]*files.KubeBinary)
+
+ criDockerd, ok := binariesMap[common.CriDockerd]
+ if !ok {
+ return errors.New("get KubeBinary key cri-dockerd by pipeline cache failed")
+ }
+
+ dst := filepath.Join(common.TmpDir, criDockerd.FileName)
+ if err := runtime.GetRunner().Scp(criDockerd.Path(), dst); err != nil {
+ return errors.Wrap(errors.WithStack(err), fmt.Sprintf("sync cri-dockerd binaries failed"))
+ }
+
+ if _, err := runtime.GetRunner().SudoCmd(
+ fmt.Sprintf("mkdir -p /usr/bin && tar -zxf %s && mv cri-dockerd/* /usr/bin && rm -rf cri-dockerd", dst),
+ false); err != nil {
+ return errors.Wrap(errors.WithStack(err), fmt.Sprintf("install container runtime cri-dockerd binaries failed"))
+ }
+ return nil
+}
+
type EnableContainerdForDocker struct {
common.KubeAction
}
@@ -90,6 +123,19 @@ func (e *EnableDocker) Execute(runtime connector.Runtime) error {
return nil
}
+type EnableCriDockerd struct {
+ common.KubeAction
+}
+
+func (e *EnableCriDockerd) Execute(runtime connector.Runtime) error {
+ if _, err := runtime.GetRunner().SudoCmd(
+ "systemctl daemon-reload && systemctl enable cri-docker && systemctl start cri-docker",
+ false); err != nil {
+ return errors.Wrap(errors.WithStack(err), fmt.Sprintf("enable and start cri-docker failed"))
+ }
+ return nil
+}
+
type DockerLoginRegistry struct {
common.KubeAction
}
@@ -141,6 +187,15 @@ func (d *DisableDocker) Execute(runtime connector.Runtime) error {
filepath.Join("/etc/systemd/system", templates.DockerService.Name()),
filepath.Join("/etc/docker", templates.DockerConfig.Name()),
}
+
+ if kubernetes.IsAtLeastV124(d.KubeConf.Cluster.Kubernetes.Version) && d.KubeConf.Cluster.Kubernetes.ContainerManager == common.Docker {
+ if _, err := runtime.GetRunner().SudoCmd("systemctl disable cri-docker && systemctl stop cri-docker",
+ false); err != nil {
+ return errors.Wrap(errors.WithStack(err), fmt.Sprintf("disable and stop cri-docker failed"))
+ }
+ files = append(files, filepath.Join("/etc/systemd/system", templates.CriDockerService.Name()))
+ }
+
if d.KubeConf.Cluster.Registry.DataRoot != "" {
files = append(files, d.KubeConf.Cluster.Registry.DataRoot)
} else {
diff --git a/cmd/kk/pkg/container/module.go b/cmd/kk/pkg/container/module.go
index ba8a8b688..61a7bfa5d 100644
--- a/cmd/kk/pkg/container/module.go
+++ b/cmd/kk/pkg/container/module.go
@@ -30,6 +30,7 @@ import (
"github.com/kubesphere/kubekey/v3/cmd/kk/pkg/images"
"github.com/kubesphere/kubekey/v3/cmd/kk/pkg/kubernetes"
"github.com/kubesphere/kubekey/v3/cmd/kk/pkg/registry"
+ versionk8s "github.com/kubesphere/kubekey/v3/cmd/kk/pkg/version/kubernetes"
)
type InstallContainerModule struct {
@@ -73,6 +74,19 @@ func InstallDocker(m *InstallContainerModule) []task.Interface {
Retry: 2,
}
+ syncCriDockerdBinaries := &task.RemoteTask{
+ Name: "SyncCriDockerdBinaries",
+ Desc: "Sync cri-dockerd binaries",
+ Hosts: m.Runtime.GetHostsByRole(common.K8s),
+ Prepare: &prepare.PrepareCollection{
+ &kubernetes.NodeInCluster{Not: true},
+ &CriDockerdExist{Not: true},
+ },
+ Action: new(SyncCriDockerdBinaries),
+ Parallel: true,
+ Retry: 2,
+ }
+
generateContainerdService := &task.RemoteTask{
Name: "GenerateContainerdService",
Desc: "Generate containerd service",
@@ -161,6 +175,48 @@ func InstallDocker(m *InstallContainerModule) []task.Interface {
Parallel: true,
}
+ generateCriDockerdService := &task.RemoteTask{
+ Name: "GenerateCriDockerdService",
+ Desc: "Generate cri-dockerd service",
+ Hosts: m.Runtime.GetHostsByRole(common.K8s),
+ Prepare: &prepare.PrepareCollection{
+ &kubernetes.NodeInCluster{Not: true},
+ &CriDockerdExist{Not: true},
+ },
+ Action: &action.Template{
+ Template: templates.CriDockerService,
+ Dst: filepath.Join("/etc/systemd/system", templates.CriDockerService.Name()),
+ },
+ Parallel: true,
+ }
+
+ enableCriDockerd := &task.RemoteTask{
+ Name: "EnableCriDockerd",
+ Desc: "Enable cri-dockerd",
+ Hosts: m.Runtime.GetHostsByRole(common.K8s),
+ Prepare: &prepare.PrepareCollection{
+ &kubernetes.NodeInCluster{Not: true},
+ &CriDockerdExist{Not: true},
+ },
+ Action: new(EnableCriDockerd),
+ Parallel: true,
+ }
+
+ if versionk8s.IsAtLeastV124(m.KubeConf.Cluster.Kubernetes.Version) && m.KubeConf.Cluster.Kubernetes.ContainerManager == common.Docker {
+ return []task.Interface{
+ syncBinaries,
+ syncCriDockerdBinaries,
+ generateContainerdService,
+ generateDockerService,
+ generateDockerConfig,
+ enableContainerdForDocker,
+ enableDocker,
+ dockerLoginRegistry,
+ generateCriDockerdService,
+ enableCriDockerd,
+ }
+ }
+
return []task.Interface{
syncBinaries,
generateContainerdService,
diff --git a/cmd/kk/pkg/container/prepares.go b/cmd/kk/pkg/container/prepares.go
index fd12032f8..d0f0ba829 100644
--- a/cmd/kk/pkg/container/prepares.go
+++ b/cmd/kk/pkg/container/prepares.go
@@ -41,6 +41,24 @@ func (d *DockerExist) PreCheck(runtime connector.Runtime) (bool, error) {
return !d.Not, nil
}
+type CriDockerdExist struct {
+ common.KubePrepare
+ Not bool
+}
+
+func (d *CriDockerdExist) PreCheck(runtime connector.Runtime) (bool, error) {
+ output, err := runtime.GetRunner().SudoCmd("if [ -z $(command -v cri-dockerd) ] || [ ! -e /var/run/cri-dockerd.sock ]; "+
+ "then echo 'not exist'; "+
+ "fi", false)
+ if err != nil {
+ return false, err
+ }
+ if strings.Contains(output, "not exist") {
+ return d.Not, nil
+ }
+ return !d.Not, nil
+}
+
type CrictlExist struct {
common.KubePrepare
Not bool
diff --git a/cmd/kk/pkg/container/templates/cri_dockerd_service.go b/cmd/kk/pkg/container/templates/cri_dockerd_service.go
new file mode 100644
index 000000000..ed5ca4196
--- /dev/null
+++ b/cmd/kk/pkg/container/templates/cri_dockerd_service.go
@@ -0,0 +1,63 @@
+/*
+ Copyright 2021 The KubeSphere Authors.
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+*/
+
+package templates
+
+import (
+ "text/template"
+
+ "github.com/lithammer/dedent"
+)
+
+var CriDockerService = template.Must(template.New("cri-docker.service").Parse(
+ dedent.Dedent(`[Unit]
+Description=CRI Interface for Docker Application Container Engine
+Documentation=https://docs.mirantis.com
+
+[Service]
+Type=notify
+ExecStart=/usr/bin/cri-dockerd --pod-infra-container-image docker.io/kubesphere/pause:3.8
+ExecReload=/bin/kill -s HUP $MAINPID
+TimeoutSec=0
+RestartSec=2
+Restart=always
+
+# Note that StartLimit* options were moved from "Service" to "Unit" in systemd 229.
+# Both the old, and new location are accepted by systemd 229 and up, so using the old location
+# to make them work for either version of systemd.
+StartLimitBurst=3
+
+# Note that StartLimitInterval was renamed to StartLimitIntervalSec in systemd 230.
+# Both the old, and new name are accepted by systemd 230 and up, so using the old name to make
+# this option work for either version of systemd.
+StartLimitInterval=60s
+
+# Having non-zero Limit*s causes performance problems due to accounting overhead
+# in the kernel. We recommend using cgroups to do container-local accounting.
+LimitNOFILE=infinity
+LimitNPROC=infinity
+LimitCORE=infinity
+
+# Comment TasksMax if your systemd version does not support it.
+# Only systemd 226 and above support this option.
+TasksMax=infinity
+Delegate=yes
+KillMode=process
+
+[Install]
+WantedBy=multi-user.target
+
+ `)))
diff --git a/cmd/kk/pkg/files/file.go b/cmd/kk/pkg/files/file.go
index bba319b6c..a3a8cc0d4 100644
--- a/cmd/kk/pkg/files/file.go
+++ b/cmd/kk/pkg/files/file.go
@@ -44,6 +44,7 @@ const (
k3s = "k3s"
k8e = "k8e"
docker = "docker"
+ cridockerd = "cri-dockerd"
crictl = "crictl"
registry = "registry"
harbor = "harbor"
@@ -58,6 +59,7 @@ const (
CNI = "cni"
CRICTL = "crictl"
DOCKER = "docker"
+ CRIDOCKERD = "cri-dockerd"
ETCD = "etcd"
HELM = "helm"
KUBE = "kube"
@@ -147,6 +149,10 @@ func NewKubeBinary(name, arch, version, prePath string, getCmd func(path, url st
if component.Zone == "cn" {
component.Url = fmt.Sprintf("https://mirrors.aliyun.com/docker-ce/linux/static/stable/%s/docker-%s.tgz", util.ArchAlias(arch), version)
}
+ case cridockerd:
+ component.Type = CRIDOCKERD
+ component.FileName = fmt.Sprintf("cri-dockerd-%s.tgz", version)
+ component.Url = fmt.Sprintf("https://github.com/Mirantis/cri-dockerd/releases/download/v%s/cri-dockerd-%s.%s.tgz", version, version, arch)
case crictl:
component.Type = CRICTL
component.FileName = fmt.Sprintf("crictl-%s-linux-%s.tar.gz", version, arch)
diff --git a/cmd/kk/pkg/kubernetes/tasks.go b/cmd/kk/pkg/kubernetes/tasks.go
index fce0e8cfb..aaeda50fd 100644
--- a/cmd/kk/pkg/kubernetes/tasks.go
+++ b/cmd/kk/pkg/kubernetes/tasks.go
@@ -46,6 +46,7 @@ import (
"github.com/kubesphere/kubekey/v3/cmd/kk/pkg/images"
"github.com/kubesphere/kubekey/v3/cmd/kk/pkg/kubernetes/templates"
"github.com/kubesphere/kubekey/v3/cmd/kk/pkg/utils"
+ "github.com/kubesphere/kubekey/v3/cmd/kk/pkg/version/kubernetes"
)
type GetClusterStatus struct {
@@ -715,10 +716,15 @@ func (u *UpgradeKubeMaster) Execute(runtime connector.Runtime) error {
return errors.Wrap(errors.WithStack(err), fmt.Sprintf("stop kubelet failed: %s", host.GetName()))
}
- if versionutil.MustParseSemantic(u.KubeConf.Cluster.Kubernetes.Version).AtLeast(versionutil.MustParseSemantic("v1.24.0")) {
+ if kubernetes.IsAtLeastV124(u.KubeConf.Cluster.Kubernetes.Version){
if _, err := runtime.GetRunner().SudoCmd("sed -i 's/ --network-plugin=cni / /g' /var/lib/kubelet/kubeadm-flags.env", false); err != nil {
return errors.Wrap(errors.WithStack(err), fmt.Sprintf("update kubelet config failed: %s", host.GetName()))
}
+ if u.KubeConf.Cluster.Kubernetes.ContainerManager == common.Docker {
+ if _, err := runtime.GetRunner().SudoCmd("sed -i 's/ --container-runtime=remote / /g' /var/lib/kubelet/kubeadm-flags.env", false); err != nil {
+ return errors.Wrap(errors.WithStack(err), fmt.Sprintf("update kubelet config failed: %s", host.GetName()))
+ }
+ }
}
if err := SetKubeletTasks(runtime, u.KubeAction); err != nil {
diff --git a/cmd/kk/pkg/pipelines/upgrade_cluster.go b/cmd/kk/pkg/pipelines/upgrade_cluster.go
index 8aafd4f0f..918f5303c 100644
--- a/cmd/kk/pkg/pipelines/upgrade_cluster.go
+++ b/cmd/kk/pkg/pipelines/upgrade_cluster.go
@@ -40,7 +40,7 @@ func NewUpgradeClusterPipeline(runtime *common.KubeRuntime) error {
m := []module.Module{
&precheck.GreetingsModule{},
&precheck.NodePreCheckModule{},
- &precheck.ClusterPreCheckModule{},
+ &precheck.ClusterPreCheckModule{SkipDependencyCheck: runtime.Arg.SkipDependencyCheck},
&confirm.UpgradeConfirmModule{Skip: runtime.Arg.SkipConfirmCheck},
&artifact.UnArchiveModule{Skip: noArtifact},
&kubernetes.SetUpgradePlanModule{Step: kubernetes.ToV121},
diff --git a/cmd/kk/pkg/utils/client.go b/cmd/kk/pkg/utils/client.go
index 98f22cfa8..af92b6933 100644
--- a/cmd/kk/pkg/utils/client.go
+++ b/cmd/kk/pkg/utils/client.go
@@ -17,12 +17,12 @@
package utils
import (
- "os"
- "path/filepath"
-
"github.com/pkg/errors"
"k8s.io/client-go/kubernetes"
+ "k8s.io/client-go/rest"
"k8s.io/client-go/tools/clientcmd"
+ "os"
+ "path/filepath"
)
func NewClient(config string) (*kubernetes.Clientset, error) {
@@ -41,13 +41,8 @@ func NewClient(config string) (*kubernetes.Clientset, error) {
if err != nil {
return nil, err
}
- // create the clientset
- clientset, err := kubernetes.NewForConfig(configCluster)
- if err != nil {
- return nil, err
- }
- return clientset, nil
+ return newForClient(configCluster)
}
func homeDir() string {
@@ -56,3 +51,33 @@ func homeDir() string {
}
return os.Getenv("USERPROFILE")
}
+
+func KubeConfigFormByte(data []byte) (*rest.Config, error) {
+ ClientConfig, err := clientcmd.NewClientConfigFromBytes(data)
+ if err != nil {
+ return nil, err
+ }
+ restConfig, err := ClientConfig.ClientConfig()
+ if err != nil {
+ return nil, err
+ }
+ return restConfig, nil
+}
+
+func NewClientForCluster(kubeConfig []byte) (*kubernetes.Clientset, error) {
+
+ forClientConfig, err := KubeConfigFormByte(kubeConfig)
+ if err != nil {
+ return nil, err
+ }
+
+ return newForClient(forClientConfig)
+}
+
+func newForClient(config *rest.Config) (*kubernetes.Clientset, error) {
+ client, err := kubernetes.NewForConfig(config)
+ if err != nil {
+ return nil, err
+ }
+ return client, nil
+}
diff --git a/cmd/kk/pkg/version/kubernetes/version_enum.go b/cmd/kk/pkg/version/kubernetes/version_enum.go
index e0fffdbbf..730466d35 100644
--- a/cmd/kk/pkg/version/kubernetes/version_enum.go
+++ b/cmd/kk/pkg/version/kubernetes/version_enum.go
@@ -103,3 +103,16 @@ func SupportedK8sVersionList() []string {
return versionsList
}
+
+func IsAtLeastV124(clusterVersion string) bool {
+ parsedVersion, err := versionutil.ParseGeneric(clusterVersion)
+ if err != nil {
+ return false
+ }
+
+ if parsedVersion.AtLeast(versionutil.MustParseSemantic("v1.24.0")) {
+ return true
+ }
+
+ return false
+}
\ No newline at end of file
diff --git a/go.mod b/go.mod
index 0b0055c8f..fab48a89f 100644
--- a/go.mod
+++ b/go.mod
@@ -33,7 +33,8 @@ require (
github.com/spf13/cobra v1.5.0
github.com/spf13/pflag v1.0.5
github.com/spf13/viper v1.12.0
- golang.org/x/crypto v0.0.0-20220919173607-35f4265a4bc0
+ github.com/xuri/excelize/v2 v2.8.0
+ golang.org/x/crypto v0.12.0
gopkg.in/yaml.v3 v3.0.1
helm.sh/helm/v3 v3.9.4
k8s.io/api v0.25.4
@@ -180,6 +181,7 @@ require (
github.com/moby/term v0.0.0-20210619224110-3f7ff695adc6 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect
+ github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 // indirect
github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00 // indirect
github.com/morikuni/aec v1.0.0 // indirect
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
@@ -197,6 +199,8 @@ require (
github.com/prometheus/client_model v0.2.0 // indirect
github.com/prometheus/common v0.37.0 // indirect
github.com/prometheus/procfs v0.7.3 // indirect
+ github.com/richardlehane/mscfb v1.0.4 // indirect
+ github.com/richardlehane/msoleps v1.0.3 // indirect
github.com/rivo/uniseg v0.2.0 // indirect
github.com/rubenv/sql-migrate v1.1.1 // indirect
github.com/russross/blackfriday v1.6.0 // indirect
@@ -219,17 +223,19 @@ require (
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect
github.com/xeipuuv/gojsonschema v1.2.0 // indirect
github.com/xlab/treeprint v1.1.0 // indirect
+ github.com/xuri/efp v0.0.0-20230802181842-ad255f2331ca // indirect
+ github.com/xuri/nfp v0.0.0-20230819163627-dc951e3ffe1a // indirect
go.etcd.io/bbolt v1.3.6 // indirect
go.mozilla.org/pkcs7 v0.0.0-20210826202110-33d05740a352 // indirect
go.opencensus.io v0.23.0 // indirect
go.starlark.net v0.0.0-20200306205701-8dd3e2ee1dd5 // indirect
go.uber.org/atomic v1.9.0 // indirect
- golang.org/x/net v0.1.0 // indirect
+ golang.org/x/net v0.14.0 // indirect
golang.org/x/oauth2 v0.0.0-20220909003341-f21342109be1 // indirect
- golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4 // indirect
- golang.org/x/sys v0.1.0 // indirect
- golang.org/x/term v0.1.0 // indirect
- golang.org/x/text v0.4.0 // indirect
+ golang.org/x/sync v0.1.0 // indirect
+ golang.org/x/sys v0.11.0 // indirect
+ golang.org/x/term v0.11.0 // indirect
+ golang.org/x/text v0.12.0 // indirect
golang.org/x/time v0.0.0-20220722155302-e5dcc9cfc0b9 // indirect
golang.org/x/xerrors v0.0.0-20220609144429-65e65417b02f // indirect
gomodules.xyz/jsonpatch/v2 v2.2.0 // indirect
diff --git a/go.sum b/go.sum
index a64458c9f..e15f0f228 100644
--- a/go.sum
+++ b/go.sum
@@ -943,6 +943,8 @@ github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9G
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
github.com/modood/table v0.0.0-20220527013332-8d47e76dad33 h1:T5IbS9C1G2zeHb6eBy6OfIvj5tfQB23kGFpewCJuGDg=
github.com/modood/table v0.0.0-20220527013332-8d47e76dad33/go.mod h1:41qyXVI5QH9/ObyPj27CGCVau5v/njfc3Gjj7yzr0HQ=
+github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 h1:RWengNIwukTxcDr9M+97sNutRR1RKhG96O6jWumTTnw=
+github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826/go.mod h1:TaXosZuwdSHYgviHp1DAtfrULt5eUgsSMsZf+YrPgl8=
github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00 h1:n6/2gBQ3RWajuToeY6ZtZTIKv2v7ThUy5KKusIT0yc0=
github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00/go.mod h1:Pm3mSP3c5uWn86xMLZ5Sa7JB9GsEZySvHYXCTK4E9q4=
github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A=
@@ -1096,6 +1098,11 @@ github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1
github.com/prometheus/procfs v0.7.3 h1:4jVXhlkAyzOScmCkXBTOLRLTz8EeU+eyjrwB/EPq0VU=
github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA=
github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU=
+github.com/richardlehane/mscfb v1.0.4 h1:WULscsljNPConisD5hR0+OyZjwK46Pfyr6mPu5ZawpM=
+github.com/richardlehane/mscfb v1.0.4/go.mod h1:YzVpcZg9czvAuhk9T+a3avCpcFPMUWm7gK3DypaEsUk=
+github.com/richardlehane/msoleps v1.0.1/go.mod h1:BWev5JBpU9Ko2WAgmZEuiz4/u3ZYTKbjLycmwiWUfWg=
+github.com/richardlehane/msoleps v1.0.3 h1:aznSZzrwYRl3rLKRT3gUk9am7T/mLNSnJINvN0AQoVM=
+github.com/richardlehane/msoleps v1.0.3/go.mod h1:BWev5JBpU9Ko2WAgmZEuiz4/u3ZYTKbjLycmwiWUfWg=
github.com/rifflock/lfshook v0.0.0-20180920164130-b9218ef580f5 h1:mZHayPoR0lNmnHyvtYjDeq0zlVHn9K/ZXoy17ylucdo=
github.com/rifflock/lfshook v0.0.0-20180920164130-b9218ef580f5/go.mod h1:GEXHk5HgEKCvEIIrSpFI3ozzG5xOKA2DVlEX/gGnewM=
github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY=
@@ -1255,12 +1262,19 @@ github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q
github.com/xlab/treeprint v1.1.0 h1:G/1DjNkPpfZCFt9CSh6b5/nY4VimlbHF3Rh4obvtzDk=
github.com/xlab/treeprint v1.1.0/go.mod h1:gj5Gd3gPdKtR1ikdDK6fnFLdmIS0X30kTTuNd/WEJu0=
github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=
+github.com/xuri/efp v0.0.0-20230802181842-ad255f2331ca h1:uvPMDVyP7PXMMioYdyPH+0O+Ta/UO1WFfNYMO3Wz0eg=
+github.com/xuri/efp v0.0.0-20230802181842-ad255f2331ca/go.mod h1:ybY/Jr0T0GTCnYjKqmdwxyxn2BQf2RcQIIvex5QldPI=
+github.com/xuri/excelize/v2 v2.8.0 h1:Vd4Qy809fupgp1v7X+nCS/MioeQmYVVzi495UCTqB7U=
+github.com/xuri/excelize/v2 v2.8.0/go.mod h1:6iA2edBTKxKbZAa7X5bDhcCg51xdOn1Ar5sfoXRGrQg=
+github.com/xuri/nfp v0.0.0-20230819163627-dc951e3ffe1a h1:Mw2VNrNNNjDtw68VsEj2+st+oCSn4Uz7vZw6TbhcV1o=
+github.com/xuri/nfp v0.0.0-20230819163627-dc951e3ffe1a/go.mod h1:WwHg+CVyzlv/TX9xqBFXEZAuxOPxn2k1GNHwG41IIUQ=
github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
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.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
github.com/yvasiyarov/go-metrics v0.0.0-20150112132944-c25f46c4b940 h1:p7OofyZ509h8DmPLh8Hn+EIIZm/xYhdZHJ9GnXHdr6U=
github.com/yvasiyarov/gorelic v0.0.7 h1:4DTF1WOM2ZZS/xMOkTFBOcb6XiHu/PKn3rVo6dbewQE=
github.com/yvasiyarov/newrelic_platform_go v0.0.0-20160601141957-9c099fbc30e9 h1:AsFN8kXcCVkUFHyuzp1FtYbzp1nCO/H6+1uPSGEyPzM=
@@ -1356,8 +1370,8 @@ golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5y
golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
-golang.org/x/crypto v0.0.0-20220919173607-35f4265a4bc0 h1:a5Yg6ylndHHYJqIPrdq0AhvR6KTvDTAvgBtaidhEevY=
-golang.org/x/crypto v0.0.0-20220919173607-35f4265a4bc0/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
+golang.org/x/crypto v0.12.0 h1:tFM/ta59kqch6LlvYnPa0yx5a83cL2nHflFhYKvv9Yk=
+golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98yw=
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=
@@ -1370,6 +1384,8 @@ golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EH
golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU=
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/image v0.11.0 h1:ds2RoQvBvYTiJkwpSFDwCcDFNX7DqjL2WsUgTNk0Ooo=
+golang.org/x/image v0.11.0/go.mod h1:bglhjqbqVuEb9e9+eNR45Jfu7D+T4Qan+NhQk8Ck2P8=
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=
@@ -1393,6 +1409,8 @@ 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.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
+golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
@@ -1459,9 +1477,12 @@ golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4/go.mod h1:CfG3xpIq0wQ8r1q4Su
golang.org/x/net v0.0.0-20220607020251-c690dde0001d/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.0.0-20220617184016-355a448f1bc9/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.0.0-20220624214902-1bab6f366d9e/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
+golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.0.0-20220909164309-bea034e7d591/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk=
-golang.org/x/net v0.1.0 h1:hZ/3BUoy5aId7sCpA/Tc5lt8DkFgdVS2onTpJsZ/fl0=
-golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco=
+golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
+golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
+golang.org/x/net v0.14.0 h1:BONx9s002vGdD9umnlX1Po8vOZmrgH34qlHcD1MfK14=
+golang.org/x/net v0.14.0/go.mod h1:PpSgVXXLK0OxS0F31C1/tv6XNguvCrnXIDrFMspZIUI=
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=
@@ -1498,8 +1519,9 @@ golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJ
golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
-golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4 h1:uVc8UZUe6tr40fFVnUP5Oj+veunVezqYl9z7DYw9xzw=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o=
+golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
@@ -1622,17 +1644,22 @@ golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.0.0-20220610221304-9f5ed59c137d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220615213510-4f61da869c0c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220909162455-aba9fc2a8ff2/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.1.0 h1:kunALQeHf1/185U1i0GOB/fy1IPRDDpuoOOqRReG57U=
-golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.11.0 h1:eG7RXZHdqOJ1i+0lgLgCpSXAp6M3LYlAo6osgSi0xOM=
+golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
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-20210220032956-6a3ed077a48d/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210615171337-6886f2dfbf5b/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
-golang.org/x/term v0.1.0 h1:g6Z6vPFA9dYBAF7DWcH6sCcOntplXsDKcliusYijMlw=
-golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
+golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
+golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
+golang.org/x/term v0.11.0 h1:F9tnn/DA/Im8nCwm+fX+1/eBwi4qFjRT++MhtVC4ZX0=
+golang.org/x/term v0.11.0/go.mod h1:zC9APTIj3jG3FdV/Ons+XE1riIZXG4aZ4GTHiPZJPIU=
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=
@@ -1642,8 +1669,10 @@ golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
-golang.org/x/text v0.4.0 h1:BrVqGRd7+k1DiOgtnFvAkoQEWQvBc25ouMJM6429SFg=
-golang.org/x/text v0.4.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.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
+golang.org/x/text v0.12.0 h1:k+n5B8goJNdU7hSvEtMUz3d1Q6D/XW4COJSJR6fN0mc=
+golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
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=
@@ -1722,6 +1751,8 @@ 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.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
+golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
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=
diff --git a/version/components.json b/version/components.json
index 2de3b3cee..ff58f9af3 100644
--- a/version/components.json
+++ b/version/components.json
@@ -969,58 +969,20 @@
},
"docker": {
"amd64": {
- "20.10.2": "97017e32a8ecbdd1826bb3c7b1424303ee0dea3f900d33591b1df5e394ed4eed",
- "20.10.3": "47065a47f0692cd5af03073c7386fe090d9ef5ac88a7d8455a884d8e15809be5",
- "20.10.4": "6ec28b6a251e093f5cf32569c4bfce4821eda02923b33c060694e6ca2c851daa",
- "20.10.5": "3f18edc66e1faae607d428349e77f9800bdea554528521f0f6c49fc3f1de6abf",
- "20.10.6": "e3b6c3b11518281a51fb0eee73138482b83041e908f01adf8abd3a24b34ea21e",
- "20.10.7": "34ad50146fce29b28e5115a1e8510dd5232459c9a4a9f28f65909f92cca314d9",
- "20.10.8": "7ea11ecb100fdc085dbfd9ab1ff380e7f99733c890ed815510a5952e5d6dd7e0",
- "20.10.9": "caf74e54b58c0b38bb4d96c8f87665f29b684371c9a325562a3904b8c389995e",
- "20.10.10": "1719446f99cd56e87d0c67019996af4ea859f11891bfd89de2252d6c916ccaaa",
- "20.10.11": "dd6ff72df1edfd61ae55feaa4aadb88634161f0aa06dbaaf291d1be594099ff3",
- "20.10.12": "ee9b5be14e54bf92f48c82c2e6a83fbdd1c5329e8f247525a9ed2fe90d9f89a5",
- "20.10.13": "39edf7c8d773939ff5e4d318ae565691a9c7e754ed768e172757e58898fb7079",
- "20.10.14": "7ca4aeeed86619909ae584ce3405da3766d495f98904ffbd9d859add26b83af5",
- "20.10.15": "9ccfc39305ae1d8882d18c9c431544fca82913d6df717409ac2244ac58c4f070",
- "20.10.16": "b43ac6c4d2f0b64e445c6564860e4fccd6331f4a61815a60642c7748b53c59ff",
- "20.10.17": "969210917b5548621a2b541caf00f86cc6963c6cf0fb13265b9731c3b98974d9",
- "20.10.18": "0629b063fa3aa5660f3fb96f67edb0e20e92d5050b82403f95faf1c142177401",
- "20.10.19": "ddcd732baaa03958cc8f326a5dca09bcd8f348bb7d2737aaf67bbdd7d80302d1",
- "20.10.20": "a303cee9125c89abbbb6c4f044b3e2c01c7895e373b90d8de16a7ed25bb2530a",
- "20.10.21": "2582bed8772b283bda9d4565c0af76ee653c93d93dc6b8d0aad795d731a1bb81",
- "20.10.22": "945c3a3ddcb79ee7307496c2f39eb3d8372466e8654e63d60bbb462e4a3c1427",
- "20.10.23": "0ee39f72cc434137d294c14d30897826bad6e24979e421f51a252769ad37e6d1",
- "23.0.0": "6a03bbda96845b7451be2f6aba69c3816c60a97de318e83fd1b39d1be262d8af",
- "23.0.1": "ec8a71e79125d3ca76f7cc295f35eea225f4450e0ffe0775f103e2952ff580f6",
- "24.0.6": "99792dec613df93169a118b05312a722a63604b868e4c941b1b436abcf3bb70f"
+ "24.0.6": "99792dec613df93169a118b05312a722a63604b868e4c941b1b436abcf3bb70f",
+ "24.0.9": "692ecfc28333485d184f628b74c25b2894cee9495a51a5418ba60ef95bf733ca"
},
"arm64": {
- "20.10.2": "9ea59f249ae92bbaa9831a22f2affa2edc9e824f9daaba831ca51d6d22ef2df5",
- "20.10.3": "4dcd105f721297f314bb53622e67dd981a743d72f4b2bfe4f42a8790e0892c82",
- "20.10.4": "bd9fb2f770eb508b3273237c5604266b6cd93789d048069bd6b16efbf8919fca",
- "20.10.5": "83157b92d7469117c2720fc44074749e080b3c510ae35b8a57c66a016cf07dd5",
- "20.10.6": "998b3b6669335f1a1d8c475fb7c211ed1e41c2ff37275939e2523666ccb7d910",
- "20.10.7": "be8c9a5a06ebec8fb1d36e867cd00fb5777746a9812a0cae2966778ff899c525",
- "20.10.8": "4eb9d5e2adf718cd7ee59f6951715f3113c9c4ee49c75c9efb9747f2c3457b2b",
- "20.10.9": "0259f8b6572f02cf0dafd7388ca0e4adfdbbfaba81cfb1b7443e89fccbed22c7",
- "20.10.10": "8db47cdcd7ac6e082c9ce83347d8fb99eaa01e04b0c8d94851e8d58f350a3633",
- "20.10.11": "87a4219c54552797ffd38790b72832372a90eceb7c8e451c36a682093d57dae6",
- "20.10.12": "e1f964e9a7a824bbe2164560c0eb335fab9cc7ee9eb90da36c250c073459cf17",
- "20.10.13": "debed306ed9a4e70dcbcb228a0b3898f9730099e324f34bb0e76abbaddf7a6a7",
- "20.10.14": "ea971edc1179088bfd25edd04a0c12848143d15cb8202ebb93a6a08973464fd0",
- "20.10.15": "46102273fab8d6b8a7cf248a928ebaa4bee43114001c593b0d07092a34a439e1",
- "20.10.16": "2f35d8d422b63a59279084c159c9092b63b6d974a7fcd868167aee4cc5f79f3b",
- "20.10.17": "249244024b507a6599084522cc73e73993349d13264505b387593f2b2ed603e6",
- "20.10.18": "aa2b2da571fb9160df87fd5a831f203fb97655e35fb9c4e8d46e72078ae16acf",
- "20.10.19": "a04414b3fcf537f0cff17cf01e2b7cb3e39013c10d12e7959547f11aaf71f63c",
- "20.10.20": "ef69a2a8ddb87026a8b19e240b2ae3087764b7285860df7faee24e04024f2eb7",
- "20.10.21": "b4ceb6151d4dd1bfc7557f5fe0317e29cfcac91f798c34fae7dee891a811f8ee",
- "20.10.22": "2c75cd6c3dc9b81cb5bde664c882e4339a2054e09cf09606f9f7dd6970e7f078",
- "20.10.23": "5c40bb7dcd1aad94be49ad75d24e7fd409119ed0eaad04f5d13c4fddfb397c8a",
- "23.0.0": "2919ff3448187d4f13cfbe2332707cff3f6dcf2baaac42a34bea8dd21f434f4a",
- "23.0.1": "3865f837dbd951b19eeb5f7d87aada2e865b2017e9462fe389f0e5d9a438324d",
- "24.0.6": "d9f58aecc42451503e82e6e0562cafa1812b334c92186a7f486e111e70a0f5bd"
+ "24.0.6": "d9f58aecc42451503e82e6e0562cafa1812b334c92186a7f486e111e70a0f5bd",
+ "24.0.9": "7e999590330a15469de20ac37051407d222ea73c71c10c05d61666d42c5922d1"
+ }
+ },
+ "cri-dockerd": {
+ "amd64": {
+ "0.3.9": "a6d9b4b796e9eff830311a2349d259507302cb3955dd07b78296b91e40e8b433"
+ },
+ "arm64": {
+ "0.3.9": "f5051002b4f95b0e8fe7fbd5f8de4493350e010834d2a8b647f2b26c45c6c203"
}
},
"containerd": {