Skip to content

Commit

Permalink
feat(native): support join nodes for existing cluster that is not han…
Browse files Browse the repository at this point in the history
…lded by AutoK3s
  • Loading branch information
JacieChao committed Mar 31, 2022
1 parent 80b5961 commit e4f41ba
Show file tree
Hide file tree
Showing 19 changed files with 322 additions and 115 deletions.
2 changes: 1 addition & 1 deletion cmd/list.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ func listCluster() {
table.SetAlignment(tablewriter.ALIGN_LEFT)
table.SetHeader([]string{"Name", "Region", "Provider", "Status", "Masters", "Workers", "Version"})

filters, err := cluster.ListClusters()
filters, err := cluster.ListClusters("")
if err != nil {
logrus.Fatalln(err)
}
Expand Down
32 changes: 32 additions & 0 deletions docs/i18n/en_us/native/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,20 @@ autok3s -d join \
--worker-ips <worker-ip-2,worker-ip-3>
```

If you want to join a worker node to an existing K3s cluster which is not handled by AutoK3s, please use the following command.

> PS: The existing cluster is not handled by AutoK3s, so it's better to use the same ssh connect information for both master node and worker node so that we can access both VM with the same ssh config.
```bash
autok3s -d join \
--provider native \
--name myk3s \
--ip <master-ip> \
--ssh-user <ssh-user> \
--ssh-key-path <ssh-key-path> \
--worker-ips <worker-ip>
```

### HA Cluster

The commands to add one or more nodes for an existing HA K3s cluster varies based on the types of HA cluster. Please choose one of the following commands to run.
Expand Down Expand Up @@ -142,6 +156,8 @@ This command will delete a k3s cluster named "myk3s".
autok3s -d delete --provider native --name myk3s
```

> PS: If the cluster is an existing K3s cluster which is not handled by AutoK3s, we won't uninstall it when delete the cluster from AutoK3s.
## List K3s Clusters

This command will list the clusters that you have created on this machine.
Expand Down Expand Up @@ -202,6 +218,22 @@ autok3s kubectl config get-contexts
autok3s kubectl config use-context <context>
```

## SSH K3s Cluster's Node

Login to a specific k3s cluster node via ssh, i.e. myk3s.

```bash
autok3s ssh --provider native --name myk3s
```

> If the cluster is an existing one which is not handled by AutoK3s, you can't use Execute Shell from UI, but you can access the cluster nodes via CLI.
If the ssh config is different between the existing nodes and current nodes(joined with AutoK3s), you can use the command below to switch the ssh config

```bash
autok3s ssh --provider native --name myk3s <ip> --ssh-user ubuntu --ssh-key-path ~/.ssh/id_rsa
```

## Other Usages

More usage details please running `autok3s <sub-command> --provider native --help` commands.
Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ require (
google.golang.org/api v0.62.0
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b
gorm.io/driver/sqlite v1.1.4
gorm.io/gorm v1.20.12
gorm.io/gorm v1.23.3
k8s.io/api v0.22.4
k8s.io/apimachinery v0.22.4
k8s.io/client-go v12.0.0+incompatible
Expand Down
7 changes: 4 additions & 3 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -1040,8 +1040,9 @@ github.com/jinzhu/inflection v0.0.0-20170102125226-1c35d901db3d/go.mod h1:h+uFLl
github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E=
github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc=
github.com/jinzhu/now v1.0.1/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
github.com/jinzhu/now v1.1.1 h1:g39TucaRWyV3dwDO++eEc6qf8TVIQ/Da48WmqjZ3i7E=
github.com/jinzhu/now v1.1.1/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
github.com/jinzhu/now v1.1.4 h1:tHnRBy1i5F2Dh8BAFxqFzxKqqvezXrL2OW1TnX+Mlas=
github.com/jinzhu/now v1.1.4/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
github.com/jmespath/go-jmespath v0.0.0-20160202185014-0b12d6b521d8/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
github.com/jmespath/go-jmespath v0.3.0/go.mod h1:9QtRXoHjLGCJ5IBSaohpXITPlowMeeYCZ7fLUTSywik=
Expand Down Expand Up @@ -2615,8 +2616,8 @@ gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C
gorm.io/driver/sqlite v1.1.4 h1:PDzwYE+sI6De2+mxAneV9Xs11+ZyKV6oxD3wDGkaNvM=
gorm.io/driver/sqlite v1.1.4/go.mod h1:mJCeTFr7+crvS+TRnWc5Z3UvwxUN1BGBLMrf5LA9DYw=
gorm.io/gorm v1.20.7/go.mod h1:0HFTzE/SqkGTzK6TlDPPQbAYCluiVvhzoA1+aVyzenw=
gorm.io/gorm v1.20.12 h1:ebZ5KrSHzet+sqOCVdH9mTjW91L298nX3v5lVxAzSUY=
gorm.io/gorm v1.20.12/go.mod h1:0HFTzE/SqkGTzK6TlDPPQbAYCluiVvhzoA1+aVyzenw=
gorm.io/gorm v1.23.3 h1:jYh3nm7uLZkrMVfA8WVNjDZryKfr7W+HTlInVgKFJAg=
gorm.io/gorm v1.23.3/go.mod h1:l2lP/RyAtc1ynaTjFksBde/O8v9oOGIApu2/xRitmZk=
gotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo=
gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw=
gotest.tools/v3 v3.0.2/go.mod h1:3SzNCllyD9/Y+b5r9JIKQ474KzkZyqLqEfYqMsX94Bk=
Expand Down
2 changes: 1 addition & 1 deletion hack/make-rules/autok3s.sh
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ CURR_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd -P)"

# The root of the autok3s directory
ROOT_DIR="${CURR_DIR}"
UI_VERSION="v0.4.8"
UI_VERSION="v0.4.9-rc1"

source "${ROOT_DIR}/hack/lib/init.sh"
source "${CURR_DIR}/hack/lib/constant.sh"
Expand Down
19 changes: 12 additions & 7 deletions pkg/cluster/base.go
Original file line number Diff line number Diff line change
Expand Up @@ -450,7 +450,8 @@ func (p *ProviderBase) JoinNodes(cloudInstanceFunc func(ssh *types.SSH) (*types.
}

p.syncExistNodes()
c.Status = p.Status
c.Status.MasterNodes = p.Status.MasterNodes
c.Status.WorkerNodes = p.Status.WorkerNodes

added := &types.Cluster{
Metadata: c.Metadata,
Expand Down Expand Up @@ -498,11 +499,12 @@ func (p *ProviderBase) MergeConfig() ([]byte, error) {
return nil, err
}
if state == nil {
return nil, fmt.Errorf("[%s] cluster %s is not exist", p.Provider, p.Name)
return nil, nil
}
p.overwriteMetadata(state)
p.Status = types.Status{
Status: state.Status,
Status: state.Status,
Standalone: state.Standalone,
}
masterNodes := make([]types.Node, 0)
err = json.Unmarshal(state.MasterNodes, &masterNodes)
Expand Down Expand Up @@ -630,6 +632,8 @@ func (p *ProviderBase) DeleteCluster(force bool, delete func(f bool) (string, er
func (p *ProviderBase) GetClusterStatus(kubeCfg string, c *types.ClusterInfo, describeFunc func() ([]types.Node, error)) *types.ClusterInfo {
p.Logger = common.NewLogger(common.Debug, nil)

c.Master = p.Master
c.Worker = p.Worker
client, err := GetClusterConfig(p.ContextName, kubeCfg)
if err != nil {
p.Logger.Errorf("[%s] failed to generate kube client for cluster %s: %v", p.Provider, p.ContextName, err)
Expand Down Expand Up @@ -717,8 +721,8 @@ func (p *ProviderBase) SaveCredential(secrets map[string]string) error {
}

// ListClusters list clusters.
func ListClusters() ([]*types.ClusterInfo, error) {
stateList, err := common.DefaultDB.ListCluster()
func ListClusters(providerName string) ([]*types.ClusterInfo, error) {
stateList, err := common.DefaultDB.ListCluster(providerName)
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -795,10 +799,10 @@ func (p *ProviderBase) syncExistNodes() {

// Describe describe cluster info.
func (p *ProviderBase) Describe(kubeCfg string, c *types.ClusterInfo, describeInstance func() ([]types.Node, error)) *types.ClusterInfo {
c.Master = p.Master
c.Worker = p.Worker
if kubeCfg == "" {
c.Status = common.StatusMissing
c.Master = p.Master
c.Worker = p.Worker
return c
}
p.Logger = common.NewLogger(common.Debug, nil)
Expand Down Expand Up @@ -827,6 +831,7 @@ func (p *ProviderBase) Describe(kubeCfg string, c *types.ClusterInfo, describeIn
InstanceStatus: instance.InstanceStatus,
InternalIP: instance.InternalIPAddress,
ExternalIP: instance.PublicIPAddress,
Standalone: instance.Standalone,
Status: types.ClusterStatusUnknown,
ContainerRuntimeVersion: types.ClusterStatusUnknown,
Version: types.ClusterStatusUnknown,
Expand Down
32 changes: 31 additions & 1 deletion pkg/cluster/cluster.go
Original file line number Diff line number Diff line change
Expand Up @@ -332,6 +332,34 @@ func (p *ProviderBase) Join(merged, added *types.Cluster) error {
// sync master & worker numbers.
merged.Master = strconv.Itoa(len(merged.MasterNodes))
merged.Worker = strconv.Itoa(len(merged.WorkerNodes))

if p.Provider == "native" {
// check cluster context exists
kubeCfg := filepath.Join(common.CfgPath, common.KubeCfgFile)
clientConfig, err := clientcmd.LoadFromFile(kubeCfg)
if err != nil {
return err
}
contexts := clientConfig.Contexts
if _, ok := contexts[p.ContextName]; !ok {
// get k3s cluster config.
cfg, err := p.execute(&types.Node{
PublicIPAddress: []string{merged.IP},
SSH: merged.SSH,
Master: true,
}, []string{catCfgCommand})
if err == nil {
// merge current cluster to kube config.
if err := SaveCfg(cfg, merged.IP, p.ContextName); err != nil {
p.Logger.Warnf("[%s] can't save kubeconfig file with error: %v", merged.Provider, err)
}
_ = os.Setenv(clientcmd.RecommendedConfigPathEnvVar, filepath.Join(common.CfgPath, common.KubeCfgFile))
} else {
p.Logger.Warnf("[%s] can't get kubeconfig file from master %s", merged.Provider, merged.IP)
}
}
}

merged.Status.Status = common.StatusRunning
// write current cluster to state file.
if err = common.DefaultDB.SaveCluster(merged); err != nil {
Expand Down Expand Up @@ -536,7 +564,9 @@ func (p *ProviderBase) initWorker(wg *sync.WaitGroup, errChan chan error, k3sScr
}
}

sortedExtraArgs += fmt.Sprintf(" --node-external-ip %s", worker.PublicIPAddress[0])
if len(worker.PublicIPAddress) > 0 {
sortedExtraArgs += fmt.Sprintf(" --node-external-ip %s", worker.PublicIPAddress[0])
}
sortedExtraArgs += " " + extraArgs

p.Logger.Infof("[cluster] k3s worker command: %s", fmt.Sprintf(joinCommand, k3sScript, k3sMirror, cluster.IP,
Expand Down
1 change: 1 addition & 0 deletions pkg/common/db.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ var (
ssh_agent_auth bool,
manifests TEXT,
enable TEXT,
standalone bool,
unique (name, provider)
);`,
`CREATE TABLE IF NOT EXISTS templates
Expand Down
10 changes: 8 additions & 2 deletions pkg/common/model.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ type ClusterState struct {
types.Metadata `json:",inline" mapstructure:",squash" gorm:"embedded"`
Options []byte `json:"options,omitempty" gorm:"type:bytes"`
Status string `json:"status" yaml:"status"`
Standalone bool `json:"standalone" yaml:"standalone" gorm:"type:bool"`
MasterNodes []byte `json:"master-nodes,omitempty" gorm:"type:bytes"`
WorkerNodes []byte `json:"worker-nodes,omitempty" gorm:"type:bytes"`
types.SSH `json:",inline" mapstructure:",squash" gorm:"embedded"`
Expand Down Expand Up @@ -334,6 +335,7 @@ func (d *Store) SaveCluster(cluster *types.Cluster) error {
MasterNodes: masterNodeBytes,
WorkerNodes: workerNodeBytes,
SSH: cluster.SSH,
Standalone: cluster.Status.Standalone,
}

if result.RowsAffected == 0 {
Expand Down Expand Up @@ -373,9 +375,13 @@ func (d *Store) DeleteCluster(name, provider string) error {
}

// ListCluster list cluster.
func (d *Store) ListCluster() ([]*ClusterState, error) {
func (d *Store) ListCluster(provider string) ([]*ClusterState, error) {
clusterList := make([]*ClusterState, 0)
result := d.DB.Find(&clusterList)
db := d.DB
if provider != "" {
db = db.Where("provider = ?", provider)
}
result := db.Find(&clusterList)
return clusterList, result.Error
}

Expand Down
22 changes: 12 additions & 10 deletions pkg/providers/alibaba/flag.go
Original file line number Diff line number Diff line change
Expand Up @@ -96,17 +96,19 @@ func (p *Alibaba) MergeClusterOptions() error {
if err != nil {
return err
}
stateOption, err := p.GetProviderOptions(opt)
if err != nil {
return err
}
option := stateOption.(*alibaba.Options)
p.CloudControllerManager = option.CloudControllerManager
if opt != nil {
stateOption, err := p.GetProviderOptions(opt)
if err != nil {
return err
}
option := stateOption.(*alibaba.Options)
p.CloudControllerManager = option.CloudControllerManager

// merge options.
source := reflect.ValueOf(&p.Options).Elem()
target := reflect.ValueOf(option).Elem()
utils.MergeConfig(source, target)
// merge options.
source := reflect.ValueOf(&p.Options).Elem()
target := reflect.ValueOf(option).Elem()
utils.MergeConfig(source, target)
}
return nil
}

Expand Down
22 changes: 12 additions & 10 deletions pkg/providers/aws/flag.go
Original file line number Diff line number Diff line change
Expand Up @@ -169,17 +169,19 @@ func (p *Amazon) MergeClusterOptions() error {
if err != nil {
return err
}
stateOption, err := p.GetProviderOptions(opt)
if err != nil {
return err
}
option := stateOption.(*aws.Options)
p.CloudControllerManager = option.CloudControllerManager
if opt != nil {
stateOption, err := p.GetProviderOptions(opt)
if err != nil {
return err
}
option := stateOption.(*aws.Options)
p.CloudControllerManager = option.CloudControllerManager

// merge options.
source := reflect.ValueOf(&p.Options).Elem()
target := reflect.ValueOf(option).Elem()
utils.MergeConfig(source, target)
// merge options.
source := reflect.ValueOf(&p.Options).Elem()
target := reflect.ValueOf(option).Elem()
utils.MergeConfig(source, target)
}

return nil
}
Expand Down
22 changes: 12 additions & 10 deletions pkg/providers/google/flag.go
Original file line number Diff line number Diff line change
Expand Up @@ -160,17 +160,19 @@ func (p *Google) MergeClusterOptions() error {
if err != nil {
return err
}
stateOption, err := p.GetProviderOptions(opt)
if err != nil {
return err
}
option := stateOption.(*google.Options)
p.CloudControllerManager = option.CloudControllerManager
if opt != nil {
stateOption, err := p.GetProviderOptions(opt)
if err != nil {
return err
}
option := stateOption.(*google.Options)
p.CloudControllerManager = option.CloudControllerManager

// merge options
source := reflect.ValueOf(&p.Options).Elem()
target := reflect.ValueOf(option).Elem()
utils.MergeConfig(source, target)
// merge options
source := reflect.ValueOf(&p.Options).Elem()
target := reflect.ValueOf(option).Elem()
utils.MergeConfig(source, target)
}

return nil
}
Expand Down
20 changes: 11 additions & 9 deletions pkg/providers/harvester/flag.go
Original file line number Diff line number Diff line change
Expand Up @@ -126,16 +126,18 @@ func (h *Harvester) MergeClusterOptions() error {
if err != nil {
return err
}
stateOption, err := h.GetProviderOptions(opt)
if err != nil {
return err
}
option := stateOption.(*harvestertypes.Options)
if opt != nil {
stateOption, err := h.GetProviderOptions(opt)
if err != nil {
return err
}
option := stateOption.(*harvestertypes.Options)

// merge options.
source := reflect.ValueOf(&h.Options).Elem()
target := reflect.ValueOf(option).Elem()
utils.MergeConfig(source, target)
// merge options.
source := reflect.ValueOf(&h.Options).Elem()
target := reflect.ValueOf(option).Elem()
utils.MergeConfig(source, target)
}

return nil
}
Expand Down
20 changes: 11 additions & 9 deletions pkg/providers/k3d/flag.go
Original file line number Diff line number Diff line change
Expand Up @@ -195,16 +195,18 @@ func (p *K3d) MergeClusterOptions() error {
if err != nil {
return err
}
stateOption, err := p.GetProviderOptions(opt)
if err != nil {
return err
}
option := stateOption.(*k3d.Options)
if opt != nil {
stateOption, err := p.GetProviderOptions(opt)
if err != nil {
return err
}
option := stateOption.(*k3d.Options)

// merge options.
source := reflect.ValueOf(&p.Options).Elem()
target := reflect.ValueOf(option).Elem()
utils.MergeConfig(source, target)
// merge options.
source := reflect.ValueOf(&p.Options).Elem()
target := reflect.ValueOf(option).Elem()
utils.MergeConfig(source, target)
}

return nil
}
Expand Down
Loading

0 comments on commit e4f41ba

Please sign in to comment.