[ADD] modify install node

This commit is contained in:
凡羊羊 2019-08-06 19:32:45 +08:00
parent d4a49a18f1
commit eafe220983
6 changed files with 474 additions and 168 deletions

View File

@ -19,18 +19,11 @@
package cmd
import (
"bytes"
"fmt"
"io/ioutil"
"net"
"os"
"path"
"github.com/goodrain/rainbond/grctl/clients"
"github.com/goodrain/rainbond/util"
"github.com/goodrain/rainbond/node/nodem/client"
"github.com/urfave/cli"
"github.com/goodrain/rainbond/node/nodem/client"
ansibleUtil "github.com/goodrain/rainbond/util/ansible"
)
//NewCmdAnsible ansible config cmd
@ -44,16 +37,21 @@ func NewCmdAnsible() cli.Command {
Usage: "Manage the ansible hosts config environment",
Flags: []cli.Flag{
cli.StringFlag{
Name: "hosts-file-path,p",
Name: "hosts-file-path",
Usage: "hosts file path",
Value: "/opt/rainbond/rainbond-ansible/inventory/hosts",
},
cli.StringFlag{
Name: "config-file-path",
Usage: "install config path",
Value: "/opt/rainbond/rainbond-ansible/scripts/installer/global.sh",
},
},
Action: func(c *cli.Context) error {
Common(c)
hosts, err := clients.RegionClient.Nodes().List()
handleErr(err)
return WriteHostsFile(c.String("p"), hosts)
return WriteHostsFile(c.String("hosts-file-path"), c.String("config-file-path"), hosts)
},
},
},
@ -62,139 +60,6 @@ func NewCmdAnsible() cli.Command {
}
//WriteHostsFile write hosts file
func WriteHostsFile(filePath string, hosts []*client.HostNode) error {
config := GetAnsibleHostConfig(filePath)
for i := range hosts {
config.AddHost(hosts[i])
}
return config.WriteFile()
}
//AnsibleHost ansible host config
type AnsibleHost struct {
AnsibleHostIP net.IP
//ssh port
AnsibleHostPort int
HostID string
Role client.HostRule
}
func (a *AnsibleHost) String() string {
return fmt.Sprintf("%s ansible_host=%s ansible_port=%d ip=%s port=%d role=%s", a.HostID, a.AnsibleHostIP, a.AnsibleHostPort, a.AnsibleHostIP, a.AnsibleHostPort, a.Role)
}
//AnsibleHostGroup ansible host group config
type AnsibleHostGroup struct {
Name string
HostList []*AnsibleHost
}
//AddHost add host
func (a *AnsibleHostGroup) AddHost(h *AnsibleHost) {
for _, old := range a.HostList {
if old.AnsibleHostIP.String() == h.AnsibleHostIP.String() {
return
}
}
a.HostList = append(a.HostList, h)
}
func (a *AnsibleHostGroup) String() string {
rebuffer := bytes.NewBuffer(nil)
rebuffer.WriteString(fmt.Sprintf("[%s]\n", a.Name))
for i := range a.HostList {
if a.Name == "all" {
rebuffer.WriteString(a.HostList[i].String() + "\n")
} else {
rebuffer.WriteString(a.HostList[i].HostID + "\n")
}
}
rebuffer.WriteString("\n")
return rebuffer.String()
}
//AnsibleHostConfig ansible hosts config
type AnsibleHostConfig struct {
FileName string
GroupList map[string]*AnsibleHostGroup
}
//GetAnsibleHostConfig get config
func GetAnsibleHostConfig(name string) *AnsibleHostConfig {
return &AnsibleHostConfig{
FileName: name,
GroupList: map[string]*AnsibleHostGroup{
"all": &AnsibleHostGroup{Name: "all"},
"manage": &AnsibleHostGroup{Name: "manage"},
"new-manage": &AnsibleHostGroup{Name: "new-manage"},
"gateway": &AnsibleHostGroup{Name: "gateway"},
"new-gateway": &AnsibleHostGroup{Name: "new-gateway"},
"compute": &AnsibleHostGroup{Name: "compute"},
"new-compute": &AnsibleHostGroup{Name: "new-compute"},
},
}
}
//Content return config file content
func (c *AnsibleHostConfig) Content() string {
return c.ContentBuffer().String()
}
//ContentBuffer content buffer
func (c *AnsibleHostConfig) ContentBuffer() *bytes.Buffer {
rebuffer := bytes.NewBuffer(nil)
for i := range c.GroupList {
rebuffer.WriteString(c.GroupList[i].String())
}
return rebuffer
}
//WriteFile write config file
func (c *AnsibleHostConfig) WriteFile() error {
if c.FileName == "" {
return fmt.Errorf("config file name can not be empty")
}
if err := util.CheckAndCreateDir(path.Dir(c.FileName)); err != nil {
return err
}
if err := ioutil.WriteFile(c.FileName+".tmp", c.ContentBuffer().Bytes(), 0755); err != nil {
return err
}
return os.Rename(c.FileName+".tmp", c.FileName)
}
func getSSHPort() int {
return 22
}
//AddHost add host
func (c *AnsibleHostConfig) AddHost(h *client.HostNode) {
//check role
//check status
ansibleHost := &AnsibleHost{
AnsibleHostIP: net.ParseIP(h.InternalIP),
AnsibleHostPort: getSSHPort(),
HostID: h.ID,
Role: h.Role,
}
c.GroupList["all"].AddHost(ansibleHost)
if h.Role.HasRule("manage") {
if h.Status == client.NotInstalled || h.Status == client.InstallFailed {
c.GroupList["new-manage"].AddHost(ansibleHost)
} else {
c.GroupList["manage"].AddHost(ansibleHost)
}
}
if h.Role.HasRule("compute") {
if h.Status == client.NotInstalled || h.Status == client.InstallFailed {
c.GroupList["new-compute"].AddHost(ansibleHost)
} else {
c.GroupList["compute"].AddHost(ansibleHost)
}
}
if h.Role.HasRule("gateway") {
if h.Status == client.NotInstalled || h.Status == client.InstallFailed {
c.GroupList["new-gateway"].AddHost(ansibleHost)
} else {
c.GroupList["gateway"].AddHost(ansibleHost)
}
}
func WriteHostsFile(filePath, installConfPath string, hosts []*client.HostNode) error {
return ansibleUtil.WriteHostsFile(filePath, installConfPath, hosts)
}

View File

@ -200,6 +200,11 @@ func NewCmdInit() cli.Command {
Usage: "use test shell",
Hidden: true,
},
cli.StringFlag{
Name: "install_ssh_port",
Usage: "new node ssh port",
Value: "22",
},
},
Usage: "grctl init cluster",
Action: func(c *cli.Context) error {
@ -322,6 +327,7 @@ func getConfig(c *cli.Context) map[string]string {
configs["EXCSDB_PORT"] = c.String("excsdb-port")
configs["EXCSDB_USER"] = c.String("excsdb-user")
configs["EXDB_TYPE"] = c.String("exdb-type")
configs["INSTALL_SSH_PORT"] = c.String("install_ssh_port")
return configs
}
func initCluster(c *cli.Context) {

View File

@ -23,7 +23,6 @@ import (
"fmt"
"io/ioutil"
"os"
"os/exec"
"strconv"
"strings"
@ -582,7 +581,7 @@ func NewCmdNode() cli.Command {
Usage: "Install a exist node into the cluster",
Flags: []cli.Flag{
cli.StringFlag{
Name: "hosts-file-path,p",
Name: "hosts-file-path",
Usage: "hosts file path",
Value: "/opt/rainbond/rainbond-ansible/inventory/hosts",
},
@ -616,16 +615,28 @@ func installNode(node *client.HostNode) {
logrus.Errorf("install node scripts is not found")
return
}
line := fmt.Sprintf("/opt/rainbond/rainbond-ansible/scripts/node.sh %s %s %s %s %s %s %s", node.Role[0], node.HostName,
node.InternalIP, linkModel, node.RootPass, node.KeyPath, node.ID)
cmd := exec.Command("bash", "-c", line)
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
cmd.Stdin = os.Stdin
// node stauts: installing
if _, err := clients.RegionClient.Nodes().UpdateNodeStatus(node.ID, client.Installing); err != nil {
logrus.Errorf("update node %s status failure %s", node.ID, err.Error())
}
err := cmd.Run()
// install node
option := coreutil.NodeInstallOption{
HostRole: node.Role[0],
HostName: node.HostName,
InternalIP: node.InternalIP,
LinkModel: linkModel,
RootPass: node.RootPass,
KeyPath: node.KeyPath,
NodeID: node.ID,
Stdin: os.Stdin,
Stderr: os.Stderr,
}
err := coreutil.RunNodeInstallCmd(option, func(line string) {
// run log func
fmt.Fprint(os.Stdout, line) // write log to os.Stdout
})
if err != nil {
logrus.Errorf("Error executing shell script %s", err.Error())
if _, err := clients.RegionClient.Nodes().UpdateNodeStatus(node.ID, client.InstallFailed); err != nil {
@ -633,6 +644,8 @@ func installNode(node *client.HostNode) {
}
return
}
// node status success
if _, err := clients.RegionClient.Nodes().UpdateNodeStatus(node.ID, client.InstallSuccess); err != nil {
logrus.Errorf("update node %s status failure %s", node.ID, err.Error())
}
@ -700,7 +713,7 @@ func installNodeCommand(c *cli.Context) error {
nodes, err := clients.RegionClient.Nodes().List()
handleErr(err)
//write ansible hosts file
WriteHostsFile(c.String("p"), nodes)
WriteHostsFile(c.String("hosts-file-path"), nodes)
installNode(node)
return nil
}

View File

@ -22,7 +22,6 @@ import (
"errors"
"fmt"
"os"
"os/exec"
"sort"
"strconv"
"time"
@ -30,6 +29,7 @@ import (
"github.com/goodrain/rainbond/event"
"github.com/goodrain/rainbond/util"
ansibleUtil "github.com/goodrain/rainbond/util/ansible"
"github.com/Sirupsen/logrus"
"github.com/goodrain/rainbond/cmd/node/option"
@ -38,6 +38,7 @@ import (
"github.com/goodrain/rainbond/node/masterserver/node"
"github.com/goodrain/rainbond/node/nodem/client"
"github.com/goodrain/rainbond/node/utils"
coreutil "github.com/goodrain/rainbond/util"
"github.com/twinj/uuid"
)
@ -99,10 +100,48 @@ func (n *NodeService) InstallNode(node *client.HostNode) *utils.APIHandleError {
node.Status = client.Installing
node.NodeStatus.Status = client.Installing
n.nodecluster.UpdateNode(node)
// prepare install scripts
flag, err := n.beforeInstall()
if err != nil {
return utils.CreateAPIHandleError(400, err)
}
if !flag {
return nil
}
go n.AsynchronousInstall(node)
return nil
}
// check install scripts exists or not, if more than one master node has install scripts, choose one master node do it
func (n *NodeService) beforeInstall() (flag bool, err error) {
// ansible file must exists
// if ok, _ := util.FileExists("/opt/rainbond/rainbond-ansible/scripts/node.sh"); !ok {
// // TODO 通过etcd创建任务
// return false, nil
// }
// TODO 存在任务则加锁etcd全局锁让自己能够执行加锁失败则不让执行
return true, nil
}
// write ansible hosts file
func (n *NodeService) writeHostsFile() error {
hosts, err := n.GetAllNode()
if err != nil {
return err.Err
}
// use default hosts file path and default install config file path
erro := ansibleUtil.WriteHostsFile("/opt/rainbond/rainbond-ansible/inventory/hosts", "/opt/rainbond/rainbond-ansible/scripts/installer/global.sh", hosts)
if erro != nil {
return err
}
return nil
}
//UpdateNodeStatus update node status
func (n *NodeService) UpdateNodeStatus(nodeID, status string) *utils.APIHandleError {
node := n.nodecluster.GetNode(nodeID)
@ -120,6 +159,12 @@ func (n *NodeService) UpdateNodeStatus(nodeID, status string) *utils.APIHandleEr
//AsynchronousInstall AsynchronousInstall
func (n *NodeService) AsynchronousInstall(node *client.HostNode) {
// write ansible hosts file
err := n.writeHostsFile()
if err != nil {
logrus.Error("write hosts file error ", err.Error())
return
}
linkModel := "pass"
if node.KeyPath != "" {
linkModel = "key"
@ -129,18 +174,15 @@ func (n *NodeService) AsynchronousInstall(node *client.HostNode) {
}); err != nil {
logrus.Errorf("create event manager faliure")
}
//TODO: write log to event log
//logger := event.GetManager().GetLogger(node.ID + "-insatll")
// start add node script
logrus.Infof("Begin install node %s", node.ID)
// TODO: write ansible hosts file
line := fmt.Sprintf("./node.sh %s %s %s %s %s %s %s", node.Role[0], node.HostName,
node.InternalIP, linkModel, node.RootPass, node.KeyPath, node.ID)
fileName := node.HostName + ".log"
cmd := exec.Command("bash", "-c", line)
if err := util.CheckAndCreateDir("/grdata/downloads/log/"); err != nil {
logrus.Errorf("check and create log dir failure %s", err.Error())
}
fileName := node.HostName + ".log"
f, err := os.OpenFile("/grdata/downloads/log/"+fileName, os.O_WRONLY|os.O_CREATE|os.O_SYNC, 0755)
if err != nil {
logrus.Errorf("open log file %s failure %s", "/grdata/downloads/log/"+fileName, err.Error())
@ -150,10 +192,31 @@ func (n *NodeService) AsynchronousInstall(node *client.HostNode) {
return
}
defer f.Close()
cmd.Stdout = f
cmd.Dir = "/opt/rainbond/rainbond-ansible/scripts"
cmd.Stderr = f
err = cmd.Run()
option := coreutil.NodeInstallOption{
HostRole: node.Role[0],
HostName: node.HostName,
InternalIP: node.InternalIP,
LinkModel: linkModel,
RootPass: node.RootPass,
KeyPath: node.KeyPath,
NodeID: node.ID,
Stdin: nil,
Stderr: f,
}
// write log to event log
logger := event.GetManager().GetLogger(node.ID + "-insatll")
err = coreutil.RunNodeInstallCmd(option, func(line string) {
// run log func
logger.Info(line, map[string]string{"step": "node-install", "status": "installing"}) // write log to eventLog
_, err = f.WriteString(line) // write log to file
if err != nil {
logrus.Error(err)
return
}
// fmt.Fprint(os.Stdout, line) //write os.Stdout
})
if err != nil {
if _, err := f.Write([]byte(err.Error())); err != nil {
logrus.Errorf("Error write file %s", err.Error())
@ -164,9 +227,12 @@ func (n *NodeService) AsynchronousInstall(node *client.HostNode) {
n.nodecluster.UpdateNode(node)
return
}
logrus.Infof("Install node %s successful", node.ID)
node.Status = client.InstallSuccess
node.NodeStatus.Status = client.InstallSuccess
n.nodecluster.UpdateNode(node)
}

216
util/ansible/ansible.go Normal file
View File

@ -0,0 +1,216 @@
package ansible
import (
"bufio"
"bytes"
"fmt"
"io/ioutil"
"net"
"os"
"path"
"sort"
"strconv"
"strings"
"time"
"github.com/goodrain/rainbond/node/nodem/client"
"github.com/goodrain/rainbond/util"
)
//WriteHostsFile write hosts file
func WriteHostsFile(filePath, installConfPath string, hosts []*client.HostNode) error {
config := GetAnsibleHostConfig(filePath)
for i := range hosts {
config.AddHost(hosts[i], installConfPath)
}
return config.WriteFile()
}
//AnsibleHost ansible host config
type AnsibleHost struct {
AnsibleHostIP net.IP
//ssh port
AnsibleHostPort int
HostID string
Role client.HostRule
CreateTime time.Time
}
func (a *AnsibleHost) String() string {
if a.Role.HasRule("all") {
return fmt.Sprintf("%s ansible_host=%s ansible_port=%d ip=%s port=%d role=%s", a.HostID, a.AnsibleHostIP, a.AnsibleHostPort, a.AnsibleHostIP, a.AnsibleHostPort, a.Role)
} else if a.Role.HasRule("etcd") {
return fmt.Sprintf("%s ansible_host=%s NODE_NAME=etcd1", a.HostID, a.AnsibleHostIP)
} else {
return fmt.Sprintf("%s ansible_host=%s", a.HostID, a.AnsibleHostIP)
}
}
type HostsList []*AnsibleHost
func (list HostsList) Len() int {
return len(list)
}
func (list HostsList) Less(i, j int) bool {
return list[i].CreateTime.Before(list[j].CreateTime)
}
func (list HostsList) Swap(i, j int) {
list[i], list[j] = list[j], list[i]
}
//AnsibleHostGroup ansible host group config
type AnsibleHostGroup struct {
Name string
HostList HostsList
}
//AddHost add host
func (a *AnsibleHostGroup) AddHost(h *AnsibleHost) {
for _, old := range a.HostList {
if old.AnsibleHostIP.String() == h.AnsibleHostIP.String() {
return
}
}
a.HostList = append(a.HostList, h)
}
func (a *AnsibleHostGroup) String() string {
rebuffer := bytes.NewBuffer(nil)
rebuffer.WriteString(fmt.Sprintf("[%s]\n", a.Name))
for i := range a.HostList {
if a.Name == "all" {
rebuffer.WriteString(a.HostList[i].String() + "\n")
} else {
rebuffer.WriteString(a.HostList[i].HostID + "\n")
}
}
rebuffer.WriteString("\n")
return rebuffer.String()
}
//AnsibleHostConfig ansible hosts config
type AnsibleHostConfig struct {
FileName string
GroupList map[string]*AnsibleHostGroup
}
//GetAnsibleHostConfig get config
func GetAnsibleHostConfig(name string) *AnsibleHostConfig {
return &AnsibleHostConfig{
FileName: name,
GroupList: map[string]*AnsibleHostGroup{
"all": &AnsibleHostGroup{Name: "all"},
"manage": &AnsibleHostGroup{Name: "manage"},
"new-manage": &AnsibleHostGroup{Name: "new-manage"},
"gateway": &AnsibleHostGroup{Name: "gateway"},
"new-gateway": &AnsibleHostGroup{Name: "new-gateway"},
"compute": &AnsibleHostGroup{Name: "compute"},
"new-compute": &AnsibleHostGroup{Name: "new-compute"},
},
}
}
//Content return config file content
func (c *AnsibleHostConfig) Content() string {
return c.ContentBuffer().String()
}
//ContentBuffer content buffer
func (c *AnsibleHostConfig) ContentBuffer() *bytes.Buffer {
rebuffer := bytes.NewBuffer(nil)
for i := range c.GroupList {
sort.Sort(c.GroupList[i].HostList) // sort host by createTime
rebuffer.WriteString(c.GroupList[i].String())
}
return rebuffer
}
//WriteFile write config file
func (c *AnsibleHostConfig) WriteFile() error {
if c.FileName == "" {
return fmt.Errorf("config file name can not be empty")
}
if err := util.CheckAndCreateDir(path.Dir(c.FileName)); err != nil {
return err
}
if err := ioutil.WriteFile(c.FileName+".tmp", c.ContentBuffer().Bytes(), 0755); err != nil {
return err
}
return os.Rename(c.FileName+".tmp", c.FileName)
}
func getSSHPort(configFile string) int {
if ok, _ := util.FileExists(configFile); !ok {
return 22
}
file, err := os.OpenFile(configFile, os.O_RDONLY, 0666)
if err != nil {
return 22
}
defer file.Close()
reader := bufio.NewReader(file)
for {
str, _, err := reader.ReadLine()
if err != nil {
break
}
line := strings.TrimSpace(string(str))
if strings.Contains(line, "=") && !strings.HasPrefix(line, "#") {
keyvalue := strings.SplitN(string(line), "=", 2)
if len(keyvalue) == 2 || keyvalue[0] == "INSTALL_SSH_PORT" {
port, err := strconv.Atoi(keyvalue[1])
if err != nil {
return 22
} else {
return port
}
}
}
}
return 22
}
//AddHost add host
func (c *AnsibleHostConfig) AddHost(h *client.HostNode, installConfPath string) {
//check role
//check status
ansibleHost := &AnsibleHost{
AnsibleHostIP: net.ParseIP(h.InternalIP),
AnsibleHostPort: getSSHPort(installConfPath),
HostID: h.ID,
Role: h.Role,
CreateTime: h.CreateTime,
}
c.GroupList["all"].AddHost(ansibleHost)
if h.Role.HasRule("manage") {
if h.Status == client.NotInstalled || h.Status == client.InstallFailed {
c.GroupList["new-manage"].AddHost(ansibleHost)
} else {
c.GroupList["manage"].AddHost(ansibleHost)
}
}
if h.Role.HasRule("compute") {
if h.Status == client.NotInstalled || h.Status == client.InstallFailed {
c.GroupList["new-compute"].AddHost(ansibleHost)
} else {
c.GroupList["compute"].AddHost(ansibleHost)
}
}
if h.Role.HasRule("gateway") {
if h.Status == client.NotInstalled || h.Status == client.InstallFailed {
c.GroupList["new-gateway"].AddHost(ansibleHost)
} else {
c.GroupList["gateway"].AddHost(ansibleHost)
}
}
for i := range h.NodeStatus.Conditions {
if h.NodeStatus.Conditions[i].Type == "etcd" {
c.GroupList["etcd"].AddHost(ansibleHost)
break
}
}
}

140
util/node.go Normal file
View File

@ -0,0 +1,140 @@
// Copyright (C) 2014-2018 Goodrain Co., Ltd.
// RAINBOND, Application Management Platform
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version. For any non-GPL usage of Rainbond,
// one or multiple Commercial Licenses authorized by Goodrain Co., Ltd.
// must be obtained first.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package util
import (
"bufio"
"fmt"
"io"
"os"
"os/exec"
"strings"
"github.com/Sirupsen/logrus"
)
type NodeInstallOption struct {
HostRole string
HostName string
InternalIP string
LinkModel string
RootPass string
KeyPath string
NodeID string
Stdin *os.File
Stderr *os.File
}
func RunNodeInstallCmd(option NodeInstallOption, runLog func(line string)) (err error) {
// ansible file must exists
if ok, _ := FileExists("/opt/rainbond/rainbond-ansible/scripts/node.sh"); !ok {
err = fmt.Errorf("install node scripts is not found")
logrus.Error(err)
return err
}
// ansible's param can't send nil nor empty string
if err = preCheckNodeInstall(option); err != nil {
return
}
line := fmt.Sprintf("/opt/rainbond/rainbond-ansible/scripts/node.sh %s %s %s %s %s %s %s",
option.HostRole, option.HostName, option.InternalIP, option.LinkModel, option.RootPass, option.KeyPath, option.NodeID)
cmd := exec.Command("bash", "-c", line)
cmd.Stderr = option.Stderr
cmd.Stdin = option.Stdin
stdout, err := cmd.StdoutPipe()
if err != nil {
logrus.Errorf("install node failed")
return err
}
// for another log
reader := bufio.NewReader(stdout)
go func() {
for {
line, err := reader.ReadString('\n')
if err == io.EOF {
break
}
if err != nil {
logrus.Errorf("install node failed")
return
}
if runLog != nil {
runLog(line)
}
}
}()
err = cmd.Start()
if err != nil {
logrus.Errorf("install node failed")
return err
}
err = cmd.Wait()
if err != nil {
logrus.Errorf("install node finished with error : %v", err.Error())
}
return
}
func preCheckNodeInstall(option NodeInstallOption) (err error) {
// TODO check param
if strings.TrimSpace(option.HostRole) == "" {
err = fmt.Errorf("install node failed, install scripts needs param hostRole")
logrus.Error(err)
return
}
if strings.TrimSpace(option.HostName) == "" {
err = fmt.Errorf("install node failed, install scripts needs param hostName")
logrus.Error(err)
return
}
if strings.TrimSpace(option.InternalIP) == "" {
err = fmt.Errorf("install node failed, install scripts needs param internalIP")
logrus.Error(err)
return
}
if strings.TrimSpace(option.LinkModel) == "" {
err = fmt.Errorf("install node failed, install scripts needs param linkModel")
logrus.Error(err)
return
}
if strings.TrimSpace(option.RootPass) == "" {
err = fmt.Errorf("install node failed, install scripts needs param rootPass")
logrus.Error(err)
return
}
if strings.TrimSpace(option.KeyPath) == "" {
err = fmt.Errorf("install node failed, install scripts needs param keyPath")
logrus.Error(err)
return
}
if strings.TrimSpace(option.NodeID) == "" {
err = fmt.Errorf("install node failed, install scripts needs param nodeID")
logrus.Error(err)
return
}
return
}