diff --git a/README.md b/README.md index 7b3943debbb..2a9892cc29d 100644 --- a/README.md +++ b/README.md @@ -92,6 +92,7 @@ yurtctl convert --provider [minikube|kubeadm|kind] // To convert an existing Ku yurtctl revert // To uninstall and revert back to the original cluster settings yurtctl join // To allow a new node to join OpenYurt yurtctl reset // To revert changes to the node made by the join command +yurtctl init // To init an OpenYurt Cluster ``` Please check [yurtctl tutorial](./docs/tutorial/yurtctl.md) for more details. diff --git a/README.zh.md b/README.zh.md index f33e8741258..a09c97b8f7c 100644 --- a/README.zh.md +++ b/README.zh.md @@ -76,6 +76,7 @@ yurtctl convert --provider [minikube|kubeadm|kind] // 一键式转换原生Kube yurtctl revert // 一键式恢复OpenYurt集群为Kubernetes集群 yurtctl join // 往OpenYurt中接入一个节点(在边缘节点上执行) yurtctl reset // 从OpenYurt中清除边缘节点(在边缘节点上执行) +yurtctl init // 初始化OpenYurt集群 ``` 请查看 [yurtctl教程](./docs/tutorial/yurtctl.md)来获得更多使用细节。 diff --git a/docs/tutorial/yurtctl.md b/docs/tutorial/yurtctl.md index e8295e454ba..e80f94fdb7e 100644 --- a/docs/tutorial/yurtctl.md +++ b/docs/tutorial/yurtctl.md @@ -197,14 +197,14 @@ In addition, the path of the kubelet service configuration can be set by the opt and the path of the directory on edge node containing static pod files can be set by the option `--pod-manifest-path`. ## Create OpenYurt cluster -`yurtctl init` will create an OpenYurt cluster, but the user needs to install the runtime in advance and ensure that the swap partition of the node has been closed. +`yurtctl init` will create an OpenYurt cluster, and the user doesn't need to do pre-work, such as install the runtime in advance or ensure that the swap partition of the node has been closed. Using `yurtctl` to create an OpenYurt cluster can be done by doing the following: ``` -$ _output/bin/yurtctl init --image-repository=registry.cn-hangzhou.aliyuncs.com/google_containers --kubernetes-version=v1.18.8 --pod-network-cidr=10.244.0.0/16 +$ _output/bin/yurtctl init --apiserver-advertise-address 1.2.3.4 --openyurt-version v0.5.0 --passwd 1234 ``` -In addition, the OpenYurt components version can be set by the option `--yurt-version`, -and the OpenYurt components image registry can be set by the option `--yurt-image-registry`. +The `--apiserver-advertise-address` is the IP address of master, `--passwd` is ssh password of master, `--openyurt-version` is the the OpenYurt cluster version. +In addition, and the OpenYurt cluster image registry can be set by the option `--image-registry`. If user want to get more help, please use `yurtctl init -h`. ## Join Edge-Node/Cloud-Node to OpenYurt diff --git a/pkg/yurtctl/cmd/cmd.go b/pkg/yurtctl/cmd/cmd.go index d708ee1c56c..fa496d95119 100644 --- a/pkg/yurtctl/cmd/cmd.go +++ b/pkg/yurtctl/cmd/cmd.go @@ -51,9 +51,9 @@ func NewYurtctlCommand() *cobra.Command { cmds.AddCommand(revert.NewRevertCmd()) cmds.AddCommand(markautonomous.NewMarkAutonomousCmd()) cmds.AddCommand(clusterinfo.NewClusterInfoCmd()) + cmds.AddCommand(yurtinit.NewCmdInit()) cmds.AddCommand(join.NewCmdJoin(os.Stdout, nil)) cmds.AddCommand(reset.NewCmdReset(os.Stdin, os.Stdout, nil)) - cmds.AddCommand(yurtinit.NewCmdInit(os.Stdout, nil)) klog.InitFlags(nil) // goflag.Parse() diff --git a/pkg/yurtctl/cmd/yurtinit/init.go b/pkg/yurtctl/cmd/yurtinit/init.go index 65f5ce7ddbf..5bf3acf80df 100644 --- a/pkg/yurtctl/cmd/yurtinit/init.go +++ b/pkg/yurtctl/cmd/yurtinit/init.go @@ -1,6 +1,5 @@ /* -Copyright 2021 The OpenYurt Authors. -Copyright 2019 The Kubernetes Authors. +Copyright 2020 The OpenYurt Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -19,620 +18,272 @@ package yurtinit import ( "bytes" - "crypto/x509" + "encoding/json" "fmt" - "io" - "net" + "io/ioutil" "os" - "path/filepath" + "os/exec" + "runtime" "strings" - "text/template" - "github.com/lithammer/dedent" - "github.com/pkg/errors" "github.com/spf13/cobra" flag "github.com/spf13/pflag" - "k8s.io/apimachinery/pkg/util/sets" - clientset "k8s.io/client-go/kubernetes" - "k8s.io/client-go/tools/clientcmd" - clientcertutil "k8s.io/client-go/util/cert" - kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm" - kubeadmscheme "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/scheme" - kubeadmapiv1beta2 "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/v1beta2" - "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/validation" - "k8s.io/kubernetes/cmd/kubeadm/app/cmd/options" - kubephases "k8s.io/kubernetes/cmd/kubeadm/app/cmd/phases/init" - "k8s.io/kubernetes/cmd/kubeadm/app/cmd/phases/workflow" - cmdutil "k8s.io/kubernetes/cmd/kubeadm/app/cmd/util" - kubeadmconstants "k8s.io/kubernetes/cmd/kubeadm/app/constants" - "k8s.io/kubernetes/cmd/kubeadm/app/features" - certsphase "k8s.io/kubernetes/cmd/kubeadm/app/phases/certs" - kubeconfigphase "k8s.io/kubernetes/cmd/kubeadm/app/phases/kubeconfig" - "k8s.io/kubernetes/cmd/kubeadm/app/util/apiclient" - configutil "k8s.io/kubernetes/cmd/kubeadm/app/util/config" - kubeconfigutil "k8s.io/kubernetes/cmd/kubeadm/app/util/kubeconfig" - "k8s.io/kubernetes/cmd/kubeadm/app/util/pubkeypin" + "k8s.io/klog/v2" - yurtphase "github.com/openyurtio/openyurt/pkg/yurtctl/cmd/yurtinit/phases" + "github.com/openyurtio/openyurt/pkg/yurtctl/util" + "github.com/openyurtio/openyurt/pkg/yurtctl/util/edgenode" + strutil "github.com/openyurtio/openyurt/pkg/yurtctl/util/strings" + tmplutil "github.com/openyurtio/openyurt/pkg/yurtctl/util/templates" ) -var ( - initDoneTempl = template.Must(template.New("init").Parse(dedent.Dedent(` - Your OpenYurt cluster control-plane has initialized successfully! - - To start using your cluster, you need to run the following as a regular user: - - mkdir -p $HOME/.kube - sudo cp -i {{.KubeConfigPath}} $HOME/.kube/config - sudo chown $(id -u):$(id -g) $HOME/.kube/config - - Then you can join any number of edge-nodes by running the following on each as root: - - {{.joinEdgeNodeCommand}} - - And you can join any number of cloud-nodes by running the following on each as root: - - {{.joinCloudNodeCommand}} - - `))) - - joinCommandTemplate = template.Must(template.New("join-edge-node").Parse(`` + - `yurtctl join {{.ControlPlaneHostPort}} --token {{.Token}} \ - {{range $h := .CAPubKeyPins}}--discovery-token-ca-cert-hash {{$h}} {{end}} --node-type={{.NodeType}}`, - )) +const ( + // APIServerAdvertiseAddress flag sets the IP address the API Server will advertise it's listening on. Specify '0.0.0.0' to use the address of the default network interface. + APIServerAdvertiseAddress = "apiserver-advertise-address" + //YurttunnelServerAddress flag sets the IP address of Yurttunnel Server. + YurttunnelServerAddress = "yurt-tunnel-server-address" + // NetworkingServiceSubnet flag sets the range of IP address for service VIPs. + NetworkingServiceSubnet = "service-cidr" + // NetworkingPodSubnet flag sets the range of IP addresses for the pod network. If set, the control plane will automatically allocate CIDRs for every node. + NetworkingPodSubnet = "pod-network-cidr" + // OpenYurtVersion flag sets the OpenYurt version for the control plane. + OpenYurtVersion = "openyurt-version" + // ImageRepository flag sets the container registry to pull control plane images from. + ImageRepository = "image-repository" + // PassWd flag is the password of master server. + PassWd = "passwd" + + TmpDownloadDir = "/tmp" + + SealerUrlFormat = "https://github.com/alibaba/sealer/releases/download/%s/sealer-%s-linux-%s.tar.gz" + DefaultSealerVersion = "v0.6.0" + + InitClusterImage = "%s/openyurt-cluster:%s" + SealerRunCmd = "sealer apply -f %s/Clusterfile" + + fileMode = 0666 + dirMode = 0755 + + OpenYurtClusterfile = ` +apiVersion: sealer.cloud/v2 +kind: Cluster +metadata: + name: my-cluster +spec: + hosts: + - ips: + - {{.apiserver_address}} + roles: + - master + image: {{.cluster_image}} + ssh: + passwd: {{.passwd}} + pk: /root/.ssh/id_rsa + user: root +--- +apiVersion: sealer.cloud/v2 +kind: KubeadmConfig +metadata: + name: default-kubernetes-config +spec: + networking: + {{if .pod_subnet }} + podSubnet: {{.pod_subnet}} + {{end}} + {{if .service_subnet}} + serviceSubnet: {{.service_subnet}} + {{end}} + controllerManager: + extraArgs: + controllers: -nodelifecycle,*,bootstrapsigner,tokencleaner +--- +apiVersion: kubeproxy.config.k8s.io/v1alpha1 +kind: KubeProxyConfiguration +featureGates: + EndpointSliceProxying: true +--- +apiVersion: sealer.aliyun.com/v1alpha1 +kind: Plugin +metadata: + name: MyShell +spec: + type: SHELL + action: PostInstall # PreInit PreInstall PostInstall + data: | + sed -i 's/${YurttunnelServerAddress}/{{.yurttunnel_server_address}}/g' manifests/yurttunnel-server.yaml && kubectl apply -f manifests/. +` ) -// initOptions defines all the init options exposed via flags by kubeadm init. -// Please note that this structure includes the public kubeadm config API, but only a subset of the options -// supported by this api will be exposed as a flag. -type initOptions struct { - cfgPath string - kubeconfigDir string - kubeconfigPath string - featureGatesString string - ignorePreflightErrors []string - bto *options.BootstrapTokenOptions - externalInitCfg *kubeadmapiv1beta2.InitConfiguration - externalClusterCfg *kubeadmapiv1beta2.ClusterConfiguration - kustomizeDir string - installCNIFile string - isConvertOpenYurtCluster bool - openyurtImageRegistry string - openyurtVersion string - openyurtTunnelServerAddress string -} - -// compile-time assert that the local data object satisfies the phases data interface. -var _ yurtphase.YurtInitData = &initData{} +var ( + ValidSealerVersions = []string{ + "v0.6.0", + } +) -// initData defines all the runtime information used when running the kubeadm init workflow; -// this data is shared across all the phases that are included in the workflow. -type initData struct { - cfg *kubeadmapi.InitConfiguration - skipTokenPrint bool - dryRun bool - kubeconfigDir string - kubeconfigPath string - ignorePreflightErrors sets.String - certificatesDir string - dryRunDir string - externalCA bool - client clientset.Interface - outputWriter io.Writer - uploadCerts bool - skipCertificateKeyPrint bool - kustomizeDir string - cniFileName string - isConvertOpenYurtCluster bool - openyurtImageRegistry string - openyurtVersion string - openyurtTunnelServerAddress string +// clusterInitializer init a node to master of openyurt cluster +type clusterInitializer struct { + InitOptions } -// NewCmdInit returns "kubeadm init" command. -// NB. initOptions is exposed as parameter for allowing unit testing of -// the newInitOptions method, that implements all the command options validation logic -func NewCmdInit(out io.Writer, initOptions *initOptions) *cobra.Command { - if initOptions == nil { - initOptions = newInitOptions() - } - initRunner := workflow.NewRunner() +// NewCmdInit use tool sealer to initializer a master of OpenYurt cluster. +// It will deploy all openyurt components, such as yurt-app-manager, yurt-tunnel-server, etc. +func NewCmdInit() *cobra.Command { + o := NewInitOptions() cmd := &cobra.Command{ Use: "init", - Short: "Run this command in order to set up the Kubernetes control plane", + Short: "Run this command in order to set up the OpenYurt control plane", RunE: func(cmd *cobra.Command, args []string) error { - c, err := initRunner.InitData(args) - if err != nil { + if err := o.Validate(); err != nil { return err } - - data := c.(*initData) - fmt.Printf("[init] Using Kubernetes version: %s\n", data.cfg.KubernetesVersion) - - if err := initRunner.Run(args); err != nil { + initializer := NewInitializerWithOptions(o) + if err := initializer.Run(); err != nil { return err } - - return showJoinCommand(data, out) + return nil }, Args: cobra.NoArgs, } - // adds flags to the init command - // init command local flags could be eventually inherited by the sub-commands automatically generated for phases - AddInitConfigFlags(cmd.Flags(), initOptions.externalInitCfg) - AddClusterConfigFlags(cmd.Flags(), initOptions.externalClusterCfg, &initOptions.featureGatesString) - AddInitOtherFlags(cmd.Flags(), initOptions) - initOptions.bto.AddTokenFlag(cmd.Flags()) - initOptions.bto.AddTTLFlag(cmd.Flags()) - options.AddImageMetaFlags(cmd.Flags(), &initOptions.externalClusterCfg.ImageRepository) - - // defines additional flag that are not used by the init command but that could be eventually used - // by the sub-commands automatically generated for phases - initRunner.SetAdditionalFlags(func(flags *flag.FlagSet) { - options.AddKubeConfigFlag(flags, &initOptions.kubeconfigPath) - options.AddKubeConfigDirFlag(flags, &initOptions.kubeconfigDir) - options.AddControlPlanExtraArgsFlags(flags, &initOptions.externalClusterCfg.APIServer.ExtraArgs, &initOptions.externalClusterCfg.ControllerManager.ExtraArgs, &initOptions.externalClusterCfg.Scheduler.ExtraArgs) - }) - - // initialize the workflow runner with the list of phases - initRunner.AppendPhase(yurtphase.NewPreparePhase()) - initRunner.AppendPhase(kubephases.NewPreflightPhase()) - initRunner.AppendPhase(kubephases.NewKubeletStartPhase()) - initRunner.AppendPhase(kubephases.NewCertsPhase()) - initRunner.AppendPhase(kubephases.NewKubeConfigPhase()) - initRunner.AppendPhase(yurtphase.NewAllInAoneControlPlanePhase()) - initRunner.AppendPhase(kubephases.NewWaitControlPlanePhase()) - initRunner.AppendPhase(kubephases.NewUploadConfigPhase()) - initRunner.AppendPhase(yurtphase.NewMarkCloudNode()) - initRunner.AppendPhase(kubephases.NewBootstrapTokenPhase()) - initRunner.AppendPhase(kubephases.NewKubeletFinalizePhase()) - initRunner.AppendPhase(kubephases.NewAddonPhase()) - initRunner.AppendPhase(yurtphase.NewInstallCNIPhase()) - initRunner.AppendPhase(yurtphase.NewInstallYurtAddonsPhase()) - - // sets the data builder function, that will be used by the runner - // both when running the entire workflow or single phases - initRunner.SetDataInitializer(func(cmd *cobra.Command, args []string) (workflow.RunData, error) { - return newInitData(cmd, args, initOptions, out) - }) - - // binds the Runner to kubeadm init command by altering - // command help, adding --skip-phases flag and by adding phases subcommands - initRunner.BindToCommand(cmd) - + addFlags(cmd.Flags(), o) return cmd } -// AddInitConfigFlags adds init flags bound to the config to the specified flagset -func AddInitConfigFlags(flagSet *flag.FlagSet, cfg *kubeadmapiv1beta2.InitConfiguration) { - flagSet.StringVar( - &cfg.LocalAPIEndpoint.AdvertiseAddress, options.APIServerAdvertiseAddress, cfg.LocalAPIEndpoint.AdvertiseAddress, - "The IP address the API Server will advertise it's listening on. If not set the default network interface will be used.", - ) - flagSet.Int32Var( - &cfg.LocalAPIEndpoint.BindPort, options.APIServerBindPort, cfg.LocalAPIEndpoint.BindPort, - "Port for the API Server to bind to.", +func addFlags(flagset *flag.FlagSet, o *InitOptions) { + flagset.StringVarP( + &o.AdvertiseAddress, APIServerAdvertiseAddress, "", o.AdvertiseAddress, + "The IP address the API Server will advertise it's listening on.", ) - cmdutil.AddCRISocketFlag(flagSet, &cfg.NodeRegistration.CRISocket) -} - -// AddClusterConfigFlags adds cluster flags bound to the config to the specified flagset -func AddClusterConfigFlags(flagSet *flag.FlagSet, cfg *kubeadmapiv1beta2.ClusterConfiguration, featureGatesString *string) { - flagSet.StringVar( - &cfg.Networking.ServiceSubnet, options.NetworkingServiceSubnet, cfg.Networking.ServiceSubnet, + flagset.StringVarP( + &o.YurttunnelServerAddress, YurttunnelServerAddress, "", o.YurttunnelServerAddress, + "The yurt-tunnel-server address.") + flagset.StringVarP( + &o.ServiceSubnet, NetworkingServiceSubnet, "", o.ServiceSubnet, "Use alternative range of IP address for service VIPs.", ) - flagSet.StringVar( - &cfg.Networking.PodSubnet, options.NetworkingPodSubnet, cfg.Networking.PodSubnet, + flagset.StringVarP( + &o.PodSubnet, NetworkingPodSubnet, "", o.PodSubnet, "Specify range of IP addresses for the pod network. If set, the control plane will automatically allocate CIDRs for every node.", ) - flagSet.StringVar( - &cfg.Networking.DNSDomain, options.NetworkingDNSDomain, cfg.Networking.DNSDomain, - `Use alternative domain for services, e.g. "myorg.internal".`, + flagset.StringVarP(&o.Password, PassWd, "p", o.Password, + "set master server ssh password", ) - flagSet.StringVar( - &cfg.ControlPlaneEndpoint, options.ControlPlaneEndpoint, cfg.ControlPlaneEndpoint, - `Specify a stable IP address or DNS name for the control plane.`, + flagset.StringVarP( + &o.OpenYurtVersion, OpenYurtVersion, "", o.OpenYurtVersion, + `Choose a specific OpenYurt version for the control plane.`, ) - options.AddKubernetesVersionFlag(flagSet, &cfg.KubernetesVersion) - flagSet.StringSliceVar( - &cfg.APIServer.CertSANs, options.APIServerCertSANs, cfg.APIServer.CertSANs, - `Optional extra Subject Alternative Names (SANs) to use for the API Server serving certificate. Can be both IP addresses and DNS names.`, + flagset.StringVarP(&o.ImageRepository, ImageRepository, "", o.ImageRepository, + "Choose a registry to pull cluster images from", ) - options.AddFeatureGatesStringFlag(flagSet, featureGatesString) -} - -// AddInitOtherFlags adds init flags that are not bound to a configuration file to the given flagset -// Note: All flags that are not bound to the cfg object should be allowed in cmd/kubeadm/app/apis/kubeadm/validation/validation.go -func AddInitOtherFlags(flagSet *flag.FlagSet, initOptions *initOptions) { - options.AddConfigFlag(flagSet, &initOptions.cfgPath) - flagSet.StringSliceVar( - &initOptions.ignorePreflightErrors, options.IgnorePreflightErrors, initOptions.ignorePreflightErrors, - "A list of checks whose errors will be shown as warnings. Example: 'IsPrivilegedUser,Swap'. Value 'all' ignores errors from all checks.", - ) - flagSet.StringVar(&initOptions.openyurtImageRegistry, "yurt-image-registry", "", - "Choose a container registry to pull OpenYurt component images from") - flagSet.StringVar(&initOptions.openyurtVersion, "yurt-version", "", - "Choose a specific OpenYurt version") - flagSet.StringVar(&initOptions.openyurtTunnelServerAddress, "yurt-tunnel-server-address", "", - "Choose an accessible address for tunnelAgent when deployed in an isolated network") - flagSet.StringVar(&initOptions.installCNIFile, "install-cni-file", "", - "Configure install cni yaml file.") - flagSet.BoolVar( - &initOptions.isConvertOpenYurtCluster, "is-convert-openyurt", true, "Convert kubernetes cluster to OpenYurt cluster.") - options.AddKustomizePodsFlag(flagSet, &initOptions.kustomizeDir) -} - -// newInitOptions returns a struct ready for being used for creating cmd init flags. -func newInitOptions() *initOptions { - // initialize the public kubeadm config API by applying defaults - externalInitCfg := &kubeadmapiv1beta2.InitConfiguration{} - kubeadmscheme.Scheme.Default(externalInitCfg) - - externalClusterCfg := &kubeadmapiv1beta2.ClusterConfiguration{} - kubeadmscheme.Scheme.Default(externalClusterCfg) - - // Create the options object for the bootstrap token-related flags, and override the default value for .Description - bto := options.NewBootstrapTokenOptions() - bto.Description = "The default bootstrap token generated by 'kubeadm init'." - - return &initOptions{ - externalInitCfg: externalInitCfg, - externalClusterCfg: externalClusterCfg, - bto: bto, - kubeconfigDir: kubeadmconstants.KubernetesDir, - kubeconfigPath: kubeadmconstants.GetAdminKubeConfigPath(), - } -} - -// newInitData returns a new initData struct to be used for the execution of the kubeadm init workflow. -// This func takes care of validating initOptions passed to the command, and then it converts -// options into the internal InitConfiguration type that is used as input all the phases in the kubeadm init workflow -func newInitData(cmd *cobra.Command, args []string, options *initOptions, out io.Writer) (*initData, error) { - // Re-apply defaults to the public kubeadm API (this will set only values not exposed/not set as a flags) - kubeadmscheme.Scheme.Default(options.externalInitCfg) - kubeadmscheme.Scheme.Default(options.externalClusterCfg) - - // Validate standalone flags values and/or combination of flags and then assigns - // validated values to the public kubeadm config API when applicable - var err error - if options.externalClusterCfg.FeatureGates, err = features.NewFeatureGate(&features.InitFeatureGates, options.featureGatesString); err != nil { - return nil, err - } - - if err = validation.ValidateMixedArguments(cmd.Flags()); err != nil { - return nil, err - } - - if err = options.bto.ApplyTo(options.externalInitCfg); err != nil { - return nil, err - } - - // Either use the config file if specified, or convert public kubeadm API to the internal InitConfiguration - // and validates InitConfiguration - cfg, err := configutil.LoadOrDefaultInitConfiguration(options.cfgPath, options.externalInitCfg, options.externalClusterCfg) - if err != nil { - return nil, err - } - - ignorePreflightErrorsSet, err := validation.ValidateIgnorePreflightErrors(options.ignorePreflightErrors, cfg.NodeRegistration.IgnorePreflightErrors) - if err != nil { - return nil, err - } - // Also set the union of pre-flight errors to InitConfiguration, to provide a consistent view of the runtime configuration: - cfg.NodeRegistration.IgnorePreflightErrors = ignorePreflightErrorsSet.List() - - // override node name and CRI socket from the command line options - if options.externalInitCfg.NodeRegistration.Name != "" { - cfg.NodeRegistration.Name = options.externalInitCfg.NodeRegistration.Name - } - if options.externalInitCfg.NodeRegistration.CRISocket != "" { - cfg.NodeRegistration.CRISocket = options.externalInitCfg.NodeRegistration.CRISocket - } - - if err := configutil.VerifyAPIServerBindAddress(cfg.LocalAPIEndpoint.AdvertiseAddress); err != nil { - return nil, err - } - if err := features.ValidateVersion(features.InitFeatureGates, cfg.FeatureGates, cfg.KubernetesVersion); err != nil { - return nil, err - } - - // Checks if an external CA is provided by the user (when the CA Cert is present but the CA Key is not) - externalCA, err := certsphase.UsingExternalCA(&cfg.ClusterConfiguration) - if externalCA { - // In case the certificates signed by CA (that should be provided by the user) are missing or invalid, - // returns, because kubeadm can't regenerate them without the CA Key - if err != nil { - return nil, errors.Wrapf(err, "invalid or incomplete external CA") - } - - // Validate that also the required kubeconfig files exists and are invalid, because - // kubeadm can't regenerate them without the CA Key - kubeconfigDir := options.kubeconfigDir - if err := kubeconfigphase.ValidateKubeconfigsForExternalCA(kubeconfigDir, cfg); err != nil { - return nil, err - } - } - - // Checks if an external Front-Proxy CA is provided by the user (when the Front-Proxy CA Cert is present but the Front-Proxy CA Key is not) - externalFrontProxyCA, err := certsphase.UsingExternalFrontProxyCA(&cfg.ClusterConfiguration) - if externalFrontProxyCA { - // In case the certificates signed by Front-Proxy CA (that should be provided by the user) are missing or invalid, - // returns, because kubeadm can't regenerate them without the Front-Proxy CA Key - if err != nil { - return nil, errors.Wrapf(err, "invalid or incomplete external front-proxy CA") - } - } - - if options.openyurtTunnelServerAddress != "" { - _, _, err = net.SplitHostPort(options.openyurtTunnelServerAddress) - if err != nil { - return nil, errors.Wrapf(err, "invalid yurt tunnel server address") - } - } - - return &initData{ - cfg: cfg, - certificatesDir: cfg.CertificatesDir, - skipTokenPrint: false, - kubeconfigDir: options.kubeconfigDir, - kubeconfigPath: options.kubeconfigPath, - ignorePreflightErrors: ignorePreflightErrorsSet, - externalCA: externalCA, - outputWriter: out, - uploadCerts: false, - skipCertificateKeyPrint: false, - kustomizeDir: options.kustomizeDir, - isConvertOpenYurtCluster: options.isConvertOpenYurtCluster, - openyurtVersion: options.openyurtVersion, - cniFileName: options.installCNIFile, - openyurtImageRegistry: options.openyurtImageRegistry, - openyurtTunnelServerAddress: options.openyurtTunnelServerAddress, - }, nil -} - -// UploadCerts returns Uploadcerts flag. -func (d *initData) UploadCerts() bool { - return d.uploadCerts -} - -// CertificateKey returns the key used to encrypt the certs. -func (d *initData) CertificateKey() string { - return d.cfg.CertificateKey -} - -// SetCertificateKey set the key used to encrypt the certs. -func (d *initData) SetCertificateKey(key string) { - d.cfg.CertificateKey = key -} - -// SkipCertificateKeyPrint returns the skipCertificateKeyPrint flag. -func (d *initData) SkipCertificateKeyPrint() bool { - return d.skipCertificateKeyPrint -} - -// Cfg returns initConfiguration. -func (d *initData) Cfg() *kubeadmapi.InitConfiguration { - return d.cfg } -// DryRun returns the DryRun flag. -func (d *initData) DryRun() bool { - return d.dryRun -} - -// SkipTokenPrint returns the SkipTokenPrint flag. -func (d *initData) SkipTokenPrint() bool { - return d.skipTokenPrint -} - -// IgnorePreflightErrors returns the IgnorePreflightErrors flag. -func (d *initData) IgnorePreflightErrors() sets.String { - return d.ignorePreflightErrors -} - -// CertificateWriteDir returns the path to the certificate folder or the temporary folder path in case of DryRun. -func (d *initData) CertificateWriteDir() string { - if d.dryRun { - return d.dryRunDir +func NewInitializerWithOptions(o *InitOptions) *clusterInitializer { + return &clusterInitializer{ + *o, } - return d.certificatesDir -} - -// CertificateDir returns the CertificateDir as originally specified by the user. -func (d *initData) CertificateDir() string { - return d.certificatesDir } -// KubeConfigDir returns the path of the Kubernetes configuration folder or the temporary folder path in case of DryRun. -func (d *initData) KubeConfigDir() string { - if d.dryRun { - return d.dryRunDir - } - return d.kubeconfigDir -} - -// KubeConfigPath returns the path to the kubeconfig file to use for connecting to Kubernetes -func (d *initData) KubeConfigPath() string { - if d.dryRun { - d.kubeconfigPath = filepath.Join(d.dryRunDir, kubeadmconstants.AdminKubeConfigFileName) +// Run use sealer to initialize the master node. +func (ci *clusterInitializer) Run() error { + if err := CheckAndInstallSealer(); err != nil { + return err } - return d.kubeconfigPath -} -// ManifestDir returns the path where manifest should be stored or the temporary folder path in case of DryRun. -func (d *initData) ManifestDir() string { - if d.dryRun { - return d.dryRunDir + if err := ci.PrepareClusterfile(); err != nil { + return err } - return kubeadmconstants.GetStaticPodDirectory() -} -// KubeletDir returns path of the kubelet configuration folder or the temporary folder in case of DryRun. -func (d *initData) KubeletDir() string { - if d.dryRun { - return d.dryRunDir + if err := ci.InstallCluster(); err != nil { + return err } - return kubeadmconstants.KubeletRunDirectory -} - -// ExternalCA returns true if an external CA is provided by the user. -func (d *initData) ExternalCA() bool { - return d.externalCA -} - -// OutputWriter returns the io.Writer used to write output to by this command. -func (d *initData) OutputWriter() io.Writer { - return d.outputWriter -} - -//IsConvertYurtCluster return whether to convert to OpenYurt cluster. -func (d *initData) IsConvertYurtCluster() bool { - return d.isConvertOpenYurtCluster -} - -//OpenYurtImageRegistry return the image registry to install OpenYurt component. -func (d *initData) OpenYurtImageRegistry() string { - return d.openyurtImageRegistry -} - -//OpenYurtVersion return the OpenYurt version. -func (d *initData) OpenYurtVersion() string { - return d.openyurtVersion -} - -//CNIFileName return the cni install yaml. -func (d *initData) CNIFileName() string { - return d.cniFileName -} - -// YurtTunnelAddress return the openyurtTunnelServerAddress -func (d *initData) YurtTunnelAddress() string { - return d.openyurtTunnelServerAddress + return nil } -// Client returns a Kubernetes client to be used by kubeadm. -// This function is implemented as a singleton, thus avoiding to recreate the client when it is used by different phases. -// Important. This function must be called after the admin.conf kubeconfig file is created. -func (d *initData) Client() (clientset.Interface, error) { - if d.client == nil { - if d.dryRun { - svcSubnetCIDR, err := kubeadmconstants.GetKubernetesServiceCIDR(d.cfg.Networking.ServiceSubnet, features.Enabled(d.cfg.FeatureGates, features.IPv6DualStack)) - if err != nil { - return nil, errors.Wrapf(err, "unable to get internal Kubernetes Service IP from the given service CIDR (%s)", d.cfg.Networking.ServiceSubnet) +// CheckAndInstallSealer install sealer, skip install if it exists +func CheckAndInstallSealer() error { + klog.Infof("Check and install sealer") + sealerExist := false + if _, err := exec.LookPath("sealer"); err == nil { + if b, err := exec.Command("sealer", "version").CombinedOutput(); err == nil { + info := make(map[string]string) + if err := json.Unmarshal(b, &info); err != nil { + return fmt.Errorf("Can't get the existing sealer version: %v", err) } - // If we're dry-running, we should create a faked client that answers some GETs in order to be able to do the full init flow and just logs the rest of requests - dryRunGetter := apiclient.NewInitDryRunGetter(d.cfg.NodeRegistration.Name, svcSubnetCIDR.String()) - d.client = apiclient.NewDryRunClient(dryRunGetter, os.Stdout) - } else { - // If we're acting for real, we should create a connection to the API server and wait for it to come up - var err error - d.client, err = kubeconfigutil.ClientSetFromFile(d.KubeConfigPath()) - if err != nil { - return nil, err + sealerVersion := info["gitVersion"] + if strutil.IsInStringLst(ValidSealerVersions, sealerVersion) { + klog.Infof("Sealer %s already exist, skip install.", sealerVersion) + sealerExist = true + } else { + return fmt.Errorf("The existing sealer version %s is not supported, please clean it. Valid server versions are %v.", sealerVersion, ValidSealerVersions) } } } - return d.client, nil -} -// Tokens returns an array of token strings. -func (d *initData) Tokens() []string { - tokens := []string{} - for _, bt := range d.cfg.BootstrapTokens { - tokens = append(tokens, bt.Token.String()) + if !sealerExist { + // download and install sealer + packageUrl := fmt.Sprintf(SealerUrlFormat, DefaultSealerVersion, DefaultSealerVersion, runtime.GOARCH) + savePath := fmt.Sprintf("%s/sealer-%s-linux-%s.tar.gz", TmpDownloadDir, DefaultSealerVersion, runtime.GOARCH) + klog.V(1).Infof("Download sealer from: %s", packageUrl) + if err := util.DownloadFile(packageUrl, savePath, 3); err != nil { + return fmt.Errorf("Download sealer fail: %v", err) + } + if err := util.Untar(savePath, TmpDownloadDir); err != nil { + return err + } + comp := "sealer" + target := fmt.Sprintf("/usr/bin/%s", comp) + if err := edgenode.CopyFile(TmpDownloadDir+"/"+comp, target, 0755); err != nil { + return err + } } - return tokens + return nil } -// KustomizeDir returns the folder where kustomize patches for static pod manifest are stored -func (d *initData) KustomizeDir() string { - return d.kustomizeDir +// InstallCluster initialize the master of openyurt cluster by calling sealer +func (ci *clusterInitializer) InstallCluster() error { + klog.Infof("init an openyurt cluster") + runCmd := fmt.Sprintf(SealerRunCmd, TmpDownloadDir) + cmd := exec.Command("bash", "-c", runCmd) + return execCmd(cmd) } -func printJoinCommand(out io.Writer, adminKubeConfigPath, token string, i *initData) error { - joinEdgeNodeCommand, err := getJoinCommand(adminKubeConfigPath, token, "edge-node") +// PrepareClusterfile fill the template and write the Clusterfile to the /tmp +func (ci *clusterInitializer) PrepareClusterfile() error { + klog.Infof("generate Clusterfile for openyurt") + err := os.MkdirAll(TmpDownloadDir, dirMode) if err != nil { return err } - joinCloudNodeCommand, err := getJoinCommand(adminKubeConfigPath, token, "cloud-node") + + clusterfile, err := tmplutil.SubsituteTemplate(OpenYurtClusterfile, map[string]string{ + "apiserver_address": ci.AdvertiseAddress, + "cluster_image": fmt.Sprintf(InitClusterImage, ci.ImageRepository, ci.OpenYurtVersion), + "passwd": ci.Password, + "pod_subnet": ci.PodSubnet, + "service_subnet": ci.ServiceSubnet, + "yurttunnel_server_address": ci.YurttunnelServerAddress, + }) if err != nil { return err } - ctx := map[string]interface{}{ - "KubeConfigPath": adminKubeConfigPath, - "ControlPlaneEndpoint": i.Cfg().ControlPlaneEndpoint, - "joinEdgeNodeCommand": joinEdgeNodeCommand, - "joinCloudNodeCommand": joinCloudNodeCommand, - } - - return initDoneTempl.Execute(out, ctx) -} - -// showJoinCommand prints the join command after all the phases in init have finished -func showJoinCommand(i *initData, out io.Writer) error { - adminKubeConfigPath := i.KubeConfigPath() - - // Prints the join command, multiple times in case the user has multiple tokens - for _, token := range i.Tokens() { - if err := printJoinCommand(out, adminKubeConfigPath, token, i); err != nil { - return errors.Wrap(err, "failed to print join command") - } + err = ioutil.WriteFile(fmt.Sprintf("%s/Clusterfile", TmpDownloadDir), []byte(clusterfile), fileMode) + if err != nil { + return err } - return nil } -//getJoinCommand returns the yurtctl join command for a given token and nodeType. -func getJoinCommand(kubeConfigFile, token, nodeType string) (string, error) { - // load the kubeconfig file to get the CA certificate and endpoint - config, err := clientcmd.LoadFromFile(kubeConfigFile) - if err != nil { - return "", errors.Wrap(err, "failed to load kubeconfig") - } - - // load the default cluster config - clusterConfig := kubeconfigutil.GetClusterFromKubeConfig(config) - if clusterConfig == nil { - return "", errors.New("failed to get default cluster config") - } - - // load CA certificates from the kubeconfig (either from PEM data or by file path) - var caCerts []*x509.Certificate - if clusterConfig.CertificateAuthorityData != nil { - caCerts, err = clientcertutil.ParseCertsPEM(clusterConfig.CertificateAuthorityData) - if err != nil { - return "", errors.Wrap(err, "failed to parse CA certificate from kubeconfig") - } - } else if clusterConfig.CertificateAuthority != "" { - caCerts, err = clientcertutil.CertsFromFile(clusterConfig.CertificateAuthority) - if err != nil { - return "", errors.Wrap(err, "failed to load CA certificate referenced by kubeconfig") - } - } else { - return "", errors.New("no CA certificates found in kubeconfig") - } - - // hash all the CA certs and include their public key pins as trusted values - publicKeyPins := make([]string, 0, len(caCerts)) - for _, caCert := range caCerts { - publicKeyPins = append(publicKeyPins, pubkeypin.Hash(caCert)) - } - - ctx := map[string]interface{}{ - "Token": token, - "CAPubKeyPins": publicKeyPins, - "ControlPlaneHostPort": strings.Replace(clusterConfig.Server, "https://", "", -1), - "NodeType": nodeType, - } - - var out bytes.Buffer - err = joinCommandTemplate.Execute(&out, ctx) +func execCmd(cmd *exec.Cmd) error { + var stdout, stderr bytes.Buffer + cmd.Stdout = &stdout + cmd.Stderr = &stderr + err := cmd.Run() + outStr, errStr := string(stdout.Bytes()), string(stderr.Bytes()) + fmt.Printf(outStr) if err != nil { - return "", errors.Wrap(err, "failed to render join command template") + pos := strings.Index(errStr, "Usage:") + fmt.Printf(errStr[:pos]) } - return out.String(), nil + return err } diff --git a/pkg/yurtctl/cmd/yurtinit/options.go b/pkg/yurtctl/cmd/yurtinit/options.go new file mode 100644 index 00000000000..783874bbe01 --- /dev/null +++ b/pkg/yurtctl/cmd/yurtinit/options.go @@ -0,0 +1,89 @@ +/* +Copyright 2020 The OpenYurt 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 yurtinit + +import ( + "fmt" + "net" + + "github.com/pkg/errors" + + "github.com/openyurtio/openyurt/pkg/yurtctl/constants" +) + +// InitOptions defines all the init options exposed via flags by yurtctl init. +type InitOptions struct { + AdvertiseAddress string + YurttunnelServerAddress string + ServiceSubnet string + PodSubnet string + Password string + ImageRepository string + OpenYurtVersion string +} + +func NewInitOptions() *InitOptions { + return &InitOptions{ + ImageRepository: constants.DefaultOpenYurtImageRegistry, + OpenYurtVersion: constants.DefaultOpenYurtVersion, + } +} + +func (o *InitOptions) Validate() error { + if err := validateServerAddress(o.AdvertiseAddress); err != nil { + return err + } + if o.YurttunnelServerAddress != "" { + if err := validateServerAddress(o.YurttunnelServerAddress); err != nil { + return err + } + } + if o.Password == "" { + return fmt.Errorf("password can't be empty.") + } + + if o.PodSubnet != "" { + if err := validateCidrString(o.PodSubnet); err != nil { + return err + } + } + if o.ServiceSubnet != "" { + if err := validateCidrString(o.ServiceSubnet); err != nil { + return err + } + } + return nil +} + +func validateServerAddress(address string) error { + ip := net.ParseIP(address) + if ip == nil { + return errors.Errorf("cannot parse IP address: %s", address) + } + if !ip.IsGlobalUnicast() { + return errors.Errorf("cannot use %q as the bind address for the API Server", address) + } + return nil +} + +func validateCidrString(cidr string) error { + _, _, err := net.ParseCIDR(cidr) + if err != nil { + return nil + } + return nil +} diff --git a/pkg/yurtctl/cmd/yurtinit/phases/controlplane.go b/pkg/yurtctl/cmd/yurtinit/phases/controlplane.go deleted file mode 100644 index d196d61d30c..00000000000 --- a/pkg/yurtctl/cmd/yurtinit/phases/controlplane.go +++ /dev/null @@ -1,130 +0,0 @@ -/* -Copyright 2021 The OpenYurt 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 phases - -import ( - "fmt" - "strings" - - v1 "k8s.io/api/core/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm" - "k8s.io/kubernetes/cmd/kubeadm/app/cmd/phases/workflow" - kubeadmconstants "k8s.io/kubernetes/cmd/kubeadm/app/constants" - "k8s.io/kubernetes/cmd/kubeadm/app/phases/controlplane" - "k8s.io/kubernetes/cmd/kubeadm/app/phases/etcd" - etcdutil "k8s.io/kubernetes/cmd/kubeadm/app/util/etcd" - "k8s.io/kubernetes/cmd/kubeadm/app/util/staticpod" -) - -func NewAllInAoneControlPlanePhase() workflow.Phase { - return workflow.Phase{ - Name: "Generate all-in-one controlplane static pod yaml.", - Short: "Generate all-in-one controlplane static pod yaml.", - Run: runAllInAoneControlPlane, - } -} - -func runAllInAoneControlPlane(c workflow.RunData) error { - data, ok := c.(YurtInitData) - if !ok { - return fmt.Errorf("Install controlplane phase invoked with an invalid data struct. ") - } - cfg := data.Cfg() - return CreateStaticPodFile(data.ManifestDir(), cfg.NodeRegistration.Name, &cfg.ClusterConfiguration, &cfg.LocalAPIEndpoint, data.IsConvertYurtCluster()) -} - -func CreateStaticPodFile(manifestDir, nodeName string, - cfg *kubeadmapi.ClusterConfiguration, - endpoint *kubeadmapi.APIEndpoint, - convertYurtCluster bool) error { - masterSpecs := controlplane.GetStaticPodSpecs(cfg, endpoint) - if convertYurtCluster { - if err := closeNodeLifeCycleController(masterSpecs); err != nil { - return err - } - } - var containers []v1.Container - var volumes []v1.Volume - for _, spec := range masterSpecs { - componentName := spec.Name - for _, v := range spec.Spec.Volumes { - v.Name = componentName + "-" + v.Name - volumes = append(volumes, v) - } - for _, c := range spec.Spec.Containers { - for i := 0; i < len(c.VolumeMounts); i++ { - c.VolumeMounts[i].Name = componentName + "-" + c.VolumeMounts[i].Name - } - containers = append(containers, c) - } - } - - etcdSpec := etcd.GetEtcdPodSpec(cfg, endpoint, nodeName, []etcdutil.Member{}) - componentName := etcdSpec.Name - for _, v := range etcdSpec.Spec.Volumes { - v.Name = componentName + "-" + v.Name - volumes = append(volumes, v) - } - for _, c := range etcdSpec.Spec.Containers { - for i := 0; i < len(c.VolumeMounts); i++ { - c.VolumeMounts[i].Name = componentName + "-" + c.VolumeMounts[i].Name - } - containers = append(containers, c) - } - pod := componentPod("controlplane", containers, volumes, map[string]string{kubeadmconstants.KubeAPIServerAdvertiseAddressEndpointAnnotationKey: endpoint.String()}) - return staticpod.WriteStaticPodToDisk("controlplane", manifestDir, pod) -} - -func componentPod(name string, containers []v1.Container, volumes []v1.Volume, annotations map[string]string) v1.Pod { - return v1.Pod{ - TypeMeta: metav1.TypeMeta{ - APIVersion: "v1", - Kind: "Pod", - }, - ObjectMeta: metav1.ObjectMeta{ - Name: name, - Namespace: metav1.NamespaceSystem, - Labels: map[string]string{"component": name, "tier": kubeadmconstants.ControlPlaneTier}, - Annotations: annotations, - }, - Spec: v1.PodSpec{ - Containers: containers, - PriorityClassName: "system-cluster-critical", - HostNetwork: true, - Volumes: volumes, - }, - } -} - -func closeNodeLifeCycleController(masterSpecs map[string]v1.Pod) error { - cmPod, ok := masterSpecs[kubeadmconstants.KubeControllerManager] - if !ok { - return fmt.Errorf("Spec %s is not exists.", kubeadmconstants.KubeControllerManager) - } - cmd := cmPod.Spec.Containers[0].Command - var newCmd []string - for _, p := range cmd { - if strings.Contains(p, "--controllers=") { - p = p + ",-nodelifecycle" - } - newCmd = append(newCmd, p) - } - cmPod.Spec.Containers[0].Command = newCmd - masterSpecs[kubeadmconstants.KubeControllerManager] = cmPod - return nil -} diff --git a/pkg/yurtctl/cmd/yurtinit/phases/install_cni.go b/pkg/yurtctl/cmd/yurtinit/phases/install_cni.go deleted file mode 100644 index fc9c774672c..00000000000 --- a/pkg/yurtctl/cmd/yurtinit/phases/install_cni.go +++ /dev/null @@ -1,88 +0,0 @@ -/* -Copyright 2021 The OpenYurt 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 phases - -import ( - "fmt" - - "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" - "k8s.io/cli-runtime/pkg/genericclioptions" - "k8s.io/cli-runtime/pkg/resource" - cmdutil "k8s.io/kubectl/pkg/cmd/util" - "k8s.io/kubectl/pkg/util" - "k8s.io/kubernetes/cmd/kubeadm/app/cmd/phases/workflow" - kubeContants "k8s.io/kubernetes/cmd/kubeadm/app/constants" - - "github.com/openyurtio/openyurt/pkg/yurtctl/constants" -) - -func NewInstallCNIPhase() workflow.Phase { - return workflow.Phase{ - Name: "Install flannel.", - Short: "Install flannel.", - Run: runInstallCNI, - } -} - -func runInstallCNI(c workflow.RunData) error { - data, ok := c.(YurtInitData) - if !ok { - return fmt.Errorf("Install cni phase invoked with an invalid data struct. ") - } - cniInstallFile := constants.FlannelIntallFile - if data.CNIFileName() != "" { - cniInstallFile = data.CNIFileName() - } - fileNameOption := &resource.FilenameOptions{ - Filenames: []string{cniInstallFile}, - } - adminKubeConfig := kubeContants.GetAdminKubeConfigPath() - configFlag := &genericclioptions.ConfigFlags{KubeConfig: &adminKubeConfig} - builder := resource.NewBuilder(configFlag) - r := builder.Unstructured(). - Schema(nil). - ContinueOnError(). - NamespaceParam("").DefaultNamespace(). - FilenameParam(false, fileNameOption). - LabelSelectorParam(""). - Flatten(). - Do() - infos, err := r.Infos() - if err != nil { - return err - } - for _, info := range infos { - if err := applyOneObject(info); err != nil { - return err - } - } - return nil -} - -func applyOneObject(info *resource.Info) error { - if err := util.CreateApplyAnnotation(info.Object, unstructured.UnstructuredJSONScheme); err != nil { - return cmdutil.AddSourceToErr("creating", info.Source, err) - } - - helper := resource.NewHelper(info.Client, info.Mapping) - obj, err := helper.Create(info.Namespace, true, info.Object) - if err != nil { - return cmdutil.AddSourceToErr("creating", info.Source, err) - } - info.Refresh(obj, true) - return nil -} diff --git a/pkg/yurtctl/cmd/yurtinit/phases/install_yurt_addons.go b/pkg/yurtctl/cmd/yurtinit/phases/install_yurt_addons.go deleted file mode 100644 index 9b408974cd1..00000000000 --- a/pkg/yurtctl/cmd/yurtinit/phases/install_yurt_addons.go +++ /dev/null @@ -1,90 +0,0 @@ -/* -Copyright 2021 The OpenYurt 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 phases - -import ( - "fmt" - "net" - "runtime" - - "k8s.io/client-go/dynamic" - "k8s.io/client-go/kubernetes" - "k8s.io/client-go/tools/clientcmd" - "k8s.io/kubernetes/cmd/kubeadm/app/cmd/phases/workflow" - kubeContants "k8s.io/kubernetes/cmd/kubeadm/app/constants" - - YurtContants "github.com/openyurtio/openyurt/pkg/yurtctl/constants" - kubeutil "github.com/openyurtio/openyurt/pkg/yurtctl/util/kubernetes" -) - -func NewInstallYurtAddonsPhase() workflow.Phase { - return workflow.Phase{ - Name: "Install OpenYurt component.", - Short: "Install OpenYurt component.", - Run: runInstallYurtAddons, - } -} - -func runInstallYurtAddons(c workflow.RunData) error { - data, ok := c.(YurtInitData) - if !ok { - return fmt.Errorf("Install yurt addons phase invoked with an invalid data struct. ") - } - if !data.IsConvertYurtCluster() { - return nil - } - - restCfg, err := clientcmd.BuildConfigFromFlags("", kubeContants.GetAdminKubeConfigPath()) - if err != nil { - return err - } - client, err := kubernetes.NewForConfig(restCfg) - if err != nil { - return err - } - dynamicClient, err := dynamic.NewForConfig(restCfg) - if err != nil { - return err - } - imageRegistry := data.OpenYurtImageRegistry() - version := data.OpenYurtVersion() - tunnelServerAddress := data.YurtTunnelAddress() - - if len(imageRegistry) == 0 { - imageRegistry = YurtContants.DefaultOpenYurtImageRegistry - } - if len(version) == 0 { - version = YurtContants.DefaultOpenYurtVersion - } - if err := kubeutil.DeployYurtControllerManager(client, fmt.Sprintf("%s/%s:%s", imageRegistry, YurtContants.YurtControllerManager, version)); err != nil { - return err - } - if err := kubeutil.DeployYurtAppManager(client, fmt.Sprintf("%s/%s:%s", imageRegistry, YurtContants.YurtAppManager, version), dynamicClient, runtime.GOARCH); err != nil { - return err - } - var certIP string - if data.YurtTunnelAddress() != "" { - certIP, _, _ = net.SplitHostPort(data.YurtTunnelAddress()) - } - if err := kubeutil.DeployYurttunnelServer(client, certIP, fmt.Sprintf("%s/%s:%s", imageRegistry, YurtContants.YurtTunnelServer, version), runtime.GOARCH); err != nil { - return err - } - if err := kubeutil.DeployYurttunnelAgent(client, tunnelServerAddress, fmt.Sprintf("%s/%s:%s", imageRegistry, YurtContants.YurtTunnelAgent, version)); err != nil { - return err - } - return nil -} diff --git a/pkg/yurtctl/cmd/yurtinit/phases/label_cloud_node.go b/pkg/yurtctl/cmd/yurtinit/phases/label_cloud_node.go deleted file mode 100644 index 62ee71087c9..00000000000 --- a/pkg/yurtctl/cmd/yurtinit/phases/label_cloud_node.go +++ /dev/null @@ -1,63 +0,0 @@ -/* -Copyright 2021 The OpenYurt 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 phases - -import ( - "fmt" - - v1 "k8s.io/api/core/v1" - clientset "k8s.io/client-go/kubernetes" - "k8s.io/kubernetes/cmd/kubeadm/app/cmd/phases/workflow" - "k8s.io/kubernetes/cmd/kubeadm/app/util/apiclient" - - "github.com/openyurtio/openyurt/pkg/projectinfo" -) - -func NewMarkCloudNode() workflow.Phase { - return workflow.Phase{ - Name: "mark cloud node", - Short: "Mark a node as a cloud-node", - Run: runMarkCloudNode, - } -} - -func runMarkCloudNode(c workflow.RunData) error { - data, ok := c.(YurtInitData) - if !ok { - return fmt.Errorf("Label cloud node phase invoked with an invalid data struct. ") - } - client, err := data.Client() - if err != nil { - return err - } - nodeRegistration := data.Cfg().NodeRegistration - return LabelCloudNode(client, nodeRegistration.Name, - map[string]string{projectinfo.GetEdgeWorkerLabelKey(): "false"}) -} - -// LabelCloudNode set cloud-node label -func LabelCloudNode(client clientset.Interface, nodeName string, label map[string]string) error { - return apiclient.PatchNode(client, nodeName, func(n *v1.Node) { - labelCloudNode(n, label) - }) -} - -func labelCloudNode(n *v1.Node, labels map[string]string) { - for k, v := range labels { - n.ObjectMeta.Labels[k] = v - } -} diff --git a/pkg/yurtctl/cmd/yurtinit/phases/prepare.go b/pkg/yurtctl/cmd/yurtinit/phases/prepare.go deleted file mode 100644 index 6facfaeb2ed..00000000000 --- a/pkg/yurtctl/cmd/yurtinit/phases/prepare.go +++ /dev/null @@ -1,64 +0,0 @@ -/* -Copyright 2021 The OpenYurt 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 phases - -import ( - "fmt" - - "k8s.io/kubernetes/cmd/kubeadm/app/cmd/phases/workflow" - - "github.com/openyurtio/openyurt/pkg/yurtctl/util/kubernetes" - "github.com/openyurtio/openyurt/pkg/yurtctl/util/system" -) - -// NewEdgeNodePhase creates a yurtctl workflow phase that initialize the node environment. -func NewPreparePhase() workflow.Phase { - return workflow.Phase{ - Name: "Initialize system environment.", - Short: "Initialize system environment.", - Run: runPrepare, - } -} - -//runPrepare executes the node initialization process. -func runPrepare(c workflow.RunData) error { - data, ok := c.(YurtInitData) - if !ok { - return fmt.Errorf("Prepare phase invoked with an invalid data struct. ") - } - initCfg := data.Cfg() - - if err := system.SetIpv4Forward(); err != nil { - return err - } - if err := system.SetBridgeSetting(); err != nil { - return err - } - if err := system.SetSELinux(); err != nil { - return err - } - if err := kubernetes.CheckAndInstallKubelet(initCfg.ClusterConfiguration.KubernetesVersion); err != nil { - return err - } - if err := kubernetes.SetKubeletService(); err != nil { - return err - } - if err := kubernetes.SetKubeletUnitConfig(); err != nil { - return err - } - return nil -} diff --git a/pkg/yurtctl/cmd/yurtinit/phases/types.go b/pkg/yurtctl/cmd/yurtinit/phases/types.go deleted file mode 100644 index 2dcaa0debb7..00000000000 --- a/pkg/yurtctl/cmd/yurtinit/phases/types.go +++ /dev/null @@ -1,30 +0,0 @@ -/* -Copyright 2021 The OpenYurt 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 phases - -import ( - phases "k8s.io/kubernetes/cmd/kubeadm/app/cmd/phases/init" -) - -type YurtInitData interface { - phases.InitData - IsConvertYurtCluster() bool - OpenYurtVersion() string - OpenYurtImageRegistry() string - YurtTunnelAddress() string - CNIFileName() string -}