Merge pull request #78 from fanux/develop

merge
This commit is contained in:
cuisongliu
2020-03-26 12:15:28 +08:00
committed by GitHub
16 changed files with 235 additions and 184 deletions
+1 -1
View File
@@ -26,8 +26,8 @@ var initCmd = &cobra.Command{
Long: `sealos init --master 192.168.0.2 --master 192.168.0.3 --master 192.168.0.4 --node 192.168.0.5 --user root --passwd your-server-password`,
Run: func(cmd *cobra.Command, args []string) {
c := &install.SealConfig{}
c.Dump("")
install.BuildInit()
c.Dump("")
},
}
+1 -2
View File
@@ -3,14 +3,13 @@ module github.com/fanux/sealos
go 1.13
require (
github.com/cuisongliu/sshcmd v0.0.0-20200324095132-757019718a50
github.com/cuisongliu/sshcmd v0.0.0-20200324171807-1615e61773b1
github.com/fanux/sealgate v0.0.5
github.com/mitchellh/go-homedir v1.1.0
github.com/pkg/errors v0.8.1
github.com/spf13/cobra v0.0.5
github.com/spf13/viper v1.5.0
github.com/wonderivan/logger v1.0.0
golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586
gopkg.in/yaml.v2 v2.2.8
k8s.io/api v0.17.3
k8s.io/apimachinery v0.17.3
+2 -2
View File
@@ -30,8 +30,8 @@ github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3Ee
github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE=
github.com/cuisongliu/sshcmd v0.0.0-20200324095132-757019718a50 h1:KvJ/qwYCUlYUiHJxaqKxF1obxqI+dvYFAVbjqj9U2RA=
github.com/cuisongliu/sshcmd v0.0.0-20200324095132-757019718a50/go.mod h1:jAEBZhFW5kNey9B+59lR8mfQaCQsyp8b8QaI7RhESxE=
github.com/cuisongliu/sshcmd v0.0.0-20200324171807-1615e61773b1 h1:VhGG7tHUJ8sud9OgypR5VmiUrsWB+kq7h/ivOf1Tfyg=
github.com/cuisongliu/sshcmd v0.0.0-20200324171807-1615e61773b1/go.mod h1:jAEBZhFW5kNey9B+59lR8mfQaCQsyp8b8QaI7RhESxE=
github.com/davecgh/go-spew v0.0.0-20151105211317-5215b55f46b2/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
+93
View File
@@ -0,0 +1,93 @@
package install
import (
"fmt"
"github.com/cuisongliu/sshcmd/pkg/cmd"
"github.com/cuisongliu/sshcmd/pkg/filesize"
"github.com/cuisongliu/sshcmd/pkg/md5sum"
"github.com/wonderivan/logger"
"net/url"
"path"
"sync"
)
//location : url
//md5
//dst: /root
//hook: cd /root && rm -rf kube && tar zxvf %s && cd /root/kube/shell && sh init.sh
func SendPackage(location string, hosts []string, dst, hook string) {
location, md5 := downloadFile(location)
PkgUrl = location
pkg := path.Base(location)
fullPath := fmt.Sprintf("%s/%s", dst, pkg)
mkDstDir := fmt.Sprintf("mkdir -p %s || true", dst)
var wm sync.WaitGroup
for _, host := range hosts {
wm.Add(1)
go func(host string) {
defer wm.Done()
SSHConfig.Cmd(host, mkDstDir)
logger.Debug("[%s]please wait for mkDstDir", host)
if SSHConfig.IsFilExist(host, fullPath) {
logger.Warn("[%s]SendPackage: file is exist", host)
} else {
if ok := SSHConfig.CopyForMD5(host, location, fullPath, md5); ok {
logger.Info("[%s]copy file md5 validate success", host)
} else {
logger.Error("[%s]copy file md5 validate failed", host)
}
}
if hook != "" {
logger.Debug("[%s]please wait for hook", host)
SSHConfig.Cmd(host, hook)
}
}(host)
}
wm.Wait()
}
//
func downloadFile(location string) (filePATH, md5 string) {
if _, isUrl := isUrl(location); isUrl {
absPATH := "/tmp/sealos/" + path.Base(location)
if cmd.IsFilExist(absPATH) {
//logs
logger.Warn("[%s] file is exist", absPATH)
location = absPATH
goto end
}
//generator download cmd
dwnCmd := downloadCmd(location)
//go func watch filesize
go cmd.LoggerFileSize(absPATH, int(filesize.Do(location)))
//os exec download command
cmd.Cmd("/bin/sh", "-c", "mkdir -p /tmp/sealos && cd /tmp/sealos && "+dwnCmd)
location = absPATH
}
end:
//file md5
md5 = md5sum.FromLocal(location)
return location, md5
}
//根据url 获取command
func downloadCmd(url string) string {
//only http
u, isHttp := isUrl(url)
var c = ""
if isHttp {
param := ""
if u.Scheme == "https" {
param = "--no-check-certificate"
}
c = fmt.Sprintf(" wget %s %s", param, url)
}
return c
}
func isUrl(u string) (url.URL, bool) {
if uu, err := url.Parse(u); err == nil && uu != nil && uu.Host != "" {
return *uu, true
}
return url.URL{}, false
}
+1 -1
View File
@@ -23,7 +23,7 @@ func BuildInit() {
}
i.CheckValid()
i.Print()
i.SendPackage("kube")
i.SendPackage()
i.Print("SendPackage")
i.KubeadmConfigInstall()
i.Print("SendPackage", "KubeadmConfigInstall")
+3 -27
View File
@@ -7,7 +7,6 @@ import (
"github.com/wonderivan/logger"
"io"
"os"
"os/exec"
"path"
"strings"
"sync"
@@ -52,29 +51,6 @@ func AppInstall(url string) {
Exec(pkgConfig, *c)
}
func LoadRemoteFile(url string) string {
isHttp := strings.HasPrefix(url, "http")
if !isHttp {
logger.Info("using local package %s", url)
return url
}
logger.Info("wait for wget app package...")
wgetParam := ""
if strings.HasPrefix(url, "https") {
wgetParam = "--no-check-certificate"
}
wgetCommand := fmt.Sprintf(" wget %s ", wgetParam)
cmd := fmt.Sprintf("%s %s", wgetCommand, url)
c := exec.Command("sh", "-c", cmd)
out, err := c.CombinedOutput()
if err != nil {
logger.Error(err)
}
logger.Info("%s", out)
return path.Base(url)
}
// LoadConfig from tar package
/*
kube.tar
@@ -90,7 +66,7 @@ STOP systemctl top
APPLY kubectl apply -f
*/
func LoadConfig(packageFile string) (*PkgConfig, error) {
filename := LoadRemoteFile(packageFile)
filename, _ := downloadFile(packageFile)
file, err := os.Open(filename)
if err != nil {
@@ -189,7 +165,7 @@ func (r *RunOnEveryNodes) Run(config SealConfig, url, pkgName string) {
workspace := fmt.Sprintf("/root/%s", pkgName)
nodes := append(config.Masters, config.Nodes...)
FetchPackage(url, nodes, workspace)
SendPackage(url, nodes, workspace, "")
for _, node := range nodes {
wg.Add(1)
go func(node string) {
@@ -210,7 +186,7 @@ type RunOnMaster struct {
func (r *RunOnMaster) Run(config SealConfig, url, pkgName string) {
workspace := fmt.Sprintf("/root/%s", pkgName)
FetchPackage(url, []string{config.Masters[0]}, workspace)
SendPackage(url, []string{config.Masters[0]}, workspace, "")
tarCmd := fmt.Sprintf("tar xvf %s.tar", pkgName)
CmdWorkSpace(config.Masters[0], tarCmd, workspace)
for _, cmd := range r.Cmd {
+2 -2
View File
@@ -27,7 +27,7 @@ func joinMastersFunc(joinMasters []string) {
Nodes: nodes,
}
i.CheckValid()
i.SendPackage("kube")
i.SendPackage()
i.GeneratorCerts()
i.JoinMasters(joinMasters)
//master join to MasterIPs
@@ -46,7 +46,7 @@ func joinNodesFunc(joinNodes []string) {
Nodes: nodes,
}
i.CheckValid()
i.SendPackage("kube")
i.SendPackage()
i.GeneratorToken()
i.JoinNodes()
//node join to NodeIPs
+9 -2
View File
@@ -1,6 +1,13 @@
package install
import (
"fmt"
"path"
)
//SendPackage is
func (s *SealosInstaller) SendPackage(packName string) {
SendPackage(PkgUrl, s.Hosts, packName)
func (s *SealosInstaller) SendPackage() {
pkg := path.Base(PkgUrl)
hook := fmt.Sprintf("cd /root && rm -rf kube && tar zxvf %s && cd /root/kube/shell && sh init.sh", pkg)
SendPackage(PkgUrl, s.Hosts, "/root", hook)
}
-132
View File
@@ -2,22 +2,16 @@ package install
import (
"fmt"
"github.com/cuisongliu/sshcmd/pkg/filesize"
"github.com/wonderivan/logger"
"math/big"
"math/rand"
"net"
"net/url"
"os"
"path"
"strconv"
"strings"
"sync"
"time"
)
const oneMBByte = 1024 * 1024
//VersionToInt v1.15.6 => 115
func VersionToInt(version string) int {
// v1.15.6 => 1.15.6
@@ -38,119 +32,6 @@ func IpFormat(host string) string {
return ipAndPort[0]
}
func SendPackage(url string, hosts []string, packName string) {
pkg := path.Base(url)
//only http
isHttp := strings.HasPrefix(url, "http")
wgetCommand := ""
if isHttp {
wgetParam := ""
if strings.HasPrefix(url, "https") {
wgetParam = "--no-check-certificate"
}
wgetCommand = fmt.Sprintf(" wget %s ", wgetParam)
}
remoteCmd := fmt.Sprintf("cd /root && %s %s && tar zxvf %s", wgetCommand, url, pkg)
localCmd := fmt.Sprintf("cd /root && rm -rf %s && tar zxvf %s ", packName, pkg)
kubeLocal := fmt.Sprintf("/root/%s", pkg)
var kubeCmd string
if packName == "kube" {
kubeCmd = "cd /root/kube/shell && sh init.sh"
} else {
kubeCmd = fmt.Sprintf("cd /root/%s && docker load -i images.tar", packName)
}
var wm sync.WaitGroup
for _, host := range hosts {
wm.Add(1)
go func(host string) {
defer wm.Done()
logger.Debug("[%s]please wait for tar zxvf exec", host)
if SSHConfig.IsFilExist(host, kubeLocal) {
logger.Warn("[%s]SendPackage: file is exist", host)
SSHConfig.Cmd(host, localCmd)
} else {
if isHttp {
go SSHConfig.LoggerFileSize(host, kubeLocal, int(filesize.Do(url)))
SSHConfig.Cmd(host, remoteCmd)
rMD5 := SSHConfig.Md5Sum(host, kubeLocal) //获取已经上传文件的md5
uMd5 := UrlGetMd5(url) //获取url的md5值
logger.Debug("[%s] remote file local %s, md5 is %s", host, kubeLocal, rMD5)
logger.Debug("[%s] url is %s, md5 is %s", host, url, uMd5)
if strings.TrimSpace(rMD5) == strings.TrimSpace(uMd5) {
logger.Info("[%s]file md5 validate success", host)
} else {
logger.Error("[%s]copy file md5 validate failed", host)
}
} else {
if ok := SSHConfig.CopyForMD5(host, url, kubeLocal, ""); ok {
SSHConfig.Cmd(host, localCmd)
logger.Info("[%s]file md5 validate success", host)
} else {
logger.Error("[%s]file md5 validate failed", host)
}
}
}
SSHConfig.Cmd(host, kubeCmd)
}(host)
}
wm.Wait()
}
// FetchPackage if url exist wget it, or scp the local package to hosts
// dst is the remote offline path like /root
func FetchPackage(url string, hosts []string, dst string) {
pkg := path.Base(url)
fullDst := fmt.Sprintf("%s/%s", dst, pkg)
mkdstdir := fmt.Sprintf("mkdir -p %s || true", dst)
//only http
isHttp := strings.HasPrefix(url, "http")
wgetCommand := ""
if isHttp {
wgetParam := ""
if strings.HasPrefix(url, "https") {
wgetParam = "--no-check-certificate"
}
wgetCommand = fmt.Sprintf(" wget %s ", wgetParam)
}
remoteCmd := fmt.Sprintf("cd %s && %s %s", dst, wgetCommand, url)
var wm sync.WaitGroup
for _, host := range hosts {
wm.Add(1)
go func(host string) {
defer wm.Done()
logger.Debug("[%s]please wait for copy offline package", host)
SSHConfig.Cmd(host, mkdstdir)
if SSHConfig.IsFilExist(host, fullDst) {
logger.Warn("[%s]SendPackage: [%s] file is exist", host, fullDst)
} else {
if isHttp {
go SSHConfig.LoggerFileSize(host, fullDst, int(filesize.Do(url)))
SSHConfig.Cmd(host, remoteCmd)
rMD5 := SSHConfig.Md5Sum(host, fullDst) //获取已经上传文件的md5
uMd5 := UrlGetMd5(url) //获取url的md5值
logger.Debug("[%s] remote file local %s, md5 is %s", host, fullDst, rMD5)
logger.Debug("[%s] url is %s, md5 is %s", host, url, uMd5)
if strings.TrimSpace(rMD5) == strings.TrimSpace(uMd5) {
logger.Info("[%s]file md5 validate success", host)
} else {
logger.Error("[%s]copy file md5 validate failed", host)
}
} else {
if !SSHConfig.CopyForMD5(host, url, fullDst, "") {
logger.Error("[%s]copy file md5 validate failed", host)
} else {
logger.Info("[%s]file md5 validate success", host)
}
}
}
}(host)
}
wm.Wait()
}
// RandString 生成随机字符串
func RandString(len int) string {
var r *rand.Rand
@@ -272,19 +153,6 @@ func SliceRemoveStr(ss []string, s string) (result []string) {
return
}
func UrlGetMd5(downloadUrl string) string {
u, err := url.Parse(downloadUrl)
if err == nil {
p := u.Path
if paths := strings.Split(p, "/"); len(paths) > 2 {
if paths = strings.Split(paths[1], "-"); len(paths) > 1 {
return paths[0]
}
}
}
return ""
}
//判断当前host的hostname
func isHostName(master, host string) string {
hostString := SSHConfig.CmdToString(master, "kubectl get nodes | grep -v NAME | awk '{print $1}'", ",")
+14 -12
View File
@@ -18,6 +18,13 @@ func TestProcess(t *testing.T) {
//bar(100, 1, 0)
}
func TestNotReadyNode(t *testing.T) {
SSHConfig.User = "root"
SSHConfig.Password = "PaaS@123"
ss := isHostName("172.27.139.74", "172.27.139.126")
print(ss)
}
func TestPrint(t *testing.T) {
//User = "root"
//Passwd = "admin"
@@ -29,12 +36,7 @@ func TestPrint(t *testing.T) {
}
func TestVersionToInt(t *testing.T) {
t.Log(ParseIPs([]string{"1.1.1.1-1.1.1.5"}))
}
func TestUrlGetMd5(t *testing.T) {
aa := UrlGetMd5("https://sealyun.oss-cn-beijing.aliyuncs.com/37374d999dbadb788ef0461844a70151-1.16.0/kube1.16.0.tar.gz")
t.Log(aa)
t.Log(ParseIPs([]string{"172.26.13.133-172.26.13.136:2222"}))
}
func TestSliceRemoveStr(t *testing.T) {
@@ -55,17 +57,17 @@ func TestParseIPs(t *testing.T) {
{
"test multiple ips",
args{[]string{"192.168.0.2-192.168.0.6"}},
[]string{"192.168.0.2","192.168.0.3","192.168.0.4","192.168.0.5","192.168.0.6"},
[]string{"192.168.0.2", "192.168.0.3", "192.168.0.4", "192.168.0.5", "192.168.0.6"},
},
{
"test multiple ips",
args{[]string{"192.168.0.2-192.168.0.3","192.168.0.5-192.168.0.6"}},
[]string{"192.168.0.2","192.168.0.3","192.168.0.5","192.168.0.6"},
args{[]string{"192.168.0.2-192.168.0.3", "192.168.0.5-192.168.0.6"}},
[]string{"192.168.0.2", "192.168.0.3", "192.168.0.5", "192.168.0.6"},
},
{
"test multiple ips",
args{[]string{"192.168.0.2-192.168.0.4","192.168.0.8"}},
[]string{"192.168.0.2","192.168.0.3","192.168.0.4","192.168.0.8"},
args{[]string{"192.168.0.2-192.168.0.4", "192.168.0.8"}},
[]string{"192.168.0.2", "192.168.0.3", "192.168.0.4", "192.168.0.8"},
},
}
for _, tt := range tests {
@@ -75,4 +77,4 @@ func TestParseIPs(t *testing.T) {
}
})
}
}
}
+37
View File
@@ -0,0 +1,37 @@
package cmd
import (
"bytes"
"github.com/wonderivan/logger"
"os"
"os/exec"
)
//Cmd is exec on os ,no return
func Cmd(name string, arg ...string) {
logger.Info("[os]exec cmd is : ", name, arg)
cmd := exec.Command(name, arg[:]...)
cmd.Stdin = os.Stdin
cmd.Stderr = os.Stderr
cmd.Stdout = os.Stdout
err := cmd.Run()
if err != nil {
logger.Error("os call error.", err)
}
}
//CmdToString is exec on os , return result
func CmdToString(name string, arg ...string) string {
logger.Info("[os]exec cmd is : ", name, arg)
cmd := exec.Command(name, arg[:]...)
cmd.Stdin = os.Stdin
var b bytes.Buffer
cmd.Stdout = &b
cmd.Stderr = &b
err := cmd.Run()
if err != nil {
logger.Error("os call error.", err)
return ""
}
return b.String()
}
+58
View File
@@ -0,0 +1,58 @@
package cmd
import (
"fmt"
"github.com/wonderivan/logger"
"path"
"strconv"
"strings"
"time"
)
const oneMBByte = 1024 * 1024
//WatchFileSize is
func LoggerFileSize(filename string, size int) {
t := time.NewTicker(3 * time.Second) //every 3s check file
defer t.Stop()
for {
select {
case <-t.C:
length := CmdToString("/bin/sh", "-c", "ls -l "+filename+" | awk '{print $5}'", "")
length = strings.Replace(length, "\n", "", -1)
length = strings.Replace(length, "\r", "", -1)
lengthByte, _ := strconv.Atoi(length)
if lengthByte == size {
t.Stop()
}
lengthFloat := float64(lengthByte)
value, _ := strconv.ParseFloat(fmt.Sprintf("%.2f", lengthFloat/oneMBByte), 64)
logger.Alert("[%s]transfer total size is: %.2f%s", filename, value, "MB")
}
}
}
//RemoteFilExist is
func IsFilExist(filepath string) bool {
// if remote file is
// ls -l | grep aa | wc -l
fileName := path.Base(filepath) // aa
fileDirName := path.Dir(filepath)
fileCommand := fmt.Sprintf("ls -l %s | grep %s | wc -l", fileDirName, fileName)
data := strings.Replace(CmdToString("/bin/sh", "-c", fileCommand), "\r", "", -1)
data = strings.Replace(data, "\n", "", -1)
count, err := strconv.Atoi(strings.TrimSpace(data))
defer func() {
if r := recover(); r != nil {
logger.Error("[%s]RemoteFilExist:%s", filepath, err)
}
}()
if err != nil {
panic(1)
}
if count == 0 {
return false
} else {
return true
}
}
+4
View File
@@ -4,6 +4,7 @@ import (
"fmt"
"github.com/wonderivan/logger"
"os/exec"
"strings"
)
func FromLocal(localPath string) string {
@@ -14,5 +15,8 @@ func FromLocal(localPath string) string {
logger.Error(err)
}
md5 := string(out)
md5 = strings.ReplaceAll(md5, "\n", "")
md5 = strings.ReplaceAll(md5, "\r", "")
return md5
}
+5 -2
View File
@@ -19,11 +19,14 @@ func (ss *SSH) Connect(host string) (*ssh.Session, error) {
config := ssh.Config{
Ciphers: []string{"aes128-ctr", "aes192-ctr", "aes256-ctr", "aes128-gcm@openssh.com", "arcfour256", "arcfour128", "aes128-cbc", "3des-cbc", "aes192-cbc", "aes256-cbc"},
}
DefaultTimeout := time.Duration(1) * time.Minute
if ss.Timeout == nil {
ss.Timeout = &DefaultTimeout
}
clientConfig := &ssh.ClientConfig{
User: ss.User,
Auth: auth,
Timeout: time.Duration(1) * time.Minute,
Timeout: *ss.Timeout,
Config: config,
HostKeyCallback: func(hostname string, remote net.Addr, key ssh.PublicKey) error {
return nil
+3
View File
@@ -1,7 +1,10 @@
package sshutil
import "time"
type SSH struct {
User string
Password string
PkFile string
Timeout *time.Duration
}
+2 -1
View File
@@ -10,7 +10,8 @@ github.com/aliyun/alibaba-cloud-sdk-go/sdk/requests
github.com/aliyun/alibaba-cloud-sdk-go/sdk/responses
github.com/aliyun/alibaba-cloud-sdk-go/sdk/utils
github.com/aliyun/alibaba-cloud-sdk-go/services/ecs
# github.com/cuisongliu/sshcmd v0.0.0-20200324095132-757019718a50
# github.com/cuisongliu/sshcmd v0.0.0-20200324171807-1615e61773b1
github.com/cuisongliu/sshcmd/pkg/cmd
github.com/cuisongliu/sshcmd/pkg/filesize
github.com/cuisongliu/sshcmd/pkg/md5sum
github.com/cuisongliu/sshcmd/pkg/sshutil