github.com/1aal/kubeblocks@v0.0.0-20231107070852-e1c03e598921/pkg/cli/cmd/infrastructure/tasks/kubernetes.go (about)

     1  /*
     2  Copyright (C) 2022-2023 ApeCloud Co., Ltd
     3  
     4  This file is part of KubeBlocks project
     5  
     6  This program is free software: you can redistribute it and/or modify
     7  it under the terms of the GNU Affero General Public License as published by
     8  the Free Software Foundation, either version 3 of the License, or
     9  (at your option) any later version.
    10  
    11  This program is distributed in the hope that it will be useful
    12  but WITHOUT ANY WARRANTY; without even the implied warranty of
    13  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    14  GNU Affero General Public License for more details.
    15  
    16  You should have received a copy of the GNU Affero General Public License
    17  along with this program.  If not, see <http://www.gnu.org/licenses/>.
    18  */
    19  
    20  package tasks
    21  
    22  import (
    23  	"fmt"
    24  	"path/filepath"
    25  	"strings"
    26  
    27  	"github.com/StudioSol/set"
    28  	kubekeyapiv1alpha2 "github.com/kubesphere/kubekey/v3/cmd/kk/apis/kubekey/v1alpha2"
    29  	"github.com/kubesphere/kubekey/v3/cmd/kk/pkg/bootstrap/os"
    30  	"github.com/kubesphere/kubekey/v3/cmd/kk/pkg/bootstrap/os/templates"
    31  	"github.com/kubesphere/kubekey/v3/cmd/kk/pkg/common"
    32  	"github.com/kubesphere/kubekey/v3/cmd/kk/pkg/core/connector"
    33  	"github.com/kubesphere/kubekey/v3/cmd/kk/pkg/core/task"
    34  	"github.com/kubesphere/kubekey/v3/cmd/kk/pkg/kubernetes"
    35  	"k8s.io/client-go/tools/clientcmd"
    36  	clientcmdapi "k8s.io/client-go/tools/clientcmd/api"
    37  
    38  	"github.com/1aal/kubeblocks/pkg/cli/cmd/infrastructure/builder"
    39  	"github.com/1aal/kubeblocks/pkg/cli/cmd/infrastructure/constant"
    40  	"github.com/1aal/kubeblocks/pkg/cli/cmd/infrastructure/types"
    41  	cfgcore "github.com/1aal/kubeblocks/pkg/configuration/core"
    42  	"github.com/1aal/kubeblocks/pkg/gotemplate"
    43  )
    44  
    45  type PrepareK8sBinariesModule struct {
    46  	common.KubeModule
    47  
    48  	// kubernetes version
    49  	BinaryVersion types.InfraVersionInfo
    50  }
    51  
    52  type ConfigureNodeOSModule struct {
    53  	common.KubeModule
    54  	Nodes []types.ClusterNode
    55  }
    56  
    57  type SaveKubeConfigModule struct {
    58  	common.KubeModule
    59  
    60  	OutputKubeconfig string
    61  }
    62  
    63  func (p *PrepareK8sBinariesModule) Init() {
    64  	p.Name = "PrepareK8sBinariesModule"
    65  	p.Desc = "Download installation binaries for kubernetes"
    66  
    67  	p.Tasks = []task.Interface{
    68  		&task.LocalTask{
    69  			Name:   "PrepareK8sBinaries",
    70  			Desc:   "Download installation binaries",
    71  			Action: &DownloadKubernetesBinary{BinaryVersion: p.BinaryVersion},
    72  		}}
    73  }
    74  
    75  func (c *ConfigureNodeOSModule) Init() {
    76  	c.Name = "ConfigureNodeOSModule"
    77  	c.Desc = "Init os dependencies"
    78  	c.Tasks = []task.Interface{
    79  		&task.RemoteTask{
    80  			Name:     "GetOSData",
    81  			Desc:     "Get OS release",
    82  			Hosts:    c.Runtime.GetAllHosts(),
    83  			Action:   new(os.GetOSData),
    84  			Parallel: true,
    85  		},
    86  		&task.RemoteTask{
    87  			Name:     "SetHostName",
    88  			Desc:     "Prepare to init OS",
    89  			Hosts:    c.Runtime.GetAllHosts(),
    90  			Action:   new(os.NodeConfigureOS),
    91  			Parallel: true,
    92  		},
    93  		&task.RemoteTask{
    94  			Name:  "GenerateScript",
    95  			Desc:  "Generate init os script",
    96  			Hosts: c.Runtime.GetAllHosts(),
    97  			Action: &NodeScriptGenerator{
    98  				Hosts: templates.GenerateHosts(c.Runtime, c.KubeConf),
    99  				Nodes: c.Nodes,
   100  			},
   101  			Parallel: true,
   102  		},
   103  		&task.RemoteTask{
   104  			Name:     "ExecScript",
   105  			Desc:     "Exec init os script",
   106  			Hosts:    c.Runtime.GetAllHosts(),
   107  			Action:   new(os.NodeExecScript),
   108  			Parallel: true,
   109  		}}
   110  }
   111  
   112  func (p *SaveKubeConfigModule) Init() {
   113  	p.Name = "SaveKubeConfigModule"
   114  	p.Desc = "Save kube config to local file"
   115  
   116  	p.Tasks = []task.Interface{
   117  		&task.LocalTask{
   118  			Name:   "SaveKubeConfig",
   119  			Desc:   "Save kube config to local file",
   120  			Action: &SaveKubeConfig{outputKubeconfig: p.OutputKubeconfig},
   121  		}}
   122  }
   123  
   124  type DownloadKubernetesBinary struct {
   125  	common.KubeAction
   126  	BinaryVersion types.InfraVersionInfo
   127  }
   128  
   129  func (d *DownloadKubernetesBinary) Execute(runtime connector.Runtime) error {
   130  	archSet := set.NewLinkedHashSetString()
   131  	for _, host := range runtime.GetAllHosts() {
   132  		archSet.Add(host.GetArch())
   133  	}
   134  
   135  	for _, arch := range archSet.AsSlice() {
   136  		binariesMap, err := downloadKubernetesBinaryWithArch(runtime.GetWorkDir(), arch, d.BinaryVersion)
   137  		if err != nil {
   138  			return err
   139  		}
   140  		d.PipelineCache.Set(common.KubeBinaries+"-"+arch, binariesMap)
   141  	}
   142  	return nil
   143  }
   144  
   145  type SaveKubeConfig struct {
   146  	common.KubeAction
   147  
   148  	outputKubeconfig string
   149  }
   150  
   151  func (c *SaveKubeConfig) Execute(runtime connector.Runtime) error {
   152  	master := runtime.GetHostsByRole(common.Master)[0]
   153  
   154  	status, ok := c.PipelineCache.Get(common.ClusterStatus)
   155  	if !ok {
   156  		return cfgcore.MakeError("failed to get kubernetes status.")
   157  	}
   158  	cluster := status.(*kubernetes.KubernetesStatus)
   159  	kubeConfigStr := cluster.KubeConfig
   160  	kc, err := clientcmd.Load([]byte(kubeConfigStr))
   161  	if err != nil {
   162  		return err
   163  	}
   164  	updateClusterAPIServer(kc, master, c.KubeConf.Cluster.ControlPlaneEndpoint)
   165  	kcFile := GetDefaultConfig()
   166  	existingKC, err := kubeconfigLoad(kcFile)
   167  	if err != nil {
   168  		return err
   169  	}
   170  	if c.outputKubeconfig == "" {
   171  		c.outputKubeconfig = kcFile
   172  	}
   173  	if existingKC != nil {
   174  		return kubeconfigMerge(kc, existingKC, c.outputKubeconfig)
   175  	}
   176  	return kubeconfigWrite(kc, c.outputKubeconfig)
   177  }
   178  
   179  type NodeScriptGenerator struct {
   180  	common.KubeAction
   181  
   182  	Nodes []types.ClusterNode
   183  	Hosts []string
   184  }
   185  
   186  func (c *NodeScriptGenerator) Execute(runtime connector.Runtime) error {
   187  	foundHostOptions := func(nodes []types.ClusterNode, host connector.Host) types.NodeOptions {
   188  		for _, node := range nodes {
   189  			switch {
   190  			default:
   191  				return types.NodeOptions{}
   192  			case node.Name != host.GetName():
   193  			case node.NodeOptions != nil:
   194  				return *node.NodeOptions
   195  			}
   196  		}
   197  		return types.NodeOptions{}
   198  	}
   199  
   200  	scriptsTemplate := builder.Template{
   201  		Template: constant.ConfigureOSScripts,
   202  		Dst:      filepath.Join(common.KubeScriptDir, "initOS.sh"),
   203  		Values: gotemplate.TplValues{
   204  			"Hosts":   c.Hosts,
   205  			"Options": foundHostOptions(c.Nodes, runtime.RemoteHost()),
   206  		}}
   207  	return scriptsTemplate.Execute(runtime)
   208  }
   209  
   210  func updateClusterAPIServer(kc *clientcmdapi.Config, master connector.Host, endpoint kubekeyapiv1alpha2.ControlPlaneEndpoint) {
   211  	cpePrefix := fmt.Sprintf("https://%s:", endpoint.Domain)
   212  	for _, cluster := range kc.Clusters {
   213  		if strings.HasPrefix(cluster.Server, cpePrefix) {
   214  			cluster.Server = fmt.Sprintf("https://%s:%d", master.GetAddress(), endpoint.Port)
   215  		}
   216  	}
   217  }