From 905ceada4da0099fa3b4ea8c7f032cfd4fc2f471 Mon Sep 17 00:00:00 2001 From: cuisongliu Date: Sun, 19 Dec 2021 18:38:03 +0800 Subject: [PATCH] add infra module (#754) * hotfix(master): add infra module --- .github/workflows/go.yml | 9 +- .gitignore | 1 + .golangci.yml | 2 +- .goreleaser.yml | 6 +- Makefile | 90 ++-- cmd/clean.go | 2 +- cmd/cloud.go | 74 --- cmd/cni.go | 10 +- cmd/delete.go | 2 +- cmd/etcd.go | 2 +- cmd/init.go | 2 +- cmd/install.go | 8 +- cmd/ipvs.go | 2 +- cmd/join.go | 2 +- cmd/root.go | 2 +- cmd/version.go | 41 +- go.mod | 8 +- go.sum | 120 +---- hack/template/boilerplate.go.txt | 13 + pkg/appmanager/appmanager.go | 2 +- pkg/appmanager/deleteapp.go | 2 +- pkg/appmanager/installapp.go | 2 +- pkg/cni/calico_yaml.go | 56 +-- pkg/infra/README.md | 3 + pkg/infra/aliyun/ali_const.go | 85 ++++ pkg/infra/aliyun/ali_ecs.go | 522 +++++++++++++++++++++ pkg/infra/aliyun/ali_provider.go | 248 ++++++++++ pkg/infra/aliyun/ali_vpc.go | 175 +++++++ pkg/infra/infra.go | 53 +++ pkg/infra/infra_test.go | 123 +++++ pkg/install/check.go | 2 +- pkg/install/clean.go | 2 +- pkg/install/cloud.go | 202 -------- pkg/install/etcd_restore.go | 2 +- pkg/install/etcd_save.go | 2 +- pkg/install/exec.go | 9 +- pkg/install/exit.go | 2 +- pkg/install/generator.go | 2 +- pkg/install/generator_test.go | 2 +- pkg/install/init.go | 2 +- pkg/install/join.go | 2 +- pkg/install/sealos.go | 2 +- pkg/install/send.go | 2 +- pkg/install/upgrade.go | 2 +- pkg/kubernetes/apis/version/version.go | 37 -- pkg/kubernetes/cert/kubeconfig.go | 2 +- pkg/kubernetes/kubeconfig/kubeconfig.go | 2 +- pkg/kubernetes/nodeclient/node.go | 2 +- pkg/types/{v1 => v1alpha1}/types.go | 68 +-- pkg/types/{v1 => v1alpha1}/vars.go | 2 +- pkg/types/v1beta1/defaults.go | 67 +++ pkg/types/v1beta1/doc.go | 21 + pkg/types/v1beta1/register.go | 25 + pkg/types/v1beta1/types.go | 123 +++++ pkg/types/v1beta1/zz_generated.deepcopy.go | 204 ++++++++ pkg/types/validation/validation.go | 94 ++++ pkg/utils/file.go | 16 +- pkg/utils/hosts.go | 195 ++++++++ pkg/utils/http.go | 2 +- pkg/utils/iputils.go | 41 +- pkg/utils/logger/conn.go | 1 - pkg/utils/logger/console.go | 2 - pkg/utils/logger/log.go | 2 +- pkg/utils/retry.go | 33 ++ pkg/utils/ssh/scp.go | 6 +- pkg/utils/ssh/types.go | 4 +- pkg/utils/strings.go | 13 +- pkg/utils/version.go | 30 ++ pkg/version/base.go | 52 ++ pkg/version/types.go | 32 ++ pkg/version/version.go | 35 ++ test/{ => old}/cronjob.yaml.example | 0 test/{ => old}/join-node-and-nodes.sh | 0 test/{ => old}/network-cird-test.sh | 0 test/{ => old}/note.sh | 0 test/{ => old}/test-sealos-beijing.sh | 0 test/{ => old}/test.sh | 0 test/{ => old}/testUpgrade.md | 0 test/{ => old}/testforlocal.sh | 0 test/testhelper/helper.go | 50 ++ test/testhelper/settings/common.go | 53 +++ test/testhelper/settings/settings.go | 42 ++ test/testhelper/utils.go | 155 ++++++ 83 files changed, 2685 insertions(+), 628 deletions(-) delete mode 100644 cmd/cloud.go create mode 100644 hack/template/boilerplate.go.txt create mode 100644 pkg/infra/README.md create mode 100644 pkg/infra/aliyun/ali_const.go create mode 100644 pkg/infra/aliyun/ali_ecs.go create mode 100644 pkg/infra/aliyun/ali_provider.go create mode 100644 pkg/infra/aliyun/ali_vpc.go create mode 100644 pkg/infra/infra.go create mode 100644 pkg/infra/infra_test.go delete mode 100644 pkg/install/cloud.go delete mode 100644 pkg/kubernetes/apis/version/version.go rename pkg/types/{v1 => v1alpha1}/types.go (81%) rename pkg/types/{v1 => v1alpha1}/vars.go (99%) create mode 100644 pkg/types/v1beta1/defaults.go create mode 100644 pkg/types/v1beta1/doc.go create mode 100644 pkg/types/v1beta1/register.go create mode 100644 pkg/types/v1beta1/types.go create mode 100644 pkg/types/v1beta1/zz_generated.deepcopy.go create mode 100644 pkg/types/validation/validation.go create mode 100644 pkg/utils/hosts.go create mode 100644 pkg/utils/retry.go create mode 100644 pkg/version/base.go create mode 100644 pkg/version/types.go create mode 100644 pkg/version/version.go rename test/{ => old}/cronjob.yaml.example (100%) rename test/{ => old}/join-node-and-nodes.sh (100%) rename test/{ => old}/network-cird-test.sh (100%) rename test/{ => old}/note.sh (100%) rename test/{ => old}/test-sealos-beijing.sh (100%) rename test/{ => old}/test.sh (100%) rename test/{ => old}/testUpgrade.md (100%) rename test/{ => old}/testforlocal.sh (100%) create mode 100644 test/testhelper/helper.go create mode 100644 test/testhelper/settings/common.go create mode 100644 test/testhelper/settings/settings.go create mode 100644 test/testhelper/utils.go diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml index 9f25b515e..33dd163b6 100755 --- a/.github/workflows/go.yml +++ b/.github/workflows/go.yml @@ -2,7 +2,7 @@ name: CI env: # Common versions - GO_VERSION: '1.14' + GO_VERSION: '1.16' on: push: @@ -27,10 +27,6 @@ jobs: go-version: ${{ env.GO_VERSION }} - name: Run Check License run: | - wget https://github.com/google/addlicense/releases/download/v1.0.0/addlicense_1.0.0_Linux_x86_64.tar.gz - tar -zxvf addlicense_1.0.0_Linux_x86_64.tar.gz -C $(go env GOPATH)/bin - chmod a+x $(go env GOPATH)/bin/addlicense - rm -rf addlicense_1.0.0_Linux_x86_64.tar.gz make filelicense modifyCode=$(git status -s | grep M | wc -l) git status -s @@ -52,9 +48,6 @@ jobs: with: go-version: ${{ env.GO_VERSION }} - - name: Install go ci lint - run: curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $(go env GOPATH)/bin v1.39.0 - - name: Run Linter run: make lint diff --git a/.gitignore b/.gitignore index 24b24b618..ccfe442c6 100644 --- a/.gitignore +++ b/.gitignore @@ -12,3 +12,4 @@ dist .vscode test/Note.md .ossutil_checkpoint +bin diff --git a/.golangci.yml b/.golangci.yml index ed78a7544..97741b0be 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -16,7 +16,7 @@ linters: enable: - gofmt - goimports - - golint + - revive - stylecheck - goconst - gosimple diff --git a/.goreleaser.yml b/.goreleaser.yml index 8cffe708f..d0f4969b5 100644 --- a/.goreleaser.yml +++ b/.goreleaser.yml @@ -14,9 +14,9 @@ builds: - amd64 - arm64 ldflags: - - -X github.com/linuxsuren/cobra-extension/version.version={{.Version}} - - -X github.com/linuxsuren/cobra-extension/version.commit={{.ShortCommit}} - - -X github.com/linuxsuren/cobra-extension/version.date={{.Date}} + - -X github.com/fanux/sealos/pkg/version.gitVersion={{.Version}} + - -X github.com/fanux/sealos/pkg/version.gitCommit={{.ShortCommit}} + - -X github.com/fanux/sealos/pkg/version.buildDate={{.Date}} - -s -w #archives: # - replacements: diff --git a/Makefile b/Makefile index ad691360e..a783fb177 100644 --- a/Makefile +++ b/Makefile @@ -8,32 +8,36 @@ else GOBIN=$(shell go env GOBIN) endif -install-golint: ## check license if not exist install addlicense tools -ifeq (, $(shell which golangci-lint)) - @{ \ - set -e ;\ - o install github.com/golangci/golangci-lint/cmd/golangci-lint@v1.39.0 ;\ - } -GOLINT_BIN=$(GOBIN)/golangci-lint -else -GOLINT_BIN=$(shell which golangci-lint) -endif +SHELL = /usr/bin/env bash -o pipefail +.SHELLFLAGS = -ec + +PROJECT_DIR := $(shell dirname $(abspath $(lastword $(MAKEFILE_LIST)))) +define go-get-tool +@[ -f $(1) ] || { \ +set -e ;\ +TMP_DIR=$$(mktemp -d) ;\ +cd $$TMP_DIR ;\ +go mod init tmp ;\ +echo "Downloading $(2)" ;\ +GOBIN=$(PROJECT_DIR)/bin go get $(2) ;\ +rm -rf $$TMP_DIR ;\ +} +endef + +GOLINT_BIN = $(shell pwd)/bin/golangci-lint +install-golint: ## check license if not exist install go-lint tools + $(call go-get-tool,$(GOLINT_BIN),github.com/golangci/golangci-lint/cmd/golangci-lint@v1.43.0) lint: install-golint ## Run go lint against code. $(GOLINT_BIN) run -v ./... default: build -install-goreleaser: ## check license if not exist install addlicense tools -ifeq (, $(shell which goreleaser)) - @{ \ - set -e ;\ - go install github.com/goreleaser/goreleaser@latest ;\ - } -GORELEASER_BIN=$(GOBIN)/goreleaser -else -GORELEASER_BIN=$(shell which goreleaser) -endif + +GORELEASER_BIN = $(shell pwd)/bin/goreleaser +install-goreleaser: ## check license if not exist install go-lint tools + $(call go-get-tool,$(GORELEASER_BIN),github.com/goreleaser/goreleaser@latest) + build: SHELL:=/bin/bash build: install-goreleaser clean ## build binaries by default @@ -46,40 +50,22 @@ help: ## this help clean: ## clean rm -rf dist -install-addlicense: ## check license if not exist install addlicense tools -ifeq (, $(shell which addlicense)) - @{ \ - set -e ;\ - LICENSE_TMP_DIR=$$(mktemp -d) ;\ - cd $$LICENSE_TMP_DIR ;\ - go mod init tmp ;\ - go get -v github.com/google/addlicense ;\ - rm -rf $$LICENSE_TMP_DIR ;\ - } -ADDLICENSE_BIN=$(GOBIN)/addlicense -else -ADDLICENSE_BIN=$(shell which addlicense) -endif +ADDLICENSE_BIN = $(shell pwd)/bin/addlicense +install-addlicense: ## check license if not exist install go-lint tools + $(call go-get-tool,$(ADDLICENSE_BIN),github.com/google/addlicense@latest) - -filelicense: SHELL:=/bin/bash -filelicense: ## add license +filelicense: +filelicense: install-addlicense for file in ${Dirs} ; do \ if [[ $$file != '_output' && $$file != 'docs' && $$file != 'vendor' && $$file != 'logger' && $$file != 'applications' ]]; then \ $(ADDLICENSE_BIN) -y $(shell date +"%Y") -c "sealos." -f hack/template/LICENSE ./$$file ; \ fi \ done -install-ossutil: ## check ossutil if not exist install ossutil tools -ifeq (, $(shell which ossutil)) - @{ \ - set -e ;\ - curl -sfL https://raw.githubusercontent.com/securego/gosec/master/install.sh | sh -s -- -b $(GOBIN) v2.2.0 ;\ - } -OSSUTIL_BIN=$(GOBIN)/ossutil -else -OSSUTIL_BIN=$(shell which ossutil) -endif +OSSUTIL_BIN = $(shell pwd)/bin/ossutil +install-ossutil: ## check license if not exist install go-lint tools + $(call go-get-tool,$(OSSUTIL_BIN),github.com/aliyun/ossutil@latest) + push-oss:install-ossutil build $(OSSUTIL_BIN) cp -f dist/sealos_linux_amd64/sealos oss://sealyun-temp/sealos/${COMMIT_ID}/sealos @@ -87,3 +73,13 @@ push-oss:install-ossutil build generator-contributors: git log --format='%aN <%aE>' | sort -uf > CONTRIBUTORS + + +HEAD_FILE := hack/template/boilerplate.go.txt +INPUT_DIR := github.com/fanux/sealos/pkg/types/v1beta1 +deepcopy: + deepcopy-gen \ + --input-dirs="$(INPUT_DIR)" \ + -O zz_generated.deepcopy \ + --go-header-file "$(HEAD_FILE)" \ + --output-base "${GOPATH}/src" diff --git a/cmd/clean.go b/cmd/clean.go index 71697262c..85369e60e 100644 --- a/cmd/clean.go +++ b/cmd/clean.go @@ -17,7 +17,7 @@ package cmd import ( "os" - v1 "github.com/fanux/sealos/pkg/types/v1" + v1 "github.com/fanux/sealos/pkg/types/v1alpha1" "github.com/fanux/sealos/pkg/utils" "github.com/fanux/sealos/pkg/install" diff --git a/cmd/cloud.go b/cmd/cloud.go deleted file mode 100644 index be3ad79fe..000000000 --- a/cmd/cloud.go +++ /dev/null @@ -1,74 +0,0 @@ -// Copyright © 2021 sealos. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package cmd - -import ( - "fmt" - "os" - - "github.com/fanux/sealos/pkg/utils" - - install "github.com/fanux/sealos/pkg/install" - - "github.com/fanux/sealgate/cloud" - "github.com/spf13/cobra" -) - -var p bool - -// cloudCmd represents the cloud command -var cloudCmd = &cobra.Command{ - Use: "cloud", - Short: "sealos on cloud", - Long: `sealos will create vms vpc switch security group on cloud and install kubernetes on it`, - Run: func(cmd *cobra.Command, args []string) { - fmt.Println("install kubernetes on cloud...") - var key, sec string - if key = os.Getenv("ACCESS_KEY_ID"); key != "" { - install.C.AccessKey = key - } - if sec = os.Getenv("ACCESS_KEY_SECRET"); sec != "" { - install.C.AccessKey = sec - } - install.CloudInstall(&install.C) - }, -} - -func init() { - rootCmd.AddCommand(cloudCmd) - cloudCmd.Flags().StringVar(&install.C.AccessKey, "accessKey", "", "cloud provider accessKey, like LTAIah2bOOcr0uuT") - cloudCmd.Flags().StringVar(&install.C.AccessSecret, "accessSecret", "", "cloud provider accessSecret, like FN3FcvXUctbudisnHs89bcYlbsZuImh") - cloudCmd.Flags().StringVar(&install.C.Provider, "provider", cloud.ALI, "cloud provider type,current support ali") - cloudCmd.Flags().IntVar(&install.C.Master, "master", 1, "the number of master vms") - cloudCmd.Flags().IntVar(&install.C.Node, "node", 1, "the number of node vms") - cloudCmd.Flags().StringVar(&install.C.Version, "version", "v1.16.0", "kubernetes version") - cloudCmd.Flags().StringVar(&install.C.Flavor, "flavor", "2C4G", "the type of vms") - cloudCmd.Flags().StringVar(&install.C.Name, "name", "sealyun"+utils.RandString(8), "the name of your cluster") - cloudCmd.Flags().StringVar(&install.C.Passwd, "passwd", "Fanux#123", "the passwd of your vm servers") - cloudCmd.Flags().StringVar(&install.C.Region, "region", "cn-hongkong", "cloud provider region") - cloudCmd.Flags().StringVar(&install.C.Zone, "zone", "cn-hongkong-b", "cloud provider region") - cloudCmd.Flags().StringVar(&install.C.Image, "image", "centos_7_04_64_20G_alibase_201701015.vhd", "vm os image") - cloudCmd.Flags().BoolVar(&p, "y", false, "prompt or not") - - // Here you will define your flags and configuration settings. - - // Cobra supports Persistent Flags which will work for this command - // and all subcommands, e.g.: - // cloudCmd.PersistentFlags().String("foo", "", "A help for foo") - - // Cobra supports local flags which will only run when this command - // is called directly, e.g.: - // cloudCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle") -} diff --git a/cmd/cni.go b/cmd/cni.go index 282f05c3b..ed9e0f528 100644 --- a/cmd/cni.go +++ b/cmd/cni.go @@ -24,7 +24,7 @@ import ( ) var cniType string -var version string +var cniVersion string // cniCmd represents the cni command var cniCmd = &cobra.Command{ @@ -35,15 +35,15 @@ var cniCmd = &cobra.Command{ logger.Error("unsupport cni: ", cniType) return } - if version == "" { - logger.Error("cni version should not nil ", version) + if cniVersion == "" { + logger.Error("cni version should not nil ", cniVersion) return } yaml := cni.NewNetwork(cniType, cni.MetaData{ Interface: "interface=eth.*|en.*|em.*", IPIP: true, MTU: "1440", - Version: version, + Version: cniVersion, }).Manifests("") fmt.Println(yaml) }, @@ -53,7 +53,7 @@ func init() { rootCmd.AddCommand(cniCmd) cniCmd.Flags().StringVarP(&cniType, "cni-type", "t", cni.CALICO, "print cni yaml, cni tpye just like, calico.flannel.cilium") - cniCmd.Flags().StringVarP(&version, "version", "v", "", "calico version") + cniCmd.Flags().StringVarP(&cniVersion, "version", "v", "", "calico version") // Here you will define your flags and configuration settings. diff --git a/cmd/delete.go b/cmd/delete.go index 2c0b89202..c3ed7abc1 100644 --- a/cmd/delete.go +++ b/cmd/delete.go @@ -17,7 +17,7 @@ package cmd import ( "os" - v1 "github.com/fanux/sealos/pkg/types/v1" + v1 "github.com/fanux/sealos/pkg/types/v1alpha1" install "github.com/fanux/sealos/pkg/install" diff --git a/cmd/etcd.go b/cmd/etcd.go index 61895f36b..c0c14321a 100644 --- a/cmd/etcd.go +++ b/cmd/etcd.go @@ -19,7 +19,7 @@ import ( "os" "time" - v1 "github.com/fanux/sealos/pkg/types/v1" + v1 "github.com/fanux/sealos/pkg/types/v1alpha1" "github.com/fanux/sealos/pkg/utils" install "github.com/fanux/sealos/pkg/install" diff --git a/cmd/init.go b/cmd/init.go index 423078a22..95c21acaa 100644 --- a/cmd/init.go +++ b/cmd/init.go @@ -17,7 +17,7 @@ package cmd import ( "os" - v1 "github.com/fanux/sealos/pkg/types/v1" + v1 "github.com/fanux/sealos/pkg/types/v1alpha1" "github.com/fanux/sealos/pkg/utils" "github.com/fanux/sealos/pkg/cni" diff --git a/cmd/install.go b/cmd/install.go index f4d14c775..9abe8e020 100644 --- a/cmd/install.go +++ b/cmd/install.go @@ -17,7 +17,7 @@ package cmd import ( "os" - v1 "github.com/fanux/sealos/pkg/types/v1" + v1 "github.com/fanux/sealos/pkg/types/v1alpha1" "github.com/fanux/sealos/pkg/utils" install "github.com/fanux/sealos/pkg/install" @@ -29,12 +29,12 @@ import ( var ( AppURL string - installExample string = ` + installExample = ` # when usr -f flag , you need add something to config file. - # Apply the configuration in values.yaml to a kubernetes Cluster. + # Apply the configuration in values.yaml to a kubernetes Infra. sealos install --pkg-url /root/dashboard.tar -f values.yaml - # Apply the yaml passed into stdin to a kubenertes Cluster. + # Apply the yaml passed into stdin to a kubenertes Infra. cat values.yaml | sealos install --pkg-url /root/dashboard.tar -f - # Set the WorkDir for your Package diff --git a/cmd/ipvs.go b/cmd/ipvs.go index 7df759aa2..3aa752929 100644 --- a/cmd/ipvs.go +++ b/cmd/ipvs.go @@ -15,7 +15,7 @@ package cmd import ( - v1 "github.com/fanux/sealos/pkg/types/v1" + v1 "github.com/fanux/sealos/pkg/types/v1alpha1" "github.com/spf13/cobra" ) diff --git a/cmd/join.go b/cmd/join.go index 35049417d..897bebebf 100644 --- a/cmd/join.go +++ b/cmd/join.go @@ -17,7 +17,7 @@ package cmd import ( "os" - v1 "github.com/fanux/sealos/pkg/types/v1" + v1 "github.com/fanux/sealos/pkg/types/v1alpha1" "github.com/fanux/sealos/pkg/utils" install "github.com/fanux/sealos/pkg/install" diff --git a/cmd/root.go b/cmd/root.go index a3560a916..9a4d0fe0e 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -18,7 +18,7 @@ import ( "fmt" "os" - v1 "github.com/fanux/sealos/pkg/types/v1" + v1 "github.com/fanux/sealos/pkg/types/v1alpha1" "github.com/fanux/sealos/pkg/utils" "github.com/fanux/sealos/pkg/utils/logger" diff --git a/cmd/version.go b/cmd/version.go index 5f479d52d..b463e0f01 100644 --- a/cmd/version.go +++ b/cmd/version.go @@ -15,23 +15,36 @@ package cmd import ( + "encoding/json" "fmt" - "runtime" - "strings" - extver "github.com/linuxsuren/cobra-extension/version" + "github.com/fanux/sealos/pkg/version" + "github.com/spf13/cobra" ) -func init() { - // it's possible to have multiple choices for users to choose GitHub or aliyun as their download source - // see also https://github.com/LinuxSuRen/cobra-extension/issues/6 - const name = "sealos" - verCmd := extver.NewVersionCmd("fanux", name, name, func(ver string) string { - if strings.HasPrefix(ver, "v") { - ver = strings.TrimPrefix(ver, "v") +var shortPrint bool + +var versionCmd = &cobra.Command{ + Use: "version", + Short: "version", + Args: cobra.NoArgs, + Example: `sealer version`, + RunE: func(cmd *cobra.Command, args []string) error { + marshalled, err := json.Marshal(version.Get()) + if err != nil { + return err } - return fmt.Sprintf("https://github.com/fanux/sealos/releases/download/v%s/%s_%s_%s_%s.tar.gz", - ver, name, ver, runtime.GOOS, runtime.GOARCH) - }) - rootCmd.AddCommand(verCmd) + if shortPrint { + fmt.Println(version.Get().String()) + } else { + fmt.Println(string(marshalled)) + } + return nil + + }, +} + +func init() { + rootCmd.AddCommand(versionCmd) + versionCmd.Flags().BoolVar(&shortPrint, "short", false, "If true, print just the cniVersion number.") } diff --git a/go.mod b/go.mod index 20f7ce266..00bda2d9b 100644 --- a/go.mod +++ b/go.mod @@ -1,14 +1,16 @@ module github.com/fanux/sealos -go 1.13 +go 1.15 require ( + github.com/aliyun/alibaba-cloud-sdk-go v1.61.985 github.com/aliyun/aliyun-oss-go-sdk v2.2.0+incompatible github.com/baiyubin/aliyun-sts-go-sdk v0.0.0-20180326062324-cfa1a18b161f // indirect github.com/dustin/go-humanize v1.0.0 // indirect - github.com/fanux/sealgate v0.0.5 github.com/google/uuid v1.1.2 // indirect - github.com/linuxsuren/cobra-extension v0.0.8 + github.com/mitchellh/go-homedir v1.1.0 + github.com/onsi/ginkgo v1.11.0 + github.com/onsi/gomega v1.7.0 github.com/pkg/errors v0.9.1 github.com/pkg/sftp v1.11.0 github.com/prometheus/common v0.13.0 // indirect diff --git a/go.sum b/go.sum index 7500a2949..248d84fe0 100644 --- a/go.sum +++ b/go.sum @@ -11,7 +11,6 @@ cloud.google.com/go/firestore v1.1.0/go.mod h1:ulACoGHTpvq5r8rxGJ4ddJZBZqakUQqCl cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= -github.com/AlecAivazis/survey/v2 v2.2.2/go.mod h1:9FJRdMdDm8rnT+zHVbvQT2RTSTLq0Ttd6q3Vl2fahjk= github.com/Azure/go-autorest/autorest v0.9.0/go.mod h1:xyHB1BMZT0cuDHU7I0+g046+BFDTQ8rEZB0s4Yfa6bI= github.com/Azure/go-autorest/autorest/adal v0.5.0/go.mod h1:8Z9fGy2MpX0PvDjB1pEgQTmVqjGhiHBW7RJJEciWzS0= github.com/Azure/go-autorest/autorest/date v0.1.0/go.mod h1:plvfp3oPSKwf2DNjlBjWF/7vwR+cUD/ELuzDCXwHUVA= @@ -24,35 +23,29 @@ github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03 github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0= github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ= -github.com/Netflix/go-expect v0.0.0-20180615182759-c93bf25de8e8/go.mod h1:oX5x61PbNXchhh0oikYAH+4Pcfw5LKv21+Jnpr6r6Pc= github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= -github.com/Pallinder/go-randomdata v1.2.0/go.mod h1:yHmJgulpD2Nfrm0cR9tI/+oAgRqCQQixsA8HyRZfV9Y= github.com/PuerkitoBio/purell v1.0.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= github.com/PuerkitoBio/urlesc v0.0.0-20160726150825-5bd2802263f2/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo= github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI= github.com/VividCortex/gohistogram v1.0.0/go.mod h1:Pf5mBqqDxYaXu3hDrrU+w6nw50o/4+TcAqDqk/vUH7g= github.com/afex/hystrix-go v0.0.0-20180502004556-fa1af6a1f4f5/go.mod h1:SkGFH1ia65gfNATL8TAiHDNxPzPdmEL5uirI2Uyuz6c= -github.com/alcortesm/tgz v0.0.0-20161220082320-9c5fe88206d7/go.mod h1:6zEj6s6u/ghQa61ZWa/C2Aw3RkjiTBOix7dkqa1VLIs= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho= -github.com/aliyun/alibaba-cloud-sdk-go v0.0.0-20191115143122-2863a2c99a71 h1:403lX+Je3enjqcePi8bSN6QWzhuzx71dBViv+PhqHUA= -github.com/aliyun/alibaba-cloud-sdk-go v0.0.0-20191115143122-2863a2c99a71/go.mod h1:mNZkuqaeM5UCiAdkV4r+lrheu8Q5fe/487bRFrGYZ8A= +github.com/aliyun/alibaba-cloud-sdk-go v1.61.985 h1:ETObK47vrphrw9wC+2/SinHL59YQtle2eBtSRucLTRQ= +github.com/aliyun/alibaba-cloud-sdk-go v1.61.985/go.mod h1:pUKYbK5JQ+1Dfxk80P0qxGqe5dkxDoabbZS7zOcouyA= github.com/aliyun/aliyun-oss-go-sdk v2.2.0+incompatible h1:ht2+VfbXtNLGhCsnTMc6/N26nSTBK6qdhktjYyjJQkk= github.com/aliyun/aliyun-oss-go-sdk v2.2.0+incompatible/go.mod h1:T/Aws4fEfogEE9v+HPhhw+CntffsBHJ8nXQCwKr0/g8= -github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c= github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ= github.com/apache/thrift v0.13.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ= github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= -github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs= github.com/aryann/difflib v0.0.0-20170710044230-e206f873d14a/go.mod h1:DAHtR1m6lCRdSC2Tm3DSWRPvIPr6xNKyeHdqDQSQT+A= -github.com/atotto/clipboard v0.1.2/go.mod h1:ZY9tmq7sm5xIbd9bOK4onWV4S6X0u6GY7Vn0Yu86PYI= github.com/aws/aws-lambda-go v1.13.3/go.mod h1:4UKl9IzQMoD+QF79YdCuzCwp8VbmG4VAQwij/eHl5CU= github.com/aws/aws-sdk-go v1.27.0/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= github.com/aws/aws-sdk-go-v2 v0.18.0/go.mod h1:JWVYvqSMppoMJC0x5wdwiImzgXTI9FuZwxzkQq9wy+g= @@ -71,7 +64,6 @@ github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko= github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= github.com/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+qY= github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= -github.com/chai2010/gettext-go v0.0.0-20170215093142-bf70f2a70fb1/go.mod h1:/iP1qXHoty45bqomnu2LM+VVyAEdWN+vtSHGlQgyxbw= github.com/clbanning/x2j v0.0.0-20191024224557-825249438eec/go.mod h1:jMjuTZXRI4dUb/I5gc9Hdhagfvm9+RyrPryS/auMzxE= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa h1:OaNxuTZr7kxeODyLWsRMC+OD03aFUH+mW6r2d+MWa5Y= @@ -80,7 +72,6 @@ github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= -github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk= github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= github.com/coreos/go-semver v0.3.0 h1:wkHLiw0WNATZnSG7epLsujiMCgPAc9xhjJ4tgnAxmfM= github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= @@ -90,11 +81,9 @@ github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7 github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f h1:lBNOc5arjvs8E5mO2tbpBpLoyyu8B6e44T7hJy6potg= 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/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= -github.com/danieljoos/wincred v1.0.2/go.mod h1:SnuYRW9lp1oJrZX/dXJqr0cPK5gYXqx3EJbmjhLdK9U= 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= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -111,23 +100,17 @@ github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFP github.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M= github.com/elazarl/goproxy v0.0.0-20180725130230-947c36da3153/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc= github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= -github.com/emirpasic/gods v1.12.0/go.mod h1:YfzfFFoVP/catgzJb4IKIqXjX78Ha8FMSDh3ymbK86o= github.com/envoyproxy/go-control-plane v0.6.9/go.mod h1:SBwIajubJHhxtWwsL9s8ss4safvEdbitLhGGK48rN6g= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/evanphx/json-patch v4.2.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= -github.com/fanux/sealgate v0.0.5 h1:KCBf+x3TdjCEVVNCjdkeMukDE0kZx9QE39Yy2IazkiM= -github.com/fanux/sealgate v0.0.5/go.mod h1:y3141RLsCSgid4+H0O+7CoAqIHDGB0r0mcR8TYnqvps= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= -github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc= github.com/franela/goblin v0.0.0-20200105215937-c9ffbefa60db/go.mod h1:7dvUGVsVBjqR7JHJk0brhHOZYGmfBYOrK0ZhYMEtBr4= github.com/franela/goreq v0.0.0-20171204163338-bcd34c9993f8/go.mod h1:ZhphrRTfi2rbfLwlschooIH4+wKKDR4Pdxhh+TRoA20= +github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= -github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4= -github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= github.com/ghodss/yaml v0.0.0-20150909031657-73d445a93680/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= -github.com/gliderlabs/ssh v0.2.2/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= @@ -142,7 +125,6 @@ github.com/go-openapi/spec v0.0.0-20160808142527-6aced65f8501/go.mod h1:J8+jY1nA github.com/go-openapi/swag v0.0.0-20160704191624-1d0bd113de87/go.mod h1:DXUve3Dpr1UfpPtxFw+EFuQ41HhCWZfha5jSVRG7C7I= github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= -github.com/godbus/dbus v4.1.0+incompatible/go.mod h1:/YcGZj5zSblfDWMMoOzV4fas9FZnQYTkDnsGvmh2Grw= github.com/gogo/googleapis v1.1.0/go.mod h1:gf4bu3Q80BeJ6H1S1vYPm8/ELATdvryBaNFGgqEef3s= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= @@ -159,8 +141,6 @@ github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4er github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= -github.com/golang/mock v1.4.4 h1:l75CXGRSwbaYNpl/Z2X1XIIAMSCquvXgpVZDhwEIJsc= -github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= github.com/golang/protobuf v0.0.0-20161109072736-4bd1920723d7/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= @@ -183,10 +163,6 @@ github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMyw github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.0 h1:/QaMHBdZ26BB3SSst0Iwl10Epc+xhTquomWX0oZEB6w= github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-github/v29 v29.0.3 h1:IktKCTwU//aFHnpA+2SLIi7Oo9uhAzgsdZNbcAqhgdc= -github.com/google/go-github/v29 v29.0.3/go.mod h1:CHKiKKPHJ0REzfwc14QMklvtHwCveD0PxlMjLlzAM5E= -github.com/google/go-querystring v1.0.0 h1:Xkwi/a1rcvNg1PPYe5vI8GbeBY/jrVuDX5ASuANWTrk= -github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/gofuzz v1.1.0 h1:Hsa8mG0dQ46ij8Sl2AYJDUv1oA9/d6Vk+3LG99Oe02g= github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= @@ -213,10 +189,6 @@ github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc= github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= -github.com/gosuri/uilive v0.0.3 h1:kvo6aB3pez9Wbudij8srWo4iY6SFTTxTKOkb+uRCE8I= -github.com/gosuri/uilive v0.0.3/go.mod h1:qkLSc0A5EXSP6B04TrN4oQoxqFI7A8XvoXSlJi8cwk8= -github.com/gosuri/uiprogress v0.0.1 h1:0kpv/XY/qTmFWl/SkaJykZXrBBzwwadmW8fRb7RJSxw= -github.com/gosuri/uiprogress v0.0.1/go.mod h1:C1RTYn4Sc7iEyf6j8ft5dyoZ4212h8G1ol9QQluh5+0= github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4 h1:z53tR0945TRRQO/fLEVPI6SMv7ZflF0TEaTAoU7tOzg= @@ -241,7 +213,6 @@ github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdv github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/hashicorp/go-version v1.2.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= -github.com/hashicorp/go-version v1.2.1/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= @@ -250,7 +221,7 @@ github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ= github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I= github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc= -github.com/hinshun/vt10x v0.0.0-20180616224451-1954e6464174/go.mod h1:DqJ97dSdRW1W22yXSB90986pcOyQ7r45iio1KN2ez1A= +github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/hudl/fargo v1.3.0/go.mod h1:y3CKSmjA+wD2gak7sUSXTAoopbhU08POFhmITJgmKTg= github.com/imdario/mergo v0.3.5 h1:JboBksRwiiAJWvIYJVo46AfV+IAIKZpfrSzVKj42R4Q= @@ -258,11 +229,6 @@ github.com/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJ github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= github.com/influxdata/influxdb1-client v0.0.0-20191209144304-8bf82d3c094d/go.mod h1:qj24IKcXYK6Iy9ceXlo3Tc+vtHo9lIhSX5JddghvEPo= -github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo= -github.com/jenkins-zh/jenkins-cli v0.0.32 h1:q3KyWeYegQ4ncLI6zoPAXFkRXjaAGdjCI2qEc7fmOGk= -github.com/jenkins-zh/jenkins-cli v0.0.32/go.mod h1:uE1mH9PNITrg0sugv6HXuM/CSddg0zxXoYu3w57I3JY= -github.com/jenkins-zh/jenkins-formulas v0.0.5/go.mod h1:zS8fm8u5L6FcjZM0QznXsLV9T2UtSVK+hT6Sm76iUZ4= -github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af h1:pmfjZENx5imkbgOkpRUYLnmbU7UEFbjtDA2hxJ1ichM= github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= github.com/jonboulle/clockwork v0.1.0 h1:VKV+ZcuP6l3yW9doeqz6ziZGgcynBVQO+obU0+0hcPo= @@ -279,8 +245,6 @@ github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7 github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= -github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8= -github.com/kevinburke/ssh_config v0.0.0-20190725054713-01f96b0aa0cd/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM= github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= @@ -293,18 +257,10 @@ github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFB github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= -github.com/kr/pty v1.1.4/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= -github.com/kr/pty v1.1.8/go.mod h1:O1sed60cT9XZ5uDucP5qwvh+TE3NnUj51EiZO/lmSfw= github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/lightstep/lightstep-tracer-common/golang/gogo v0.0.0-20190605223551-bc2310a04743/go.mod h1:qklhhLq1aX+mtWk9cPHPzaBjWImj5ULL6C7HFJtXQMM= github.com/lightstep/lightstep-tracer-go v0.18.1/go.mod h1:jlF1pusYV4pidLvZ+XD0UBX0ZE6WURAspgAczcDHrL4= -github.com/linuxsuren/cobra-extension v0.0.6/go.mod h1:qcEJv7BbL0UpK6MbrTESP/nKf1+z1wQdMAnE1NBl3QQ= -github.com/linuxsuren/cobra-extension v0.0.8 h1:0YGETwoxyz8mfijbhZKnfiyuSeCKA6nQx7d0Fd/7O/k= -github.com/linuxsuren/cobra-extension v0.0.8/go.mod h1:+eJXhTxKdianYLGSU8W58pnedcml6eZrOfXASHWJhRg= -github.com/linuxsuren/http-downloader v0.0.2-0.20201207132639-19888a6beaec/go.mod h1:zRZY9FCDBuYNDxbI2Ny5suasZsMk7J6q9ecQ3V3PIqI= -github.com/linuxsuren/http-downloader v0.0.6 h1:JuCgWVT4/pw8MAhYe+ngE7BwcO575L1aPDc9Fgx+2ig= -github.com/linuxsuren/http-downloader v0.0.6/go.mod h1:xxgh2OE7WGL9TwDE9L8Gh7Lqq9fFPuHbh5tofUitEfE= github.com/lithammer/dedent v1.1.0 h1:VNzHMVCBNG1j0fh3OrsFRkVUwStdDArbgBWoPAffktY= github.com/lithammer/dedent v1.1.0/go.mod h1:jrXYCQtgg0nJiN+StA2KgR7w6CiQNv9Fd/Z9BP0jIOc= github.com/lyft/protoc-gen-validate v0.0.13/go.mod h1:XbGvPuh87YZc5TdIa2/I4pLk0QoUACkjt2znoq26NVQ= @@ -312,20 +268,15 @@ github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czP github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/mailru/easyjson v0.0.0-20160728113105-d5b7844b561a/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= -github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= -github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= -github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= -github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY= -github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= -github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE= github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg= @@ -351,8 +302,6 @@ github.com/nats-io/nats.go v1.9.1/go.mod h1:ZjDU1L/7fJ09jvUSRVBR2e7+RnLiiIQyqyzE github.com/nats-io/nkeys v0.1.0/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w= github.com/nats-io/nkeys v0.1.3/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w= github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c= -github.com/nxadm/tail v1.4.4 h1:DQuhQpB1tVlglWS2hLQ5OV6B5r8aGxSrPc5Qo6uTN78= -github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= github.com/oklog/oklog v0.3.2/go.mod h1:FCV+B7mhrz4o+ueLpx+KqkyXRGMWOYEvfiXtdGtbWGs= github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA= github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= @@ -360,18 +309,12 @@ github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:v github.com/onsi/ginkgo v0.0.0-20170829012221-11459a886d9c/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.11.0 h1:JAKSXpt1YjtLA7YpPiqO9ss6sNXEsPfSGdwN0UHqzrw= github.com/onsi/ginkgo v1.11.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= -github.com/onsi/ginkgo v1.14.2 h1:8mVmC9kjFFmA8H4pKMUhcblgifdkOIXPvbhN1T36q1M= -github.com/onsi/ginkgo v1.14.2/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY= github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= +github.com/onsi/gomega v1.7.0 h1:XPnZz8VVBHjVsy1vzJmRwIcSwiUO+JFfrv/xGiigmME= github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= -github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= -github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= -github.com/onsi/gomega v1.10.3/go.mod h1:V9xEwhxec5O8UDM77eCW8vLymOMltsqPVYWrpDsH8xc= -github.com/onsi/gomega v1.10.4 h1:NiTx7EEvBzu9sFOD1zORteLSt3o8gnlvZZwSE9TnY9U= -github.com/onsi/gomega v1.10.4/go.mod h1:g/HbgYopi++010VEqkFgJHKC09uJiW9UkXvMUuKHUCQ= github.com/op/go-logging v0.0.0-20160315200505-970db520ece7/go.mod h1:HzydrMdWErDVzsI23lYNej1Htcns9BCg93Dk0bBINWk= github.com/opentracing-contrib/go-observer v0.0.0-20170622124052-a52f23424492/go.mod h1:Ngi6UdF0k5OKD5t5wlmGhe/EDKPoUM3BXZSSfIuJbis= github.com/opentracing/basictracer-go v1.0.0/go.mod h1:QfBfYuafItcjQuMwinw9GhYKwFXS9KnPs5lxoYwgW74= @@ -384,11 +327,9 @@ github.com/openzipkin/zipkin-go v0.2.2/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnh github.com/pact-foundation/pact-go v1.0.4/go.mod h1:uExwJY4kCzNPcHRj+hCR/HBbOOIwwtUjcrb0b5/5kLM= github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k= -github.com/pelletier/go-buffruneio v0.2.0/go.mod h1:JkE26KsDizTr40EUHkXVtNPvgGtbSNq5BcowyYOWdKo= github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= github.com/performancecopilot/speed v3.0.0+incompatible/go.mod h1:/CLtqpZ5gBg1M9iaPbIdPPGyKcA8hKdoy6hAWba7Yac= github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU= -github.com/phayes/freeport v0.0.0-20180830031419-95f893ade6f2/go.mod h1:iIss55rKnNBTvrwdmkUpLnDpZoAHvWaiq5+iMmen4AE= github.com/pierrec/lz4 v1.0.2-0.20190131084431-473cd7ce01a1/go.mod h1:3/3N9NVKO0jef7pBehbT1qWhCMrIgbYNnFAZCqQ5LRc= github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= @@ -434,7 +375,6 @@ github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40T github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= -github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= github.com/samuel/go-zookeeper v0.0.0-20190923202752-2cc03de413da/go.mod h1:gi+0XIa01GRL2eRQVjQkKGqKF3SF9vZR/HnPullcV2E= @@ -443,7 +383,6 @@ github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdh github.com/sealyun/lvscare v1.1.2-alpha.2 h1:SlnEAXOPn5gC6l8tgvbn9fApyJaQ0ecQHSV3cEfvQYY= github.com/sealyun/lvscare v1.1.2-alpha.2/go.mod h1:FtOEdsXuYtw9Jwd/Jct25K+PcpUFSDemvF4VgNygjj0= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= -github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= @@ -462,7 +401,6 @@ github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk= github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= -github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU= github.com/spf13/cobra v0.0.6/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE= github.com/spf13/cobra v1.1.1 h1:KfztREH0tPxJJ+geloSLaAkaPkr4ki2Er5quFV1TDo4= github.com/spf13/cobra v1.1.1/go.mod h1:WnodtKOvamDL/PwE2M4iKs8aMDBZ5Q5klgD3qfVJQMI= @@ -472,29 +410,22 @@ github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnIn github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= -github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s= github.com/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/yZzE= -github.com/spf13/viper v1.5.0/go.mod h1:AkYRkVJF8TkSG/xet6PzXX+l39KhhXa2pdqVSxnTcn4= github.com/spf13/viper v1.7.0/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg= -github.com/src-d/gcfg v1.4.0/go.mod h1:p/UMsR43ujA89BJY9duynAwIpvqEujIH/jFlfL7jWoI= github.com/streadway/amqp v0.0.0-20190404075320-75d898a42a94/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw= github.com/streadway/amqp v0.0.0-20190827072141-edfb9018d271/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw= github.com/streadway/handy v0.0.0-20190108123426-d5acb3125c2a/go.mod h1:qNTQ5P5JnDBl6z3cMAg/SywNDC5ABu5ApDIw6lUbRmI= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= -github.com/stretchr/testify v1.2.1/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= -github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0= -github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5 h1:LnC5Kc/wtumK+WB441p7ynQJzVuNRJiqddSIE3IlSEQ= github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc= -github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= github.com/vishvananda/netlink v1.1.0 h1:1iyaYNBLmP6L0220aDnYQpo1QEV4t4hJ+xEEhhJH8j0= @@ -503,11 +434,9 @@ github.com/vishvananda/netns v0.0.0-20191106174202-0a2b9b5464df h1:OviZH7qLw/7Zo github.com/vishvananda/netns v0.0.0-20191106174202-0a2b9b5464df/go.mod h1:JP3t17pCcGlemwknint6hfoeCVQrEMVwxRLRjXpq+BU= github.com/wonderivan/logger v1.0.0 h1:Z6Nz+3SNcizolx3ARH11axdD4DXjFpb2J+ziGUVlv/U= github.com/wonderivan/logger v1.0.0/go.mod h1:NObMfQ3WOLKfYEZuGeZQfuQfSPE5+QNgRddVMzsAT/k= -github.com/xanzy/ssh-agent v0.2.1/go.mod h1:mLlQY/MoOhWBj+gOGMQkOeiEvkx+8pJSI+0Bx9h2kr4= github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2 h1:eY9dn8+vbi4tKz5Qo6v2eYzo7kUS51QINcR5jNpbZS8= github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= -github.com/zalando/go-keyring v0.0.0-20200121091418-667557018717/go.mod h1:RaxNwUITJaHVdQ0VC7pELPZ3tOWn13nr0gZMZEhpVU0= go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= go.etcd.io/bbolt v1.3.3 h1:MUGmc65QhB3pIlaQ5bB4LwqSj6GIonVJXpZiaKNyaKk= go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= @@ -537,12 +466,9 @@ go.uber.org/zap v1.16.0 h1:uFRZXykJGK9lLY4HtgSw44DnIcAM+kRBP7x5m+NpAOM= go.uber.org/zap v1.16.0/go.mod h1:MA8QOfq0BHJwdXa996Y4dYkAqRKB8/1K1QMMZVaNZjQ= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= -golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190211182817-74369b46fc67/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= -golang.org/x/crypto v0.0.0-20190219172222-a4c6cb3142f2/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20190530122614-20be4c3c3ed5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= @@ -589,14 +515,10 @@ golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20191004110552-13f9640d40b9/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200625001655-4c5254603344 h1:vGXIOMxbNfDTk/aXCmfdLgkrSV+Z2tcbze+pEc3v5W4= golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= -golang.org/x/net v0.0.0-20201006153459-a7d1128ccaa0/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.0.0-20201202161906-c7110b5ffcbb h1:eBmm0M9fYhWpKZLjQUUKka/LtIxf46G4fxeEz5KJr9U= -golang.org/x/net v0.0.0-20201202161906-c7110b5ffcbb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45 h1:SVwTIAaPC2U/AvvLNZ2a7OVsmBpC8L5BlwK1whH3hm0= @@ -616,43 +538,31 @@ golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5h golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190209173611-3b5209105503/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190221075227-b4e8571b14e0/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190530182044-ad28b68e88f1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190606203320-7fc4e5ec1444/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191022100944-742c48ecaeb7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191220142924-d4481acd189f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae h1:Ih9Yo4hSPImZOpfGuA4bR/ORKTAbhZo2AbWNRCnevdo= golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f h1:+Nyd8tzPX9R7BWHguqsrbFdRx3WQ/1ib8I44HXV5yTA= -golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/text v0.0.0-20160726164857-2910a502d2bf/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= -golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.4 h1:0YWbFKbhXG/wIiuHDSKpS0Iy7FSA+u45VtBMfQcFTTc= -golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= @@ -676,7 +586,6 @@ golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgw golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190624222133-a101b041ded4/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190729092621-ff9f1409240a/go.mod h1:jcCCGcm9btYwXyDqrUWc6MKQKKGJCWEQ3AfLSRIbEuI= golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= @@ -742,6 +651,7 @@ gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogR gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= +gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= gopkg.in/gcfg.v1 v1.2.3/go.mod h1:yesOnuUOFQAhST5vPY4nbZsb/huCgGGXlipJsBn0b3o= gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= @@ -752,9 +662,6 @@ gopkg.in/ini.v1 v1.61.0 h1:LBCdW4FmFYL4s/vDZD1RQYX7oAR6IjujCYgMdbHBR10= gopkg.in/ini.v1 v1.61.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= gopkg.in/square/go-jose.v2 v2.2.2/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= -gopkg.in/src-d/go-billy.v4 v4.3.2/go.mod h1:nDjArDMp+XMs1aFAESLRjfGSgfvoYN0hDfzEk0GjC98= -gopkg.in/src-d/go-git-fixtures.v3 v3.5.0/go.mod h1:dLBcvytrw/TYZsNTWCnkNF2DSIlzWYqTe3rJR56Ac7g= -gopkg.in/src-d/go-git.v4 v4.13.1/go.mod h1:nx5NYcxdKxq5fpltdHnPa2Exj4Sx0EclMWZQbYDu2z8= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI= @@ -767,8 +674,6 @@ gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= -gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= -gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gotest.tools/v3 v3.0.2 h1:kG1BFyqVHuQoVQiR1bWGnfz/fmHvvuiSPIV7rvl360E= gotest.tools/v3 v3.0.2/go.mod h1:3SzNCllyD9/Y+b5r9JIKQ474KzkZyqLqEfYqMsX94Bk= honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= @@ -795,7 +700,6 @@ k8s.io/kube-openapi v0.0.0-20200121204235-bf4fb3bd569c h1:/KUFqjjqAcY4Us6luF5RDN k8s.io/kube-openapi v0.0.0-20200121204235-bf4fb3bd569c/go.mod h1:GRQhZsXIAJ1xR0C9bd8UpWHZ5plfAS9fzPjJuQ6JL3E= k8s.io/utils v0.0.0-20200324210504-a9aa75ae1b89 h1:d4vVOjXm687F1iLSP2q3lyPPuyvTUt3aVoBpi2DqRsU= k8s.io/utils v0.0.0-20200324210504-a9aa75ae1b89/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew= -moul.io/http2curl v1.0.0/go.mod h1:f6cULg+e4Md/oW1cYmwW4IWQOVl2lGbmCNGOHvzX2kE= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= sigs.k8s.io/structured-merge-diff/v3 v3.0.0-20200116222232-67a7b8c61874/go.mod h1:PlARxl6Hbt/+BC80dRLi1qAmnMqwqDg62YvvVkZjemw= sigs.k8s.io/structured-merge-diff/v3 v3.0.0 h1:dOmIZBMfhcHS09XZkMyUgkq5trg3/jRyJYFZUiaOp8E= diff --git a/hack/template/boilerplate.go.txt b/hack/template/boilerplate.go.txt new file mode 100644 index 000000000..62d84cc8d --- /dev/null +++ b/hack/template/boilerplate.go.txt @@ -0,0 +1,13 @@ +// Copyright © 2021 sealos. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. diff --git a/pkg/appmanager/appmanager.go b/pkg/appmanager/appmanager.go index 487a399b6..7f5ce7ff3 100644 --- a/pkg/appmanager/appmanager.go +++ b/pkg/appmanager/appmanager.go @@ -24,7 +24,7 @@ import ( "strings" "sync" - v1 "github.com/fanux/sealos/pkg/types/v1" + v1 "github.com/fanux/sealos/pkg/types/v1alpha1" "github.com/fanux/sealos/pkg/utils" "github.com/fanux/sealos/pkg/utils/ssh" diff --git a/pkg/appmanager/deleteapp.go b/pkg/appmanager/deleteapp.go index b1015263d..d9ed9a2ab 100644 --- a/pkg/appmanager/deleteapp.go +++ b/pkg/appmanager/deleteapp.go @@ -18,7 +18,7 @@ import ( "fmt" "os" - v1 "github.com/fanux/sealos/pkg/types/v1" + v1 "github.com/fanux/sealos/pkg/types/v1alpha1" install "github.com/fanux/sealos/pkg/utils" "github.com/fanux/sealos/pkg/utils/logger" diff --git a/pkg/appmanager/installapp.go b/pkg/appmanager/installapp.go index c28301934..704ca10ad 100644 --- a/pkg/appmanager/installapp.go +++ b/pkg/appmanager/installapp.go @@ -19,7 +19,7 @@ import ( "fmt" "io/ioutil" - v1 "github.com/fanux/sealos/pkg/types/v1" + v1 "github.com/fanux/sealos/pkg/types/v1alpha1" "github.com/fanux/sealos/pkg/utils/logger" diff --git a/pkg/cni/calico_yaml.go b/pkg/cni/calico_yaml.go index 1331b6a6c..9ad628eff 100644 --- a/pkg/cni/calico_yaml.go +++ b/pkg/cni/calico_yaml.go @@ -84,7 +84,7 @@ spec: listKind: BGPConfigurationList plural: bgpconfigurations singular: bgpconfiguration - scope: Cluster + scope: Infra versions: - name: v1 schema: @@ -218,7 +218,7 @@ spec: listKind: BGPPeerList plural: bgppeers singular: bgppeer - scope: Cluster + scope: Infra versions: - name: v1 schema: @@ -325,7 +325,7 @@ spec: listKind: BlockAffinityList plural: blockaffinities singular: blockaffinity - scope: Cluster + scope: Infra versions: - name: v1 schema: @@ -386,7 +386,7 @@ spec: listKind: ClusterInformationList plural: clusterinformations singular: clusterinformation - scope: Cluster + scope: Infra versions: - name: v1 schema: @@ -450,7 +450,7 @@ spec: listKind: FelixConfigurationList plural: felixconfigurations singular: felixconfiguration - scope: Cluster + scope: Infra versions: - name: v1 schema: @@ -1013,7 +1013,7 @@ spec: listKind: GlobalNetworkPolicyList plural: globalnetworkpolicies singular: globalnetworkpolicy - scope: Cluster + scope: Infra versions: - name: v1 schema: @@ -1784,7 +1784,7 @@ spec: listKind: GlobalNetworkSetList plural: globalnetworksets singular: globalnetworkset - scope: Cluster + scope: Infra versions: - name: v1 schema: @@ -1837,7 +1837,7 @@ spec: listKind: HostEndpointList plural: hostendpoints singular: hostendpoint - scope: Cluster + scope: Infra versions: - name: v1 schema: @@ -1945,7 +1945,7 @@ spec: listKind: IPAMBlockList plural: ipamblocks singular: ipamblock - scope: Cluster + scope: Infra versions: - name: v1 schema: @@ -2026,7 +2026,7 @@ spec: listKind: IPAMConfigList plural: ipamconfigs singular: ipamconfig - scope: Cluster + scope: Infra versions: - name: v1 schema: @@ -2082,7 +2082,7 @@ spec: listKind: IPAMHandleList plural: ipamhandles singular: ipamhandle - scope: Cluster + scope: Infra versions: - name: v1 schema: @@ -2138,7 +2138,7 @@ spec: listKind: IPPoolList plural: ippools singular: ippool - scope: Cluster + scope: Infra versions: - name: v1 schema: @@ -2237,7 +2237,7 @@ spec: listKind: KubeControllersConfigurationList plural: kubecontrollersconfigurations singular: kubecontrollersconfiguration - scope: Cluster + scope: Infra versions: - name: v1 schema: @@ -3653,7 +3653,7 @@ spec: configMapKeyRef: name: calico-config key: calico_backend - # Cluster type to identify the deployment type + # Infra type to identify the deployment type - name: CLUSTER_TYPE value: "k8s,bgp" # Auto-detect the BGP IP address. @@ -3870,7 +3870,7 @@ metadata: --- -# This manifest creates a Pod Disruption Budget for Controller to allow K8s Cluster Autoscaler to evict +# This manifest creates a Pod Disruption Budget for Controller to allow K8s Infra Autoscaler to evict apiVersion: policy/v1beta1 kind: PodDisruptionBudget @@ -3941,7 +3941,7 @@ kind: CustomResourceDefinition metadata: name: felixconfigurations.crd.projectcalico.org spec: - scope: Cluster + scope: Infra group: crd.projectcalico.org version: v1 names: @@ -3955,7 +3955,7 @@ kind: CustomResourceDefinition metadata: name: ipamblocks.crd.projectcalico.org spec: - scope: Cluster + scope: Infra group: crd.projectcalico.org version: v1 names: @@ -3970,7 +3970,7 @@ kind: CustomResourceDefinition metadata: name: blockaffinities.crd.projectcalico.org spec: - scope: Cluster + scope: Infra group: crd.projectcalico.org version: v1 names: @@ -3985,7 +3985,7 @@ kind: CustomResourceDefinition metadata: name: ipamhandles.crd.projectcalico.org spec: - scope: Cluster + scope: Infra group: crd.projectcalico.org version: v1 names: @@ -4000,7 +4000,7 @@ kind: CustomResourceDefinition metadata: name: ipamconfigs.crd.projectcalico.org spec: - scope: Cluster + scope: Infra group: crd.projectcalico.org version: v1 names: @@ -4015,7 +4015,7 @@ kind: CustomResourceDefinition metadata: name: bgppeers.crd.projectcalico.org spec: - scope: Cluster + scope: Infra group: crd.projectcalico.org version: v1 names: @@ -4030,7 +4030,7 @@ kind: CustomResourceDefinition metadata: name: bgpconfigurations.crd.projectcalico.org spec: - scope: Cluster + scope: Infra group: crd.projectcalico.org version: v1 names: @@ -4045,7 +4045,7 @@ kind: CustomResourceDefinition metadata: name: ippools.crd.projectcalico.org spec: - scope: Cluster + scope: Infra group: crd.projectcalico.org version: v1 names: @@ -4060,7 +4060,7 @@ kind: CustomResourceDefinition metadata: name: hostendpoints.crd.projectcalico.org spec: - scope: Cluster + scope: Infra group: crd.projectcalico.org version: v1 names: @@ -4075,7 +4075,7 @@ kind: CustomResourceDefinition metadata: name: clusterinformations.crd.projectcalico.org spec: - scope: Cluster + scope: Infra group: crd.projectcalico.org version: v1 names: @@ -4090,7 +4090,7 @@ kind: CustomResourceDefinition metadata: name: globalnetworkpolicies.crd.projectcalico.org spec: - scope: Cluster + scope: Infra group: crd.projectcalico.org version: v1 names: @@ -4105,7 +4105,7 @@ kind: CustomResourceDefinition metadata: name: globalnetworksets.crd.projectcalico.org spec: - scope: Cluster + scope: Infra group: crd.projectcalico.org version: v1 names: @@ -4484,7 +4484,7 @@ spec: configMapKeyRef: name: calico-config key: calico_backend - # Cluster type to identify the deployment type + # Infra type to identify the deployment type - name: CLUSTER_TYPE value: "k8s,bgp" # Auto-detect the BGP IP address. diff --git a/pkg/infra/README.md b/pkg/infra/README.md new file mode 100644 index 000000000..bd2dd4653 --- /dev/null +++ b/pkg/infra/README.md @@ -0,0 +1,3 @@ +# infra模块 + +根据Clusterfile里的定义去申请IaaS资源,保障IaaS资源与Clusterfile中的定义保持终态一致 diff --git a/pkg/infra/aliyun/ali_const.go b/pkg/infra/aliyun/ali_const.go new file mode 100644 index 000000000..c7f8837dc --- /dev/null +++ b/pkg/infra/aliyun/ali_const.go @@ -0,0 +1,85 @@ +/* +Copyright 2021 cuisongliu@qq.com. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package aliyun + +import ( + "time" + + v2 "github.com/fanux/sealos/pkg/types/v1beta1" +) + +const ( + EnvAccessKey = "ECS_AKID" + EnvAccessSecret = "ECS_AKSK" + EnvRegion = "ECS_REGION" +) + +const ( + Scheme = "https" + IPProtocol = "tcp" + APIServerPortRange = "6443/6443" + SSHPortRange = "22/22" + SourceCidrIP = "0.0.0.0/0" + CidrBlock = "172.16.0.0/24" + Policy = "accept" + DestinationResource = "InstanceType" + InstanceChargeType = "PostPaid" + InternetChargeType = "PayByTraffic" + defaultImageAmdID = "centos_7_9_x64_20G_alibase_20210927.vhd" + defaultImageArmID = "anolisos_7_7_arm64_20G_anck_alibase_20211118.vhd" + Product = "product" + Role = "role" + Master = "master" + Node = "node" + Stopped = "Stopped" + AvailableTypeStatus = "WithStock" + Bandwidth = "100" + AliDomain = "www.sealyun.com/" + DefaultRegionID = "cn-shanghai" + TryTimes = 10 + TrySleepTime = time.Second + JustGetInstanceInfo = 0 +) + +type ResourceName string + +const ( + EipID ResourceName = AliDomain + "EipID" + VpcID ResourceName = AliDomain + "VpcID" + VSwitchID ResourceName = AliDomain + "VSwitchID" + SecurityGroupID ResourceName = AliDomain + "SecurityGroupID" + SystemInfo ResourceName = AliDomain + "SystemInfo" + ShouldBeDeleteInstancesIDs ResourceName = "ShouldBeDeleteInstancesIDs" +) + +func (r ResourceName) Value(status v2.InfraStatus) string { + var value string + switch r { + case EipID: + value = status.EIPID + case VpcID: + value = status.VpcID + case VSwitchID: + value = status.VSwitchID + case SecurityGroupID: + value = status.SecurityGroupID + case ShouldBeDeleteInstancesIDs: + value = status.ShouldBeDeleteInstancesIDs + default: + } + return value +} diff --git a/pkg/infra/aliyun/ali_ecs.go b/pkg/infra/aliyun/ali_ecs.go new file mode 100644 index 000000000..d65fcfbde --- /dev/null +++ b/pkg/infra/aliyun/ali_ecs.go @@ -0,0 +1,522 @@ +// Copyright © 2021 Alibaba Group Holding Ltd. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package aliyun + +import ( + "errors" + "fmt" + "os" + "strings" + + v2 "github.com/fanux/sealos/pkg/types/v1beta1" + "github.com/fanux/sealos/pkg/utils" + "github.com/fanux/sealos/pkg/utils/logger" + + "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/services/ecs" +) + +type Instance struct { + CPU int + Memory float64 + InstanceID string + PrimaryIPAddress string +} + +type EcsManager struct { +} + +func (a *AliProvider) RetryEcsRequest(request requests.AcsRequest, response responses.AcsResponse) error { + return a.RetryEcsAction(request, response, TryTimes) +} + +func (a *AliProvider) RetryEcsAction(request requests.AcsRequest, response responses.AcsResponse, tryTimes int) error { + return utils.Retry(tryTimes, TrySleepTime, func() error { + err := a.EcsClient.DoAction(request, response) + if err != nil { + return err + } + return nil + }) +} + +func (a *AliProvider) RetryEcsInstanceType(request requests.AcsRequest, response responses.AcsResponse, instances []string) error { + for i := 0; i < len(instances); i++ { + switch req := request.(type) { + case *ecs.ModifyInstanceSpecRequest: + req.InstanceType = instances[i] + case *ecs.RunInstancesRequest: + req.InstanceType = instances[i] + } + err := a.RetryEcsAction(request, response, 4) + if err == nil { + a.Infra.Spec.Instance.Type = instances[i] + logger.Debug("use SystemInfo type: %s", instances[i]) + break + } else if i == len(instances)-1 { + return fmt.Errorf("failed to get ecs SystemInfo type, %v", err) + } + } + return nil +} + +func (a *AliProvider) TryGetInstance(request *ecs.DescribeInstancesRequest, response *ecs.DescribeInstancesResponse, expectCount int) error { + return utils.Retry(TryTimes, TrySleepTime, func() error { + err := a.EcsClient.DoAction(request, response) + var ipList []string + if err != nil { + return err + } + instances := response.Instances.Instance + if expectCount == -1 { + return nil + } + + if len(instances) != expectCount { + return errors.New("the number of instances is not as expected") + } + for _, instance := range instances { + if instance.NetworkInterfaces.NetworkInterface[0].PrimaryIpAddress == "" { + return errors.New("PrimaryIpAddress cannt nob be nil") + } + if len(ipList) != 0 && !utils.NotIn(instance.NetworkInterfaces.NetworkInterface[0].PrimaryIpAddress, ipList) { + return errors.New("PrimaryIpAddress cannt nob be same") + } + + ipList = append(ipList, instance.NetworkInterfaces.NetworkInterface[0].PrimaryIpAddress) + } + + return nil + }) +} + +func (a *AliProvider) InputIPlist(instanceRole string) (ipList []string, err error) { + var hosts *v2.Hosts + switch instanceRole { + case Master: + hosts = &a.Infra.Spec.Masters + case Node: + hosts = a.Infra.Spec.Nodes + } + if hosts == nil { + return nil, err + } + instances, err := a.GetInstancesInfo(instanceRole, hosts.Count) + if err != nil { + return nil, err + } + for _, instance := range instances { + ipList = append(ipList, instance.PrimaryIPAddress) + } + return ipList, nil +} + +func (a *AliProvider) GetInstanceStatus(instanceID string) (instanceStatus string, err error) { + request := ecs.CreateDescribeInstanceStatusRequest() + request.Scheme = Scheme + request.InstanceId = &[]string{instanceID} + response := ecs.CreateDescribeInstanceStatusResponse() + err = a.RetryEcsRequest(request, response) + if err != nil { + return "", fmt.Errorf("get SystemInfo status failed %v , error :%v", instanceID, err) + } + if len(response.InstanceStatuses.InstanceStatus) == 0 { + return "", fmt.Errorf("SystemInfo list is empty") + } + return response.InstanceStatuses.InstanceStatus[0].Status, nil +} + +func (a *AliProvider) PoweroffInstance(instanceID string) error { + request := ecs.CreateStopInstancesRequest() + request.Scheme = Scheme + request.InstanceId = &[]string{instanceID} + + response := ecs.CreateStopInstancesResponse() + return a.RetryEcsRequest(request, response) +} + +func (a *AliProvider) StartInstance(instanceID string) error { + request := ecs.CreateStartInstanceRequest() + request.Scheme = Scheme + request.InstanceId = instanceID + + response := ecs.CreateStartInstanceResponse() + return a.RetryEcsRequest(request, response) +} + +func (a *AliProvider) ChangeInstanceType(instanceID, instanceRole string, cpu int, memory float64) error { + instanceStatus, err := a.GetInstanceStatus(instanceID) + if err != nil { + return err + } + if instanceStatus != Stopped { + err = a.PoweroffInstance(instanceID) + if err != nil { + return err + } + } + + expectInstanceType, err := a.GetAvailableResource(instanceRole, cpu, memory) + if err != nil { + return err + } + + request := ecs.CreateModifyInstanceSpecRequest() + request.Scheme = Scheme + request.InstanceId = instanceID + //_, err = d.Client.ModifyInstanceSpec(request) + response := ecs.CreateModifyInstanceSpecResponse() + err = a.RetryEcsInstanceType(request, response, expectInstanceType) + if err != nil { + return err + } + return a.StartInstance(instanceID) +} + +func (a *AliProvider) GetInstancesInfo(instancesRole string, expectCount int) (instances []Instance, err error) { + var count int + tag := make(map[string]string) + tag[Product] = a.Infra.Name + tag[Role] = instancesRole + if expectCount == 0 { + count = -1 + } else { + count = expectCount + } + instancesTags := CreateDescribeInstancesTag(tag) + request := ecs.CreateDescribeInstancesRequest() + request.Scheme = Scheme + request.RegionId = a.Infra.Status.RegionID + request.VSwitchId = a.Infra.Status.VSwitchID + request.SecurityGroupId = a.Infra.Status.SecurityGroupID + request.Tag = &instancesTags + response := ecs.CreateDescribeInstancesResponse() + err = a.TryGetInstance(request, response, count) + if err != nil { + return nil, err + } + + for _, i := range response.Instances.Instance { + instances = append(instances, + Instance{ + CPU: i.Cpu, + Memory: float64(i.Memory / 1024), + InstanceID: i.InstanceId, + PrimaryIPAddress: i.NetworkInterfaces.NetworkInterface[0].PrimaryIpAddress}) + } + return +} + +func (a *AliProvider) ReconcileInstances(instanceRole string) error { + var hosts *v2.Hosts + var instances []Instance + var instancesIDs string + var IPList []string + switch instanceRole { + case Master: + hosts = &a.Infra.Spec.Masters + instancesIDs = a.Infra.Status.MasterIDs + if hosts.Count == 0 { + return errors.New("master count not set") + } + case Node: + hosts = a.Infra.Spec.Nodes + instancesIDs = a.Infra.Status.NodeIDs + if hosts == nil { + return nil + } + } + if hosts == nil { + return errors.New("hosts not set") + } + var err error + if instancesIDs != "" { + instances, err = a.GetInstancesInfo(instanceRole, JustGetInstanceInfo) + } + if err != nil { + return err + } + if i := hosts.Count; len(instances) < i { + err = a.RunInstances(instanceRole, i-len(instances)) + if err != nil { + return err + } + ipList, err := a.InputIPlist(instanceRole) + if err != nil { + return err + } + IPList = utils.AppendIPList(IPList, ipList) + logger.Info("get scale up IP list %v, append iplist %v, host count %s", ipList, IPList, hosts.Count) + } + + for _, instance := range instances { + if instance.CPU != hosts.CPU || instance.Memory != hosts.Memory { + err = a.ChangeInstanceType(instance.InstanceID, instanceRole, hosts.CPU, hosts.Memory) + if err != nil { + return err + } + } + } + if instanceRole == Master { + a.Infra.Status.Masters = IPList + } else { + a.Infra.Status.Nodes = IPList + } + logger.Info("reconcile %s instances success %v ", instanceRole, IPList) + return nil +} + +func (a *AliProvider) DeleteInstances() error { + instanceIDs := strings.Split(a.Infra.Status.ShouldBeDeleteInstancesIDs, ",") + if len(instanceIDs) == 0 { + return nil + } + request := ecs.CreateDeleteInstancesRequest() + request.Scheme = Scheme + request.InstanceId = &instanceIDs + request.Force = requests.NewBoolean(true) + //_, err := d.Client.DeleteInstances(request) + response := ecs.CreateDeleteInstancesResponse() + err := a.RetryEcsRequest(request, response) + if err != nil { + return err + } + a.Infra.Status.ShouldBeDeleteInstancesIDs = "" + return nil +} + +func CreateDescribeInstancesTag(tags map[string]string) (instanceTags []ecs.DescribeInstancesTag) { + for k, v := range tags { + instanceTags = append(instanceTags, ecs.DescribeInstancesTag{Key: k, Value: v}) + } + return +} + +func CreateInstanceDataDisk(dataDisks []string, category string) (instanceDisks []ecs.RunInstancesDataDisk) { + for _, v := range dataDisks { + instanceDisks = append(instanceDisks, + ecs.RunInstancesDataDisk{Size: v, Category: category}) + } + return +} + +type InstanceInfo struct { + InstanceType string + ZoneID string +} + +func (a *AliProvider) GetAvailableResourcesForSystem() (instances *InstanceInfo, err error) { + request := ecs.CreateDescribeAvailableResourceRequest() + request.Scheme = Scheme + if a.Infra.Status.ZoneID != "" { + request.ZoneId = a.Infra.Status.ZoneID + } + if a.Infra.Spec.Instance.Type != "" { + request.InstanceType = a.Infra.Spec.Instance.Type + } + + request.RegionId = a.Infra.Status.RegionID + request.DestinationResource = DestinationResource + request.InstanceChargeType = InstanceChargeType + request.SystemDiskCategory = a.Infra.Spec.Instance.SystemCategory + request.DataDiskCategory = a.Infra.Spec.Instance.DataCategory + request.SpotStrategy = a.Infra.Status.SpotStrategy + + response := ecs.CreateDescribeAvailableResourceResponse() + err = a.EcsClient.DoAction(request, response) + if err != nil { + return nil, err + } + if len(response.AvailableZones.AvailableZone) < 1 { + return nil, fmt.Errorf("resources not find") + } + for _, i := range response.AvailableZones.AvailableZone { + for _, f := range i.AvailableResources.AvailableResource { + for _, r := range f.SupportedResources.SupportedResource { + if r.StatusCategory == AvailableTypeStatus { + return &InstanceInfo{ + InstanceType: r.Value, + ZoneID: i.ZoneId, + }, nil + } + } + } + } + return +} +func (a *AliProvider) GetAvailableResource(instanceRole string, cores int, memory float64) (instanceType []string, err error) { + request := ecs.CreateDescribeAvailableResourceRequest() + request.Scheme = Scheme + request.RegionId = a.Infra.Status.RegionID + request.ZoneId = a.Infra.Status.ZoneID + request.DestinationResource = DestinationResource + request.InstanceChargeType = InstanceChargeType + request.Cores = requests.NewInteger(cores) + request.Memory = requests.NewFloat(memory) + + response := ecs.CreateDescribeAvailableResourceResponse() + err = a.EcsClient.DoAction(request, response) + if err != nil { + return nil, err + } + if len(response.AvailableZones.AvailableZone) < 1 { + return nil, fmt.Errorf("resources not find") + } + for _, i := range response.AvailableZones.AvailableZone { + for _, f := range i.AvailableResources.AvailableResource { + for _, r := range f.SupportedResources.SupportedResource { + if r.StatusCategory == AvailableTypeStatus { + instanceType = append(instanceType, r.Value) + } + } + } + } + var defaultInstanceType []string + switch instanceRole { + case Master: + defaultInstanceType = []string{a.Infra.Status.MasterInstanceType} + case Node: + defaultInstanceType = []string{a.Infra.Status.NodeInstanceType} + } + instanceType = append(defaultInstanceType, instanceType...) + return +} + +func (a *AliProvider) RunInstances(instanceRole string, count int) error { + var hosts *v2.Hosts + switch instanceRole { + case Master: + hosts = &a.Infra.Spec.Masters + case Node: + hosts = a.Infra.Spec.Nodes + } + instances := hosts + if instances == nil { + return errors.New("host not set") + } + systemDiskSize := instances.Disks.System + var instanceType []string + var err error + + instanceType, err = a.GetAvailableResource(instanceRole, instances.CPU, instances.Memory) + if err != nil { + return err + } + tag := make(map[string]string) + tag[Product] = a.Infra.Name + tag[Role] = instanceRole + instancesTag := CreateInstanceTag(tag) + + dataDisks := instances.Disks.Data + datadisk := CreateInstanceDataDisk(dataDisks, a.Infra.Spec.Instance.DataCategory) + + request := ecs.CreateRunInstancesRequest() + request.Scheme = Scheme + request.ImageId = a.Infra.Spec.Instance.ImageID + request.Password = a.Infra.Spec.Auth.Passwd + request.SecurityGroupId = a.Infra.Status.SecurityGroupID + request.VSwitchId = a.Infra.Status.VSwitchID + request.SystemDiskSize = systemDiskSize + request.SystemDiskCategory = a.Infra.Spec.Instance.SystemCategory + request.DataDisk = &datadisk + request.SpotStrategy = a.Infra.Status.SpotStrategy + request.Amount = requests.NewInteger(count) + request.Tag = &instancesTag + //response, err := d.Client.RunInstances(request) + response := ecs.CreateRunInstancesResponse() + err = a.RetryEcsInstanceType(request, response, instanceType) + if err != nil { + return err + } + + instancesIDs := strings.Join(response.InstanceIdSets.InstanceIdSet, ",") + switch instanceRole { + case Master: + a.Infra.Status.MasterIDs += instancesIDs + case Node: + a.Infra.Status.NodeIDs += instancesIDs + } + + return nil +} + +func (a *AliProvider) AuthorizeSecurityGroup(securityGroupID, portRange string) bool { + request := ecs.CreateAuthorizeSecurityGroupRequest() + request.Scheme = Scheme + request.SecurityGroupId = securityGroupID + request.IpProtocol = IPProtocol + request.PortRange = portRange + request.SourceCidrIp = SourceCidrIP + request.Policy = Policy + + response := ecs.CreateAuthorizeSecurityGroupResponse() + err := a.RetryEcsRequest(request, response) + if err != nil { + logger.Error("%v", err) + return false + } + return response.BaseResponse.IsSuccess() +} + +func (a *AliProvider) CreateSecurityGroup() error { + request := ecs.CreateCreateSecurityGroupRequest() + request.Scheme = Scheme + request.RegionId = a.Infra.Status.RegionID + request.VpcId = a.Infra.Status.VpcID + response := ecs.CreateCreateSecurityGroupResponse() + err := a.RetryEcsRequest(request, response) + if err != nil { + return err + } + + if !a.AuthorizeSecurityGroup(response.SecurityGroupId, SSHPortRange) { + return fmt.Errorf("authorize securitygroup ssh port failed") + } + if !a.AuthorizeSecurityGroup(response.SecurityGroupId, APIServerPortRange) { + return fmt.Errorf("authorize securitygroup apiserver port failed") + } + a.Infra.Status.SecurityGroupID = response.SecurityGroupId + return nil +} + +func (a *AliProvider) DeleteSecurityGroup() error { + request := ecs.CreateDeleteSecurityGroupRequest() + request.Scheme = Scheme + request.SecurityGroupId = a.Infra.Status.SecurityGroupID + + response := ecs.CreateDeleteSecurityGroupResponse() + return a.RetryEcsRequest(request, response) +} + +func CreateInstanceTag(tags map[string]string) (instanceTags []ecs.RunInstancesTag) { + for k, v := range tags { + instanceTags = append(instanceTags, ecs.RunInstancesTag{Key: k, Value: v}) + } + return +} + +func LoadConfig(config *Config) error { + config.AccessKey = os.Getenv(EnvAccessKey) + config.AccessSecret = os.Getenv(EnvAccessSecret) + config.regionID = os.Getenv(EnvRegion) + if config.regionID == "" { + config.regionID = DefaultRegionID + } + if config.AccessKey == "" || config.AccessSecret == "" || config.regionID == "" { + return fmt.Errorf("please set accessKey and accessKeySecret ENV, example: export ACCESSKEYID=xxx export ACCESSKEYSECRET=xxx , how to get AK SK: https://ram.console.aliyun.com/manage/ak") + } + return nil +} diff --git a/pkg/infra/aliyun/ali_provider.go b/pkg/infra/aliyun/ali_provider.go new file mode 100644 index 000000000..2cc41b4d6 --- /dev/null +++ b/pkg/infra/aliyun/ali_provider.go @@ -0,0 +1,248 @@ +// Copyright © 2021 Alibaba Group Holding Ltd. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package aliyun + +import ( + "errors" + "strings" + + "github.com/fanux/sealos/pkg/types/validation" + + v2 "github.com/fanux/sealos/pkg/types/v1beta1" + "github.com/fanux/sealos/pkg/utils/logger" + + "github.com/aliyun/alibaba-cloud-sdk-go/services/ecs" + "github.com/aliyun/alibaba-cloud-sdk-go/services/vpc" +) + +type ActionName string + +const ( + CreateVPC ActionName = "CreateVPC" + CreateVSwitch ActionName = "CreateVSwitch" + CreateSecurityGroup ActionName = "CreateSecurityGroup" + ReconcileInstance ActionName = "ReconcileInstance" + BindEIP ActionName = "BindEIP" + ReleaseEIP ActionName = "ReleaseEIP" + ClearInstances ActionName = "ClearInstances" + DeleteVSwitch ActionName = "DeleteVSwitch" + DeleteSecurityGroup ActionName = "DeleteSecurityGroup" + DeleteVPC ActionName = "DeleteVPC" + GetSystemInfo ActionName = "GetSystemInfo" +) + +type AliProvider struct { + Config Config + EcsClient ecs.Client + VpcClient vpc.Client + Infra *v2.Infra +} + +type Config struct { + AccessKey string + AccessSecret string + regionID string +} + +type Alifunc func() error + +func (a *AliProvider) ReconcileResource(resourceKey ResourceName, action Alifunc) error { + if resourceKey.Value(a.Infra.Status) != "" { + logger.Warn("create resource exists %s: %s", resourceKey, resourceKey.Value(a.Infra.Status)) + return nil + } + if err := action(); err != nil { + logger.Error("reconcile resource %s failed err: %s", resourceKey, err) + return err + } + if resourceKey.Value(a.Infra.Status) != "" { + logger.Info("create resource success %s: %s", resourceKey, resourceKey.Value(a.Infra.Status)) + } + return nil +} + +func (a *AliProvider) DeleteResource(resourceKey ResourceName, action Alifunc) { + val := resourceKey.Value(a.Infra.Status) + if val == "" { + logger.Warn("delete resource not exists %s", resourceKey) + return + } + if err := action(); err != nil { + logger.Error("delete resource %s failed err: %s", resourceKey, err) + } else { + logger.Info("delete resource Success %s: %s", resourceKey, val) + } +} + +var RecocileFuncMap = map[ActionName]func(provider *AliProvider) error{ + CreateVPC: func(aliProvider *AliProvider) error { + return aliProvider.ReconcileResource(VpcID, aliProvider.CreateVPC) + }, + + CreateVSwitch: func(aliProvider *AliProvider) error { + return aliProvider.ReconcileResource(VSwitchID, aliProvider.CreateVSwitch) + }, + CreateSecurityGroup: func(aliProvider *AliProvider) error { + return aliProvider.ReconcileResource(SecurityGroupID, aliProvider.CreateSecurityGroup) + }, + ReconcileInstance: func(aliProvider *AliProvider) error { + err := aliProvider.ReconcileInstances(Master) + if err != nil { + return err + } + + err = aliProvider.ReconcileInstances(Node) + if err != nil { + return err + } + return nil + }, + GetSystemInfo: func(aliProvider *AliProvider) error { + return aliProvider.ReconcileResource(SystemInfo, aliProvider.SystemInfo) + }, + BindEIP: func(aliProvider *AliProvider) error { + return aliProvider.ReconcileResource(EipID, aliProvider.BindEipForMaster0) + }, +} + +var DeleteFuncMap = map[ActionName]func(provider *AliProvider){ + ReleaseEIP: func(aliProvider *AliProvider) { + aliProvider.DeleteResource(EipID, aliProvider.ReleaseEipAddress) + }, + ClearInstances: func(aliProvider *AliProvider) { + var instanceIDs []string + roles := []string{Master, Node} + for _, role := range roles { + instances, err := aliProvider.GetInstancesInfo(role, JustGetInstanceInfo) + if err != nil { + logger.Error("get %s instanceinfo failed %v", role, err) + } + for _, instance := range instances { + instanceIDs = append(instanceIDs, instance.InstanceID) + } + } + if len(instanceIDs) != 0 { + aliProvider.Infra.Status.ShouldBeDeleteInstancesIDs = strings.Join(instanceIDs, ",") + } + aliProvider.DeleteResource(ShouldBeDeleteInstancesIDs, aliProvider.DeleteInstances) + }, + DeleteVSwitch: func(aliProvider *AliProvider) { + aliProvider.DeleteResource(VSwitchID, aliProvider.DeleteVSwitch) + }, + DeleteSecurityGroup: func(aliProvider *AliProvider) { + aliProvider.DeleteResource(SecurityGroupID, aliProvider.DeleteSecurityGroup) + }, + DeleteVPC: func(aliProvider *AliProvider) { + aliProvider.DeleteResource(VpcID, aliProvider.DeleteVPC) + }, +} + +func (a *AliProvider) NewClient() error { + ecsClient, err := ecs.NewClientWithAccessKey(a.Config.regionID, a.Config.AccessKey, a.Config.AccessSecret) + if err != nil { + return err + } + vpcClient, err := vpc.NewClientWithAccessKey(a.Config.regionID, a.Config.AccessKey, a.Config.AccessSecret) + if err != nil { + return err + } + a.EcsClient = *ecsClient + a.VpcClient = *vpcClient + a.Infra.Status.RegionID = a.Config.regionID + return nil +} + +func (a *AliProvider) ClearCluster() { + todolist := []ActionName{ + ReleaseEIP, + ClearInstances, + DeleteVSwitch, + DeleteSecurityGroup, + DeleteVPC, + } + for _, name := range todolist { + DeleteFuncMap[name](a) + } +} + +func (a *AliProvider) Reconcile() error { + if a.Infra.Annotations == nil { + a.Infra.Annotations = make(map[string]string) + } + if a.Infra.DeletionTimestamp != nil { + logger.Info("DeletionTimestamp not nil Clear Infra") + a.ClearCluster() + return nil + } + todolist := []ActionName{ + CreateVPC, + GetSystemInfo, + CreateVSwitch, + CreateSecurityGroup, + ReconcileInstance, + BindEIP, + } + + for _, actionname := range todolist { + err := RecocileFuncMap[actionname](a) + if err != nil { + return err + } + } + + return nil +} + +func (a *AliProvider) Apply() error { + if err := v2.Default(a.Infra, defaultInfra); err != nil { + return err + } + if err := validation.ValidateInfra(a.Infra); len(err) != 0 { + return err.ToAggregate() + } + return a.Reconcile() +} + +func defaultInfra(infra *v2.Infra) error { + //https://help.aliyun.com/document_detail/63440.htm?spm=a2c4g.11186623.0.0.f5952752gkxpB7#t9856.html + if infra.Spec.Instance.IsSeize { + infra.Status.SpotStrategy = "SpotAsPriceGo" + } else { + infra.Status.SpotStrategy = "NoSpot" + } + if infra.Spec.Platform == v2.ARM64 { + switch infra.Status.RegionID { + case "cn-shanghai": + infra.Status.ZoneID = "cn-shanghai-l" + case "cn-beijing": + infra.Status.ZoneID = "cn-beijing-k" + case "cn-hangzhou": + infra.Status.ZoneID = "cn-hangzhou-i" + default: + return errors.New("not available ZoneID for arm, support RegionID[cn-shanghai,cn-beijing,cn-hangzhou]") + } + infra.Spec.Instance.ImageID = defaultImageArmID + } else { + infra.Spec.Instance.ImageID = defaultImageAmdID + } + //"cloud_efficiency", "cloud_essd", "cloud_ssd" + if infra.Spec.Instance.SystemCategory == "" { + infra.Spec.Instance.SystemCategory = "cloud_efficiency" + } + if infra.Spec.Instance.DataCategory == "" { + infra.Spec.Instance.DataCategory = "cloud_efficiency" + } + return nil +} diff --git a/pkg/infra/aliyun/ali_vpc.go b/pkg/infra/aliyun/ali_vpc.go new file mode 100644 index 000000000..8020eb7ed --- /dev/null +++ b/pkg/infra/aliyun/ali_vpc.go @@ -0,0 +1,175 @@ +// Copyright © 2021 Alibaba Group Holding Ltd. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package aliyun + +import ( + "errors" + + "github.com/fanux/sealos/pkg/utils/logger" + + "github.com/fanux/sealos/pkg/utils" + + "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/services/vpc" +) + +type VpcManager struct { + Config Config + Client *vpc.Client +} + +func (a *AliProvider) RetryVpcRequest(request requests.AcsRequest, response responses.AcsResponse) error { + return utils.Retry(TryTimes, TrySleepTime, func() error { + err := a.VpcClient.DoAction(request, response) + if err != nil { + return err + } + return nil + }) +} + +func (a *AliProvider) CreateVPC() error { + request := vpc.CreateCreateVpcRequest() + request.Scheme = Scheme + request.RegionId = a.Infra.Status.RegionID + //response, err := d.Client.CreateVpc(request) + response := vpc.CreateCreateVpcResponse() + err := a.RetryVpcRequest(request, response) + if err != nil { + return err + } + a.Infra.Status.VpcID = response.VpcId + return nil +} + +func (a *AliProvider) DeleteVPC() error { + request := vpc.CreateDeleteVpcRequest() + request.Scheme = Scheme + request.VpcId = a.Infra.Status.VpcID + + //response, err := d.Client.DeleteVpc(request) + response := vpc.CreateDeleteVpcResponse() + return a.RetryVpcRequest(request, response) +} + +func (a *AliProvider) CreateVSwitch() error { + request := vpc.CreateCreateVSwitchRequest() + request.Scheme = Scheme + request.ZoneId = a.Infra.Status.ZoneID + request.CidrBlock = CidrBlock + request.VpcId = a.Infra.Status.VpcID + request.RegionId = a.Infra.Status.RegionID + //response, err := d.Client.CreateVSwitch(request) + response := vpc.CreateCreateVSwitchResponse() + err := a.RetryVpcRequest(request, response) + if err != nil { + return err + } + a.Infra.Status.VSwitchID = response.VSwitchId + return nil +} + +func (a *AliProvider) DeleteVSwitch() error { + request := vpc.CreateDeleteVSwitchRequest() + request.Scheme = Scheme + request.VSwitchId = a.Infra.Status.VSwitchID + + response := vpc.CreateDeleteVSwitchResponse() + return a.RetryVpcRequest(request, response) +} + +func (a *AliProvider) SystemInfo() error { + availableInstance, err := a.GetAvailableResourcesForSystem() + if err != nil { + return err + } + a.Infra.Spec.Instance.Type = availableInstance.InstanceType + a.Infra.Status.MasterInstanceType = availableInstance.InstanceType + a.Infra.Status.NodeInstanceType = availableInstance.InstanceType + a.Infra.Status.ZoneID = availableInstance.ZoneID + + logger.Info("fetch resource success %s: %s", "ZoneID", a.Infra.Status.ZoneID) + logger.Info("fetch resource success %s: %s", "InstanceType", a.Infra.Spec.Instance.Type) + return nil +} + +func (a *AliProvider) BindEipForMaster0() error { + instances, err := a.GetInstancesInfo(Master, JustGetInstanceInfo) + if err != nil { + return err + } + if len(instances) == 0 { + return errors.New("can not find master0 ") + } + master0 := instances[0] + eIP, eIPID, err := a.AllocateEipAddress() + if err != nil { + return err + } + err = a.AssociateEipAddress(master0.InstanceID, eIPID) + if err != nil { + return err + } + a.Infra.Status.EIP = eIP + a.Infra.Status.EIPID = eIPID + a.Infra.Status.Master0ID = master0.InstanceID + a.Infra.Status.Master0InternalIP = master0.PrimaryIPAddress + return nil +} + +func (a *AliProvider) AllocateEipAddress() (eIP, eIPID string, err error) { + request := vpc.CreateAllocateEipAddressRequest() + request.Scheme = Scheme + request.Bandwidth = Bandwidth + request.InternetChargeType = InternetChargeType + response := vpc.CreateAllocateEipAddressResponse() + err = a.RetryVpcRequest(request, response) + if err != nil { + return "", "", err + } + return response.EipAddress, response.AllocationId, nil +} + +func (a *AliProvider) AssociateEipAddress(instanceID, eipID string) error { + request := vpc.CreateAssociateEipAddressRequest() + request.Scheme = Scheme + request.InstanceId = instanceID + request.AllocationId = eipID + + response := vpc.CreateAssociateEipAddressResponse() + return a.RetryVpcRequest(request, response) +} + +func (a *AliProvider) UnassociateEipAddress() error { + request := vpc.CreateUnassociateEipAddressRequest() + request.Scheme = Scheme + request.AllocationId = a.Infra.Status.EIPID + request.Force = requests.NewBoolean(true) + response := vpc.CreateUnassociateEipAddressResponse() + return a.RetryVpcRequest(request, response) +} + +func (a *AliProvider) ReleaseEipAddress() error { + err := a.UnassociateEipAddress() + if err != nil { + return err + } + request := vpc.CreateReleaseEipAddressRequest() + request.Scheme = Scheme + request.AllocationId = a.Infra.Status.EIPID + response := vpc.CreateReleaseEipAddressResponse() + return a.RetryVpcRequest(request, response) +} diff --git a/pkg/infra/infra.go b/pkg/infra/infra.go new file mode 100644 index 000000000..a4b5838ac --- /dev/null +++ b/pkg/infra/infra.go @@ -0,0 +1,53 @@ +// Copyright © 2021 Alibaba Group Holding Ltd. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package infra + +import ( + "fmt" + + "github.com/fanux/sealos/pkg/infra/aliyun" + v2 "github.com/fanux/sealos/pkg/types/v1beta1" +) + +type Interface interface { + // Apply apply iaas resources and save metadata info like vpc instance id to cluster status + // https://github.com/fanux/sealgate/tree/master/cloud + Apply() error +} + +func newAliProvider(infra *v2.Infra) (Interface, error) { + config := new(aliyun.Config) + err := aliyun.LoadConfig(config) + if err != nil { + return nil, err + } + aliProvider := new(aliyun.AliProvider) + aliProvider.Config = *config + aliProvider.Infra = infra + err = aliProvider.NewClient() + if err != nil { + return nil, err + } + return aliProvider, nil +} + +func NewDefaultProvider(infra *v2.Infra) (Interface, error) { + switch infra.Spec.Provider { + case v2.AliyunProvider: + return newAliProvider(infra) + default: + return nil, fmt.Errorf("the provider is invalid, please set the provider correctly") + } +} diff --git a/pkg/infra/infra_test.go b/pkg/infra/infra_test.go new file mode 100644 index 000000000..4932727d4 --- /dev/null +++ b/pkg/infra/infra_test.go @@ -0,0 +1,123 @@ +// Copyright © 2021 Alibaba Group Holding Ltd. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package infra + +import ( + "fmt" + "os" + "testing" + "time" + + "sigs.k8s.io/yaml" + + v2 "github.com/fanux/sealos/pkg/types/v1beta1" + + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +func TestApply(t *testing.T) { + //setup infra + password := os.Getenv("SealosPassword") + infra := v2.Infra{ + TypeMeta: metav1.TypeMeta{ + Kind: "Infra", + APIVersion: v2.SchemeGroupVersion.String(), + }, + ObjectMeta: metav1.ObjectMeta{ + Name: "my-infra", + }, + Spec: v2.InfraSpec{ + Instance: v2.Instance{ + IsSeize: true, + Type: "ecs.c6r.large", + }, + Platform: v2.ARM64, + Masters: v2.Hosts{ + Count: 1, + CPU: 2, + Memory: 4, + Disks: v2.Disks{ + System: "100", + Data: []string{"100"}, + }, + }, + Nodes: &v2.Hosts{ + Count: 1, + CPU: 2, + Memory: 4, + Disks: v2.Disks{ + System: "100", + Data: []string{"100"}, + }, + }, + Provider: v2.AliyunProvider, + Auth: v2.Auth{ + Passwd: password, + }, + }, + } + + aliProvider, err := NewDefaultProvider(&infra) + if err != nil { + fmt.Printf("%v", err) + } else { + fmt.Printf("%v", aliProvider.Apply()) + } + + t.Run("modify instance type", func(t *testing.T) { + infra.Spec.Masters.CPU = 4 + infra.Spec.Masters.Memory = 8 + infra.Spec.Nodes.CPU = 4 + infra.Spec.Nodes.Memory = 8 + fmt.Printf("%v", aliProvider.Apply()) + }) + + t.Run("add instance count", func(t *testing.T) { + infra.Spec.Masters.Count = 5 + infra.Spec.Nodes.Count = 5 + fmt.Printf("%v", aliProvider.Apply()) + fmt.Printf("%v \n", infra.Spec.Masters) + fmt.Printf("%v \n", infra.Spec.Nodes) + }) + + t.Run("reduce instance count", func(t *testing.T) { + infra.Spec.Masters.Count = 1 + infra.Spec.Nodes.Count = 1 + fmt.Printf("%v", aliProvider.Apply()) + }) + + t.Run("modify instance type & count both", func(t *testing.T) { + infra.Spec.Masters.CPU = 8 + infra.Spec.Masters.Memory = 16 + infra.Spec.Nodes.CPU = 8 + infra.Spec.Nodes.Memory = 16 + infra.Spec.Masters.Count = 5 + infra.Spec.Nodes.Count = 5 + fmt.Printf("%v", aliProvider.Apply()) + }) + + // todo + t.Run("modify instance system disk", func(t *testing.T) { + + }) + + j, _ := yaml.Marshal(&infra) + t.Log("output yaml:", string(j)) + //teardown + time.Sleep(20 * time.Second) + now := metav1.Now() + infra.ObjectMeta.DeletionTimestamp = &now + t.Log(fmt.Sprintf("%v", aliProvider.Apply())) +} diff --git a/pkg/install/check.go b/pkg/install/check.go index 21ab53690..062d6923c 100644 --- a/pkg/install/check.go +++ b/pkg/install/check.go @@ -18,7 +18,7 @@ import ( "fmt" "os" - v1 "github.com/fanux/sealos/pkg/types/v1" + v1 "github.com/fanux/sealos/pkg/types/v1alpha1" "github.com/fanux/sealos/pkg/utils" "github.com/fanux/sealos/pkg/cni" diff --git a/pkg/install/clean.go b/pkg/install/clean.go index 001f024e1..c477740f2 100644 --- a/pkg/install/clean.go +++ b/pkg/install/clean.go @@ -20,7 +20,7 @@ import ( "strings" "sync" - v1 "github.com/fanux/sealos/pkg/types/v1" + v1 "github.com/fanux/sealos/pkg/types/v1alpha1" "github.com/fanux/sealos/pkg/utils" "github.com/fanux/sealos/pkg/utils/ssh" diff --git a/pkg/install/cloud.go b/pkg/install/cloud.go deleted file mode 100644 index 49567b563..000000000 --- a/pkg/install/cloud.go +++ /dev/null @@ -1,202 +0,0 @@ -// Copyright © 2021 sealos. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package install - -import ( - "fmt" - "os" - "strings" - - v1 "github.com/fanux/sealos/pkg/types/v1" - - "github.com/fanux/sealos/pkg/utils/logger" - - "github.com/fanux/sealgate/cloud" - extver "github.com/linuxsuren/cobra-extension/version" -) - -//VersionURL is base64 encode k8s version and offline package url -var ( - VersionURL string - URLMap map[string]string - DefaultURL = "https://sealyun.oss-cn-beijing.aliyuncs.com/37374d999dbadb788ef0461844a70151-1.16.0/kube1.16.0.tar.gz" -) - -//Flags is command line paras -type Flags struct { - Master int - MasterType string - Node int - NodeType string - Version string - Flavor string - Passwd string - Zone string - Interaction bool - Image string -} - -// Cluster is cluster metadata -type Cluster struct { - cloud.Config - Flags - Name string - Masters []cloud.VM - Nodes []cloud.VM - VPCID string - SwitchID string - SecuretyGroupID string -} - -var C Cluster -var ClusterDir = v1.DefaultConfigPath + "/clusters/" - -// 2019.11.28 今天刚修完陪产假,在新装修的公寓中写代码,刚配的眼镜感觉带着有点不舒服,看屏幕不是很清楚 -/* - 配眼镜的人也不是很专业,二宝还是个女儿,非常可爱而且非常乖,不像大宝那么吵。 一直很想写日记但是不知道往哪里写合适 - 既然github要把代码存两千年那为啥不写到代码里,如此这便成为我第一篇代码日记。 - - 碳纤维地暖开了半天还是冰凉的,感觉是被忽悠了。 - - 一写代码就精神万分,一搞管理上的杂事就效率很低,所以做技术还是要专注些。 -*/ -func CloudInstall(c *Cluster) { - URLMap = make(map[string]string) - URLMap["v1.16.0"] = DefaultURL - - config := c.Config - p := cloud.NewProvider(config) - - _ = v1.Dump(fmt.Sprintf("%s%s.yaml", ClusterDir, c.Name), c) - - //TODO concurrence create master and nodes vms, should not create two vpcs - /* - var wg sync.WaitGroup - wg.Add(2) - - go func() { - // create masters vms - res, err := p.Create(newRequest(c, "master", true, c.Master)) - if err != nil { - logger.Error("init cluster failed: %s", err) - return - } - c.Masters = res.VMs - c.VPCID = res.VPCID - c.SwitchID = res.SwitchID - c.SecuretyGroupID = res.SecuretyGroupID - wg.Done() - }() - - go func() { - // create nodes vms - res, err := p.Create(newRequest(c, "node", false, c.Node)) - if err != nil { - logger.Error("init cluster failed: %s", err) - return - } - c.Nodes = res.VMs - wg.Done() - }() - wg.Wait() - */ - // create masters vms - res, err := p.Create(newRequest(c, "master", true, c.Master)) - if err != nil { - logger.Error("init cluster failed: %s", err) - return - } - c.Masters = res.VMs - c.VPCID = res.VPCID - c.SwitchID = res.SwitchID - c.SecuretyGroupID = res.SecuretyGroupID - - // create nodes vms - res, err = p.Create(newRequest(c, "node", false, c.Node)) - if err != nil { - logger.Error("init cluster failed: %s", err) - return - } - c.Nodes = res.VMs - - //TODO wget package on master0 and scp to other nodes - logger.Info("wait few minute for download offline package on master0...") - cmd := newWgetCommand(c) - CmdWorkSpace(c.Masters[0].FIP, cmd, "/root") - - // exec sealos init on master0 - cmd = newCommand(c) - CmdWorkSpace(c.Masters[0].FIP, cmd, "/root") -} - -func getURL(version string) string { - url, ok := URLMap[version] - if !ok { - logger.Error("version offline package not found: %s", version) - os.Exit(1) - return DefaultURL - } - return url -} - -func getLocalURL(version string) string { - return fmt.Sprintf("/root/kube%s.tar.gz", version[1:]) -} - -func newCommand(c *Cluster) string { - //TODO should download it on master0 and copy to other nodes - version := extver.GetVersion() - if strings.HasPrefix(version, "v") { - version = strings.TrimPrefix(version, "v") - } - releaseURL := fmt.Sprintf("https://github.com/fanux/sealos/releases/download/v%s/sealos_%s_linux_amd64.tar.gz", - version, version) - cmd := fmt.Sprintf("wget %s -O -| tar -xz && chmod +x sealos", releaseURL) - cmd += fmt.Sprintf(" && ./sealos init --passwd %s --pkg-url %s --version %s", c.Passwd, getLocalURL(c.Version), c.Version) - for _, master := range c.Masters { - cmd += fmt.Sprintf(" --master %s", master.IP) - } - for _, node := range c.Nodes { - cmd += fmt.Sprintf(" --node %s", node.IP) - } - return cmd -} - -func newWgetCommand(c *Cluster) string { - cmd := fmt.Sprintf("cd /root && wget %s", getURL(c.Version)) - return cmd -} - -func newRequest(c *Cluster, namePrefix string, fip bool, num int) cloud.Request { - r := cloud.Request{ - Num: num, - Image: c.Flags.Image, - NamePrefix: namePrefix, - FIP: fip, - Flavor: c.Flags.Flavor, - Passwd: c.Flags.Passwd, - ZoneID: c.Flags.Zone, - VPCID: c.VPCID, - SwitchID: c.SwitchID, - SecuretyGroupID: c.SecuretyGroupID, - } - return r -} - -// CmdWorkSpace exec cmd on specified workdir. -func CmdWorkSpace(node, cmd, workdir string) { - command := fmt.Sprintf("cd %s && %s", workdir, cmd) - _ = v1.SSHConfig.CmdAsync(node, command) -} diff --git a/pkg/install/etcd_restore.go b/pkg/install/etcd_restore.go index b3568ef1f..75ab03ab9 100644 --- a/pkg/install/etcd_restore.go +++ b/pkg/install/etcd_restore.go @@ -22,7 +22,7 @@ import ( "sync" "time" - v1 "github.com/fanux/sealos/pkg/types/v1" + v1 "github.com/fanux/sealos/pkg/types/v1alpha1" "github.com/fanux/sealos/pkg/utils" "github.com/fanux/sealos/pkg/utils/ssh" diff --git a/pkg/install/etcd_save.go b/pkg/install/etcd_save.go index f60f9e7dc..e52173930 100644 --- a/pkg/install/etcd_save.go +++ b/pkg/install/etcd_save.go @@ -23,7 +23,7 @@ import ( "sync" "time" - v1 "github.com/fanux/sealos/pkg/types/v1" + v1 "github.com/fanux/sealos/pkg/types/v1alpha1" "github.com/fanux/sealos/pkg/utils" "github.com/fanux/sealos/pkg/utils/ssh" diff --git a/pkg/install/exec.go b/pkg/install/exec.go index d6c04af3a..01bea7da3 100644 --- a/pkg/install/exec.go +++ b/pkg/install/exec.go @@ -15,11 +15,12 @@ package install import ( + "fmt" "os" "strings" "sync" - v1 "github.com/fanux/sealos/pkg/types/v1" + v1 "github.com/fanux/sealos/pkg/types/v1alpha1" "github.com/fanux/sealos/pkg/utils" "github.com/fanux/sealos/pkg/kubernetes/nodeclient" @@ -154,3 +155,9 @@ func (e *ExecFlag) execByNodeIP() { } wg.Wait() } + +// CmdWorkSpace exec cmd on specified workdir. +func CmdWorkSpace(node, cmd, workdir string) { + command := fmt.Sprintf("cd %s && %s", workdir, cmd) + _ = v1.SSHConfig.CmdAsync(node, command) +} diff --git a/pkg/install/exit.go b/pkg/install/exit.go index 618a23d09..8e3011753 100644 --- a/pkg/install/exit.go +++ b/pkg/install/exit.go @@ -15,7 +15,7 @@ package install import ( - v1 "github.com/fanux/sealos/pkg/types/v1" + v1 "github.com/fanux/sealos/pkg/types/v1alpha1" "github.com/fanux/sealos/pkg/utils" "github.com/fanux/sealos/pkg/utils/logger" ) diff --git a/pkg/install/generator.go b/pkg/install/generator.go index 04ef2d904..5399c26d4 100644 --- a/pkg/install/generator.go +++ b/pkg/install/generator.go @@ -20,7 +20,7 @@ import ( "strings" "text/template" - v1 "github.com/fanux/sealos/pkg/types/v1" + v1 "github.com/fanux/sealos/pkg/types/v1alpha1" "github.com/fanux/sealos/pkg/utils" "github.com/fanux/sealos/pkg/utils/logger" diff --git a/pkg/install/generator_test.go b/pkg/install/generator_test.go index 347c5e9eb..fa3930a2e 100644 --- a/pkg/install/generator_test.go +++ b/pkg/install/generator_test.go @@ -18,7 +18,7 @@ import ( "reflect" "testing" - v1 "github.com/fanux/sealos/pkg/types/v1" + v1 "github.com/fanux/sealos/pkg/types/v1alpha1" "github.com/fanux/sealos/pkg/utils" "github.com/fanux/sealos/pkg/utils/ssh" diff --git a/pkg/install/init.go b/pkg/install/init.go index 65de13bae..35edfa27b 100644 --- a/pkg/install/init.go +++ b/pkg/install/init.go @@ -24,7 +24,7 @@ import ( "path/filepath" "strings" - v1 "github.com/fanux/sealos/pkg/types/v1" + v1 "github.com/fanux/sealos/pkg/types/v1alpha1" "github.com/fanux/sealos/pkg/utils" "github.com/fanux/sealos/pkg/utils/ssh" diff --git a/pkg/install/join.go b/pkg/install/join.go index 41bccc206..025461309 100644 --- a/pkg/install/join.go +++ b/pkg/install/join.go @@ -19,7 +19,7 @@ import ( "strings" "sync" - v1 "github.com/fanux/sealos/pkg/types/v1" + v1 "github.com/fanux/sealos/pkg/types/v1alpha1" "github.com/fanux/sealos/pkg/utils" "github.com/fanux/sealos/pkg/utils/ssh" diff --git a/pkg/install/sealos.go b/pkg/install/sealos.go index 7c02d0214..727fd51ea 100644 --- a/pkg/install/sealos.go +++ b/pkg/install/sealos.go @@ -18,7 +18,7 @@ import ( "fmt" "strings" - v1 "github.com/fanux/sealos/pkg/types/v1" + v1 "github.com/fanux/sealos/pkg/types/v1alpha1" "github.com/fanux/sealos/pkg/utils" "github.com/fanux/sealos/pkg/cni" diff --git a/pkg/install/send.go b/pkg/install/send.go index a35a2601e..a9eaf4cb3 100755 --- a/pkg/install/send.go +++ b/pkg/install/send.go @@ -18,7 +18,7 @@ import ( "fmt" "path" - v1 "github.com/fanux/sealos/pkg/types/v1" + v1 "github.com/fanux/sealos/pkg/types/v1alpha1" "github.com/fanux/sealos/pkg/utils" "github.com/fanux/sealos/pkg/utils/ssh" ) diff --git a/pkg/install/upgrade.go b/pkg/install/upgrade.go index 2c7b6af4d..47fff13fb 100644 --- a/pkg/install/upgrade.go +++ b/pkg/install/upgrade.go @@ -19,7 +19,7 @@ import ( "os" "time" - v1 "github.com/fanux/sealos/pkg/types/v1" + v1 "github.com/fanux/sealos/pkg/types/v1alpha1" "github.com/fanux/sealos/pkg/utils" nodeclient2 "github.com/fanux/sealos/pkg/kubernetes/nodeclient" diff --git a/pkg/kubernetes/apis/version/version.go b/pkg/kubernetes/apis/version/version.go deleted file mode 100644 index 72727b503..000000000 --- a/pkg/kubernetes/apis/version/version.go +++ /dev/null @@ -1,37 +0,0 @@ -/* -Copyright 2014 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package version - -// Info contains versioning information. -// TODO: Add []string of api versions supported? It's still unclear -// how we'll want to distribute that information. -type Info struct { - Major string `json:"major"` - Minor string `json:"minor"` - GitVersion string `json:"gitVersion"` - GitCommit string `json:"gitCommit"` - GitTreeState string `json:"gitTreeState"` - BuildDate string `json:"buildDate"` - GoVersion string `json:"goVersion"` - Compiler string `json:"compiler"` - Platform string `json:"platform"` -} - -// String returns info as a human-friendly version string. -func (info Info) String() string { - return info.GitVersion -} diff --git a/pkg/kubernetes/cert/kubeconfig.go b/pkg/kubernetes/cert/kubeconfig.go index 7fae7f012..b204d8c6b 100644 --- a/pkg/kubernetes/cert/kubeconfig.go +++ b/pkg/kubernetes/cert/kubeconfig.go @@ -228,7 +228,7 @@ func validateKubeConfig(outDir, filename string, config *clientcmdapi.Config) er } currentCluster := currentCtx.Cluster if currentConfig.Clusters[currentCluster] == nil { - return errors.Errorf("failed to find the given CurrentContext Cluster in Clusters of the kubeconfig file %s", kubeConfigFilePath) + return errors.Errorf("failed to find the given CurrentContext Infra in Clusters of the kubeconfig file %s", kubeConfigFilePath) } // Make sure the compared CAs are whitespace-trimmed. The function clientcmd.LoadFromFile() just decodes diff --git a/pkg/kubernetes/kubeconfig/kubeconfig.go b/pkg/kubernetes/kubeconfig/kubeconfig.go index 2c0794283..670b0509d 100644 --- a/pkg/kubernetes/kubeconfig/kubeconfig.go +++ b/pkg/kubernetes/kubeconfig/kubeconfig.go @@ -16,7 +16,7 @@ package kubeconfig import clientcmdapi "k8s.io/client-go/tools/clientcmd/api" -// GetClusterFromKubeConfig returns the default Cluster of the specified KubeConfig +// GetClusterFromKubeConfig returns the default Infra of the specified KubeConfig func GetClusterFromKubeConfig(config *clientcmdapi.Config) *clientcmdapi.Cluster { // If there is an unnamed cluster object, use it if config.Clusters[""] != nil { diff --git a/pkg/kubernetes/nodeclient/node.go b/pkg/kubernetes/nodeclient/node.go index ad0a6435c..126f6a9a7 100644 --- a/pkg/kubernetes/nodeclient/node.go +++ b/pkg/kubernetes/nodeclient/node.go @@ -19,7 +19,7 @@ import ( "fmt" "time" - v12 "github.com/fanux/sealos/pkg/types/v1" + v12 "github.com/fanux/sealos/pkg/types/v1alpha1" "github.com/fanux/sealos/pkg/utils" v1 "k8s.io/api/core/v1" diff --git a/pkg/types/v1/types.go b/pkg/types/v1alpha1/types.go similarity index 81% rename from pkg/types/v1/types.go rename to pkg/types/v1alpha1/types.go index c8ef8d85d..56b27e264 100644 --- a/pkg/types/v1/types.go +++ b/pkg/types/v1alpha1/types.go @@ -12,19 +12,19 @@ // See the License for the specific language governing permissions and // limitations under the License. -package v1 +package v1alpha1 import ( "fmt" "io/ioutil" "os" + "sigs.k8s.io/yaml" + "github.com/fanux/sealos/pkg/utils" "github.com/fanux/sealos/pkg/cni" "github.com/fanux/sealos/pkg/utils/logger" - - v2 "gopkg.in/yaml.v2" ) const ( @@ -44,40 +44,40 @@ type Metadata struct { // SealConfig for ~/.sealos/config.yaml type SealConfig struct { - Masters []string - Nodes []string + Masters []string `json:"masters"` + Nodes []string `json:"nodes"` //config from kubeadm.cfg. ex. cluster.local - DNSDomain string - APIServerCertSANs []string + DNSDomain string `json:"dnsdomain"` + APIServerCertSANs []string `json:"apiservercertsans"` //SSHConfig - User string - Passwd string - PrivateKey string - PkPassword string + User string `json:"user"` + Passwd string `json:"passwd"` + PrivateKey string `json:"privatekey"` + PkPassword string `json:"pkpassword"` //ApiServer ex. apiserver.cluster.local - APIServerDomain string - Network string - VIP string - PkgURL string - Version string - Repo string - PodCIDR string - SvcCIDR string + APIServerDomain string `json:"apiserverdomain"` + Network string `json:"network"` + VIP string `json:"vip"` + PkgURL string `json:"pkgurl"` + Version string `json:"version"` + Repo string `json:"repo"` + PodCIDR string `json:"podcidr"` + SvcCIDR string `json:"svccidr"` //certs location - CertPath string - CertEtcdPath string + CertPath string `json:"certpath"` + CertEtcdPath string `json:"certetcdpath"` //lvscare images - LvscareName string - LvscareTag string - AliOss + LvscareName string `json:"lvscarename"` + LvscareTag string `json:"lvscaretag"` + AliOss `json:"alioss"` } type AliOss struct { - OssEndpoint string - AccessKeyID string - AccessKeySecrets string - BucketName string - ObjectPath string + OssEndpoint string `json:"ossendpoint"` + AccessKeyID string `json:"accesskeyid"` + AccessKeySecrets string `json:"accesskeysecrets"` + BucketName string `json:"bucketname"` + ObjectPath string `json:"objectpath"` } //Dump is @@ -115,7 +115,7 @@ func (c *SealConfig) Dump(path string) { c.AliOss.OssEndpoint = OssEndpoint c.AliOss.BucketName = BucketName c.AliOss.ObjectPath = ObjectPath - y, err := v2.Marshal(c) + y, err := yaml.Marshal(c) if err != nil { logger.Error("dump config file failed: %s", err) } @@ -131,7 +131,7 @@ func (c *SealConfig) Dump(path string) { } func Dump(path string, content interface{}) error { - y, err := v2.Marshal(content) + y, err := yaml.Marshal(content) if err != nil { logger.Error("dump config file failed: %s", err) return err @@ -157,7 +157,7 @@ func (c *SealConfig) Load(path string) (err error) { return fmt.Errorf("read config file %s failed %w", path, err) } - err = v2.Unmarshal(y, c) + err = yaml.Unmarshal(y, c) if err != nil { return fmt.Errorf("unmarshal config file failed: %w", err) } @@ -203,7 +203,7 @@ func Load(path string, content interface{}) error { os.Exit(0) } - err = v2.Unmarshal(y, content) + err = yaml.Unmarshal(y, content) if err != nil { logger.Error("unmarshal config file failed: %s", err) } @@ -231,7 +231,7 @@ func (c *SealConfig) ShowDefaultConfig() { c.LvscareName = "fanux/lvscare" c.LvscareTag = "latest" - y, err := v2.Marshal(c) + y, err := yaml.Marshal(c) if err != nil { logger.Error("marshal config file failed: %s", err) } diff --git a/pkg/types/v1/vars.go b/pkg/types/v1alpha1/vars.go similarity index 99% rename from pkg/types/v1/vars.go rename to pkg/types/v1alpha1/vars.go index f4e100b3c..b0cd0d148 100644 --- a/pkg/types/v1/vars.go +++ b/pkg/types/v1alpha1/vars.go @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -package v1 +package v1alpha1 import ( "strconv" diff --git a/pkg/types/v1beta1/defaults.go b/pkg/types/v1beta1/defaults.go new file mode 100644 index 000000000..7952c8bf1 --- /dev/null +++ b/pkg/types/v1beta1/defaults.go @@ -0,0 +1,67 @@ +/* +Copyright 2021 cuisongliu@qq.com. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v1beta1 + +import ( + "math/rand" + "time" +) + +func Default(infra *Infra, fn func(infra *Infra) error) error { + if string(infra.Spec.Platform) == "" { + infra.Spec.Platform = AMD64 + } + if infra.Spec.Auth.User == "" { + infra.Spec.Auth.User = "root" + } + if infra.Spec.Masters.CPU <= 0 { + infra.Spec.Masters.CPU = 2 + } + if infra.Spec.Masters.Memory <= 0 { + infra.Spec.Masters.Memory = 4 + } + if len(infra.Spec.Masters.Disks.System) == 0 { + infra.Spec.Masters.Disks.System = "40" + } + if infra.Spec.Auth.Passwd == "" { + infra.Spec.Auth.Passwd = createPassword() + } + return fn(infra) +} + +const ( + digits = "0123456789" + specials = "~=+%^*/()[]{}/!@#$?|" + letter = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" + passwordLength = 16 +) + +func createPassword() string { + rand.Seed(time.Now().UnixNano()) + all := digits + specials + letter + length := passwordLength + buf := make([]byte, length) + buf[0] = digits[rand.Intn(len(digits))] + buf[1] = specials[rand.Intn(len(specials))] + for i := 2; i < length; i++ { + buf[i] = all[rand.Intn(len(all))] + } + rand.Shuffle(len(buf), func(i, j int) { + buf[i], buf[j] = buf[j], buf[i] + }) + return string(buf) +} diff --git a/pkg/types/v1beta1/doc.go b/pkg/types/v1beta1/doc.go new file mode 100644 index 000000000..42bf9350b --- /dev/null +++ b/pkg/types/v1beta1/doc.go @@ -0,0 +1,21 @@ +// Copyright © 2021 sealos. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// +k8s:deepcopy-gen=package +// +k8s:protobuf-gen=package +// +k8s:openapi-gen=false +// +k8s:defaulter-gen=TypeMeta +// +groupName=apps.sealyun.com + +package v1beta1 diff --git a/pkg/types/v1beta1/register.go b/pkg/types/v1beta1/register.go new file mode 100644 index 000000000..b65345c8e --- /dev/null +++ b/pkg/types/v1beta1/register.go @@ -0,0 +1,25 @@ +// Copyright © 2021 sealos. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package v1beta1 + +import ( + "k8s.io/apimachinery/pkg/runtime/schema" +) + +// GroupName is the group name use in this package +const GroupName = "apps.sealyun.com" + +// SchemeGroupVersion is group version used to register these objects +var SchemeGroupVersion = schema.GroupVersion{Group: GroupName, Version: "v1"} diff --git a/pkg/types/v1beta1/types.go b/pkg/types/v1beta1/types.go new file mode 100644 index 000000000..06973d811 --- /dev/null +++ b/pkg/types/v1beta1/types.go @@ -0,0 +1,123 @@ +// Copyright © 2021 sealos. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package v1beta1 + +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +// EDIT THIS FILE! THIS IS SCAFFOLDING FOR YOU TO OWN! +// NOTE: json tags are required. Any new fields you add must have json tags for the fields to be serialized. + +type Provider string + +const ( + AliyunProvider Provider = "AliyunProvider" +) + +type Platform string + +const ( + AMD64 Platform = "amd64" + ARM64 Platform = "arm64" +) + +type Auth struct { + User string `json:"user,omitempty"` + Passwd string `json:"passwd,omitempty"` +} + +type Hosts struct { + CPU int `json:"cpu,omitempty"` + Memory float64 `json:"memory,omitempty"` + Count int `json:"count,omitempty"` + Disks Disks `json:"disks"` +} +type Disks struct { + System string `json:"system,omitempty"` + Data []string `json:"data,omitempty"` +} + +type Instance struct { + SystemCategory string `json:"systemCategory,omitempty"` + DataCategory string `json:"dataCategory,omitempty"` + Type string `json:"type,omitempty"` + IsSeize bool `json:"isSeize,omitempty"` + ImageID string `json:"imageID,omitempty"` +} + +// InfraSpec defines the desired state of Infra +type InfraSpec struct { + // INSERT ADDITIONAL SPEC FIELDS - desired state of Infra + // Important: Run "make" to regenerate code after modifying this file + Instance Instance `json:"instance"` + // Foo is an example field of Infra. Edit types.go to remove/update + Provider Provider `json:"provider,omitempty"` + Platform Platform `json:"platform,omitempty"` + + Auth Auth `json:"auth,omitempty"` + Masters Hosts `json:"masters,omitempty"` + Nodes *Hosts `json:"nodes,omitempty"` +} + +// InfraStatus defines the observed state of Infra +type InfraStatus struct { + ZoneID string `json:"zoneID,omitempty"` + RegionID string `json:"regionID,omitempty"` + + VpcID string `json:"vpcID,omitempty"` + VSwitchID string `json:"vSwitchID,omitempty"` + SecurityGroupID string `json:"securityGroupID,omitempty"` + + Master0ID string `json:"master0ID,omitempty"` + Master0InternalIP string `json:"master0InternalIP,omitempty"` + EIP string `json:"eip,omitempty"` + EIPID string `json:"eipID,omitempty"` + + MasterIDs string `json:"masterIDs,omitempty"` + NodeIDs string `json:"nodeIDs,omitempty"` + + Masters []string `json:"masters,omitempty"` + Nodes []string `json:"nodes,omitempty"` + + MasterInstanceType string `json:"masterInstanceType,omitempty"` + NodeInstanceType string `json:"nodeInstanceType,omitempty"` + + SpotStrategy string `json:"spotStrategy,omitempty"` + ShouldBeDeleteInstancesIDs string `json:"shouldBeDeleteInstancesIDs,omitempty"` +} + +// +kubebuilder:object:root=true +// +kubebuilder:subresource:status +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// Infra is the Schema for the Infras API +type Infra struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + Spec InfraSpec `json:"spec,omitempty"` + Status InfraStatus `json:"status,omitempty"` +} + +// +kubebuilder:object:root=true +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// InfraList contains a list of Infra +type InfraList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + Items []Infra `json:"items"` +} diff --git a/pkg/types/v1beta1/zz_generated.deepcopy.go b/pkg/types/v1beta1/zz_generated.deepcopy.go new file mode 100644 index 000000000..382bbc9de --- /dev/null +++ b/pkg/types/v1beta1/zz_generated.deepcopy.go @@ -0,0 +1,204 @@ +// +build !ignore_autogenerated + +// Copyright © 2021 sealos. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated by deepcopy-gen. DO NOT EDIT. + +package v1beta1 + +import ( + runtime "k8s.io/apimachinery/pkg/runtime" +) + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Auth) DeepCopyInto(out *Auth) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Auth. +func (in *Auth) DeepCopy() *Auth { + if in == nil { + return nil + } + out := new(Auth) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Disks) DeepCopyInto(out *Disks) { + *out = *in + if in.Data != nil { + in, out := &in.Data, &out.Data + *out = make([]string, len(*in)) + copy(*out, *in) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Disks. +func (in *Disks) DeepCopy() *Disks { + if in == nil { + return nil + } + out := new(Disks) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Hosts) DeepCopyInto(out *Hosts) { + *out = *in + in.Disks.DeepCopyInto(&out.Disks) + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Hosts. +func (in *Hosts) DeepCopy() *Hosts { + if in == nil { + return nil + } + out := new(Hosts) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Infra) DeepCopyInto(out *Infra) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + in.Spec.DeepCopyInto(&out.Spec) + in.Status.DeepCopyInto(&out.Status) + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Infra. +func (in *Infra) DeepCopy() *Infra { + if in == nil { + return nil + } + out := new(Infra) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *Infra) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *InfraList) DeepCopyInto(out *InfraList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]Infra, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new InfraList. +func (in *InfraList) DeepCopy() *InfraList { + if in == nil { + return nil + } + out := new(InfraList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *InfraList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *InfraSpec) DeepCopyInto(out *InfraSpec) { + *out = *in + out.Instance = in.Instance + out.Auth = in.Auth + in.Masters.DeepCopyInto(&out.Masters) + if in.Nodes != nil { + in, out := &in.Nodes, &out.Nodes + *out = new(Hosts) + (*in).DeepCopyInto(*out) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new InfraSpec. +func (in *InfraSpec) DeepCopy() *InfraSpec { + if in == nil { + return nil + } + out := new(InfraSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *InfraStatus) DeepCopyInto(out *InfraStatus) { + *out = *in + if in.Masters != nil { + in, out := &in.Masters, &out.Masters + *out = make([]string, len(*in)) + copy(*out, *in) + } + if in.Nodes != nil { + in, out := &in.Nodes, &out.Nodes + *out = make([]string, len(*in)) + copy(*out, *in) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new InfraStatus. +func (in *InfraStatus) DeepCopy() *InfraStatus { + if in == nil { + return nil + } + out := new(InfraStatus) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Instance) DeepCopyInto(out *Instance) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Instance. +func (in *Instance) DeepCopy() *Instance { + if in == nil { + return nil + } + out := new(Instance) + in.DeepCopyInto(out) + return out +} diff --git a/pkg/types/validation/validation.go b/pkg/types/validation/validation.go new file mode 100644 index 000000000..502e9b69b --- /dev/null +++ b/pkg/types/validation/validation.go @@ -0,0 +1,94 @@ +// Copyright © 2021 sealos. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package validation + +import ( + "github.com/fanux/sealos/pkg/types/v1beta1" + apiequality "k8s.io/apimachinery/pkg/api/equality" + apimachineryvalidation "k8s.io/apimachinery/pkg/api/validation" + "k8s.io/apimachinery/pkg/util/validation/field" +) + +// ValidateInfraName validates that the given name can be used as a infra name. +var ValidateInfraName = apimachineryvalidation.NameIsDNSSubdomain + +func validateHosts(hosts *v1beta1.Hosts, fldPath *field.Path) field.ErrorList { + allErrors := field.ErrorList{} + if hosts.Count == 0 { + allErrors = append(allErrors, field.Invalid(fldPath.Key("count"), hosts.Count, + "hosts count not set")) + } + if hosts.CPU == 0 { + allErrors = append(allErrors, field.Invalid(fldPath.Key("cpu"), hosts.Count, + "hosts cpu not set")) + } + if hosts.Memory == 0 { + allErrors = append(allErrors, field.Invalid(fldPath.Key("memory"), hosts.Count, + "hosts memory not set")) + } + if len(hosts.Disks.System) == 0 { + allErrors = append(allErrors, field.Invalid(fldPath.Child("disks").Key("system"), hosts.Count, + "hosts system disk not set")) + } + return allErrors +} + +func ValidateInfra(infra *v1beta1.Infra) field.ErrorList { + allErrors := apimachineryvalidation.ValidateObjectMeta(&infra.ObjectMeta, false, ValidateInfraName, field.NewPath("metadata")) + allErrors = append(allErrors, validateInfraSpec(&infra.Spec, field.NewPath("spec"))...) + return allErrors +} +func validateInfraSpec(spec *v1beta1.InfraSpec, fldPath *field.Path) field.ErrorList { + allErrors := field.ErrorList{} + + allErrors = append(allErrors, validateHosts(&spec.Masters, fldPath.Child("masters"))...) + + if spec.Nodes != nil { + allErrors = append(allErrors, validateHosts(spec.Nodes, fldPath.Child("nodes"))...) + } + + switch spec.Platform { + case v1beta1.ARM64: + case v1beta1.AMD64: + default: + allErrors = append(allErrors, field.Invalid(fldPath.Key("platform"), spec.Platform, + "spec platform not support")) + } + + return allErrors +} +func ValidateInfraUpdate(infra, oldInfra *v1beta1.Infra) field.ErrorList { + allErrs := apimachineryvalidation.ValidateObjectMetaUpdate(&infra.ObjectMeta, &oldInfra.ObjectMeta, field.NewPath("metadata")) + newInfraClone := infra.DeepCopy() + if newInfraClone.Spec.Provider != oldInfra.Spec.Provider { + allErrs = append(allErrs, field.Forbidden(field.NewPath("spec").Key("provider"), "fields can't modify are forbidden")) + } + if newInfraClone.Spec.Platform != oldInfra.Spec.Platform { + allErrs = append(allErrs, field.Forbidden(field.NewPath("spec").Key("platform"), "fields can't modify are forbidden")) + } + if !apiequality.Semantic.DeepEqual(newInfraClone.Spec.Auth, oldInfra.Spec.Auth) { + allErrs = append(allErrs, field.Forbidden(field.NewPath("spec").Key("auth"), "fields can't modify are forbidden")) + } + if !apiequality.Semantic.DeepEqual(newInfraClone.Spec.Masters.Disks, oldInfra.Spec.Masters.Disks) { + allErrs = append(allErrs, field.Forbidden(field.NewPath("spec").Child("masters").Key("disks"), "fields can't modify are forbidden")) + } + if newInfraClone.Spec.Nodes != nil && oldInfra.Spec.Nodes != nil { + if !apiequality.Semantic.DeepEqual(newInfraClone.Spec.Nodes.Disks, oldInfra.Spec.Nodes.Disks) { + allErrs = append(allErrs, field.Forbidden(field.NewPath("spec").Child("nodes").Key("disks"), "fields can't modify are forbidden")) + } + } + + return allErrs +} diff --git a/pkg/utils/file.go b/pkg/utils/file.go index 32e5e09a3..144264670 100644 --- a/pkg/utils/file.go +++ b/pkg/utils/file.go @@ -17,13 +17,11 @@ package utils import ( "fmt" "os" - - "github.com/fanux/sealos/pkg/utils/logger" ) const md5sumCmd = "md5sum %s | cut -d\" \" -f1" -func FromLocal(localPath string) string { +func Md5File(localPath string) string { cmd := fmt.Sprintf(md5sumCmd, localPath) return BashEval(cmd) } @@ -37,13 +35,11 @@ func UserHomeDir() string { return home } -func FileExist(filename string) bool { - _, err := os.Stat(filename) - if !os.IsNotExist(err) { - if err == nil { - return true - } - logger.Warn(err) +func FileExist(path string) bool { + _, err := os.Stat(path) + if err == nil || os.IsExist(err) { + return true } + return false } diff --git a/pkg/utils/hosts.go b/pkg/utils/hosts.go new file mode 100644 index 000000000..465e1220d --- /dev/null +++ b/pkg/utils/hosts.go @@ -0,0 +1,195 @@ +// Copyright © 2021 sealos. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package utils + +import ( + "bufio" + "errors" + "fmt" + "io" + "os" + "strings" + + "github.com/fanux/sealos/pkg/utils/logger" +) + +type HostFile struct { + Path string + Hosts map[string]*Hostname +} + +type Hostname struct { + Comment string + Domain string + IP string +} + +func NewHostname(comment string, domain string, ip string) *Hostname { + return &Hostname{comment, domain, ip} +} +func (h *HostFile) Add(host *Hostname) { + if h.Hosts == nil { + h.Hosts = make(map[string]*Hostname) + } + h.Hosts[host.Domain] = host +} + +func (h *HostFile) Delete(host string) { + delete(h.Hosts, host) +} + +func getHostPath() string { + path := os.Getenv("GOHOST_FILE") + if path == "" { + path = "/etc/hosts" + } + return path +} + +func (h *Hostname) toString() string { + if len(h.Comment) > 0 { + h.Comment += "\n" + } + return h.Comment + h.IP + " " + h.Domain + "\n" +} +func appendToFile(filePath string, hostname *Hostname) { + fp, err := os.OpenFile(filePath, os.O_WRONLY|os.O_APPEND, 0644) + if err != nil { + logger.Warn("failed opening file %s : %s\n", filePath, err) + return + } + defer fp.Close() + + _, err = fp.WriteString(hostname.toString()) + if err != nil { + logger.Warn("failed append string: %s: %s\n", filePath, err) + return + } +} + +func (h *HostFile) ParseHostFile(path string) (map[string]*Hostname, error) { + if !FileExist(path) { + logger.Warn("path %s is not exists", path) + return nil, errors.New("path %s is not exists") + } + + fp, fpErr := os.Open(path) + if fpErr != nil { + logger.Warn("open file '%s' failed\n", path) + return nil, fmt.Errorf("open file '%s' failed ", path) + } + defer fp.Close() + + br := bufio.NewReader(fp) + hostnameMap := make(map[string]*Hostname) + curComment := "" + for { + str, rErr := br.ReadString('\n') + if rErr == io.EOF { + break + } + if len(str) == 0 || str == "\r\n" || IsEmptyLine(str) { + continue + } + + if str[0] == '#' { + // 处理注释 + curComment += str + continue + } + tmpHostnameArr := strings.Fields(str) + curDomain := TrimWS(tmpHostnameArr[1]) + if !CheckDomain(curDomain) { + return hostnameMap, errors.New(" file contain error domain" + curDomain) + } + curIP := TrimWS(tmpHostnameArr[0]) + checkIP := CheckIP(curIP) + if !checkIP { + return hostnameMap, nil + } + tmpHostname := NewHostname(curComment, curDomain, curIP) + hostnameMap[tmpHostname.Domain] = tmpHostname + + curComment = "" + } + + return hostnameMap, nil +} + +func (h *HostFile) AppendHost(domain string, ip string) { + if domain == "" || ip == "" { + return + } + + hostname := NewHostname("", domain, ip) + appendToFile(getHostPath(), hostname) +} + +func (h *HostFile) writeToFile(hostnameMap map[string]*Hostname, path string) { + if !FileExist(path) { + logger.Warn("path %s is not exists", path) + return + } + + fp, err := os.OpenFile(path, os.O_WRONLY|os.O_TRUNC|os.O_CREATE, 0644) + if err != nil { + logger.Warn("open file '%s' failed: %v", path, err) + return + } + defer fp.Close() + + for _, mapVal := range hostnameMap { + _, writeErr := fp.WriteString(mapVal.toString()) + if writeErr != nil { + logger.Warn(writeErr) + return + } + } +} + +func (h *HostFile) DeleteDomain(domain string) { + if domain == "" { + return + } + + currHostsMap, parseErr := h.ParseHostFile(getHostPath()) + if parseErr != nil { + logger.Warn("parse file failed" + parseErr.Error()) + return + } + + if len(currHostsMap) == 0 || currHostsMap[domain] == nil { + logger.Warn("domain %s not exist\n", domain) + return + } + + delete(currHostsMap, domain) + h.writeToFile(currHostsMap, getHostPath()) +} + +func (h *HostFile) ListCurrentHosts() { + currHostsMap, parseErr := h.ParseHostFile(getHostPath()) + if parseErr != nil { + logger.Warn("parse file failed" + parseErr.Error()) + return + } + if len(currHostsMap) == 0 { + return + } + + for _, mapVal := range currHostsMap { + fmt.Println(mapVal.toString()) + } +} diff --git a/pkg/utils/http.go b/pkg/utils/http.go index 671b9bc10..7047077f3 100644 --- a/pkg/utils/http.go +++ b/pkg/utils/http.go @@ -32,7 +32,7 @@ func DownloadFile(location string) (filePATH, md5 string) { location = absPATH } //file md5 - md5 = FromLocal(location) + md5 = Md5File(location) return location, md5 } diff --git a/pkg/utils/iputils.go b/pkg/utils/iputils.go index 850b7be9d..444fe7ed4 100644 --- a/pkg/utils/iputils.go +++ b/pkg/utils/iputils.go @@ -20,7 +20,7 @@ import ( "fmt" "math/big" "net" - "os" + "net/url" "strings" "github.com/fanux/sealos/pkg/utils/logger" @@ -87,24 +87,34 @@ func AssemblyIPList(args *string) error { *args = result return nil } -func CheckIP(i string) bool { - if !strings.Contains(i, ":") { - return net.ParseIP(i) != nil - } - if _, err := net.ResolveTCPAddr("tcp", i); err != nil { +func CheckIP(ipStr string) bool { + host, _, err := net.SplitHostPort(ipStr) + if err != nil { return false } - return true + ip := net.ParseIP(host) + if _, err = net.ResolveTCPAddr("tcp", ipStr); err != nil { + return false + } + return ip != nil } //IPFormat is -func IPFormat(host string) string { - ipAndPort := strings.Split(host, ":") - if len(ipAndPort) != 2 { - logger.Error("invalied host fomat [%s], must like 172.0.0.2:22", host) - os.Exit(1) +func IPFormat(ipStr string) string { + ip := net.ParseIP(ipStr) + if ip == nil { + host, _, err := net.SplitHostPort(ipStr) + if err != nil { + logger.Error("invalied host fomat [%s], must like 172.0.0.2:22.error: %s", ipStr, err) + return "" + } + ip = net.ParseIP(host) } - return ipAndPort[0] + if ip == nil { + logger.Error("invalied host fomat [%s], must like 172.0.0.2:22", ipStr) + return "" + } + return ip.String() } func HostnameAndIP(node []string) ([]string, []string) { @@ -166,3 +176,8 @@ func RemoveDeduplicate(a []string) []string { } return res } + +func CheckDomain(domain string) bool { + _, errURL := url.Parse(domain) + return errURL == nil +} diff --git a/pkg/utils/logger/conn.go b/pkg/utils/logger/conn.go index dc2e790ff..ccbde187d 100755 --- a/pkg/utils/logger/conn.go +++ b/pkg/utils/logger/conn.go @@ -41,7 +41,6 @@ func (c *connLogger) Init(jsonConfig string) error { if len(jsonConfig) == 0 { return nil } - fmt.Printf("consoleWriter Init:%s\n", jsonConfig) err := json.Unmarshal([]byte(jsonConfig), c) if err != nil { return err diff --git a/pkg/utils/logger/console.go b/pkg/utils/logger/console.go index f8db0c647..48f8a99e4 100755 --- a/pkg/utils/logger/console.go +++ b/pkg/utils/logger/console.go @@ -16,7 +16,6 @@ package logger import ( "encoding/json" - "fmt" "os" "runtime" "sync" @@ -59,7 +58,6 @@ func (c *consoleLogger) Init(jsonConfig string) error { if len(jsonConfig) == 0 { return nil } - fmt.Printf("consoleWriter Init:%s\n", jsonConfig) err := json.Unmarshal([]byte(jsonConfig), c) if runtime.GOOS == "windows" { c.Colorful = false diff --git a/pkg/utils/logger/log.go b/pkg/utils/logger/log.go index a64d1e3c4..bd92e9c09 100755 --- a/pkg/utils/logger/log.go +++ b/pkg/utils/logger/log.go @@ -153,7 +153,7 @@ func (r *LocalLogger) SetLogger(adapterName string, configs ...string) error { } config := append(configs, "{}")[0] - var num int = -1 + var num = -1 var i int var l *nameLogger for i, l = range r.outputs { diff --git a/pkg/utils/retry.go b/pkg/utils/retry.go new file mode 100644 index 000000000..b30757caf --- /dev/null +++ b/pkg/utils/retry.go @@ -0,0 +1,33 @@ +// Copyright © 2021 Alibaba Group Holding Ltd. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package utils + +import ( + "fmt" + "time" +) + +func Retry(tryTimes int, trySleepTime time.Duration, action func() error) error { + var err error + for i := 0; i < tryTimes; i++ { + err = action() + if err == nil { + return nil + } + + time.Sleep(trySleepTime * time.Duration(2*i+1)) + } + return fmt.Errorf("retry action timeout: %v", err) +} diff --git a/pkg/utils/ssh/scp.go b/pkg/utils/ssh/scp.go index 83cd9acc7..9014368e8 100644 --- a/pkg/utils/ssh/scp.go +++ b/pkg/utils/ssh/scp.go @@ -39,7 +39,7 @@ func (ss *SSH) CopyForMD5(host, localFilePath, remoteFilePath, md5 string) bool //如果有md5则可以验证 //如果没有md5则拿到本地数据后验证 if md5 == "" { - md5 = utils.FromLocal(localFilePath) + md5 = utils.Md5File(localFilePath) } logger.Debug("[ssh]source file md5 value is %s", md5) ss.Copy(host, localFilePath, remoteFilePath) @@ -362,7 +362,7 @@ func (ss *SSH) copyLocalFileToRemote(host string, sshClient *ssh.Client, sftpCli func (ss *SSH) isCopyMd5Success(sshClient *ssh.Client, localFile, remoteFile string) bool { cmd := fmt.Sprintf("md5sum %s | cut -d\" \" -f1", remoteFile) - localMd5 := utils.FromLocal(localFile) + localMd5 := utils.Md5File(localFile) sshSession, err := sshClient.NewSession() if err != nil { return false @@ -399,7 +399,7 @@ func (ss *SSH) isCopyMd5Success(sshClient *ssh.Client, localFile, remoteFile str } func (ss *SSH) ValidateMd5sumLocalWithRemote(host, localFile, remoteFile string) bool { - localMd5 := utils.FromLocal(localFile) + localMd5 := utils.Md5File(localFile) return localMd5 == ss.Md5Sum(host, remoteFile) } diff --git a/pkg/utils/ssh/types.go b/pkg/utils/ssh/types.go index 06667dc52..8272ea1db 100644 --- a/pkg/utils/ssh/types.go +++ b/pkg/utils/ssh/types.go @@ -14,7 +14,9 @@ package ssh -import "time" +import ( + "time" +) type SSH struct { User string diff --git a/pkg/utils/strings.go b/pkg/utils/strings.go index 4dd83464d..48873e821 100644 --- a/pkg/utils/strings.go +++ b/pkg/utils/strings.go @@ -20,6 +20,7 @@ import ( "bytes" "math/rand" "net" + "regexp" "sort" "strings" "time" @@ -110,7 +111,7 @@ func ContainList(list []string, toComplete string) (containerList []string) { // RandString 生成随机字符串 func RandString(len int) string { - var r *rand.Rand = rand.New(rand.NewSource(time.Now().Unix())) + var r = rand.New(rand.NewSource(time.Now().Unix())) bytes := make([]byte, len) for i := 0; i < len; i++ { b := r.Intn(26) + 65 @@ -118,3 +119,13 @@ func RandString(len int) string { } return string(bytes) } + +func IsEmptyLine(str string) bool { + re := regexp.MustCompile(`^\s*$`) + + return re.MatchString(str) +} + +func TrimWS(str string) string { + return strings.Trim(str, " \n\t") +} diff --git a/pkg/utils/version.go b/pkg/utils/version.go index 6df8f0bed..975c8d685 100644 --- a/pkg/utils/version.go +++ b/pkg/utils/version.go @@ -108,3 +108,33 @@ func VersionToIntAll(version string) int { } return 0 } + +//VersionCompare is version compare +// if v1 >= v2 return true, else return false +func VersionCompare(v1, v2 string) bool { + v1 = strings.Replace(v1, "v", "", -1) + v2 = strings.Replace(v2, "v", "", -1) + v1 = strings.Split(v1, "-")[0] + v2 = strings.Split(v2, "-")[0] + v1List := strings.Split(v1, ".") + v2List := strings.Split(v2, ".") + + if len(v1List) != 3 || len(v2List) != 3 { + logger.Error("error version format %s %s", v1, v2) + return false + } + if v1List[0] > v2List[0] { + return true + } else if v1List[0] < v2List[0] { + return false + } + if v1List[1] > v2List[1] { + return true + } else if v1List[1] < v2List[1] { + return false + } + if v1List[2] > v2List[2] { + return true + } + return true +} diff --git a/pkg/version/base.go b/pkg/version/base.go new file mode 100644 index 000000000..6f6d94482 --- /dev/null +++ b/pkg/version/base.go @@ -0,0 +1,52 @@ +// Copyright © 2021 sealos. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package version + +// Base version information. +// +// This is the fallback data used when version information from git is not +// provided via go ldflags. It provides an approximation of the Kubernetes +// version for ad-hoc builds (e.g. `go build`) that cannot get the version +// information from git. +// +// If you are looking at these fields in the git tree, they look +// strange. They are modified on the fly by the build process. The +// in-tree values are dummy values used for "git archive", which also +// works for GitHub tar downloads. +// +// When releasing a new Kubernetes version, this file is updated by +// build/mark_new_version.sh to reflect the new version, and then a +// git annotated tag (using format vX.Y where X == Major version and Y +// == Minor version) is created to point to the commit that updates +// component-base/version/base.go +var ( + // semantic version, derived by build scripts (see + // https://github.com/kubernetes/community/blob/master/contributors/design-proposals/release/versioning.md + // for a detailed discussion of this field) + // + // TODO: This field is still called "gitVersion" for legacy + // reasons. For prerelease versions, the build metadata on the + // semantic version is a git hash, but the version itself is no + // longer the direct output of "git describe", but a slight + // translation to be semver compliant. + + // NOTE: The $Format strings are replaced during 'git archive' thanks to the + // companion .gitattributes file containing 'export-subst' in this same + // directory. See also https://git-scm.com/docs/gitattributes + gitVersion = "latest" + gitCommit = "" // sha1 from git, output of $(git rev-parse HEAD) + + buildDate = "1970-01-01T00:00:00Z" // build date in ISO8601 format, output of $(date -u +'%Y-%m-%dT%H:%M:%SZ') +) diff --git a/pkg/version/types.go b/pkg/version/types.go new file mode 100644 index 000000000..9ceb824b8 --- /dev/null +++ b/pkg/version/types.go @@ -0,0 +1,32 @@ +// Copyright © 2021 sealos. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package version + +// Info contains versioning information. +// TODO: Add []string of api versions supported? It's still unclear +// how we'll want to distribute that information. +type Info struct { + GitVersion string `json:"gitVersion"` + GitCommit string `json:"gitCommit,omitempty"` + BuildDate string `json:"buildDate"` + GoVersion string `json:"goVersion"` + Compiler string `json:"compiler"` + Platform string `json:"platform"` +} + +// String returns info as a human-friendly version string. +func (info Info) String() string { + return info.GitVersion +} diff --git a/pkg/version/version.go b/pkg/version/version.go new file mode 100644 index 000000000..9c16f45a5 --- /dev/null +++ b/pkg/version/version.go @@ -0,0 +1,35 @@ +// Copyright © 2021 sealos. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package version + +import ( + "fmt" + "runtime" +) + +// Get returns the overall codebase version. It's for detecting +// what code a binary was built from. +func Get() Info { + // These variables typically come from -ldflags settings and in + // their absence fallback to the settings in ./base.go + return Info{ + GitVersion: gitVersion, + GitCommit: gitCommit, + BuildDate: buildDate, + GoVersion: runtime.Version(), + Compiler: runtime.Compiler, + Platform: fmt.Sprintf("%s/%s", runtime.GOOS, runtime.GOARCH), + } +} diff --git a/test/cronjob.yaml.example b/test/old/cronjob.yaml.example similarity index 100% rename from test/cronjob.yaml.example rename to test/old/cronjob.yaml.example diff --git a/test/join-node-and-nodes.sh b/test/old/join-node-and-nodes.sh similarity index 100% rename from test/join-node-and-nodes.sh rename to test/old/join-node-and-nodes.sh diff --git a/test/network-cird-test.sh b/test/old/network-cird-test.sh similarity index 100% rename from test/network-cird-test.sh rename to test/old/network-cird-test.sh diff --git a/test/note.sh b/test/old/note.sh similarity index 100% rename from test/note.sh rename to test/old/note.sh diff --git a/test/test-sealos-beijing.sh b/test/old/test-sealos-beijing.sh similarity index 100% rename from test/test-sealos-beijing.sh rename to test/old/test-sealos-beijing.sh diff --git a/test/test.sh b/test/old/test.sh similarity index 100% rename from test/test.sh rename to test/old/test.sh diff --git a/test/testUpgrade.md b/test/old/testUpgrade.md similarity index 100% rename from test/testUpgrade.md rename to test/old/testUpgrade.md diff --git a/test/testforlocal.sh b/test/old/testforlocal.sh similarity index 100% rename from test/testforlocal.sh rename to test/old/testforlocal.sh diff --git a/test/testhelper/helper.go b/test/testhelper/helper.go new file mode 100644 index 000000000..d0369cfac --- /dev/null +++ b/test/testhelper/helper.go @@ -0,0 +1,50 @@ +// Copyright © 2021 sealos. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package testhelper + +import ( + "errors" + "fmt" + "io" + "os/exec" + + "github.com/fanux/sealos/test/testhelper/settings" + + "github.com/onsi/ginkgo" + "github.com/onsi/gomega" + "github.com/onsi/gomega/gexec" +) + +// Start sealos cmd and return *gexec.Session +func Start(cmdLine string) (*gexec.Session, error) { + if cmdLine == "" { + return nil, errors.New("failed to start cmd, line is empty") + } + cmdLine = fmt.Sprintf("sudo -E %s", cmdLine) + execCmd := exec.Command("/bin/bash", "-c", cmdLine) // #nosec + _, err := io.WriteString(ginkgo.GinkgoWriter, fmt.Sprintf("%s\n", cmdLine)) + if err != nil { + return nil, err + } + return gexec.Start(execCmd, ginkgo.GinkgoWriter, ginkgo.GinkgoWriter) +} + +// RunCmdAndCheckResult start cmd and check expectedCode +func RunCmdAndCheckResult(cmdLine string, expectedCode int) *gexec.Session { + sess, err := Start(cmdLine) + gomega.Expect(err).NotTo(gomega.HaveOccurred()) + gomega.Eventually(sess, settings.MaxWaiteTime).Should(gexec.Exit(expectedCode)) + return sess +} diff --git a/test/testhelper/settings/common.go b/test/testhelper/settings/common.go new file mode 100644 index 000000000..3dbd0a997 --- /dev/null +++ b/test/testhelper/settings/common.go @@ -0,0 +1,53 @@ +// Copyright © 2021 sealos. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package settings + +import ( + "os" + "path/filepath" + "time" + + "github.com/mitchellh/go-homedir" +) + +const ( + SealerBinPath = "/usr/local/bin/sealos" + SubCmdInitOfSealos = "init" + DefaultSSHPassword = "Sealos123" +) + +const ( + FileMode0755 = 0755 + FileMode0644 = 0644 +) + +var ( + DefaultPollingInterval time.Duration + MaxWaiteTime time.Duration + DefaultWaiteTime time.Duration + DefaultSealosBin = "" + DefaultTestEnvDir = "" + + AccessKey = os.Getenv("ACCESSKEYID") + AccessSecret = os.Getenv("ACCESSKEYSECRET") +) + +func GetWorkDir() string { + home, err := homedir.Dir() + if err != nil { + return "" + } + return filepath.Join(home, ".sealos") +} diff --git a/test/testhelper/settings/settings.go b/test/testhelper/settings/settings.go new file mode 100644 index 000000000..ac97eaad3 --- /dev/null +++ b/test/testhelper/settings/settings.go @@ -0,0 +1,42 @@ +// Copyright © 2021 sealos. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package settings + +import ( + "os" + "time" +) + +// init test params and settings +func init() { + defaultWaiteTime := os.Getenv("DEFAULT_WAITE_TIME") + if defaultWaiteTime == "" { + DefaultWaiteTime = 300 * time.Second + } else { + DefaultWaiteTime, _ = time.ParseDuration(defaultWaiteTime) + } + + maxWaiteTime := os.Getenv("MAX_WAITE_TIME") + if maxWaiteTime == "" { + MaxWaiteTime = 2400 * time.Second + } else { + MaxWaiteTime, _ = time.ParseDuration(maxWaiteTime) + } + + pollingInterval := os.Getenv("DEFAULT_POLLING_INTERVAL") + if pollingInterval == "" { + DefaultPollingInterval = 10 + } +} diff --git a/test/testhelper/utils.go b/test/testhelper/utils.go new file mode 100644 index 000000000..deae6f21e --- /dev/null +++ b/test/testhelper/utils.go @@ -0,0 +1,155 @@ +// Copyright © 2021 sealos. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package testhelper + +import ( + "fmt" + "io/ioutil" + "os" + "path/filepath" + "time" + + "github.com/fanux/sealos/pkg/types/v1beta1" + "github.com/fanux/sealos/pkg/utils" + "github.com/fanux/sealos/pkg/utils/ssh" + "github.com/fanux/sealos/test/testhelper/settings" + + "github.com/onsi/gomega" + "github.com/onsi/gomega/gexec" + "sigs.k8s.io/yaml" +) + +func GetPwd() string { + pwd, err := os.Getwd() + CheckErr(err) + return pwd +} + +func CreateTempFile() string { + dir := os.TempDir() + file, err := ioutil.TempFile(dir, "tmpfile") + CheckErr(err) + defer CheckErr(file.Close()) + return file.Name() +} + +func RemoveTempFile(file string) { + CheckErr(os.Remove(file)) +} + +func WriteFile(fileName string, content []byte) error { + dir := filepath.Dir(fileName) + if _, err := os.Stat(dir); os.IsNotExist(err) { + if err = os.MkdirAll(dir, settings.FileMode0755); err != nil { + return err + } + } + + if err := ioutil.WriteFile(fileName, content, settings.FileMode0644); err != nil { + return err + } + return nil +} + +type SSHClient struct { + RemoteHostIP string + SSH *ssh.SSH +} + +func NewSSHClientByInfra(infra *v1beta1.Infra) *SSHClient { + config := &ssh.SSH{ + User: infra.Spec.Auth.User, + Password: infra.Spec.Auth.Passwd, + Timeout: nil, + } + return &SSHClient{ + RemoteHostIP: infra.Status.EIP, + SSH: config, + } +} + +func IsFileExist(filename string) bool { + _, err := os.Stat(filename) + return !os.IsNotExist(err) +} + +func UnmarshalYamlFile(file string, obj interface{}) error { + data, err := ioutil.ReadFile(filepath.Clean(file)) + if err != nil { + return err + } + err = yaml.Unmarshal(data, obj) + return err +} + +func MarshalYamlToFile(file string, obj interface{}) error { + data, err := yaml.Marshal(obj) + if err != nil { + return err + } + if err = WriteFile(file, data); err != nil { + return err + } + return nil +} + +// GetFileDataLocally get file data for cloud apply +func GetFileDataLocally(filePath string) string { + cmd := fmt.Sprintf("sudo -E cat %s", filePath) + result, _, err := utils.BashWithStdout(cmd) + CheckErr(err) + return result +} + +// DeleteFileLocally delete file for cloud apply +func DeleteFileLocally(filePath string) { + cmd := fmt.Sprintf("sudo -E rm -rf %s", filePath) + _, err := utils.Bash(cmd) + CheckErr(err) +} + +func CheckErr(err error) { + gomega.Expect(err).NotTo(gomega.HaveOccurred()) +} + +func CheckNotNil(obj interface{}) { + gomega.Expect(obj).NotTo(gomega.BeNil()) +} + +func CheckEqual(obj1 interface{}, obj2 interface{}) { + gomega.Expect(obj1).To(gomega.Equal(obj2)) +} + +func CheckNotEqual(obj1 interface{}, obj2 interface{}) { + gomega.Expect(obj1).NotTo(gomega.Equal(obj2)) +} + +func CheckExit0(sess *gexec.Session, waitTime time.Duration) { + gomega.Eventually(sess, waitTime).Should(gexec.Exit(0)) +} +func CheckNotExit0(sess *gexec.Session, waitTime time.Duration) { + gomega.Eventually(sess, waitTime).ShouldNot(gexec.Exit(0)) +} + +func CheckFuncBeTrue(f func() bool, t time.Duration) { + gomega.Eventually(f(), t).Should(gomega.BeTrue()) +} + +func CheckBeTrue(b bool) { + gomega.Eventually(b).Should(gomega.BeTrue()) +} +func CheckNotBeTrue(b bool) { + gomega.Eventually(b).ShouldNot(gomega.BeTrue()) +}