Skip to content

Commit

Permalink
refatcor: make run command args dealing more explicit (sealerio#1500)
Browse files Browse the repository at this point in the history
Signed-off-by: Allen Sun <[email protected]>
  • Loading branch information
allencloud authored Jun 22, 2022
1 parent a8cc909 commit 3674413
Show file tree
Hide file tree
Showing 14 changed files with 435 additions and 234 deletions.
36 changes: 24 additions & 12 deletions apply/apply.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,18 +30,23 @@ import (

type Args struct {
ClusterName string
Masters string
Nodes string
User string
Password string
Port uint16
Pk string
PkPassword string
PodCidr string
SvcCidr string
Provider string
CustomEnv []string
CMDArgs []string

// Masters and Nodes only support:
// IP list format: ip1,ip2,ip3
// IP range format: x.x.x.x-x.x.x.y
Masters string
Nodes string

User string
Password string
Port uint16
Pk string
PkPassword string
PodCidr string
SvcCidr string
Provider string
CustomEnv []string
CMDArgs []string
}

func NewApplierFromFile(path string) (applydriver.Interface, error) {
Expand Down Expand Up @@ -86,6 +91,13 @@ func NewApplierFromFile(path string) (applydriver.Interface, error) {
}, nil
}

// NewApplier news an applier.
// In NewApplier, we guarantee that no raw data could be passed in.
// And all data has to be validated and processed in the pre-process layer.
func NewApplier(cluster *v2.Cluster) (applydriver.Interface, error) {
return NewDefaultApplier(cluster)
}

func NewDefaultApplier(cluster *v2.Cluster) (applydriver.Interface, error) {
if cluster.Name == "" {
return nil, fmt.Errorf("cluster name cannot be empty")
Expand Down
178 changes: 100 additions & 78 deletions apply/run.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,115 +15,137 @@
package apply

import (
"fmt"
"strconv"
"strings"

v1 "github.com/sealerio/sealer/types/api/v1"

"github.com/sealerio/sealer/apply/applydriver"

"github.com/sealerio/sealer/common"
v1 "github.com/sealerio/sealer/types/api/v1"
v2 "github.com/sealerio/sealer/types/api/v2"
"github.com/sealerio/sealer/utils/net"
)

type ClusterArgs struct {
cluster *v2.Cluster
imageName string
runArgs *Args
hosts []v2.Host
func ConstructClusterFromArg(imageName string, runArgs *Args) (*v2.Cluster, error) {
resultHosts, err := getHosts(runArgs.Masters, runArgs.Nodes)
if err != nil {
return nil, err
}

cluster := v2.Cluster{
Spec: v2.ClusterSpec{
SSH: v1.SSH{
User: runArgs.User,
Passwd: runArgs.Password,
PkPasswd: runArgs.PkPassword,
Pk: runArgs.Pk,
Port: strconv.Itoa(int(runArgs.Port)),
},
Image: imageName,
Hosts: resultHosts,
Env: runArgs.CustomEnv,
CMDArgs: runArgs.CMDArgs,
},
}
cluster.APIVersion = common.APIVersion
cluster.Kind = common.Kind
cluster.Name = runArgs.ClusterName

return &cluster, nil
}

func PreProcessIPList(joinArgs *Args) error {
if err := net.AssemblyIPList(&joinArgs.Masters); err != nil {
return err
func NewApplierFromArgs(imageName string, runArgs *Args) (applydriver.Interface, error) {
if err := validateArgs(runArgs); err != nil {
return nil, fmt.Errorf("failed to validate input run args: %v", err)
}
if err := net.AssemblyIPList(&joinArgs.Nodes); err != nil {
return err
cluster, err := ConstructClusterFromArg(imageName, runArgs)
if err != nil {
return nil, fmt.Errorf("failed to initialize cluster instance with command args: %v", err)
}
return nil
return NewDefaultApplier(cluster)
}

func (c *ClusterArgs) SetClusterArgs() error {
c.cluster.APIVersion = common.APIVersion
c.cluster.Kind = common.Cluster
c.cluster.Name = c.runArgs.ClusterName
c.cluster.Spec.Image = c.imageName
c.cluster.Spec.Env = append(c.cluster.Spec.Env, c.runArgs.CustomEnv...)
c.cluster.Spec.CMDArgs = append(c.cluster.Spec.CMDArgs, c.runArgs.CMDArgs...)
// validateArgs validates all the input args from sealer run command.
func validateArgs(runArgs *Args) error {
// TODO: add detailed validation steps.
var errMsg []string

err := PreProcessIPList(c.runArgs)
if err != nil {
return err
// validate input masters IP info
if err := validateIPStr(runArgs.Masters); err != nil {
errMsg = append(errMsg, err.Error())
}

if net.IsIPList(c.runArgs.Masters) && (net.IsIPList(c.runArgs.Nodes) || c.runArgs.Nodes == "") {
// add common ssh config.
c.cluster.Spec.SSH = v1.SSH{
User: c.runArgs.User,
Passwd: c.runArgs.Password,
Pk: c.runArgs.Pk,
PkPasswd: c.runArgs.PkPassword,
Port: strconv.Itoa(int(c.runArgs.Port)),
// validate input nodes IP info
if len(runArgs.Nodes) != 0 {
// empty runArgs.Nodes is valid, since no nodes are input.
if err := validateIPStr(runArgs.Nodes); err != nil {
errMsg = append(errMsg, err.Error())
}
}

masters := strings.Split(c.runArgs.Masters, ",")
nodes := strings.Split(c.runArgs.Nodes, ",")
c.hosts = []v2.Host{}
if len(errMsg) == 0 {
return nil
}
return fmt.Errorf(strings.Join(errMsg, ","))
}

c.setHostWithIpsPort(masters, common.MASTER)
// If s does not contain sep and sep is not empty, Split returns a
// slice of length 1 whose only element is s.
if len(nodes) > 1 {
c.setHostWithIpsPort(nodes, common.NODE)
}
c.cluster.Spec.Hosts = c.hosts
} else {
// if user execute sealer run without password and infra info,choose local host ip as master0 ip.
ip, err := net.GetLocalDefaultIP()
// getHosts now only supports input IP list and IP range.
// IP list, like 192.168.0.1,192.168.0.2,192.168.0.3
// IP range, like 192.168.0.5-192.168.0.7, which means 192.168.0.5,192.168.0.6,192.168.0.7
// P.S. we have guaranteed that all the input masters and nodes are validated.
func getHosts(inMasters, inNodes string) ([]v2.Host, error) {
var err error
if isRange(inMasters) {
inMasters, err = net.IPRangeToList(inMasters)
if err != nil {
return err
}
c.cluster.Spec.Hosts = []v2.Host{
{
IPS: []string{ip},
Roles: []string{common.MASTER},
},
return nil, err
}
}
return err
}

func (c *ClusterArgs) setHostWithIpsPort(ips []string, role string) {
//map[ssh port]*host
hostMap := map[string]*v2.Host{}
for i := range ips {
ip, port := net.GetHostIPAndPortOrDefault(ips[i], strconv.Itoa(int(c.runArgs.Port)))
if _, ok := hostMap[port]; !ok {
hostMap[port] = &v2.Host{IPS: []string{ip}, Roles: []string{role}}
continue
if isRange(inNodes) {
if inNodes, err = net.IPRangeToList(inNodes); err != nil {
return nil, err
}
hostMap[port].IPS = append(hostMap[port].IPS, ip)
}
_, master0Port := net.GetHostIPAndPortOrDefault(ips[0], strconv.Itoa(int(c.runArgs.Port)))
for port, host := range hostMap {
host.IPS = removeDuplicate(host.IPS)
if port == master0Port && role == common.MASTER {
c.hosts = append([]v2.Host{*host}, c.hosts...)

masters := strings.Split(inMasters, ",")
masterHosts := make([]v2.Host, len(masters))
for index, master := range masters {
if index == 0 {
// only master0 should add two roles: master and master0
masterHosts = append(masterHosts, v2.Host{
IPS: []string{master},
Roles: []string{common.MASTER, common.MASTER0},
})

continue
}
c.hosts = append(c.hosts, *host)

masterHosts = append(masterHosts, v2.Host{
IPS: []string{master},
Roles: []string{common.MASTER},
})
}
}

func NewApplierFromArgs(imageName string, runArgs *Args) (applydriver.Interface, error) {
c := &ClusterArgs{
cluster: &v2.Cluster{},
imageName: imageName,
runArgs: runArgs,
nodes := strings.Split(inNodes, ",")
nodeHosts := make([]v2.Host, len(nodes))
for _, node := range nodes {
nodeHosts = append(nodeHosts, v2.Host{
IPS: []string{node},
Roles: []string{common.NODE},
})
}
if err := c.SetClusterArgs(); err != nil {
return nil, err

result := make([]v2.Host, len(masters)+len(nodes))
result = append(result, masterHosts...)
result = append(result, nodeHosts...)

return result, nil
}

func isRange(ipStr string) bool {
if len(ipStr) == 0 || !strings.Contains(ipStr, "-") {
return false
}
return NewDefaultApplier(c.cluster)
return true
}
109 changes: 0 additions & 109 deletions apply/run_test.go

This file was deleted.

Loading

0 comments on commit 3674413

Please sign in to comment.