Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor: make run command args dealing more explicit #1500

Merged
merged 1 commit into from
Jun 22, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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