Skip to content

Commit

Permalink
feat(autok3s): add upgrade cmd
Browse files Browse the repository at this point in the history
  • Loading branch information
JacieChao committed May 24, 2022
1 parent 97e95b0 commit c636c57
Show file tree
Hide file tree
Showing 15 changed files with 350 additions and 25 deletions.
59 changes: 59 additions & 0 deletions cmd/upgrade.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
package cmd

import (
"github.com/cnrancher/autok3s/pkg/providers"

"github.com/sirupsen/logrus"
"github.com/spf13/cobra"
)

var (
upgradeCmd = &cobra.Command{
Use: "upgrade",
Short: "Upgrade a K3s cluster to specified version",
}
uProvider = ""
clusterName = ""
channel = ""
version = ""
installScript = ""
)

func init() {
upgradeCmd.Flags().StringVarP(&uProvider, "provider", "p", uProvider, "Provider is a module which provides an interface for managing cloud resources")
upgradeCmd.Flags().StringVarP(&clusterName, "name", "n", clusterName, "cluster name")
upgradeCmd.Flags().StringVarP(&channel, "k3s-channel", "", channel, "Channel to use for fetching K3s download URL. Defaults to “stable”. Options include: stable, latest, testing")
upgradeCmd.Flags().StringVarP(&version, "k3s-version", "", version, "Used to specify the version of k3s cluster, overrides k3s-channel")
upgradeCmd.Flags().StringVarP(&installScript, "k3s-install-script", "", installScript, "Change the default upstream k3s install script address, see: https://rancher.com/docs/k3s/latest/en/installation/install-options/#options-for-installation-with-script")
}

// UpgradeCommand help upgrade a K3s cluster to specified version
func UpgradeCommand() *cobra.Command {
upgradeCmd.PreRunE = func(cmd *cobra.Command, args []string) error {
if clusterName == "" {
logrus.Fatalln("`-n` or `--name` must set to specify a cluster, i.e. autok3s upgrade -n <cluster-name>")
}
if uProvider == "" {
logrus.Fatalln("`-p` or `--provider` must set")
}
if uProvider == "k3d" {
logrus.Fatalln("The upgrade cluster for K3d provider is not supported yet.")
}
return nil
}
upgradeCmd.Run = func(cmd *cobra.Command, args []string) {
upgradeCluster()
}
return upgradeCmd
}

func upgradeCluster() {
up, err := providers.GetProvider(uProvider)
if err != nil {
logrus.Fatalf("failed to get provider %v: %v", uProvider, err)
}
err = up.UpgradeK3sCluster(clusterName, installScript, channel, version)
if err != nil {
logrus.Fatalf("[%s] failed to upgrade cluster %s, got error: %v", uProvider, clusterName, err)
}
}
14 changes: 14 additions & 0 deletions docs/i18n/en_us/alibaba/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -285,6 +285,20 @@ Login to a specific k3s cluster node via ssh, i.e. myk3s.
autok3s ssh --provider alibaba --name myk3s
```

## Upgrade K3s Cluster

The following command will help you to upgrade your K3s cluster version to latest version.

```
autok3s upgrade --provider aws --name myk3s --k3s-channel latest
```

If you want to upgrade K3s cluster to a specified version, you can use `--k3s-version` to overrides `--k3s-channel`.

```
autok3s upgrade --provider aws --name myk3s --k3s-version v1.22.4+k3s1
```

## Other Usages

Please run `autok3s <sub-command> --provider alibaba --help` commands, to discover other usages of AutoK3s.
Expand Down
14 changes: 14 additions & 0 deletions docs/i18n/en_us/aws/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,20 @@ Login to a specific k3s cluster node via ssh, i.e. myk3s.
autok3s ssh --provider aws --name myk3s
```

## Upgrade K3s Cluster

The following command will help you to upgrade your K3s cluster version to latest version.

```
autok3s upgrade --provider aws --name myk3s --k3s-channel latest
```

If you want to upgrade K3s cluster to a specified version, you can use `--k3s-version` to overrides `--k3s-channel`.

```
autok3s upgrade --provider aws --name myk3s --k3s-version v1.22.4+k3s1
```

## Other Usages

More usage details please running `autok3s <sub-command> --provider aws --help` commands.
Expand Down
14 changes: 14 additions & 0 deletions docs/i18n/en_us/google/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,20 @@ Login to a specific k3s cluster node via ssh, i.e. myk3s.
autok3s ssh --provider google --name myk3s
```

## Upgrade K3s Cluster

The following command will help you to upgrade your K3s cluster version to latest version.

```
autok3s upgrade --provider aws --name myk3s --k3s-channel latest
```

If you want to upgrade K3s cluster to a specified version, you can use `--k3s-version` to overrides `--k3s-channel`.

```
autok3s upgrade --provider aws --name myk3s --k3s-version v1.22.4+k3s1
```

## Other Usages

More usage details please running `autok3s <sub-command> --provider google --help` commands.
Expand Down
14 changes: 14 additions & 0 deletions docs/i18n/en_us/harvester/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,20 @@ Login to a specific k3s cluster node via ssh, i.e. myk3s.
autok3s ssh --provider harvester --name myk3s
```

## Upgrade K3s Cluster

The following command will help you to upgrade your K3s cluster version to latest version.

```
autok3s upgrade --provider aws --name myk3s --k3s-channel latest
```

If you want to upgrade K3s cluster to a specified version, you can use `--k3s-version` to overrides `--k3s-channel`.

```
autok3s upgrade --provider aws --name myk3s --k3s-version v1.22.4+k3s1
```

## Other Usages

More usage details please running `autok3s <sub-command> --provider harvester --help` commands.
Expand Down
14 changes: 14 additions & 0 deletions docs/i18n/en_us/native/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -234,6 +234,20 @@ If the ssh config is different between the existing nodes and current nodes(join
autok3s ssh --provider native --name myk3s <ip> --ssh-user ubuntu --ssh-key-path ~/.ssh/id_rsa
```

## Upgrade K3s Cluster

The following command will help you to upgrade your K3s cluster version to latest version.

```
autok3s upgrade --provider aws --name myk3s --k3s-channel latest
```

If you want to upgrade K3s cluster to a specified version, you can use `--k3s-version` to overrides `--k3s-channel`.

```
autok3s upgrade --provider aws --name myk3s --k3s-version v1.22.4+k3s1
```

## Other Usages

More usage details please running `autok3s <sub-command> --provider native --help` commands.
Expand Down
14 changes: 14 additions & 0 deletions docs/i18n/en_us/tencent/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -245,6 +245,20 @@ Login to a specific k3s cluster node via ssh, i.e. myk3s.
autok3s ssh --provider tencent --name myk3s
```

## Upgrade K3s Cluster

The following command will help you to upgrade your K3s cluster version to latest version.

```
autok3s upgrade --provider aws --name myk3s --k3s-channel latest
```

If you want to upgrade K3s cluster to a specified version, you can use `--k3s-version` to overrides `--k3s-channel`.

```
autok3s upgrade --provider aws --name myk3s --k3s-version v1.22.4+k3s1
```

## Other Usages

More usage details please running `autok3s <sub-command> --provider tencent --help` commands.
Expand Down
2 changes: 1 addition & 1 deletion main.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ func main() {
rootCmd := cmd.Command()
rootCmd.AddCommand(cmd.CompletionCommand(), cmd.VersionCommand(gitVersion, gitCommit, gitTreeState, buildDate),
cmd.ListCommand(), cmd.CreateCommand(), cmd.JoinCommand(), cmd.KubectlCommand(), cmd.DeleteCommand(),
cmd.SSHCommand(), cmd.DescribeCommand(), cmd.ServeCommand(), cmd.ExplorerCommand())
cmd.SSHCommand(), cmd.DescribeCommand(), cmd.ServeCommand(), cmd.ExplorerCommand(), cmd.UpgradeCommand())

rootCmd.PersistentPreRun = func(cmd *cobra.Command, args []string) {
metrics.ReportMetrics()
Expand Down
71 changes: 71 additions & 0 deletions pkg/cluster/base.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"bytes"
"encoding/base64"
"encoding/json"
"errors"
"fmt"
"io/ioutil"
"os"
Expand Down Expand Up @@ -1028,3 +1029,73 @@ func (p *ProviderBase) RegisterCallbacks(name, event string, fn func(interface{}
Fn: fn,
}
}

func (p *ProviderBase) UpgradeK3sCluster(clusterName, installScript, channel, version string) error {
if p.Provider == "k3d" {
return errors.New("the upgrade cluster for K3d provider is not supported yet")
}
state, err := common.DefaultDB.GetCluster(clusterName, p.Provider)
if err != nil {
return err
}
if state == nil {
return fmt.Errorf("cluster %s is not exist", clusterName)
}
p.Name = clusterName
p.ContextName = state.ContextName
logFile, err := common.GetLogFile(state.ContextName)
if err != nil {
return err
}
p.Logger = common.NewLogger(common.Debug, logFile)
p.Logger.Infof("[%s] begin to upgrade cluster %s...", p.Provider, clusterName)
state.Status = common.StatusUpgrading
// save cluster.
err = common.DefaultDB.SaveClusterState(state)
if err != nil {
return err
}

defer func() {
// update cluster status
state.Status = common.StatusRunning
_ = common.DefaultDB.SaveClusterState(state)
// remove upgrade state file and save running state.
_ = logFile.Close()
if p.Callbacks != nil {
if process, ok := p.Callbacks[state.ContextName]; ok && process.Event == "update" {
logEvent := &common.LogEvent{
Name: process.Event,
ContextName: state.ContextName,
}
process.Fn(logEvent)
}
}
}()

c := common.ConvertToCluster(state)
masterNodes := make([]types.Node, 0)
err = json.Unmarshal(state.MasterNodes, &masterNodes)
if err != nil {
return err
}
workerNodes := make([]types.Node, 0)
err = json.Unmarshal(state.WorkerNodes, &workerNodes)
if err != nil {
return err
}
c.Status.MasterNodes = masterNodes
c.Status.WorkerNodes = workerNodes
if installScript != "" {
c.InstallScript = installScript
state.InstallScript = installScript
}
if channel != "" {
c.K3sChannel = channel
state.K3sChannel = channel
}
c.K3sVersion = version
state.K3sVersion = version

return p.Upgrade(&c)
}
70 changes: 70 additions & 0 deletions pkg/cluster/cluster.go
Original file line number Diff line number Diff line change
Expand Up @@ -974,3 +974,73 @@ func DescribeClusterNodes(client *kubernetes.Clientset, instanceNodes []types.Cl
}
return instanceNodes, nil
}

func (p *ProviderBase) Upgrade(cluster *types.Cluster) error {
p.Logger.Infof("[%s] executing upgrade k3s cluster logic...", p.Provider)
if len(cluster.MasterNodes) <= 0 || len(cluster.MasterNodes[0].InternalIPAddress) <= 0 {
return errors.New("[cluster] master node internal ip address can not be empty")
}

provider, err := providers.GetProvider(p.Provider)
if err != nil {
return err
}
masterExtraArgs := cluster.MasterExtraArgs
workerExtraArgs := cluster.WorkerExtraArgs

if cluster.DataStore != "" {
cluster.Cluster = false
masterExtraArgs += " --datastore-endpoint " + cluster.DataStore
}

if cluster.Network != "" {
masterExtraArgs += fmt.Sprintf(" --flannel-backend=%s", cluster.Network)
}

if cluster.ClusterCidr != "" {
masterExtraArgs += " --cluster-cidr " + cluster.ClusterCidr
}

var tlsSans string
for _, tlsSan := range cluster.TLSSans {
tlsSans = tlsSans + fmt.Sprintf(" --tls-san %s", tlsSan)
}
// upgrade server nodes
for index, node := range cluster.MasterNodes {
extraArgs := masterExtraArgs
providerExtraArgs := provider.GenerateMasterExtraArgs(cluster, node)
if providerExtraArgs != "" {
extraArgs += providerExtraArgs
}
if index == 0 {
if cluster.Cluster {
extraArgs += " --cluster-init"
}
}
p.Logger.Infof("[cluster] k3s master command: %s", fmt.Sprintf(initCommand, cluster.InstallScript, cluster.Mirror, cluster.Token,
tlsSans, node.PublicIPAddress[0], strings.TrimSpace(extraArgs), genK3sVersion(cluster.K3sVersion, cluster.K3sChannel)))

if _, err := p.execute(&node, []string{fmt.Sprintf(initCommand, cluster.InstallScript, cluster.Mirror,
cluster.Token, tlsSans, node.PublicIPAddress[0], strings.TrimSpace(extraArgs), genK3sVersion(cluster.K3sVersion, cluster.K3sChannel))}); err != nil {
return err
}
}

// upgrade worker nodes
for _, node := range cluster.WorkerNodes {
extraArgs := workerExtraArgs
providerExtraArgs := provider.GenerateWorkerExtraArgs(cluster, node)
if providerExtraArgs != "" {
extraArgs += providerExtraArgs
}
p.Logger.Infof("[cluster] k3s worker command: %s", fmt.Sprintf(joinCommand, cluster.InstallScript, cluster.Mirror, cluster.IP,
cluster.Token, strings.TrimSpace(extraArgs), genK3sVersion(cluster.K3sVersion, cluster.K3sChannel)))

if _, err := p.execute(&node, []string{fmt.Sprintf(joinCommand, cluster.InstallScript, cluster.Mirror, cluster.IP,
cluster.Token, strings.TrimSpace(extraArgs), genK3sVersion(cluster.K3sVersion, cluster.K3sChannel))}); err != nil {
return err
}
}

return nil
}
5 changes: 3 additions & 2 deletions pkg/common/model.go
Original file line number Diff line number Diff line change
Expand Up @@ -217,14 +217,15 @@ func toClusterEvent(state *clusterEvent, schemaID string) apitypes.APIEvent {
Object: apitypes.APIObject{
Type: schemaID,
ID: state.Object.ContextName,
Object: toCluster(state.Object),
Object: ConvertToCluster(state.Object),
},
}
}

func toCluster(state *ClusterState) types.Cluster {
func ConvertToCluster(state *ClusterState) types.Cluster {
c := types.Cluster{
Metadata: state.Metadata,
SSH: state.SSH,
Status: types.Status{
Status: state.Status,
},
Expand Down
2 changes: 2 additions & 0 deletions pkg/providers/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,8 @@ type Provider interface {
BindCredential() error
// callback functions used for execute logic after create/join
RegisterCallbacks(name, event string, fn func(interface{}))
// UpgradeK3sCluster helps upgrade K3s cluster to specified version
UpgradeK3sCluster(clusterName, installScript, channel, version string) error
}

// RegisterProvider registers a provider.Factory by name.
Expand Down
4 changes: 4 additions & 0 deletions pkg/server/schema.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ func initProvider(s *types.APISchemas) {
func initCluster(s *types.APISchemas) {
s.MustImportAndCustomize(autok3stypes.KubeconfigOutput{}, nil)
s.MustImportAndCustomize(autok3stypes.EnableExplorerOutput{}, nil)
s.MustImportAndCustomize(autok3stypes.UpgradeInput{}, nil)
s.MustImportAndCustomize(autok3stypes.Cluster{}, func(schema *types.APISchema) {
schema.Store = &cluster.Store{}
common.DefaultDB.Register()
Expand All @@ -45,6 +46,9 @@ func initCluster(s *types.APISchemas) {
schema.ResourceActions["download-kubeconfig"] = wranglertypes.Action{
Output: "kubeconfigOutput",
}
schema.ResourceActions["upgrade"] = wranglertypes.Action{
Input: "upgradeInput",
}
schema.Formatter = cluster.Formatter
schema.ActionHandlers = cluster.HandleCluster()
schema.ByIDHandler = cluster.LinkCluster
Expand Down
Loading

0 comments on commit c636c57

Please sign in to comment.