github.com/alibaba/sealer@v0.8.6-0.20220430115802-37a2bdaa8173/pkg/runtime/kubeadm_runtime.go (about)

     1  // Copyright © 2021 Alibaba Group Holding Ltd.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package runtime
    16  
    17  import (
    18  	"context"
    19  	"fmt"
    20  
    21  	"github.com/alibaba/sealer/utils/platform"
    22  
    23  	"path/filepath"
    24  	"strings"
    25  	"time"
    26  
    27  	"golang.org/x/sync/errgroup"
    28  
    29  	"github.com/alibaba/sealer/pkg/runtime/kubeadm_types/v1beta2"
    30  
    31  	"github.com/alibaba/sealer/utils"
    32  
    33  	"github.com/alibaba/sealer/common"
    34  	"github.com/alibaba/sealer/logger"
    35  	v2 "github.com/alibaba/sealer/types/api/v2"
    36  	"github.com/alibaba/sealer/utils/ssh"
    37  )
    38  
    39  type Config struct {
    40  	Vlog      int
    41  	VIP       string
    42  	RegConfig *RegistryConfig
    43  	// Clusterfile: the absolute path, we need to read kubeadm config from Clusterfile
    44  	ClusterFileKubeConfig *KubeadmConfig
    45  	APIServerDomain       string
    46  }
    47  
    48  func newKubeadmRuntime(cluster *v2.Cluster, clusterFileKubeConfig *KubeadmConfig) (Interface, error) {
    49  	k := &KubeadmRuntime{
    50  		Cluster: cluster,
    51  		Config: &Config{
    52  			ClusterFileKubeConfig: clusterFileKubeConfig,
    53  			APIServerDomain:       DefaultAPIserverDomain,
    54  		},
    55  		KubeadmConfig: &KubeadmConfig{},
    56  	}
    57  	k.Config.RegConfig = GetRegistryConfig(k.getImageMountDir(), k.GetMaster0IP())
    58  	k.setCertSANS(append([]string{"127.0.0.1", k.getAPIServerDomain(), k.getVIP()}, k.GetMasterIPList()...))
    59  	// TODO args pre checks
    60  	if err := k.checkList(); err != nil {
    61  		return nil, err
    62  	}
    63  
    64  	if logger.IsDebugModel() {
    65  		k.Vlog = 6
    66  	}
    67  	return k, nil
    68  }
    69  
    70  func (k *KubeadmRuntime) checkList() error {
    71  	if len(k.Spec.Hosts) == 0 {
    72  		return fmt.Errorf("master hosts cannot be empty")
    73  	}
    74  	if k.GetMaster0IP() == "" {
    75  		return fmt.Errorf("master hosts ip cannot be empty")
    76  	}
    77  	return nil
    78  }
    79  
    80  func (k *KubeadmRuntime) getClusterName() string {
    81  	return k.Cluster.Name
    82  }
    83  
    84  func (k *KubeadmRuntime) getClusterMetadata() (*Metadata, error) {
    85  	metadata := &Metadata{}
    86  	if k.getKubeVersion() == "" {
    87  		if err := k.MergeKubeadmConfig(); err != nil {
    88  			return nil, err
    89  		}
    90  	}
    91  	metadata.Version = k.getKubeVersion()
    92  	return metadata, nil
    93  }
    94  
    95  func (k *KubeadmRuntime) getHostSSHClient(hostIP string) (ssh.Interface, error) {
    96  	return ssh.NewStdoutSSHClient(hostIP, k.Cluster)
    97  }
    98  
    99  // /var/lib/sealer/data/my-cluster
   100  func (k *KubeadmRuntime) getBasePath() string {
   101  	return common.DefaultClusterBaseDir(k.getClusterName())
   102  }
   103  
   104  // /var/lib/sealer/data/my-cluster/rootfs
   105  func (k *KubeadmRuntime) getRootfs() string {
   106  	return common.DefaultTheClusterRootfsDir(k.getClusterName())
   107  }
   108  
   109  // /var/lib/sealer/data/my-cluster/mount
   110  func (k *KubeadmRuntime) getImageMountDir() string {
   111  	return platform.DefaultMountCloudImageDir(k.getClusterName())
   112  }
   113  
   114  // /var/lib/sealer/data/my-cluster/certs
   115  func (k *KubeadmRuntime) getCertsDir() string {
   116  	return common.TheDefaultClusterCertDir(k.getClusterName())
   117  }
   118  
   119  // /var/lib/sealer/data/my-cluster/pki
   120  func (k *KubeadmRuntime) getPKIPath() string {
   121  	return common.TheDefaultClusterPKIDir(k.getClusterName())
   122  }
   123  
   124  // /var/lib/sealer/data/my-cluster/mount/etc/kubeadm.yml
   125  func (k *KubeadmRuntime) getDefaultKubeadmConfig() string {
   126  	return filepath.Join(k.getImageMountDir(), "etc", "kubeadm.yml")
   127  }
   128  
   129  // /var/lib/sealer/data/my-cluster/pki/etcd
   130  func (k *KubeadmRuntime) getEtcdCertPath() string {
   131  	return filepath.Join(k.getPKIPath(), "etcd")
   132  }
   133  
   134  // /var/lib/sealer/data/my-cluster/rootfs/statics
   135  func (k *KubeadmRuntime) getStaticFileDir() string {
   136  	return filepath.Join(k.getRootfs(), "statics")
   137  }
   138  
   139  func (k *KubeadmRuntime) getSvcCIDR() string {
   140  	return k.ClusterConfiguration.Networking.ServiceSubnet
   141  }
   142  
   143  func (k *KubeadmRuntime) setCertSANS(certSANS []string) {
   144  	k.ClusterConfiguration.APIServer.CertSANs = utils.RemoveDuplicate(append(k.getCertSANS(), certSANS...))
   145  }
   146  
   147  func (k *KubeadmRuntime) getCertSANS() []string {
   148  	return k.ClusterConfiguration.APIServer.CertSANs
   149  }
   150  
   151  func (k *KubeadmRuntime) getDNSDomain() string {
   152  	if k.ClusterConfiguration.Networking.DNSDomain == "" {
   153  		k.ClusterConfiguration.Networking.DNSDomain = "cluster.local"
   154  	}
   155  	return k.ClusterConfiguration.Networking.DNSDomain
   156  }
   157  
   158  func (k *KubeadmRuntime) getAPIServerDomain() string {
   159  	return k.Config.APIServerDomain
   160  }
   161  
   162  func (k *KubeadmRuntime) getKubeVersion() string {
   163  	return k.KubernetesVersion
   164  }
   165  
   166  func (k *KubeadmRuntime) getVIP() string {
   167  	return DefaultVIP
   168  }
   169  
   170  func (k *KubeadmRuntime) getJoinToken() string {
   171  	if k.Discovery.BootstrapToken == nil {
   172  		return ""
   173  	}
   174  	return k.JoinConfiguration.Discovery.BootstrapToken.Token
   175  }
   176  
   177  func (k *KubeadmRuntime) setJoinToken(token string) {
   178  	if k.Discovery.BootstrapToken == nil {
   179  		k.Discovery.BootstrapToken = &v1beta2.BootstrapTokenDiscovery{}
   180  	}
   181  	k.Discovery.BootstrapToken.Token = token
   182  }
   183  
   184  func (k *KubeadmRuntime) getTokenCaCertHash() string {
   185  	if k.Discovery.BootstrapToken == nil || len(k.Discovery.BootstrapToken.CACertHashes) == 0 {
   186  		return ""
   187  	}
   188  	return k.Discovery.BootstrapToken.CACertHashes[0]
   189  }
   190  
   191  func (k *KubeadmRuntime) setTokenCaCertHash(tokenCaCertHash []string) {
   192  	if k.Discovery.BootstrapToken == nil {
   193  		k.Discovery.BootstrapToken = &v1beta2.BootstrapTokenDiscovery{}
   194  	}
   195  	k.Discovery.BootstrapToken.CACertHashes = tokenCaCertHash
   196  }
   197  
   198  func (k *KubeadmRuntime) getCertificateKey() string {
   199  	if k.JoinConfiguration.ControlPlane == nil {
   200  		return ""
   201  	}
   202  	return k.JoinConfiguration.ControlPlane.CertificateKey
   203  }
   204  
   205  func (k *KubeadmRuntime) setInitCertificateKey(certificateKey string) {
   206  	k.CertificateKey = certificateKey
   207  }
   208  
   209  func (k *KubeadmRuntime) setAPIServerEndpoint(endpoint string) {
   210  	k.JoinConfiguration.Discovery.BootstrapToken.APIServerEndpoint = endpoint
   211  }
   212  
   213  func (k *KubeadmRuntime) setInitAdvertiseAddress(advertiseAddress string) {
   214  	k.InitConfiguration.LocalAPIEndpoint.AdvertiseAddress = advertiseAddress
   215  }
   216  
   217  func (k *KubeadmRuntime) setJoinAdvertiseAddress(advertiseAddress string) {
   218  	if k.JoinConfiguration.ControlPlane == nil {
   219  		k.JoinConfiguration.ControlPlane = &v1beta2.JoinControlPlane{}
   220  	}
   221  	k.JoinConfiguration.ControlPlane.LocalAPIEndpoint.AdvertiseAddress = advertiseAddress
   222  }
   223  
   224  func (k *KubeadmRuntime) cleanJoinLocalAPIEndPoint() {
   225  	k.JoinConfiguration.ControlPlane = nil
   226  }
   227  
   228  func (k *KubeadmRuntime) setControlPlaneEndpoint(endpoint string) {
   229  	k.ControlPlaneEndpoint = endpoint
   230  }
   231  
   232  func (k *KubeadmRuntime) setCgroupDriver(cGroup string) {
   233  	k.KubeletConfiguration.CgroupDriver = cGroup
   234  }
   235  
   236  func (k *KubeadmRuntime) setAPIVersion(apiVersion string) {
   237  	k.InitConfiguration.APIVersion = apiVersion
   238  	k.ClusterConfiguration.APIVersion = apiVersion
   239  	k.JoinConfiguration.APIVersion = apiVersion
   240  }
   241  func getEtcdEndpointsWithHTTPSPrefix(masters []string) string {
   242  	var tmpSlice []string
   243  	for _, ip := range masters {
   244  		tmpSlice = append(tmpSlice, fmt.Sprintf("https://%s:2379", utils.GetHostIP(ip)))
   245  	}
   246  	return strings.Join(tmpSlice, ",")
   247  }
   248  
   249  func (k *KubeadmRuntime) WaitSSHReady(tryTimes int, hosts ...string) error {
   250  	eg, _ := errgroup.WithContext(context.Background())
   251  	for _, h := range hosts {
   252  		host := h
   253  		eg.Go(func() error {
   254  			for i := 0; i < tryTimes; i++ {
   255  				sshClient, err := k.getHostSSHClient(host)
   256  				if err != nil {
   257  					return err
   258  				}
   259  				err = sshClient.Ping(host)
   260  				if err == nil {
   261  					return nil
   262  				}
   263  				time.Sleep(time.Duration(i) * time.Second)
   264  			}
   265  			return fmt.Errorf("wait for [%s] ssh ready timeout, ensure that the IP address or password is correct", host)
   266  		})
   267  	}
   268  	return eg.Wait()
   269  }