Compare commits

..

49 Commits

Author SHA1 Message Date
Ashwathi Shiva
339bb6f44a minor fixes 2020-04-24 14:35:51 -04:00
Ashwathi Shiva
443092dd2f tidied up go mod 2020-04-24 14:31:38 -04:00
Ashwathi Shiva
9b633b1088 removing previously used lib for color printing 2020-04-24 14:29:28 -04:00
Ashwathi Shiva
f0110294fc commit go.mod and go.sum files 2020-04-24 14:23:57 -04:00
Ashwathi Shiva
28372e81c9 Merge branch 'master' into preflight_cleanup_cmd
# Conflicts:
#	cmd/qliksense/preflight.go
#	pkg/preflight/all_checks.go
2020-04-24 14:23:12 -04:00
Ashwathi Shiva
a8133ed3f7 Added verbose logs in appropriate places 2020-04-24 13:53:05 -04:00
Andriy Bulynko
8255fe0971 Adding a concurrency test for a version of qlik-oss config (#343) 2020-04-24 11:35:52 -04:00
Ashwathi Shiva
f5a9ecd071 preflight clean working 2020-04-24 00:25:32 -04:00
Ashwathi Shiva
3b7db7aae6 Preflight cleanup individual checks working 2020-04-23 16:38:44 -04:00
Sanat Nayar
d9bea9b0fd Merge pull request #342 from qlik-oss/chalk_replacement
Chalk Library Replaced with Aurora
2020-04-23 10:47:53 -04:00
Sanat Nayar
0dd136f07b changed chalk in preflight 2020-04-22 22:44:42 -04:00
Sanat Nayar
9ec9801bea deleted files 2020-04-22 17:06:55 -04:00
Sanat Nayar
d48212ec8f Merge branch 'master' into chalk_replacement 2020-04-22 16:50:32 -04:00
Sanat Nayar
546a2caf3e deleted files 2020-04-22 16:49:28 -04:00
Sanat Nayar
0c26d8bb46 deleted files 2020-04-22 16:43:29 -04:00
Sanat Nayar
92cdcf2b84 changed context display to aurora 2020-04-22 16:34:46 -04:00
Andriy Bulynko
2eae380287 Upgrading kustomize api to version qlik/v0.0.21 (#341) 2020-04-22 16:23:46 -04:00
Sanat Nayar
5dd6a08e65 changed levensthein to aurora 2020-04-22 15:48:23 -04:00
Ashwathi Shiva
ed7e97332b Preflight fix output to remove symbols (#340)
* removed symbols and have all preflight checks working
2020-04-22 09:01:07 -04:00
Sanat Nayar
4b7674261c added functionality to add multiple folders 2020-04-21 17:56:31 -04:00
Sanat Nayar
2ea4366653 added recursive folder addition 2020-04-21 17:22:42 -04:00
Ashwathi Shiva
eb7517f88d Preflight beautify output (#332)
* kubernetes version check fixed with new output style
2020-04-20 09:02:55 -04:00
Foysal Iqbal
ea048f1b5f Unify install apply (#328) 2020-04-16 17:04:21 -04:00
Ilir Bekteshi
0992286e23 [action] test on supported platforms (#319) (#321)
* [action] test on supported platforms (#319)

* [action] install make on windows

* [action] go@beta to clean WFs from workarounds

* [action] Remove MacOS from matrix
2020-04-16 17:16:40 +02:00
Foysal Iqbal
6d87fadae0 Install latest (#326) 2020-04-16 10:29:56 -04:00
Andriy Bulynko
04e2cc5b22 install and apply commands can pull/push images (#322) 2020-04-16 09:58:01 -04:00
Andriy Bulynko
7b7cd7b4bf Fixing windows tests (#324) 2020-04-15 16:41:38 -04:00
Ashwathi Shiva
7a0bbcd5d8 Preflight mongo (#325)
* preflight mongo check working with ca cert
2020-04-15 16:17:21 -04:00
Sanat Nayar
6b6ef14fb1 Merge pull request #318 from qlik-oss/uninstall_confirm
Uninstall Confirmation
2020-04-15 16:03:16 -04:00
Sanat Nayar
fa0c6528e4 Merge pull request #317 from qlik-oss/context_delete
Delete Context Confirmation
2020-04-15 16:02:09 -04:00
Sanat Nayar
e6070a33c2 changed to bool 2020-04-15 10:04:53 -04:00
Sanat Nayar
0c9f264ed2 changed to bool 2020-04-15 10:01:09 -04:00
Sanat Nayar
22b9b902a9 modified tests 2020-04-15 09:32:36 -04:00
Ilir Bekteshi
3a49745622 Merge pull request #269 from qlik-oss/docs2
Update docs
2020-04-14 20:16:14 +02:00
Sanat Nayar
5795988d01 added flags 2020-04-14 13:46:40 -04:00
Sanat Nayar
e9b359c1bd changes 2020-04-14 13:31:52 -04:00
Ilir Bekteshi
044e00afc5 [docs] reorder cmds, cleanup about cmd 2020-04-14 14:07:12 +02:00
Ilir Bekteshi
2f718649f4 [docs] preflight cleanup 2020-04-14 13:42:03 +02:00
Ilir Bekteshi
c6fe7084f5 remove preflight page 2020-04-14 13:17:39 +02:00
Ilir Bekteshi
e60ce7d62d Update docs 2020-04-14 13:17:34 +02:00
Sanat Nayar
6093552ba9 changes 2020-04-13 17:33:44 -04:00
Sanat Nayar
449642e6f4 changes 2020-04-13 17:32:57 -04:00
Sanat Nayar
97b6cf21a7 changes 2020-04-13 17:14:58 -04:00
Sanat Nayar
14b6447154 changes 2020-04-13 17:09:10 -04:00
Sanat Nayar
1c60ce4cc0 changes 2020-04-13 16:57:04 -04:00
Sanat Nayar
7a8926773f changes 2020-04-13 16:50:33 -04:00
Sanat Nayar
0b868732a7 changes 2020-04-13 16:48:35 -04:00
Sanat Nayar
4f2581cde2 changes 2020-04-13 15:52:12 -04:00
Sanat Nayar
cb78b4da9f added confirmation for context-delete 2020-03-27 16:26:31 -04:00
56 changed files with 1873 additions and 758 deletions

View File

@@ -4,24 +4,43 @@ on: [pull_request]
jobs:
test:
name: Test
env:
CGO_ENABLED: 0
strategy:
matrix:
go: [1.13.x]
os: [ubuntu-latest, windows-latest]
runs-on: ${{ matrix.os }}
steps:
- name: Set up Go ${{ matrix.go }}
uses: actions/setup-go@v2-beta
with:
go-version: ${{ matrix.go }}
- uses: actions/checkout@v2
- name: setup make (Windows)
if: matrix.os == 'windows-latest'
run: choco install make -y
- run: make test
build:
name: Build
runs-on: ubuntu-latest
needs: test
steps:
- name: Set up Go 1.13
uses: actions/setup-go@v1
uses: actions/setup-go@v2-beta
with:
go-version: 1.13
- uses: actions/checkout@v2
- run: git fetch --depth=1 origin +refs/tags/*:refs/tags/*
- name: Set GOPATH
# temporary fix
# see https://github.com/actions/setup-go/issues/14
run: |
echo "##[set-env name=GOPATH;]$(dirname $GITHUB_WORKSPACE)"
echo "##[add-path]$(dirname $GITHUB_WORKSPACE)/bin"
shell: bash
- run: make test
- run: git fetch --depth=1 origin +refs/tags/*:refs/tags/*
- run: make xbuild-all

View File

@@ -12,19 +12,12 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Set up Go 1.13
uses: actions/setup-go@v1
uses: actions/setup-go@v2-beta
with:
go-version: 1.13
- uses: actions/checkout@v2
- run: git fetch --depth=1 origin +refs/tags/*:refs/tags/* # Needed in makefile for versioning
- name: Set GOPATH
# temporary fix
# see https://github.com/actions/setup-go/issues/14
run: |
echo "##[set-env name=GOPATH;]$(dirname $GITHUB_WORKSPACE)"
echo "##[add-path]$(dirname $GITHUB_WORKSPACE)/bin"
shell: bash
- run: make test
- run: make xbuild-all

View File

@@ -39,29 +39,29 @@ endif
.PHONY: build
build: clean generate
mkdir -p $(BINDIR)
go run _make_support/mkdir_all/do.go $(BINDIR)
go build -ldflags '$(LDFLAGS)' -tags "$(BUILDTAGS)" -o $(BINDIR)/$(MIXIN)$(FILE_EXT) ./cmd/$(MIXIN)
$(MAKE) clean
.PHONY: test-setup
test-setup: clean generate
ifeq ($(shell ${WHICH} docker-registry 2>${DEVNUL}),)
$(eval TMP-docker-distribution := $(shell mktemp -d))
git clone https://github.com/docker/distribution.git $(TMP-docker-distribution)/docker-distribution
cd $(TMP-docker-distribution)/docker-distribution; git checkout -b v2.7.1; make
cp $(TMP-docker-distribution)/docker-distribution/bin/registry pkg/qliksense/docker-registry
-rm -rf $(TMP-docker-distribution)
$(eval TMP-docker-distribution := $(shell go run _make_support/get_tmp_dir/do.go))
git clone https://github.com/docker/distribution.git "$(TMP-docker-distribution)/docker-distribution"
cd "$(TMP-docker-distribution)/docker-distribution" && git checkout -b v2.7.1 && "$(MAKE)"
go run _make_support/copy/do.go --src "$(TMP-docker-distribution)/docker-distribution/bin/registry" --dst pkg/qliksense/docker-registry$(FILE_EXT)
go run _make_support/remove_all/do.go "$(TMP-docker-distribution)"
endif
.PHONY: test-short
test-short: test-setup
go test -short -count=1 -tags "$(BUILDTAGS)" -v ./...
$(MAKE) clean
go test -count 1 -p 1 -tags "$(BUILDTAGS)" -v -short ./...
"$(MAKE)" clean
.PHONY: test
test: test-setup
go test -count=1 -tags "$(BUILDTAGS)" -v ./...
$(MAKE) clean
go test -count 1 -p 1 -tags "$(BUILDTAGS)" -v ./...
"$(MAKE)" clean
xbuild-all: clean generate
$(foreach OS, $(SUPPORTED_PLATFORMS), \
@@ -86,6 +86,7 @@ endif
generate: get-crds packr2
go generate ./...
go run _make_support/remove_all/do.go pkg/qliksense/crds
packr2:
ifeq ($(shell ${WHICH} packr2 2>${DEVNUL}),)
@@ -93,22 +94,22 @@ ifeq ($(shell ${WHICH} packr2 2>${DEVNUL}),)
endif
clean: clean-packr
-rm -fr pkg/qliksense/crds
go run _make_support/remove_all/do.go pkg/qliksense/crds
clean-packr: packr2
cd pkg/qliksense && packr2 clean
get-crds:
ifeq ($(QLIKSENSE_OPERATOR_DIR),)
$(eval TMP-operator := $(shell mktemp -d))
$(eval TMP-operator := $(shell go run _make_support/get_tmp_dir/do.go))
git clone https://github.com/qlik-oss/qliksense-operator.git -b master $(TMP-operator)/operator
$(MAKE) QLIKSENSE_OPERATOR_DIR=$(TMP-operator)/operator get-crds
-rm -rf $(TMP-operator)
"$(MAKE)" QLIKSENSE_OPERATOR_DIR="$(TMP-operator)/operator" get-crds
go run _make_support/remove_all/do.go "$(TMP-operator)"
else
mkdir -p pkg/qliksense/crds/cr
mkdir -p pkg/qliksense/crds/crd
mkdir -p pkg/qliksense/crds/crd-deploy
cp $(QLIKSENSE_OPERATOR_DIR)/deploy/*.yaml pkg/qliksense/crds/crd-deploy
cp $(QLIKSENSE_OPERATOR_DIR)/deploy/crds/*_crd.yaml pkg/qliksense/crds/crd
cp $(QLIKSENSE_OPERATOR_DIR)/deploy/crds/*_cr.yaml pkg/qliksense/crds/cr
go run _make_support/mkdir_all/do.go pkg/qliksense/crds/cr
go run _make_support/mkdir_all/do.go pkg/qliksense/crds/crd
go run _make_support/mkdir_all/do.go pkg/qliksense/crds/crd-deploy
go run _make_support/copy/do.go --src-pattern "$(QLIKSENSE_OPERATOR_DIR)/deploy/*.yaml" --dst pkg/qliksense/crds/crd-deploy
go run _make_support/copy/do.go --src-pattern "$(QLIKSENSE_OPERATOR_DIR)/deploy/crds/*_crd.yaml" --dst pkg/qliksense/crds/crd
go run _make_support/copy/do.go --src-pattern "$(QLIKSENSE_OPERATOR_DIR)/deploy/crds/*_cr.yaml" --dst pkg/qliksense/crds/cr
endif

View File

@@ -1,16 +1,12 @@
# (WIP) Qlik Sense installation and operations CLI
# (WIP) Qlik Sense on Kubernetes installation and operations CLI
## Documentation
To learn more about Qlik Sense installer go to https://qlik-oss.github.io/sense-installer/
To learn more about Qlik Sense on Kubernetes CLI go to https://qlik-oss.github.io/sense-installer/
## About
The Qlik Sense installer CLI (qliksense) provides an imperative interface to many of the configurations that need to be applied against the declarative structure described in [qliksense-k8s](https://github.com/qlik-oss/qliksense-k8s). This cli facilitates:
- installation of QSEoK
- installation of qliksense operator to manage QSEoK
- air gapped installation of QSEoK
The QSEoK CLI (qliksense) provides an imperative interface to many of the configurations that need to be applied against the declarative structure described in [qliksense-k8s](https://github.com/qlik-oss/qliksense-k8s).
This is a technology preview that uses Qlik modified [kustomize](https://github.com/qlik-oss/kustomize) to kubernetes manifests of the versions of the [qliksense-k8s](https://github.com/qlik-oss/qliksense-k8s) repository.

109
_make_support/copy/do.go Normal file
View File

@@ -0,0 +1,109 @@
package main
import (
"flag"
"fmt"
"io"
"os"
"path/filepath"
"github.com/otiai10/copy"
)
func main() {
srcPattern := flag.String("src-pattern", "", "Source file pattern")
src := flag.String("src", "", "Source file or directory")
dst := flag.String("dst", "", "Destination file or directory")
flag.Parse()
if *srcPattern != "" {
if dstInfo, err := os.Lstat(*dst); err != nil {
panic(err)
} else if !dstInfo.IsDir() {
panic(fmt.Errorf("%v must be a directory", *dst))
}
if matches, err := filepath.Glob(*srcPattern); err != nil {
panic(err)
} else {
for _, match := range matches {
srcInfo, err := os.Lstat(match)
if err != nil {
panic(err)
}
if srcInfo.IsDir() {
if err := copy.Copy(match, *dst, copy.Options{
OnSymlink: func(p string) copy.SymlinkAction {
return copy.Skip
},
}); err != nil {
panic(err)
}
} else if srcInfo.Mode().IsRegular() {
if err := fcopy(match, filepath.Join(*dst, filepath.Base(match)), srcInfo); err != nil {
panic(err)
}
}
}
}
} else if *src != "" {
srcInfo, err := os.Lstat(*src)
if err != nil {
panic(err)
}
if srcInfo.IsDir() {
if err := copy.Copy(*src, *dst, copy.Options{
OnSymlink: func(p string) copy.SymlinkAction {
return copy.Skip
},
}); err != nil {
panic(err)
}
} else if srcInfo.Mode().IsRegular() {
finalDestination := *dst
if dstInfo, err := os.Lstat(*dst); err != nil {
if !os.IsNotExist(err) {
panic(err)
}
} else if dstInfo.IsDir() {
finalDestination = filepath.Join(*dst, filepath.Base(*src))
} else if dstInfo.Mode().IsRegular() {
fmt.Println("WARNING: over-writing existing file: ", *dst)
if err := os.Remove(*dst); err != nil {
panic(err)
}
} else {
panic(fmt.Errorf("not sure how to copy to this dst: %v", *dst))
}
if err := fcopy(*src, finalDestination, srcInfo); err != nil {
panic(err)
}
}
}
}
func fcopy(src, dest string, info os.FileInfo) (err error) {
if err := os.MkdirAll(filepath.Dir(dest), os.ModePerm); err != nil {
return err
}
f, err := os.Create(dest)
if err != nil {
return err
}
defer f.Close()
if err = os.Chmod(f.Name(), info.Mode()); err != nil {
return err
}
s, err := os.Open(src)
if err != nil {
return err
}
defer s.Close()
_, err = io.Copy(f, s)
return err
}

View File

@@ -0,0 +1,5 @@
module github.com/qlik-oss/sense-installer/_make_support/copy
go 1.13
require github.com/otiai10/copy v1.1.1

View File

@@ -0,0 +1,8 @@
github.com/otiai10/copy v1.1.1 h1:PH7IFlRQ6Fv9vYmuXbDRLdgTHoP1w483kPNUP2bskpo=
github.com/otiai10/copy v1.1.1/go.mod h1:rrF5dJ5F0t/EWSYODDu4j9/vEeYHMkc8jt0zJChqQWw=
github.com/otiai10/curr v0.0.0-20150429015615-9b4961190c95/go.mod h1:9qAhocn7zKJG+0mI8eUu6xqkFDYS2kb2saOteoSB3cE=
github.com/otiai10/curr v1.0.0 h1:TJIWdbX0B+kpNagQrjgq8bCMrbhiuX73M2XwgtDMoOI=
github.com/otiai10/curr v1.0.0/go.mod h1:LskTG5wDwr8Rs+nNQ+1LlxRjAtTZZjtJW4rMXl6j4vs=
github.com/otiai10/mint v1.3.0/go.mod h1:F5AjcsTsWUqX+Na9fpHb52P8pcRX2CI6A3ctIT91xUo=
github.com/otiai10/mint v1.3.1 h1:BCmzIS3n71sGfHB5NMNDB3lHYPz8fWSkCAErHed//qc=
github.com/otiai10/mint v1.3.1/go.mod h1:/yxELlJQ0ufhjUwhshSj+wFjZ78CnZ48/1wtmBH1OTc=

View File

@@ -0,0 +1,14 @@
package main
import (
"fmt"
"io/ioutil"
)
func main() {
if tmpDir, err := ioutil.TempDir("", ""); err != nil {
panic(err)
} else {
fmt.Print(tmpDir)
}
}

View File

@@ -0,0 +1,3 @@
module github.com/qlik-oss/sense-installer/_make_support/get_tmp_dir
go 1.13

View File

@@ -0,0 +1,11 @@
package main
import (
"os"
)
func main() {
if err := os.MkdirAll(os.Args[1], os.ModePerm); err != nil {
panic(err)
}
}

View File

@@ -0,0 +1,3 @@
module github.com/qlik-oss/sense-installer/_make_support/mkdir_all
go 1.13

View File

@@ -0,0 +1,11 @@
package main
import (
"os"
)
func main() {
if err := os.RemoveAll(os.Args[1]); err != nil {
panic(err)
}
}

View File

@@ -0,0 +1,3 @@
module github.com/qlik-oss/sense-installer/_make_support/remove_all
go 1.13

View File

@@ -39,7 +39,7 @@ qliksense about --profile=test
then get version information based on the default profile in the qliksense-k8s repo master
`,
RunE: func(cmd *cobra.Command, args []string) error {
if gitRef, err := getAboutCommandGitRef(args); err != nil {
if gitRef, err := getSingleArg(args); err != nil {
return err
} else if vout, err := q.About(gitRef, opts.Profile); err != nil {
return err
@@ -56,7 +56,7 @@ qliksense about --profile=test
return c
}
func getAboutCommandGitRef(args []string) (string, error) {
func getSingleArg(args []string) (string, error) {
if len(args) > 1 {
return "", errors.New("too many arguments, only 1 expected")
} else if len(args) == 1 {

View File

@@ -1,7 +1,11 @@
package main
import (
"io"
"bytes"
"errors"
"fmt"
qapi "github.com/qlik-oss/sense-installer/pkg/api"
"github.com/qlik-oss/sense-installer/pkg/qliksense"
"github.com/spf13/cobra"
@@ -10,15 +14,21 @@ import (
func applyCmd(q *qliksense.Qliksense) *cobra.Command {
opts := &qliksense.InstallCommandOptions{}
filePath := ""
keepPatchFiles := false
keepPatchFiles, pull, push := false, false, false
c := &cobra.Command{
Use: "apply",
Short: "install qliksense based on provided cr file",
Long: `install qliksense based on provided cr file`,
Example: `qliksense apply -f file_name or cat cr_file | qliksense apply -f -`,
RunE: func(cmd *cobra.Command, args []string) error {
return runLoadOrApplyCommandE(cmd, func(reader io.Reader) error {
return q.ApplyCRFromReader(reader, opts, keepPatchFiles, true)
return runLoadOrApplyCommandE(cmd, func(crBytes []byte) error {
if cr, crBytesWithEula, err := getCrWithEulaInserted(crBytes); err != nil {
return err
} else if err := validatePullPushFlagsOnApply(cr, pull, push); err != nil {
return err
} else {
return q.ApplyCRFromReader(bytes.NewReader(crBytesWithEula), opts, keepPatchFiles, true, pull, push)
}
})
},
}
@@ -30,8 +40,35 @@ func applyCmd(q *qliksense.Qliksense) *cobra.Command {
f.StringVarP(&opts.MongoDbUri, "mongoDbUri", "m", "", "mongoDbUri for qliksense (i.e. mongodb://qlik-default-mongodb:27017/qliksense?ssl=false)")
f.StringVarP(&opts.RotateKeys, "rotateKeys", "r", "", "Rotate JWT keys for qliksense (yes:rotate keys/ no:use exising keys from cluster/ None: use default EJSON_KEY from env")
f.BoolVar(&keepPatchFiles, keepPatchFilesFlagName, keepPatchFiles, keepPatchFilesFlagUsage)
f.BoolVarP(&pull, pullFlagName, pullFlagShorthand, pull, pullFlagUsage)
f.BoolVarP(&push, pushFlagName, pushFlagShorthand, push, pushFlagUsage)
eulaPreRunHooks.addValidator(c.Name(), loadOrApplyCommandEulaPreRunHook)
eulaPreRunHooks.addValidator(fmt.Sprintf("%v %v", rootCommandName, c.Name()), loadOrApplyCommandEulaPreRunHook)
return c
}
func validatePullPushFlagsOnApply(cr *qapi.QliksenseCR, pull, push bool) error {
if pull && !push {
fmt.Printf("WARNING: pulling images without pushing them")
}
if push {
if registry := cr.Spec.GetImageRegistry(); registry == "" {
return errors.New("no image registry set in the CR; to set it use: qliksense config set-image-registry")
}
}
return nil
}
func getCrWithEulaInserted(crBytes []byte) (*qapi.QliksenseCR, []byte, error) {
if cr, err := qapi.CreateCRObjectFromString(string(crBytes)); err != nil {
return nil, nil, err
} else {
cr.SetEULA("yes")
if crBytesWithEula, err := qapi.K8sToYaml(cr); err != nil {
return nil, nil, err
} else {
return cr, crBytesWithEula, nil
}
}
}

View File

@@ -139,15 +139,18 @@ func deleteContextConfigCmd(q *qliksense.Qliksense) *cobra.Command {
var (
cmd *cobra.Command
)
skipConfirmation := false
cmd = &cobra.Command{
Use: "delete-context",
Short: "deletes a specific context locally (not in-cluster)",
Example: `qliksense config delete-contexts <context_name>`,
RunE: func(cmd *cobra.Command, args []string) error {
return q.DeleteContextConfig(args)
return q.DeleteContextConfig(args, skipConfirmation)
},
}
f := cmd.Flags()
f.BoolVar(&skipConfirmation, "yes", skipConfirmation, "skips confirmation")
return cmd
}

View File

@@ -48,13 +48,14 @@ var eulaPreRunHooks = eulaPreRunHooksT{
}
func commandAlwaysRequiresEulaAcceptance(commandName string) bool {
return commandName == "install" || commandName == "upgrade" || commandName == "apply"
return commandName == fmt.Sprintf("%v install", rootCommandName) ||
commandName == fmt.Sprintf("%v apply", rootCommandName)
}
func globalEulaPreRun(cmd *cobra.Command, q *qliksense.Qliksense) {
if isEulaEnforced(cmd.Name()) {
if isEulaEnforced(cmd.CommandPath()) {
if strings.TrimSpace(strings.ToLower(cmd.Flag("acceptEULA").Value.String())) != "yes" {
if eulaPreRunHook := eulaPreRunHooks.getValidator(cmd.Name()); eulaPreRunHook != nil {
if eulaPreRunHook := eulaPreRunHooks.getValidator(cmd.CommandPath()); eulaPreRunHook != nil {
if eulaAccepted, err := eulaPreRunHook(cmd, q); err != nil {
panic(err)
} else if !eulaAccepted {
@@ -70,7 +71,7 @@ func globalEulaPreRun(cmd *cobra.Command, q *qliksense.Qliksense) {
}
func globalEulaPostRun(cmd *cobra.Command, q *qliksense.Qliksense) {
if isEulaEnforced(cmd.Name()) {
if isEulaEnforced(cmd.CommandPath()) {
if err := q.SetEulaAccepted(); err != nil {
panic(err)
}

View File

@@ -1,32 +1,95 @@
package main
import (
"bytes"
"fmt"
qapi "github.com/qlik-oss/sense-installer/pkg/api"
"github.com/qlik-oss/sense-installer/pkg/qliksense"
"github.com/spf13/cobra"
)
func installCmd(q *qliksense.Qliksense) *cobra.Command {
opts := &qliksense.InstallCommandOptions{}
keepPatchFiles := false
filePath := ""
keepPatchFiles, pull, push := false, false, false
c := &cobra.Command{
Use: "install",
Short: "install a qliksense release",
Long: `install a qliksense release`,
Example: `qliksense install <version> #if no version provides, expect manifestsRoot is set somewhere in the file system`,
Use: "install",
Short: "install a qliksense release",
Long: `install a qliksense release`,
Example: `qliksense install <version> #if no version provides, expect manifestsRoot is set somewhere in the file system
# qliksense install -f file_name or cat cr_file | qliksense install -f -
`,
RunE: func(cmd *cobra.Command, args []string) error {
version := ""
if len(args) != 0 {
version = args[0]
if filePath != "" {
return runLoadOrApplyCommandE(cmd, func(crBytes []byte) error {
if cr, crBytesWithEula, err := getCrWithEulaInserted(crBytes); err != nil {
return err
} else if err := validatePullPushFlagsOnApply(cr, pull, push); err != nil {
return err
} else {
return q.ApplyCRFromReader(bytes.NewReader(crBytesWithEula), opts, keepPatchFiles, true, pull, push)
}
})
} else {
version := ""
if len(args) != 0 {
version = args[0]
}
if err := validatePullPushFlagsOnInstall(q, pull, push); err != nil {
return err
}
if pull {
fmt.Println("Pulling images...")
if err := q.PullImages(version, ""); err != nil {
return err
}
}
if push {
fmt.Println("Pushing images...")
if err := q.PushImagesForCurrentCR(); err != nil {
return err
}
}
return q.InstallQK8s(version, opts, keepPatchFiles)
}
return q.InstallQK8s(version, opts, keepPatchFiles)
},
}
eulaPreRunHooks.addValidator(fmt.Sprintf("%v %v", rootCommandName, c.Name()), func(cmd *cobra.Command, q *qliksense.Qliksense) (b bool, err error) {
if filePath != "" {
return loadOrApplyCommandEulaPreRunHook(cmd, q)
} else if qConfig, err := qapi.NewQConfigE(q.QliksenseHome); err != nil {
return false, err
} else if qcr, err := qConfig.GetCurrentCR(); err != nil {
return false, err
} else {
return qcr.IsEULA(), nil
}
})
f := c.Flags()
f.StringVarP(&opts.StorageClass, "storageClass", "s", "", "Storage class for qliksense")
f.StringVarP(&opts.MongoDbUri, "mongoDbUri", "m", "", "mongoDbUri for qliksense (i.e. mongodb://qlik-default-mongodb:27017/qliksense?ssl=false)")
f.StringVarP(&opts.RotateKeys, "rotateKeys", "r", "", "Rotate JWT keys for qliksense (yes:rotate keys/ no:use exising keys from cluster/ None: use default EJSON_KEY from env")
f.BoolVar(&keepPatchFiles, keepPatchFilesFlagName, keepPatchFiles, keepPatchFilesFlagUsage)
f.StringVarP(&filePath, "file", "f", "", "Install from a CR file")
f.BoolVarP(&pull, pullFlagName, pullFlagShorthand, pull, pullFlagUsage)
f.BoolVarP(&push, pushFlagName, pushFlagShorthand, push, pushFlagUsage)
return c
}
func validatePullPushFlagsOnInstall(q *qliksense.Qliksense, pull, push bool) error {
if pull && !push {
fmt.Printf("WARNING: pulling images without pushing them")
}
if push {
if err := ensureImageRegistrySetInCR(q); err != nil {
return err
}
}
return nil
}

View File

@@ -2,7 +2,7 @@ package main
import (
"bytes"
"io"
"fmt"
"io/ioutil"
"os"
@@ -20,8 +20,8 @@ func loadCrFile(q *qliksense.Qliksense) *cobra.Command {
Long: `load a CR a file and create necessary structure for future use`,
Example: `qliksense load -f file_name or cat cr_file | qliksense load -f -`,
RunE: func(cmd *cobra.Command, args []string) error {
return runLoadOrApplyCommandE(cmd, func(reader io.Reader) error {
return q.LoadCr(reader, overwriteExistingContext)
return runLoadOrApplyCommandE(cmd, func(buffer []byte) error {
return q.LoadCr(bytes.NewReader(buffer), overwriteExistingContext)
})
},
}
@@ -30,7 +30,7 @@ func loadCrFile(q *qliksense.Qliksense) *cobra.Command {
c.MarkFlagRequired("file")
f.BoolVarP(&overwriteExistingContext, "overwrite", "o", overwriteExistingContext, "Overwrite any existing contexts with the same name")
eulaPreRunHooks.addValidator(c.Name(), loadOrApplyCommandEulaPreRunHook)
eulaPreRunHooks.addValidator(fmt.Sprintf("%v %v", rootCommandName, c.Name()), loadOrApplyCommandEulaPreRunHook)
return c
}
@@ -70,15 +70,19 @@ func loadOrApplyCommandEulaPreRunHook(cmd *cobra.Command, q *qliksense.Qliksense
}
}
func runLoadOrApplyCommandE(cmd *cobra.Command, callBack func(io.Reader) error) error {
func runLoadOrApplyCommandE(cmd *cobra.Command, callBack func(buffer []byte) error) error {
if crBytes := eulaPreRunHooks.getPostValidationArtifact("CR"); crBytes != nil {
return callBack(bytes.NewBuffer(crBytes.([]byte)))
return callBack(crBytes.([]byte))
} else {
file, err := getCrFileFromFlag(cmd, "file")
if err != nil {
return err
}
defer file.Close()
return callBack(file)
if crBytes, err := ioutil.ReadAll(file); err != nil {
return err
} else {
return callBack(crBytes)
}
}
}

View File

@@ -2,8 +2,9 @@ package main
import (
"fmt"
"log"
. "github.com/logrusorgru/aurora"
ansi "github.com/mattn/go-colorable"
"github.com/qlik-oss/sense-installer/pkg/preflight"
"github.com/qlik-oss/sense-installer/pkg/qliksense"
@@ -21,330 +22,456 @@ func preflightCmd(q *qliksense.Qliksense) *cobra.Command {
}
func pfDnsCheckCmd(q *qliksense.Qliksense) *cobra.Command {
out := ansi.NewColorableStdout()
preflightOpts := &preflight.PreflightOptions{
MongoOptions: &preflight.MongoOptions{},
}
var preflightDnsCmd = &cobra.Command{
Use: "dns",
Short: "perform preflight dns check",
Long: `perform preflight dns check to check DNS connectivity status in the cluster`,
Example: `qliksense preflight dns`,
RunE: func(cmd *cobra.Command, args []string) error {
qp := &preflight.QliksensePreflight{Q: q}
qp := &preflight.QliksensePreflight{Q: q, P: preflightOpts}
// Preflight DNS check
fmt.Printf("Preflight DNS check\n")
fmt.Println("---------------------")
namespace, kubeConfigContents, err := preflight.InitPreflight()
if err != nil {
fmt.Printf("Preflight DNS check FAILED\n")
log.Fatal(err)
fmt.Fprintf(out, "%s\n", Red("Preflight DNS check FAILED"))
fmt.Printf("Error: %v\n", err)
return nil
}
if namespace == "" {
namespace = "default"
}
if err = qp.CheckDns(namespace, kubeConfigContents); err != nil {
fmt.Println(err)
fmt.Print("Preflight DNS check FAILED\n")
log.Fatal()
if err = qp.CheckDns(namespace, kubeConfigContents, false); err != nil {
fmt.Fprintf(out, "%s\n", Red("Preflight DNS check FAILED"))
fmt.Printf("Error: %v\n", err)
return nil
}
fmt.Fprintf(out, "%s\n", Green("Preflight DNS check PASSED"))
return nil
},
}
f := preflightDnsCmd.Flags()
f.BoolVarP(&preflightOpts.Verbose, "verbose", "v", false, "verbose mode")
return preflightDnsCmd
}
func pfK8sVersionCheckCmd(q *qliksense.Qliksense) *cobra.Command {
out := ansi.NewColorableStdout()
preflightOpts := &preflight.PreflightOptions{
MongoOptions: &preflight.MongoOptions{},
}
var preflightCheckK8sVersionCmd = &cobra.Command{
Use: "kube-version",
Short: "check kubernetes version",
Long: `check minimum valid kubernetes version on the cluster`,
Example: `qliksense preflight kube-version`,
RunE: func(cmd *cobra.Command, args []string) error {
qp := &preflight.QliksensePreflight{Q: q}
qp := &preflight.QliksensePreflight{Q: q, P: preflightOpts}
// Preflight Kubernetes minimum version check
fmt.Printf("Preflight kubernetes minimum version check\n")
fmt.Println("------------------------------------------")
namespace, kubeConfigContents, err := preflight.InitPreflight()
if err != nil {
fmt.Printf("Preflight kubernetes minimum version check FAILED\n")
log.Fatal(err)
fmt.Fprintf(out, "%s\n", Red("Preflight kubernetes minimum version check FAILED"))
fmt.Printf("Error: %v\n", err)
return nil
}
if err = qp.CheckK8sVersion(namespace, kubeConfigContents); err != nil {
fmt.Println(err)
fmt.Printf("Preflight kubernetes minimum version check FAILED\n")
log.Fatal()
fmt.Fprintf(out, "%s\n", Red("Preflight kubernetes minimum version check FAILED"))
fmt.Printf("Error: %v\n", err)
return nil
}
fmt.Fprintf(out, "%s\n", Green("Preflight kubernetes minimum version check PASSED"))
return nil
},
}
f := preflightCheckK8sVersionCmd.Flags()
f.BoolVarP(&preflightOpts.Verbose, "verbose", "v", false, "verbose mode")
return preflightCheckK8sVersionCmd
}
func pfAllChecksCmd(q *qliksense.Qliksense) *cobra.Command {
var mongodbUrl string
out := ansi.NewColorableStdout()
preflightOpts := &preflight.PreflightOptions{
MongoOptions: &preflight.MongoOptions{},
}
var preflightAllChecksCmd = &cobra.Command{
Use: "all",
Short: "perform all checks",
Long: `perform all preflight checks on the target cluster`,
Example: `qliksense preflight all`,
RunE: func(cmd *cobra.Command, args []string) error {
qp := &preflight.QliksensePreflight{Q: q}
qp := &preflight.QliksensePreflight{Q: q, P: preflightOpts}
// Preflight run all checks
fmt.Printf("Running all preflight checks\n")
fmt.Printf("Running all preflight checks...\n\n")
namespace, kubeConfigContents, err := preflight.InitPreflight()
if err != nil {
fmt.Println(err)
fmt.Printf("Running preflight check suite has FAILED...\n")
log.Fatal()
fmt.Fprintf(out, "%s\n", Red("Unable to run the preflight checks suite"))
fmt.Printf("Error: %v\n", err)
return nil
}
if namespace == "" {
namespace = "default"
}
qp.RunAllPreflightChecks(namespace, kubeConfigContents, mongodbUrl)
if err = qp.RunAllPreflightChecks(kubeConfigContents, namespace, preflightOpts); err != nil {
fmt.Fprintf(out, "%s\n", Red("1 or more preflight checks have FAILED"))
fmt.Println("Completed running all preflight checks")
return nil
}
fmt.Fprintf(out, "%s\n\n", Green("All preflight checks have PASSED"))
return nil
},
}
f := preflightAllChecksCmd.Flags()
f.StringVarP(&mongodbUrl, "mongodb-url", "", "", "mongodbUrl to try connecting to")
f.BoolVarP(&preflightOpts.Verbose, "verbose", "v", false, "verbose mode")
f.StringVarP(&preflightOpts.MongoOptions.MongodbUrl, "mongodb-url", "", "", "mongodbUrl to try connecting to")
f.StringVarP(&preflightOpts.MongoOptions.Username, "mongodb-username", "", "", "username to connect to mongodb")
f.StringVarP(&preflightOpts.MongoOptions.Password, "mongodb-password", "", "", "password to connect to mongodb")
f.StringVarP(&preflightOpts.MongoOptions.CaCertFile, "mongodb-ca-cert", "", "", "certificate to use for mongodb check")
f.StringVarP(&preflightOpts.MongoOptions.ClientCertFile, "mongodb-client-cert", "", "", "client-certificate to use for mongodb check")
f.BoolVar(&preflightOpts.MongoOptions.Tls, "mongodb-tls", false, "enable tls?")
return preflightAllChecksCmd
}
func pfDeploymentCheckCmd(q *qliksense.Qliksense) *cobra.Command {
out := ansi.NewColorableStdout()
preflightOpts := &preflight.PreflightOptions{
MongoOptions: &preflight.MongoOptions{},
}
var pfDeploymentCheckCmd = &cobra.Command{
Use: "deployment",
Short: "perform preflight deploymwnt check",
Long: `perform preflight deployment check to ensure that we can create deployments in the cluster`,
Example: `qliksense preflight deployment`,
RunE: func(cmd *cobra.Command, args []string) error {
qp := &preflight.QliksensePreflight{Q: q}
qp := &preflight.QliksensePreflight{Q: q, P: preflightOpts}
// Preflight deployments check
fmt.Printf("Preflight deployment check\n")
fmt.Println("--------------------------")
namespace, kubeConfigContents, err := preflight.InitPreflight()
if err != nil {
fmt.Printf("Preflight deployment check FAILED\n")
log.Fatal(err)
fmt.Fprintf(out, "%s\n", Red("Preflight deployment check FAILED"))
fmt.Printf("Error: %v\n", err)
return nil
}
if namespace == "" {
namespace = "default"
}
if err = qp.CheckDeployment(namespace, kubeConfigContents); err != nil {
fmt.Println(err)
fmt.Print("Preflight deploy check FAILED\n")
log.Fatal()
if err = qp.CheckDeployment(namespace, kubeConfigContents, false); err != nil {
fmt.Fprintf(out, "%s\n", Red("Preflight deployment check FAILED"))
fmt.Printf("Error: %v\n", err)
return nil
}
fmt.Fprintf(out, "%s\n", Green("Preflight deployment check PASSED"))
return nil
},
}
f := pfDeploymentCheckCmd.Flags()
f.BoolVarP(&preflightOpts.Verbose, "verbose", "v", false, "verbose mode")
return pfDeploymentCheckCmd
}
func pfServiceCheckCmd(q *qliksense.Qliksense) *cobra.Command {
out := ansi.NewColorableStdout()
preflightOpts := &preflight.PreflightOptions{
MongoOptions: &preflight.MongoOptions{},
}
var pfServiceCheckCmd = &cobra.Command{
Use: "service",
Short: "perform preflight service check",
Long: `perform preflight service check to ensure that we are able to create services in the cluster`,
Example: `qliksense preflight service`,
RunE: func(cmd *cobra.Command, args []string) error {
qp := &preflight.QliksensePreflight{Q: q}
qp := &preflight.QliksensePreflight{Q: q, P: preflightOpts}
// Preflight service check
fmt.Printf("Preflight service check\n")
fmt.Println("-----------------------")
namespace, kubeConfigContents, err := preflight.InitPreflight()
if err != nil {
fmt.Printf("Preflight service check FAILED\n")
log.Fatal(err)
fmt.Fprintf(out, "%s\n", Red("Preflight service check FAILED"))
fmt.Printf("Error: %v\n", err)
return nil
}
if namespace == "" {
namespace = "default"
}
if err = qp.CheckService(namespace, kubeConfigContents); err != nil {
fmt.Println(err)
fmt.Print("Preflight service check FAILED\n")
log.Fatal()
if err = qp.CheckService(namespace, kubeConfigContents, false); err != nil {
fmt.Fprintf(out, "%s\n", Red("Preflight service check FAILED"))
fmt.Printf("Error: %v\n", err)
return nil
}
fmt.Fprintf(out, "%s\n", Green("Preflight service check PASSED"))
return nil
},
}
f := pfServiceCheckCmd.Flags()
f.BoolVarP(&preflightOpts.Verbose, "verbose", "v", false, "verbose mode")
return pfServiceCheckCmd
}
func pfPodCheckCmd(q *qliksense.Qliksense) *cobra.Command {
out := ansi.NewColorableStdout()
preflightOpts := &preflight.PreflightOptions{
MongoOptions: &preflight.MongoOptions{},
}
var pfPodCheckCmd = &cobra.Command{
Use: "pod",
Short: "perform preflight pod check",
Long: `perform preflight pod check to ensure we can create pods in the cluster`,
Example: `qliksense preflight pod`,
RunE: func(cmd *cobra.Command, args []string) error {
qp := &preflight.QliksensePreflight{Q: q}
qp := &preflight.QliksensePreflight{Q: q, P: preflightOpts}
// Preflight pod check
fmt.Printf("Preflight pod check\n")
fmt.Println("--------------------")
namespace, kubeConfigContents, err := preflight.InitPreflight()
if err != nil {
fmt.Printf("Preflight pod check FAILED\n")
log.Fatal(err)
fmt.Fprintf(out, "%s\n", Red("Preflight pod check FAILED"))
fmt.Printf("Error: %v\n", err)
return nil
}
if namespace == "" {
namespace = "default"
}
if err = qp.CheckPod(namespace, kubeConfigContents); err != nil {
fmt.Println(err)
fmt.Print("Preflight pod check FAILED\n")
log.Fatal()
if err = qp.CheckPod(namespace, kubeConfigContents, false); err != nil {
fmt.Fprintf(out, "%s\n", Red("Preflight pod check FAILED"))
fmt.Printf("Error: %v\n", err)
return nil
}
fmt.Fprintf(out, "%s\n", Green("Preflight pod check PASSED"))
return nil
},
}
f := pfPodCheckCmd.Flags()
f.BoolVarP(&preflightOpts.Verbose, "verbose", "v", false, "verbose mode")
return pfPodCheckCmd
}
func pfCreateRoleCheckCmd(q *qliksense.Qliksense) *cobra.Command {
out := ansi.NewColorableStdout()
preflightOpts := &preflight.PreflightOptions{
MongoOptions: &preflight.MongoOptions{},
}
var preflightRoleCmd = &cobra.Command{
Use: "role",
Short: "preflight create role check",
Long: `perform preflight role check to ensure we are able to create a role in the cluster`,
Example: `qliksense preflight createRole`,
RunE: func(cmd *cobra.Command, args []string) error {
qp := &preflight.QliksensePreflight{Q: q}
qp := &preflight.QliksensePreflight{Q: q, P: preflightOpts}
// Preflight role check
fmt.Printf("Preflight role check\n")
fmt.Println("---------------------------")
namespace, _, err := preflight.InitPreflight()
if err != nil {
fmt.Printf("Preflight role check FAILED\n")
log.Fatal(err)
fmt.Fprintf(out, "%s\n", Red("Preflight role check FAILED"))
fmt.Printf("Error: %v\n", err)
return nil
}
if err = qp.CheckCreateRole(namespace); err != nil {
fmt.Println(err)
fmt.Print("Preflight role FAILED\n")
log.Fatal()
if err = qp.CheckCreateRole(namespace, false); err != nil {
fmt.Fprintf(out, "%s\n", Red("Preflight role check FAILED"))
fmt.Printf("Error: %v\n", err)
return nil
}
fmt.Fprintf(out, "%s\n", Green("Preflight role check PASSED"))
return nil
},
}
f := preflightRoleCmd.Flags()
f.BoolVarP(&preflightOpts.Verbose, "verbose", "v", false, "verbose mode")
return preflightRoleCmd
}
func pfCreateRoleBindingCheckCmd(q *qliksense.Qliksense) *cobra.Command {
out := ansi.NewColorableStdout()
preflightOpts := &preflight.PreflightOptions{
MongoOptions: &preflight.MongoOptions{},
}
var preflightRoleBindingCmd = &cobra.Command{
Use: "rolebinding",
Short: "preflight create rolebinding check",
Long: `perform preflight rolebinding check to ensure we are able to create a rolebinding in the cluster`,
Example: `qliksense preflight rolebinding`,
RunE: func(cmd *cobra.Command, args []string) error {
qp := &preflight.QliksensePreflight{Q: q}
qp := &preflight.QliksensePreflight{Q: q, P: preflightOpts}
// Preflight createRoleBinding check
fmt.Printf("Preflight rolebinding check\n")
fmt.Println("---------------------------")
namespace, _, err := preflight.InitPreflight()
if err != nil {
fmt.Printf("Preflight rolebinding check FAILED\n")
log.Fatal(err)
fmt.Fprintf(out, "%s\n", Red("Preflight rolebinding check FAILED"))
fmt.Printf("Error: %v\n", err)
return nil
}
if err = qp.CheckCreateRoleBinding(namespace); err != nil {
fmt.Println(err)
fmt.Print("Preflight rolebinding check FAILED\n")
log.Fatal()
if err = qp.CheckCreateRoleBinding(namespace, false); err != nil {
fmt.Fprintf(out, "%s\n", Red("Preflight rolebinding check FAILED"))
fmt.Printf("Error: %v\n", err)
return nil
}
fmt.Fprintf(out, "%s\n", Green("Preflight rolebinding check PASSED"))
return nil
},
}
f := preflightRoleBindingCmd.Flags()
f.BoolVarP(&preflightOpts.Verbose, "verbose", "v", false, "verbose mode")
return preflightRoleBindingCmd
}
func pfCreateServiceAccountCheckCmd(q *qliksense.Qliksense) *cobra.Command {
out := ansi.NewColorableStdout()
preflightOpts := &preflight.PreflightOptions{
MongoOptions: &preflight.MongoOptions{},
}
var preflightServiceAccountCmd = &cobra.Command{
Use: "serviceaccount",
Short: "preflight create ServiceAccount check",
Long: `perform preflight serviceaccount check to ensure we are able to create a service account in the cluster`,
Example: `qliksense preflight serviceaccount`,
RunE: func(cmd *cobra.Command, args []string) error {
qp := &preflight.QliksensePreflight{Q: q}
qp := &preflight.QliksensePreflight{Q: q, P: preflightOpts}
// Preflight createServiceAccount check
fmt.Printf("Preflight ServiceAccount check\n")
fmt.Println("-------------------------------------")
namespace, _, err := preflight.InitPreflight()
if err != nil {
fmt.Printf("Preflight serviceaccount check FAILED\n")
log.Fatal(err)
fmt.Fprintf(out, "%s\n", Red("Preflight ServiceAccount check FAILED"))
fmt.Printf("Error: %v\n", err)
return nil
}
if err = qp.CheckCreateServiceAccount(namespace); err != nil {
fmt.Println(err)
fmt.Print("Preflight serviceaccount check FAILED\n")
log.Fatal()
if err = qp.CheckCreateServiceAccount(namespace, false); err != nil {
fmt.Fprintf(out, "%s\n", Red("Preflight ServiceAccount check FAILED"))
fmt.Printf("Error: %v\n", err)
return nil
}
fmt.Fprintf(out, "%s\n", Green("Preflight ServiceAccount check PASSED"))
return nil
},
}
f := preflightServiceAccountCmd.Flags()
f.BoolVarP(&preflightOpts.Verbose, "verbose", "v", false, "verbose mode")
return preflightServiceAccountCmd
}
func pfCreateAuthCheckCmd(q *qliksense.Qliksense) *cobra.Command {
out := ansi.NewColorableStdout()
preflightOpts := &preflight.PreflightOptions{
MongoOptions: &preflight.MongoOptions{},
}
var preflightCreateAuthCmd = &cobra.Command{
Use: "authcheck",
Short: "preflight authcheck",
Long: `perform preflight authcheck that combines the role, rolebinding and serviceaccount checks`,
Example: `qliksense preflight authcheck`,
RunE: func(cmd *cobra.Command, args []string) error {
qp := &preflight.QliksensePreflight{Q: q}
qp := &preflight.QliksensePreflight{Q: q, P: preflightOpts}
// Preflight authcheck
fmt.Printf("Preflight authcheck\n")
fmt.Println("------------------------")
namespace, kubeConfigContents, err := preflight.InitPreflight()
if err != nil {
fmt.Printf("Preflight authcheck FAILED\n")
log.Fatal(err)
fmt.Fprintf(out, "%s\n", Red("Preflight authcheck FAILED"))
fmt.Printf("Error: %v\n", err)
return nil
}
if err = qp.CheckCreateRB(namespace, kubeConfigContents); err != nil {
fmt.Println(err)
fmt.Print("Preflight authcheck FAILED\n")
log.Fatal()
fmt.Fprintf(out, "%s\n", Red("Preflight authcheck FAILED"))
fmt.Printf("Error: %v\n", err)
return nil
}
fmt.Fprintf(out, "%s\n", Green("Preflight authcheck PASSED"))
return nil
},
}
f := preflightCreateAuthCmd.Flags()
f.BoolVarP(&preflightOpts.Verbose, "verbose", "v", false, "verbose mode")
return preflightCreateAuthCmd
}
func pfMongoCheckCmd(q *qliksense.Qliksense) *cobra.Command {
var mongodbUrl string
out := ansi.NewColorableStdout()
preflightOpts := &preflight.PreflightOptions{
MongoOptions: &preflight.MongoOptions{},
}
var preflightMongoCmd = &cobra.Command{
Use: "mongo",
Short: "preflight mongo OR preflight mongo --url=<url>",
Long: `perform preflight mongo check to ensure we are able to connect to a mongodb instance in the cluster`,
Example: `qliksense preflight mongo OR preflight mongo --url=<url>`,
RunE: func(cmd *cobra.Command, args []string) error {
qp := &preflight.QliksensePreflight{Q: q}
qp := &preflight.QliksensePreflight{Q: q, P: preflightOpts}
// Preflight mongo check
fmt.Printf("Preflight mongo check\n")
fmt.Println("-------------------------------------")
namespace, kubeConfigContents, err := preflight.InitPreflight()
if err != nil {
fmt.Printf("Preflight mongo check FAILED\n")
log.Fatal(err)
fmt.Fprintf(out, "%s\n", Red("Preflight mongo check FAILED"))
fmt.Printf("Error: %v\n", err)
return nil
}
if namespace == "" {
namespace = "default"
}
if err = qp.CheckMongo(kubeConfigContents, namespace, mongodbUrl); err != nil {
fmt.Println(err)
fmt.Print("Preflight mongo check FAILED\n")
log.Fatal()
if err = qp.CheckMongo(kubeConfigContents, namespace, preflightOpts, false); err != nil {
fmt.Fprintf(out, "%s\n", Red("Preflight mongo check FAILED"))
fmt.Printf("Error: %v\n", err)
return nil
}
fmt.Fprintf(out, "%s\n", Green("Preflight mongo check PASSED"))
return nil
},
}
f := preflightMongoCmd.Flags()
f.StringVarP(&mongodbUrl, "url", "", "", "mongodbUrl to try connecting to")
f.BoolVarP(&preflightOpts.Verbose, "verbose", "v", false, "verbose mode")
f.StringVarP(&preflightOpts.MongoOptions.MongodbUrl, "url", "", "", "mongodbUrl to try connecting to")
f.StringVarP(&preflightOpts.MongoOptions.Username, "username", "", "", "username to connect to mongodb")
f.StringVarP(&preflightOpts.MongoOptions.Password, "password", "", "", "password to connect to mongodb")
f.StringVarP(&preflightOpts.MongoOptions.CaCertFile, "ca-cert", "", "", "ca certificate to use for mongodb check")
f.StringVarP(&preflightOpts.MongoOptions.ClientCertFile, "client-cert", "", "", "client-certificate to use for mongodb check")
f.BoolVar(&preflightOpts.MongoOptions.Tls, "tls", false, "enable tls?")
return preflightMongoCmd
}
func pfCleanupCmd(q *qliksense.Qliksense) *cobra.Command {
out := ansi.NewColorableStdout()
preflightOpts := &preflight.PreflightOptions{
MongoOptions: &preflight.MongoOptions{},
}
var pfCleanCmd = &cobra.Command{
Use: "clean",
Short: "perform preflight clean",
Long: `perform preflight clean to ensure that all resources are cleared up in the cluster`,
Example: `qliksense preflight clean`,
RunE: func(cmd *cobra.Command, args []string) error {
qp := &preflight.QliksensePreflight{Q: q, P: preflightOpts}
// Preflight clean
namespace, kubeConfigContents, err := preflight.InitPreflight()
if err != nil {
fmt.Fprintf(out, "%s\n", Red("Preflight cleanup FAILED"))
fmt.Printf("Error: %v\n", err)
return nil
}
if namespace == "" {
namespace = "default"
}
if err = qp.Cleanup(namespace, kubeConfigContents); err != nil {
fmt.Fprintf(out, "%s\n", Red("Preflight cleanup FAILED"))
fmt.Printf("Error: %v\n", err)
return nil
}
fmt.Fprintf(out, "%s\n", Green("Preflight cleanup complete"))
return nil
},
}
f := pfCleanCmd.Flags()
f.BoolVarP(&preflightOpts.Verbose, "verbose", "v", false, "verbose mode")
return pfCleanCmd
}

View File

@@ -16,7 +16,7 @@ func pullQliksenseImages(q *qliksense.Qliksense) *cobra.Command {
Short: "Pull docker images for offline install",
Example: `qliksense pull`,
RunE: func(cmd *cobra.Command, args []string) error {
version, err := getAboutCommandGitRef(args)
version, err := getSingleArg(args)
if err != nil {
return err
}
@@ -34,11 +34,8 @@ func pushQliksenseImages(q *qliksense.Qliksense) *cobra.Command {
Short: "Push docker images for offline install",
Example: `qliksense push`,
RunE: func(cmd *cobra.Command, args []string) error {
qConfig := qapi.NewQConfig(q.QliksenseHome)
if qcr, err := qConfig.GetCurrentCR(); err != nil {
if err := ensureImageRegistrySetInCR(q); err != nil {
return err
} else if registry := qcr.Spec.GetImageRegistry(); registry == "" {
return errors.New("no image registry in config")
} else {
return q.PushImagesForCurrentCR()
}
@@ -46,3 +43,13 @@ func pushQliksenseImages(q *qliksense.Qliksense) *cobra.Command {
}
return cmd
}
func ensureImageRegistrySetInCR(q *qliksense.Qliksense) error {
qConfig := qapi.NewQConfig(q.QliksenseHome)
if qcr, err := qConfig.GetCurrentCR(); err != nil {
return err
} else if registry := qcr.Spec.GetImageRegistry(); registry == "" {
return errors.New("no image registry set in the CR; to set it use: qliksense config set-image-registry")
}
return nil
}

View File

@@ -15,7 +15,7 @@ import (
"github.com/qlik-oss/sense-installer/pkg/qliksense"
"github.com/spf13/cobra"
"github.com/spf13/viper"
"github.com/ttacon/chalk"
. "github.com/logrusorgru/aurora"
)
// To run this project in debug mode, run:
@@ -27,6 +27,13 @@ const (
qlikSenseDirVar = ".qliksense"
keepPatchFilesFlagName = "keep-config-repo-patches"
keepPatchFilesFlagUsage = "Keep config repo patch files (for debugging)"
pullFlagName = "pull"
pullFlagShorthand = "d"
pullFlagUsage = "If using private docker registry, pull (download) all required Qliksense images before install"
pushFlagName = "push"
pushFlagShorthand = "u"
pushFlagUsage = "If using private docker registry, push (upload) all downloaded Qliksense images to that registry before install"
rootCommandName = "qliksense"
)
func initAndExecute() error {
@@ -85,17 +92,20 @@ var versionCmd = &cobra.Command{
}
func commandUsesContext(commandName string) bool {
return commandName != "" && commandName != "qliksense" && commandName != "help" && commandName != "version"
return commandName != "" &&
commandName != rootCommandName &&
commandName != fmt.Sprintf("%v help", rootCommandName) &&
commandName != fmt.Sprintf("%v version", rootCommandName)
}
func getRootCmd(p *qliksense.Qliksense) *cobra.Command {
cmd := &cobra.Command{
Use: "qliksense",
Use: rootCommandName,
Short: "Qliksense cli tool",
Long: `qliksense cli tool provides functionality to perform operations on qliksense-k8s, qliksense operator, and kubernetes cluster`,
Args: cobra.ArbitraryArgs,
PersistentPreRun: func(cmd *cobra.Command, args []string) {
if commandUsesContext(cmd.Name()) {
if commandUsesContext(cmd.CommandPath()) {
globalEulaPreRun(cmd, p)
if err := p.SetUpQliksenseDefaultContext(); err != nil {
panic(err)
@@ -108,14 +118,14 @@ func getRootCmd(p *qliksense.Qliksense) *cobra.Command {
}
},
PersistentPostRun: func(cmd *cobra.Command, args []string) {
if commandUsesContext(cmd.Name()) {
if commandUsesContext(cmd.CommandPath()) {
globalEulaPostRun(cmd, p)
}
},
}
origHelpFunc := cmd.HelpFunc()
cmd.SetHelpFunc(func(cmd *cobra.Command, args []string) {
if !commandUsesContext(cmd.Name()) {
if !commandUsesContext(cmd.CommandPath()) {
cmd.Flags().MarkHidden("acceptEULA")
}
origHelpFunc(cmd, args)
@@ -162,9 +172,6 @@ func rootCmd(p *qliksense.Qliksense) *cobra.Command {
viper.SetEnvKeyReplacer(strings.NewReplacer("-", "_"))
//add upgrade command
cmd.AddCommand(upgradeCmd(p))
// add the set-context config command as a sub-command to the app config command
configCmd.AddCommand(setContextConfigCmd(p))
@@ -188,6 +195,7 @@ func rootCmd(p *qliksense.Qliksense) *cobra.Command {
// add clean-config-repo-patches command as a sub-command to the app config sub-command
configCmd.AddCommand(cleanConfigRepoPatchesCmd(p))
// open editor for config
configCmd.AddCommand(configEditCmd(p))
@@ -212,6 +220,7 @@ func rootCmd(p *qliksense.Qliksense) *cobra.Command {
preflightCmd.AddCommand(pfCreateRoleBindingCheckCmd(p))
preflightCmd.AddCommand(pfCreateServiceAccountCheckCmd(p))
preflightCmd.AddCommand(pfCreateAuthCheckCmd(p))
preflightCmd.AddCommand(pfCleanupCmd(p))
cmd.AddCommand(preflightCmd)
cmd.AddCommand(loadCrFile(p))
@@ -260,7 +269,7 @@ func levenstein(cmd *cobra.Command) {
if !strings.EqualFold(arg[1], suggest[0]) {
arg[1] = suggest[0]
out := ansi.NewColorableStdout()
fmt.Fprintln(out, chalk.Green.Color("Did you mean: "), chalk.Bold.TextStyle(strings.Join(arg, " ")), "?")
fmt.Fprintln(out, Green("Did you mean: "), Bold(strings.Join(arg, " ")), "?")
}
}
}

View File

@@ -6,6 +6,7 @@ import (
)
func uninstallCmd(q *qliksense.Qliksense) *cobra.Command {
skipConfirmation := false
c := &cobra.Command{
Use: "uninstall",
Short: "Uninstall the deployed qliksense.",
@@ -13,10 +14,15 @@ func uninstallCmd(q *qliksense.Qliksense) *cobra.Command {
Example: `qliksense uninstall <context-name>`,
RunE: func(cmd *cobra.Command, args []string) error {
if len(args) > 0 {
return q.UninstallQK8s(args[0])
return q.UninstallQK8s(args[0], skipConfirmation)
}
return q.UninstallQK8s("")
return q.UninstallQK8s("", skipConfirmation)
},
}
f := c.Flags()
f.BoolVar(&skipConfirmation, "yes", skipConfirmation, "skips confirmation")
return c
}

View File

@@ -1,23 +0,0 @@
package main
import (
"github.com/qlik-oss/sense-installer/pkg/qliksense"
"github.com/spf13/cobra"
)
func upgradeCmd(q *qliksense.Qliksense) *cobra.Command {
keepPatchFiles := false
c := &cobra.Command{
Use: "upgrade",
Short: "upgrade qliksense release",
Long: `upgrade qliksense release`,
Example: `qliksense upgrade <version>`,
RunE: func(cmd *cobra.Command, args []string) error {
return q.UpgradeQK8s(keepPatchFiles)
},
}
f := c.Flags()
f.BoolVar(&keepPatchFiles, keepPatchFilesFlagName, keepPatchFiles, keepPatchFilesFlagUsage)
return c
}

View File

@@ -1,13 +1,47 @@
# qliksense command reference
# CLI reference
## qliksense apply
### qliksense preflight
`qliksense apply` command takes input a cr file or input from pipe
Preflight checks provide pre-installation cluster conformance testing and validation before we install qliksense on the cluster. We gather a suite of conformance tests that can be easily written and run on the target cluster to verify that cluster-specific requirements are met.
We support the following tests at the moment as part of preflight checks, and the range of the suite will be expanded in future.
Run the following command to view help about the commands supported by preflight at any moment:
```
qliksense preflight
```
#### Running all checks
Run the following command to execute all preflight checks
```
qliksense preflight all --mongodb-url=<mongo-server url> --mongodb-ca-cert=<path to ca-cert file>
```
#### Running specific check
Run the following command to execute a specific check
```
qliksense preflight dns
```
### qliksense load
`qliksense load` command takes input from a file or from pipe
- `qliksense load -f cr-file.yaml`
- `cat cr-file.yaml | qliksense load -f -`
This will load the Custom Resource (CR) into `${QLIKSENSE_HOME}` folder, create context structure and set the current context to that CR.
This will also encrypt the secrets from CR while writing the CR into the disk.
### qliksense apply
`qliksense apply` command takes input from a file or from pipe
- `qliksense apply -f cr-file.yaml`
- `cat cr-file.yaml | qliksense apply -f -`
the content of `cr-file.yaml` should be something similar
The content of `cr-file.yaml` should be something like the following:
```yaml
apiVersion: qlik.com/v1
@@ -27,33 +61,26 @@ spec:
value: mongodb://qlik-test-mongodb:27017/qliksense?ssl=false
profile: docker-desktop
rotateKeys: "yes"
```
```
This will do everything `qliksense load` does and install the qliksense into the cluster.
`qliksense apply` does everything `qliksense load` does but will install Qlik Sense into the cluster as well
## qliksense load
### qliksense about
`qliksense load` command takes input a cr file or input from pipe.
`qliksense about` command will display information about [qliksense-k8s](https://github.com/qlik-oss/qliksense-k8s) release.
- `qliksense load -f cr-file.yaml`
- `cat cr-file.yaml | qliksense load -f -`
For example, running the following command will show information about default profile for `1.0.0` tag
This will load the CR into `${QLIKSENSE_HOME}` folder, create context structure and set the current context to that CR.
This will also encrypt the secrets from CR while writing the CR into the disk.
```
qliksense about 1.0.0
```
## qliksense about
Run the following command to view options for `about` command:
```
qliksense about --help
```
About action will display inside information regarding [qliksense-k8](https://github.com/qlik-oss/qliksense-k8s) release.
it will support following flags
- `qliksense about 1.0.0` display default profile for tag `1.0.0`.
- `qliksense about 1.0.0 --profile=docker-desktop`
- `qliksense about`
- assuming current directory has `manifests/docker-desktop`
- or get version information from pull of `qliksense-k8s` `master`
using other supported commands user might have built the CR into the location `~/.qliksense/myqliksense.yaml`
Using other supported commands user might have built the CR into the location `~/.qliksense/myqliksense.yaml`
```yaml
apiVersion: qlik.com/v1
@@ -62,7 +89,7 @@ metadata:
name: myqliksense
spec:
profile: docker-desktop
manifestsRoot: /Usr/ddd/my-k8-repo/manifests
manifestsRoot: /Usr/xyz/my-k8-repo/manifests
namespace: myqliksense
storageClassName: efs
configs:
@@ -77,31 +104,30 @@ spec:
valueFromKey: messagingPassword
```
In that case the command would be
In this case, the result of `qliksense about` command would display information from:
- `qliksense about`
- display from `/Usr/ddd/my-k8-repo/manifests/docker-desktop` location
- pull from `master` if directory invalid/empty
- `/Usr/xyz/my-k8-repo/manifests/docker-desktop` location, or
- Pull and show information from `master` branch if the directory is invalid or empty
## qliksense config
### qliksense config
Config action will perform operations on configurations and contexts regarding the [qliksense-k8](https://github.com/qlik-oss/qliksense-k8s) release.
`qliksense config` will perform operations on configurations and contexts regarding the [qliksense-k8](https://github.com/qlik-oss/qliksense-k8s) release.
it will support following commands:
It supports the following flags:
- `qliksense config apply` - generate the patchs and apply manifests to k8s
- `qliksense config list-contexts` - retrieves the contexts and lists them
- `qliksense config set` - configure a key value pair into the current context
- `qliksense config set-configs` - set configurations into the qliksense context as key-value pairs
- `qliksense config set-context` - sets the context in which the Kubernetes cluster and resources live in
- `qliksense config set-secrets <service_name>.<attribute>="<value>" --secret=false` - set secrets configurations into the qliksense context as key-value pairs and show encrypted value as part of CR
- `qliksense config set-secrets <service_name>.<attribute>="<value>" --secret=true` - set secrets configurations into the qliksense context as key-value pairs and show a key reference to the created Kubernetes secret resource as part of the CR
- `qliksense config apply` - generate the patches and apply manifests to K8s
- `qliksense config list-contexts` - get and list contexts
- `qliksense config set` - configure a key-value pair into the current context
- `qliksense config set-configs` - set configurations into qliksense context as key-value pairs
- `qliksense config set-context` - sets the Kubernetes context where resources are located
- `qliksense config set-secrets <service_name>.<attribute>="<value>" --secret=false` - set secrets configurations into qliksense context as key-value pairs and show encrypted value as part of CR
- `qliksense config set-secrets <service_name>.<attribute>="<value>" --secret=true` - set secrets configurations into qliksense context as key-value pairs and show a key reference to the created Kubernetes secret resource as part of the CR
- `qliksense config view` - view the qliksense operator CR
- `qliksense config delete-context` - deletes a specific context locally (not in-cluster). Deletes context in spec of `config.yaml` and locally deletes entire folder of specified context (does not delete in-cluster secrets)
- `qliksense config delete-context` - deletes a specific context locally (not in-cluster). Deletes context in spec of `config.yaml` and locally deletes entire folder of specified context (does not delete secrets from cluster)
the global file that abstracts all the contexts is `config.yaml`, located at: `~/.qliksense/config.yaml`:
The global file which abstracts all contexts is `~/.qliksense/config.yaml`
```yaml
apiVersion: config.qlik.com/v1
kind: QliksenseConfig
@@ -110,10 +136,10 @@ metadata:
spec:
contexts:
- name: qlik-default
crFile: /Users/fff/.qliksense/contexts/qlik-default/qlik-default.yaml
crFile: /Users/xyz/.qliksense/contexts/qlik-default/qlik-default.yaml
- name: myqliksense
crFile: /Users/fff/.qliksense/contexts/myqliksense/myqliksense.yaml
crFile: /Users/xyz/.qliksense/contexts/myqliksense/myqliksense.yaml
- name: hello
crFile: /Users/fff/.qliksense/contexts/hello/hello.yaml
crFile: /Users/xyz/.qliksense/contexts/hello/hello.yaml
currentContext: hello
```
```

View File

@@ -1,4 +1,4 @@
# How qliksense cli works
# How CLI works
At the initialization, `qliksense` cli creates few files in the director `~/.qliksene` and it contains following files:
@@ -48,14 +48,14 @@ qliksense config -h
In this mode `qliksense` CLI downloads the specified version from [qliksense-k8s](https://github.com/qlik-oss/qliksense-k8s) and places it in `~/.qliksense/contexts/<context-name>/qlik-k8s` folder.
The qliksense cli creates a CR for the QlikSense operator and all config operations are peformed to edit the CR.
The qliksense cli creates a CR for the QlikSense operator and all config operations are performed to edit the CR.
`qliksense install` or `qliksense config apply` will generate patches in local file system (i.e `~/.qliksense/contexts/<context-name>/qlik-k8s`) and
- Install those manifests into the cluster
- Create a custom resoruce (CR) for the `qliksene operator`.
- Create a custom resource (CR) for the `qliksene operator`.
The operator makes the association to the installed resoruces so that when `qliksense uninstall` is performed the operator can delete all kubernetes resources related to QSEoK for the current context.
The operator makes the association to the installed resources so that when `qliksense uninstall` is performed the operator can delete all kubernetes resources related to QSEoK for the current context.
## With a git repo
@@ -94,4 +94,3 @@ spec:
image: qlik-docker-oss.bintray.io/qliksense-repo-watcher
....
```

View File

@@ -5,7 +5,7 @@
- Kubernetes cluster (Docker Desktop with enabled Kubernetes)
- `kubectl` installed, configured and able to communicate with kubernetes cluster. _`qliksense` CLI uses `kubectl` under the hood to perform operations on cluster_
## Installing Sense installer
## Installing `qliksense` CLI
Download the executable for your platform from [releases page](https://github.com/qlik-oss/sense-installer/releases) and rename it to `qliksense`

View File

@@ -1,22 +1,15 @@
# Overview
The Qlik Sense installer CLI (`qliksense`) provides an imperative interface to many of the configurations that need to be applied against the declarative structure described in [qliksense-k8s](https://github.com/qlik-oss/qliksense-k8s). This cli facilitates:
The Qlik Sense on Kubernetes CLI (`qliksense`) provides an imperative interface to many of the configurations that need to be applied against the declarative structure described in [qliksense-k8s](https://github.com/qlik-oss/qliksense-k8s).
The CLI facilitates:
- Installation of QSEoK
- Installation of qliksense operator to manage QSEoK
- Air gapped installation of QSEoK
!!! info ""
This is a technology preview that uses Qlik modified [kustomize](https://github.com/qlik-oss/kustomize) for kubernetes manifests on [qliksense-k8s](https://github.com/qlik-oss/qliksense-k8s) repository
This is a technology preview that uses Qlik modified [kustomize](https://github.com/qlik-oss/kustomize) for Kubernetes manifests on [qliksense-k8s](https://github.com/qlik-oss/qliksense-k8s) repository
!!! info ""
See QlikSense [edge releases on qliksense-k8s](https://github.com/qlik-oss/qliksense-k8s/releases) repository
## Future Direction
Operations:
- Expand preflight checks
- Backup/restore operations
- Fully support airgap installation of QSEoK
- Restore unwanted deletion of kubernetes resources

View File

@@ -1,10 +1,11 @@
##Preflight checks
# Preflight checks
Preflight checks provide pre-installation cluster conformance testing and validation before we install qliksense on the cluster. We gather a suite of conformance tests that can be easily written and run on the target cluster to verify that cluster-specific requirements are met.
The suite consists of a set of `collectors` which run the specifications of every test and `analyzers` which analyze the results of every test run by the collector.
We support the following tests at the moment as part of preflight checks, and the range of the suite will be expanded in future.
Run the following command to view help about the commands supported by preflight at any moment:
```console
```shell
$ qliksense preflight
perform preflight checks on the cluster
@@ -26,7 +27,7 @@ Flags:
### DNS check
Run the following command to perform preflight DNS check. We setup a kubernetes deployment and try to reach it as part of establishing DNS connectivity in this check.
The expected output should be similar to the one shown below.
```console
```shell
$ qliksense preflight dns
Preflight DNS check
@@ -49,7 +50,7 @@ Deleted deployment: dep-dns-preflight-check
### Kubernetes version check
We check the version of the target kubernetes cluster and ensure that it falls in the valid range of kubernetes versions that are supported by qliksense.
The command to run this check and the expected similar output are as shown below:
```console
```shell
$ qliksense preflight k8s-version
Preflight kubernetes minimum version check
@@ -64,7 +65,7 @@ Completed Preflight kubernetes minimum version check
### Service check
We use the commmand below to test if we are able to create a service in the cluster.
```console
```shell
$ qliksense preflight service
Preflight service check
@@ -80,7 +81,7 @@ Completed preflight service check
### Deployment check
We use the commmand below to test if we are able to create a deployment in the cluster. After the test exexutes, we wait until the created deployment terminates before we exit the command.
```console
```shell
$ qliksense preflight deployment
Preflight deployment check
@@ -95,7 +96,7 @@ Completed preflight deployment check
### Pod check
We use the commmand below to test if we are able to create a pod in the cluster.
```console
```shell
$ qliksense preflight pod
Preflight pod check
@@ -197,6 +198,8 @@ We can check if we are able to connect to an instance of mongodb on the cluster
```shell
qliksense preflight mongo --url=<url> OR
qliksense preflight mongo
qliksense preflight mongo --url=<mongo-server url> --ca-cert=<path to ca-cert file>
Preflight mongo check
---------------------
@@ -204,7 +207,7 @@ Preflight mongodb check:
Created pod: pf-mongo-pod
stdout: MongoDB shell version v4.2.5
connecting to: <url>/?compressors=disabled&gssapiServiceName=mongodb
Implicit session: session { "id" : UUID("64f639d3-2c93-4894-80f6-ee14acaf56a5") }
Implicit session: session { "id" : UUID("...") }
MongoDB server version: 4.2.5
bye
stderr:
@@ -217,9 +220,9 @@ Completed preflight mongodb check
### Running all checks
Run the command shown below to execute all preflight checks.
```console
```shell
$ qliksense preflight all --mongodb-url=<url> OR
$ qliksense preflight all
$ qliksense preflight all --mongodb-url=<mongo-server url> --mongodb-ca-cert=<path to ca-cert file>
Running all preflight checks

23
go.mod
View File

@@ -6,11 +6,11 @@ replace (
github.com/docker/docker => github.com/moby/moby v0.7.3-0.20190826074503-38ab9da00309
golang.org/x/sys => golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a
k8s.io/apimachinery => k8s.io/apimachinery v0.0.0-20191004115801-a2eda9f80ab8
k8s.io/client-go => k8s.io/client-go v0.0.0-20191016111102-bec269661e48
k8s.io/kubectl => k8s.io/kubectl v0.0.0-20191016120415-2ed914427d51
k8s.io/apimachinery => k8s.io/apimachinery v0.17.0
k8s.io/client-go => k8s.io/client-go v0.17.0
k8s.io/kubectl => k8s.io/kubectl v0.0.0-20191219154910-1528d4eea6dd
sigs.k8s.io/kustomize/api => github.com/qlik-oss/kustomize/api v0.3.3-0.20200402170547-2e8140160c36
sigs.k8s.io/kustomize/api => github.com/qlik-oss/kustomize/api v0.3.3-0.20200424070349-b0312eb71568
)
require (
@@ -20,45 +20,40 @@ require (
github.com/Shopify/ejson v1.2.1
github.com/aws/aws-sdk-go v1.28.9 // indirect
github.com/bugsnag/bugsnag-go v1.5.3 // indirect
github.com/containerd/containerd v1.3.2 // indirect
github.com/containerd/continuity v0.0.0-20191214063359-1097c8bae83b // indirect
github.com/containers/image/v5 v5.1.0
github.com/docker/cli v0.0.0-20191212191748-ebca1413117a // indirect
github.com/docker/docker v1.4.2-0.20190924003213-a8608b5b67c7 // indirect
github.com/docker/go-metrics v0.0.1 // indirect
github.com/go-git/go-git/v5 v5.0.0
github.com/gobuffalo/envy v1.9.0 // indirect
github.com/gobuffalo/logger v1.0.3 // indirect
github.com/gobuffalo/packd v1.0.0 // indirect
github.com/gobuffalo/packr/v2 v2.7.1
github.com/gofrs/uuid v3.2.0+incompatible // indirect
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e // indirect
github.com/golang/protobuf v1.3.3 // indirect
github.com/gorilla/mux v1.7.3 // indirect
github.com/hashicorp/golang-lru v0.5.4 // indirect
github.com/jinzhu/copier v0.0.0-20190924061706-b57f9002281a
github.com/kardianos/osext v0.0.0-20190222173326-2bc1f35cddc0 // indirect
github.com/logrusorgru/aurora v0.0.0-20200102142835-e9ef32dff381
github.com/mattn/go-colorable v0.1.4
github.com/mattn/go-tty v0.0.3
github.com/mitchellh/go-homedir v1.1.0
github.com/morikuni/aec v1.0.0 // indirect
github.com/otiai10/copy v1.1.1
github.com/pkg/errors v0.8.1
github.com/pkg/errors v0.9.1
github.com/qlik-oss/k-apis v0.1.1
github.com/robfig/cron/v3 v3.0.1
github.com/rogpeppe/go-internal v1.5.2 // indirect
github.com/spf13/cobra v0.0.6
github.com/spf13/viper v1.6.1
github.com/ttacon/chalk v0.0.0-20160626202418-22c06c80ed31
golang.org/x/crypto v0.0.0-20200311171314-f7b00557c8c4 // indirect
golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a // indirect
golang.org/x/net v0.0.0-20200301022130-244492dfa37a
golang.org/x/tools v0.0.0-20200312194400-c312e98713c2 // indirect
google.golang.org/genproto v0.0.0-20200128133413-58ce757ed39b // indirect
google.golang.org/grpc v1.27.0 // indirect
gopkg.in/yaml.v2 v2.2.8
gopkg.in/yaml.v3 v3.0.0-20190924164351-c8b7dadae555
k8s.io/api v0.17.0
k8s.io/apimachinery v0.17.0
k8s.io/api v0.17.2
k8s.io/apimachinery v0.17.2
k8s.io/client-go v11.0.0+incompatible
sigs.k8s.io/kustomize/api v0.3.2
sigs.k8s.io/yaml v1.1.0

272
go.sum
View File

@@ -35,6 +35,7 @@ github.com/14rcole/gopopulate v0.0.0-20180821133914-b175b219e774/go.mod h1:6/0dY
github.com/Azure/azure-amqp-common-go/v2 v2.1.0/go.mod h1:R8rea+gJRuJR6QxTir/XuEd+YuKoUiazDC/N96FiDEU=
github.com/Azure/azure-pipeline-go v0.2.1 h1:OLBdZJ3yvOn2MezlWvbrBMTEUQC72zAftRZOMdj5HYo=
github.com/Azure/azure-pipeline-go v0.2.1/go.mod h1:UGSo8XybXnIGZ3epmeBw7Jdz+HiUVpqIlpz/HKHylF4=
github.com/Azure/azure-sdk-for-go v16.2.1+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc=
github.com/Azure/azure-sdk-for-go v29.0.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc=
github.com/Azure/azure-sdk-for-go v30.1.0+incompatible h1:HyYPft8wXpxMd0kfLtXo6etWcO+XuPbLkcgx9g2cqxU=
github.com/Azure/azure-sdk-for-go v30.1.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc=
@@ -43,6 +44,7 @@ github.com/Azure/azure-storage-blob-go v0.8.0 h1:53qhf0Oxa0nOjgbDeeYPUeyiNmafAFE
github.com/Azure/azure-storage-blob-go v0.8.0/go.mod h1:lPI3aLPpuLTeUwh1sViKXFxwl2B6teiRqI0deQUvsw0=
github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78 h1:w+iIsaOQNcT7OZ575w+acHgRric5iCyQh+xv+KJ4HB8=
github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8=
github.com/Azure/go-autorest v10.8.1+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24=
github.com/Azure/go-autorest v12.1.0+incompatible h1:x0sVyfVo0Qw9jcgVHuKIAiTHGRvQ9PsJP+43TVPV/DM=
github.com/Azure/go-autorest v12.1.0+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24=
github.com/Azure/go-autorest/autorest v0.9.0 h1:MRvx8gncNaXJqOoLmhNjUAKh33JJF8LyxPhomEtOsjs=
@@ -64,21 +66,17 @@ github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym
github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ=
github.com/DataDog/zstd v1.4.0/go.mod h1:1jcaCB/ufaK+sKp1NBhlGmpz41jOoPQ35bpF36t7BBo=
github.com/GoogleCloudPlatform/cloudsql-proxy v0.0.0-20190605020000-c4ba1fdf4d36/go.mod h1:aJ4qN3TfrelA6NZ6AXsXRfmEVaYin3EDbSPJrKS8OXo=
github.com/MakeNowJust/heredoc v0.0.0-20170808103936-bb23615498cd h1:sjQovDkwrZp8u+gxLtPgKGjk5hCxuy2hrRejBTA9xFU=
github.com/MakeNowJust/heredoc v0.0.0-20170808103936-bb23615498cd/go.mod h1:64YHyfSL2R96J44Nlwm39UHepQbyR5q10x7iYa1ks2E=
github.com/MakeNowJust/heredoc v0.0.0-20171113091838-e9091a26100e h1:eb0Pzkt15Bm7f2FFYv7sjY7NPFi3cPkS3tv1CcrFBWA=
github.com/MakeNowJust/heredoc v0.0.0-20171113091838-e9091a26100e/go.mod h1:64YHyfSL2R96J44Nlwm39UHepQbyR5q10x7iYa1ks2E=
github.com/Masterminds/goutils v1.1.0 h1:zukEsf/1JZwCMgHiK3GZftabmxiCw4apj3a28RPBiVg=
github.com/Masterminds/goutils v1.1.0/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU=
github.com/Masterminds/semver/v3 v3.0.3 h1:znjIyLfpXEDQjOIEWh+ehwpTU14UzUPub3c3sm36u14=
github.com/Masterminds/semver/v3 v3.0.3/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs=
github.com/Masterminds/sprig/v3 v3.0.2 h1:wz22D0CiSctrliXiI9ZO3HoNApweeRGftyDN+BQa3B8=
github.com/Masterminds/sprig/v3 v3.0.2/go.mod h1:oesJ8kPONMONaZgtiHNzUShJbksypC5kWczhZAf6+aU=
github.com/Masterminds/vcs v1.13.0/go.mod h1:N09YCmOQr6RLxC6UNHzuVwAdodYbbnycGHSmwVJjcKA=
github.com/Microsoft/go-winio v0.4.11/go.mod h1:VhR8bwka0BXejwEJY73c50VrPtXAaKcyvVC4A4RozmA=
github.com/Microsoft/go-winio v0.4.12/go.mod h1:VhR8bwka0BXejwEJY73c50VrPtXAaKcyvVC4A4RozmA=
github.com/Masterminds/vcs v1.13.1/go.mod h1:N09YCmOQr6RLxC6UNHzuVwAdodYbbnycGHSmwVJjcKA=
github.com/Microsoft/go-winio v0.4.15-0.20190919025122-fc70bd9a86b5 h1:ygIc8M6trr62pF5DucadTWGdEB4mEyvzi0e2nbcmcyA=
github.com/Microsoft/go-winio v0.4.15-0.20190919025122-fc70bd9a86b5/go.mod h1:tTuCMEN+UleMWgg9dVx4Hu52b1bJo+59jBh3ajtinzw=
github.com/Microsoft/hcsshim v0.8.6/go.mod h1:Op3hHsoHPAvb6lceZHDtd9OkTew38wNoXnJs8iY7rUg=
github.com/Microsoft/hcsshim v0.8.7 h1:ptnOoufxGSzauVTsdE+wMYnCWA301PdoN4xg5oRdZpg=
github.com/Microsoft/hcsshim v0.8.7/go.mod h1:OHd7sQqRFrYd3RmSgbgji+ctCwkbq2wbEYNSzOYtcBQ=
github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ=
@@ -98,12 +96,12 @@ github.com/Shopify/logrus-bugsnag v0.0.0-20171204204709-577dee27f20d/go.mod h1:H
github.com/StackExchange/wmi v0.0.0-20180116203802-5d049714c4a6/go.mod h1:3eOhrUMpNV+6aFIbp5/iudMxNCF27Vw2OZgy4xEx0Fg=
github.com/VividCortex/ewma v1.1.1 h1:MnEK4VOv6n0RSY4vtRe3h11qjxL3+t0B8yOL8iMXdcM=
github.com/VividCortex/ewma v1.1.1/go.mod h1:2Tkkvm3sRDVXaiyucHiACn4cqf7DpdyLvmxzcbUokwA=
github.com/agnivade/levenshtein v1.0.1/go.mod h1:CURSv5d9Uaml+FovSIICkLbAUZ9S4RqaHDIsdSBg7lM=
github.com/alcortesm/tgz v0.0.0-20161220082320-9c5fe88206d7 h1:uSoVVbwJiQipAclBbw+8quDsfcvFjOpI5iCf4p/cqCs=
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/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo29Kk6CurOXKm700vrz8f0KW0JNfpkRJY/8=
github.com/andybalholm/brotli v0.0.0-20190621154722-5f990b63d2d6 h1:bZ28Hqta7TFAK3Q08CMvv8y3/8ATaEqv2nGoc6yff6c=
github.com/andybalholm/brotli v0.0.0-20190621154722-5f990b63d2d6/go.mod h1:+lx6/Aqd1kLJ1GQfkvOnaZ1WGmLpMpbprPuIOOZX30U=
github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239 h1:kFOfPq6dUM1hTo4JG6LR5AXSUEsOjtdm0kw0FtQtMJA=
@@ -119,6 +117,9 @@ github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkY
github.com/asaskevich/govalidator v0.0.0-20180720115003-f9ffefc3facf/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY=
github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a h1:idn718Q4B6AGu/h5Sxe66HYVdqdGu2l9Iebqhi/AEoA=
github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY=
github.com/asaskevich/govalidator v0.0.0-20200108200545-475eaeb16496 h1:zV3ejI06GQ59hwDQAvmK1qxOQGB3WuVTRoY0okPTAv0=
github.com/asaskevich/govalidator v0.0.0-20200108200545-475eaeb16496/go.mod h1:oGkLhpf+kjZl6xBf758TQhh5XrAeiJv/7FRz/2spLIg=
github.com/aws/aws-sdk-go v1.15.11/go.mod h1:mFuSZ37Z9YOHbQEwBWztmVzqXrEkub65tZoCYDt7FT0=
github.com/aws/aws-sdk-go v1.15.27/go.mod h1:mFuSZ37Z9YOHbQEwBWztmVzqXrEkub65tZoCYDt7FT0=
github.com/aws/aws-sdk-go v1.17.4/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
github.com/aws/aws-sdk-go v1.19.18/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
@@ -127,6 +128,7 @@ github.com/aws/aws-sdk-go v1.25.36 h1:4+TL/Y2G5hsR1zdfHmjNG1ou1WEqsSWk8v7m1GaDKy
github.com/aws/aws-sdk-go v1.25.36/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
github.com/aws/aws-sdk-go v1.28.9 h1:grIuBQc+p3dTRXerh5+2OxSuWFi0iXuxbFdTSg0jaW0=
github.com/aws/aws-sdk-go v1.28.9/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
github.com/beorn7/perks v0.0.0-20160804104726-4c0e84591b9a/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
@@ -145,17 +147,17 @@ github.com/boltdb/bolt v1.3.1/go.mod h1:clJnj/oiGkjum5o1McbSZDSLxVThjynRyGBgiAx2
github.com/bombsimon/wsl v1.2.5/go.mod h1:43lEF/i0kpXbLCeDXL9LMT8c92HyBywXb0AsgMHYngM=
github.com/bshuster-repo/logrus-logstash-hook v0.4.1 h1:pgAtgj+A31JBVtEHu2uHuEx0n+2ukqUJnS2vVe5pQNA=
github.com/bshuster-repo/logrus-logstash-hook v0.4.1/go.mod h1:zsTqEiSzDgAa/8GZR7E1qaXrhYNDKBYy5/dWPTIflbk=
github.com/bugsnag/bugsnag-go v1.5.0/go.mod h1:2oa8nejYd4cQ/b0hMIopN0lCRxU0bueqREvZLWFrtK8=
github.com/bugsnag/bugsnag-go v0.0.0-20141110184014-b1d153021fcd/go.mod h1:2oa8nejYd4cQ/b0hMIopN0lCRxU0bueqREvZLWFrtK8=
github.com/bugsnag/bugsnag-go v1.5.3 h1:yeRUT3mUE13jL1tGwvoQsKdVbAsQx9AJ+fqahKveP04=
github.com/bugsnag/bugsnag-go v1.5.3/go.mod h1:2oa8nejYd4cQ/b0hMIopN0lCRxU0bueqREvZLWFrtK8=
github.com/bugsnag/panicwrap v1.2.0 h1:OzrKrRvXis8qEvOkfcxNcYbOd2O7xXS2nnKMEMABFQA=
github.com/bugsnag/panicwrap v1.2.0/go.mod h1:D/8v3kj0zr8ZAKg1AQ6crr+5VwKN5eIywRkfhyM/+dE=
github.com/bugsnag/osext v0.0.0-20130617224835-0dd3f918b21b h1:otBG+dV+YK+Soembjv71DPz3uX/V/6MMlSyD9JBQ6kQ=
github.com/bugsnag/osext v0.0.0-20130617224835-0dd3f918b21b/go.mod h1:obH5gd0BsqsP2LwDJ9aOkm/6J86V6lyAXCoQWGw3K50=
github.com/bugsnag/panicwrap v0.0.0-20151223152923-e2c28503fcd0 h1:nvj0OLI3YqYXer/kZD8Ri1aaunCxIEsOst1BVJswV0o=
github.com/bugsnag/panicwrap v0.0.0-20151223152923-e2c28503fcd0/go.mod h1:D/8v3kj0zr8ZAKg1AQ6crr+5VwKN5eIywRkfhyM/+dE=
github.com/census-instrumentation/opencensus-proto v0.2.0/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
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.0 h1:yTUvW7Vhb89inJ+8irsUqiWjh8iT6sQPZiQzI6ReGkA=
github.com/cespare/xxhash/v2 v2.1.0/go.mod h1:dgIUBU3pDso/gPgZ1osOZ0iQf77oPR28Tjxl5dIMyVM=
github.com/chai2010/gettext-go v0.0.0-20160711120539-c6fed771bfd5/go.mod h1:/iP1qXHoty45bqomnu2LM+VVyAEdWN+vtSHGlQgyxbw=
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
@@ -163,20 +165,18 @@ github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMn
github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag=
github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I=
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8=
github.com/containerd/cgroups v0.0.0-20190919134610-bf292b21730f h1:tSNMc+rJDfmYntojat8lljbt1mgKNpTxUZJsSzJ9Y1s=
github.com/containerd/cgroups v0.0.0-20190919134610-bf292b21730f/go.mod h1:OApqhQ4XNSNC13gXIwDjhOQxjWa/NxkwZXJ1EvqT0ko=
github.com/containerd/console v0.0.0-20180822173158-c12b1e7919c1/go.mod h1:Tj/on1eG8kiEhd0+fhSDzsPAFESxzBBvdyEgyryXffw=
github.com/containerd/containerd v1.2.10/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA=
github.com/containerd/containerd v1.3.0-beta.2.0.20190823190603-4a2f61c4f2b4/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA=
github.com/containerd/containerd v1.3.0-beta.2.0.20190828155532-0293cbd26c69/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA=
github.com/containerd/containerd v1.3.0/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA=
github.com/containerd/containerd v1.3.2 h1:ForxmXkA6tPIvffbrDAcPUIB32QgXkt2XFj+F0UxetA=
github.com/containerd/containerd v1.3.2/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA=
github.com/containerd/continuity v0.0.0-20180216233310-d8fb8589b0e8/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y=
github.com/containerd/continuity v0.0.0-20181203112020-004b46473808/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y=
github.com/containerd/continuity v0.0.0-20190426062206-aaeac12a7ffc/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y=
github.com/containerd/continuity v0.0.0-20191214063359-1097c8bae83b h1:pik3LX++5O3UiNWv45wfP/WT81l7ukBJzd3uUiifbSU=
github.com/containerd/continuity v0.0.0-20191214063359-1097c8bae83b/go.mod h1:Dq467ZllaHgAtVp4p1xUQWBrFXR9s/wyoTpG8zOJGkY=
github.com/containerd/continuity v0.0.0-20200107194136-26c1120b8d41 h1:kIFnQBO7rQ0XkMe6xEwbybYHBEaWmh/f++laI6Emt7M=
github.com/containerd/continuity v0.0.0-20200107194136-26c1120b8d41/go.mod h1:Dq467ZllaHgAtVp4p1xUQWBrFXR9s/wyoTpG8zOJGkY=
github.com/containerd/fifo v0.0.0-20190226154929-a9fb20d87448/go.mod h1:ODA38xgv3Kuk8dQz2ZQXpnv/UZZUHUCL7pnLehbXgQI=
github.com/containerd/go-runc v0.0.0-20180907222934-5a6d9f37cfa3/go.mod h1:IV7qH3hrUgRmyYrtgEeGWJfWbgcHL9CSRruz2Vqcph0=
github.com/containerd/ttrpc v0.0.0-20190828154514-0e0f228740de/go.mod h1:PvCDdDGpgqzQIzDW1TphrGLssLDZp2GuS+X5DkEJB8o=
@@ -190,10 +190,8 @@ github.com/containers/ocicrypt v0.0.0-20190930154801-b87a4a69c741 h1:8tQkOcednLJ
github.com/containers/ocicrypt v0.0.0-20190930154801-b87a4a69c741/go.mod h1:MeJDzk1RJHv89LjsH0Sp5KTY3ZYkjXO/C+bKAeWFIrc=
github.com/containers/storage v1.15.3 h1:+lFSQZnnKUFyUEtguIgdoQLJfWSuYz+j/wg5GxLtsN4=
github.com/containers/storage v1.15.3/go.mod h1:v0lq/3f+cXH3Y/HiDaFYRR0zilwDve7I4W7U5xQxvF8=
github.com/coreos/bbolt v1.3.1-coreos.6/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk=
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.15+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk=
github.com/coreos/go-oidc v2.1.0+incompatible/go.mod h1:CgnwVTmzoESiwO9qyAFEMiHoZ1nMCKZlZ9V6mm3/LKc=
github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
@@ -201,6 +199,7 @@ github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3Ee
github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e h1:Wf6HqHfScWJN9/ZjdUKyjop4mf3Qdd+1TvvltAvM3m8=
github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
github.com/coreos/pkg v0.0.0-20180108230652-97fdf19511ea/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
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=
@@ -215,27 +214,28 @@ github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs
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=
github.com/daviddengcn/go-colortext v0.0.0-20160507010035-511bcaf42ccd/go.mod h1:dv4zxwHi5C/8AeI+4gX4dCWOIvNi7I6JCSX0HvlKPgE=
github.com/deislabs/oras v0.7.0 h1:RnDoFd3tQYODMiUqxgQ8JxlrlWL0/VMKIKRD01MmNYk=
github.com/deislabs/oras v0.7.0/go.mod h1:sqMKPG3tMyIX9xwXUBRLhZ24o+uT4y6jgBD2RzUTKDM=
github.com/deislabs/oras v0.8.1 h1:If674KraJVpujYR00rzdi0QAmW4BxzMJPVAZJKuhQ0c=
github.com/deislabs/oras v0.8.1/go.mod h1:Mx0rMSbBNaNfY9hjpccEnxkOqJL6KGjtxNHPLC4G4As=
github.com/denverdino/aliyungo v0.0.0-20190125010748-a747050bb1ba/go.mod h1:dV8lFg6daOBZbT6/BDGIz6Y3WFGn8juu6G+CQ6LHtl0=
github.com/devigned/tab v0.1.1/go.mod h1:XG9mPq0dFghrYvoBF3xdRrJzSTX1b7IQrvaL9mzjeJY=
github.com/dgrijalva/jwt-go v0.0.0-20170104182250-a601269ab70c/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM=
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
github.com/dimchansky/utfbom v1.1.0/go.mod h1:rO41eb7gLfo8SF1jd9F8HplJm1Fewwi4mQvIirEdv+8=
github.com/docker/cli v0.0.0-20190506213505-d88565df0c2d/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8=
github.com/docker/cli v0.0.0-20191212191748-ebca1413117a h1:rgpgmLocRiSIM3zdtVgJcyvH7S2cSiIPtL7LvFY8K/0=
github.com/docker/cli v0.0.0-20191212191748-ebca1413117a/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8=
github.com/dnaeon/go-vcr v1.0.1/go.mod h1:aBB1+wY4s93YsC3HHjMBMrwTj2R9FHDzUr9KyGc8n1E=
github.com/docker/cli v0.0.0-20200130152716-5d0cf8839492 h1:FwssHbCDJD025h+BchanCwE1Q8fyMgqDr2mOQAWOLGw=
github.com/docker/cli v0.0.0-20200130152716-5d0cf8839492/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8=
github.com/docker/distribution v0.0.0-20170817175659-5f6282db7d65/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
github.com/docker/distribution v2.7.1-0.20190205005809-0d3efadf0154+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
github.com/docker/distribution v0.0.0-20191216044856-a8371794149d/go.mod h1:0+TTO4EOBfRPhZXAeF1Vu+W3hHZ8eLp8PgKVZlcvtFY=
github.com/docker/distribution v2.7.1+incompatible h1:a5mlkVzth6W5A4fOsS3D2EO5BUmsJpcB+cRlLU7cSug=
github.com/docker/distribution v2.7.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
github.com/docker/docker-credential-helpers v0.6.1/go.mod h1:WRaJzqw3CTB9bk10avuGsjVBZsD05qeibJ1/TYlvc0Y=
github.com/docker/docker-credential-helpers v0.6.3 h1:zI2p9+1NQYdnG6sMU26EX4aVGlqbInSQxQXLvzJ4RPQ=
github.com/docker/docker-credential-helpers v0.6.3/go.mod h1:WRaJzqw3CTB9bk10avuGsjVBZsD05qeibJ1/TYlvc0Y=
github.com/docker/go-connections v0.0.0-20180212134524-7beb39f0b969/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec=
github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ=
github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec=
github.com/docker/go-metrics v0.0.0-20181218153428-b84716841b82/go.mod h1:/u0gXw0Gay3ceNrsHubL3BtdOL2fHf93USgMTe0W5dI=
github.com/docker/go-metrics v0.0.0-20180209012529-399ea8c73916/go.mod h1:/u0gXw0Gay3ceNrsHubL3BtdOL2fHf93USgMTe0W5dI=
github.com/docker/go-metrics v0.0.1 h1:AgB/0SvBxihN0X8OR4SjsblXkbMvalQ8cjmtKQ2rQV8=
github.com/docker/go-metrics v0.0.1/go.mod h1:cG1hvH2utMXtqgqqYE9plW6lDxS3/5ayHzueweSI3Vw=
github.com/docker/go-units v0.3.3/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
@@ -243,25 +243,24 @@ github.com/docker/go-units v0.4.0 h1:3uh0PgVws3nIA0Q+MwDC8yjEPf9zjRfZZWXZYDct3Tw
github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
github.com/docker/libkv v0.2.1 h1:PNXYaftMVCFS5CmnDtDWTg3wbBO61Q/cEo3KX1oKxto=
github.com/docker/libkv v0.2.1/go.mod h1:r5hEwHwW8dr0TFBYGCarMNbrQOiwL1xoqDYZ/JqoTK0=
github.com/docker/libtrust v0.0.0-20150114040149-fa567046d9b1/go.mod h1:cyGadeNEkKy96OOhEzfZl+yxihPEzKnqJwvfuSUqbZE=
github.com/docker/libtrust v0.0.0-20160708172513-aabc10ec26b7 h1:UhxFibDNY/bfvqU5CAUmr9zpesgbU6SWc8/B4mflAE4=
github.com/docker/libtrust v0.0.0-20160708172513-aabc10ec26b7/go.mod h1:cyGadeNEkKy96OOhEzfZl+yxihPEzKnqJwvfuSUqbZE=
github.com/docker/spdystream v0.0.0-20160310174837-449fdfce4d96 h1:cenwrSVm+Z7QLSV/BsnenAOcDXdX4cMv4wP0B/5QbPg=
github.com/docker/spdystream v0.0.0-20160310174837-449fdfce4d96/go.mod h1:Qh8CwZgvJUkLughtfhJv5dyTYa91l1fOUCrgjqmcifM=
github.com/docker/spdystream v0.0.0-20181023171402-6480d4af844c h1:ZfSZ3P3BedhKGUhzj7BQlPSU4OvT6tfOKe3DVHzOA7s=
github.com/docker/spdystream v0.0.0-20181023171402-6480d4af844c/go.mod h1:Qh8CwZgvJUkLughtfhJv5dyTYa91l1fOUCrgjqmcifM=
github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE=
github.com/dsnet/compress v0.0.1 h1:PlZu0n3Tuv04TzpfPbrnI0HW/YwodEXDS+oPKahKF0Q=
github.com/dsnet/compress v0.0.1/go.mod h1:Aw8dCMJ7RioblQeTqt88akK31OvO8Dhf5JflhBbQEHo=
github.com/dsnet/golib v0.0.0-20171103203638-1ea166775780/go.mod h1:Lj+Z9rebOhdfkVLjJ8T6VcRQv3SXugXy999NBtR9aFY=
github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4 h1:qk/FSDDxo05wdJH28W+p5yivv7LuLYLRXPPD8KQCtZs=
github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
github.com/dustin/gojson v0.0.0-20160307161227-2e71ec9dd5ad h1:Qk76DOWdOp+GlyDKBAG3Klr9cn7N+LcYc82AZ2S7+cA=
github.com/dustin/gojson v0.0.0-20160307161227-2e71ec9dd5ad/go.mod h1:mPKfmRa823oBIgl2r20LeMSpTAteW5j7FLkc0vjmzyQ=
github.com/elazarl/goproxy v0.0.0-20170405201442-c4fc26588b6e h1:p1yVGRW3nmb85p1Sh1ZJSDm4A4iKLS5QNbvUHMgGu/M=
github.com/elazarl/goproxy v0.0.0-20170405201442-c4fc26588b6e/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc=
github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs=
github.com/emicklei/go-restful v2.9.5+incompatible h1:spTtZBk5DYEvbxMVutUuTyh1Ao2r4iyvLdACqsl/Ljk=
github.com/emicklei/go-restful v2.9.5+incompatible/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs=
github.com/emicklei/go-restful v2.11.1+incompatible h1:CjKsv3uWcCMvySPQYKxO8XX3f9zD4FeZRsW4G0B4ffE=
github.com/emicklei/go-restful v2.11.1+incompatible/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs=
github.com/emirpasic/gods v1.12.0 h1:QAUIPSaCu4G+POclxeqb3F+WPpdKqFGlw36+yOzGlrg=
github.com/emirpasic/gods v1.12.0/go.mod h1:YfzfFFoVP/catgzJb4IKIqXjX78Ha8FMSDh3ymbK86o=
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
@@ -288,11 +287,10 @@ github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/fullsailor/pkcs7 v0.0.0-20190404230743-d7302db945fa h1:RDBNVkRviHZtvDvId8XSGPu3rmpmSe+wKRcEWNgsfWU=
github.com/fullsailor/pkcs7 v0.0.0-20190404230743-d7302db945fa/go.mod h1:KnogPXtdwXqoenmZCw6S+25EAm2MkxbG0deNDu4cbSA=
github.com/garyburd/redigo v1.6.0 h1:0VruCpn7yAIIu7pWVClQC8wxCJEcG3nyzpMSHKi1PQc=
github.com/garyburd/redigo v1.6.0/go.mod h1:NR3MbYisc3/PwhQ00EMzDiPmrwpPxAn5GI05/YaO1SY=
github.com/garyburd/redigo v0.0.0-20150301180006-535138d7bcd7 h1:LofdAjjjqCSXMwLGgOgnE+rdPuvX9DxCqaHwKy7i/ko=
github.com/garyburd/redigo v0.0.0-20150301180006-535138d7bcd7/go.mod h1:NR3MbYisc3/PwhQ00EMzDiPmrwpPxAn5GI05/YaO1SY=
github.com/ghodss/yaml v0.0.0-20150909031657-73d445a93680/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
github.com/ghodss/yaml v0.0.0-20161207003320-04f313413ffd/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
github.com/ghodss/yaml v0.0.0-20180820084758-c7ce16629ff4/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk=
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
github.com/gliderlabs/ssh v0.2.2 h1:6zsha5zo/TWhRhwqCD3+EarCAgZ2yN28ipRnGPnwkI0=
@@ -302,7 +300,9 @@ github.com/globalsign/mgo v0.0.0-20181015135952-eeefdecb41b8/go.mod h1:xkRDCp4j0
github.com/go-critic/go-critic v0.3.5-0.20190904082202-d79a9f0c64db/go.mod h1:+sE8vrLDS2M0pZkBk0wy6+nLdKexVDrl/jBqQOTDThA=
github.com/go-git/gcfg v1.5.0 h1:Q5ViNfGF8zFgyJWPqYwA7qGFoMTEiBmdlkcfRmpIMa4=
github.com/go-git/gcfg v1.5.0/go.mod h1:5m20vg6GwYabIxaOonVkTdrILxQMpEShl1xiMF4ua+E=
github.com/go-git/go-billy/v5 v5.0.0 h1:7NQHvd9FVid8VL4qVUMm8XifBK+2xCoZ2lSk0agRrHM=
github.com/go-git/go-billy/v5 v5.0.0/go.mod h1:pmpqyWchKfYfrkb/UVH4otLvyi/5gJlGI4Hb3ZqZ3W0=
github.com/go-git/go-git-fixtures/v4 v4.0.1 h1:q+IFMfLx200Q3scvt2hN79JsEzy4AmBTp/pqnefH+Bc=
github.com/go-git/go-git-fixtures/v4 v4.0.1/go.mod h1:m+ICp2rF3jDhFgEZ/8yziagdT1C+ZpZcrJjappBCDSw=
github.com/go-git/go-git/v5 v5.0.0 h1:k5RWPm4iJwYtfWoxIJy4wJX9ON7ihPeZZYC1fLYDnpg=
github.com/go-git/go-git/v5 v5.0.0/go.mod h1:oYD8y9kWsGINPFJoLdaScGCN6dlKg23blmClfZwtUVA=
@@ -310,7 +310,6 @@ github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
github.com/go-ini/ini v1.25.4/go.mod h1:ByCAeIL28uOIIG0E3PJtZPDL8WnHpFKFOtgjp+3Ies8=
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=
github.com/go-ldap/ldap v3.0.2+incompatible/go.mod h1:qfd9rJvER9Q0/D/Sqn1DfHRoBp40uXYvFoEVrNEPqRc=
github.com/go-lintpack/lintpack v0.5.2/go.mod h1:NwZuYi2nUHho8XEIZ6SIxihrnPoqBTDqfpXvXAN0sXM=
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
@@ -321,6 +320,7 @@ github.com/go-openapi/analysis v0.0.0-20180825180245-b006789cd277/go.mod h1:k70t
github.com/go-openapi/analysis v0.17.0/go.mod h1:IowGgpVeD0vNm45So8nr+IcQ3pxVtpRoBWb8PVZO0ik=
github.com/go-openapi/analysis v0.18.0/go.mod h1:IowGgpVeD0vNm45So8nr+IcQ3pxVtpRoBWb8PVZO0ik=
github.com/go-openapi/analysis v0.19.2/go.mod h1:3P1osvZa9jKjb8ed2TPng3f0i/UY9snX6gxi44djMjk=
github.com/go-openapi/analysis v0.19.5/go.mod h1:hkEAkxagaIvIP7VTn8ygJNkd4kAYON2rCu0v0ObL0AU=
github.com/go-openapi/errors v0.17.0/go.mod h1:LcZQpmvG4wyF5j4IhA73wkLFQg+QJXOQHVjmcZxhka0=
github.com/go-openapi/errors v0.18.0/go.mod h1:LcZQpmvG4wyF5j4IhA73wkLFQg+QJXOQHVjmcZxhka0=
github.com/go-openapi/errors v0.19.2/go.mod h1:qX0BLWsyaKfvhluLejVpVNwNRdXZhEbTA4kxxpKBC94=
@@ -340,17 +340,21 @@ github.com/go-openapi/loads v0.17.0/go.mod h1:72tmFy5wsWx89uEVddd0RjRWPZm92WRLhf
github.com/go-openapi/loads v0.18.0/go.mod h1:72tmFy5wsWx89uEVddd0RjRWPZm92WRLhf7AC+0+OOU=
github.com/go-openapi/loads v0.19.0/go.mod h1:72tmFy5wsWx89uEVddd0RjRWPZm92WRLhf7AC+0+OOU=
github.com/go-openapi/loads v0.19.2/go.mod h1:QAskZPMX5V0C2gvfkGZzJlINuP7Hx/4+ix5jWFxsNPs=
github.com/go-openapi/loads v0.19.4/go.mod h1:zZVHonKd8DXyxyw4yfnVjPzBjIQcLt0CCsn0N0ZrQsk=
github.com/go-openapi/runtime v0.0.0-20180920151709-4f900dc2ade9/go.mod h1:6v9a6LTXWQCdL8k1AO3cvqx5OtZY/Y9wKTgaoP6YRfA=
github.com/go-openapi/runtime v0.19.0/go.mod h1:OwNfisksmmaZse4+gpV3Ne9AyMOlP1lt4sK4FXt0O64=
github.com/go-openapi/runtime v0.19.4/go.mod h1:X277bwSUBxVlCYR3r7xgZZGKVvBd/29gLDlFGtJ8NL4=
github.com/go-openapi/spec v0.0.0-20160808142527-6aced65f8501/go.mod h1:J8+jY1nAiCcj+friV/PDoE1/3eeccG9LYBs0tYvLOWc=
github.com/go-openapi/spec v0.17.0/go.mod h1:XkF/MOi14NmjsfZ8VtAKf8pIlbZzyoTvZsdfssdxcBI=
github.com/go-openapi/spec v0.18.0/go.mod h1:XkF/MOi14NmjsfZ8VtAKf8pIlbZzyoTvZsdfssdxcBI=
github.com/go-openapi/spec v0.19.2/go.mod h1:sCxk3jxKgioEJikev4fgkNmwS+3kuYdJtcsZsD5zxMY=
github.com/go-openapi/spec v0.19.3/go.mod h1:FpwSN1ksY1eteniUU7X0N/BgJ7a4WvBFVA8Lj9mJglo=
github.com/go-openapi/spec v0.19.4 h1:ixzUSnHTd6hCemgtAJgluaTSGYpLNpJY4mA2DIkdOAo=
github.com/go-openapi/spec v0.19.4/go.mod h1:FpwSN1ksY1eteniUU7X0N/BgJ7a4WvBFVA8Lj9mJglo=
github.com/go-openapi/strfmt v0.17.0/go.mod h1:P82hnJI0CXkErkXi8IKjPbNBM6lV6+5pLP5l494TcyU=
github.com/go-openapi/strfmt v0.18.0/go.mod h1:P82hnJI0CXkErkXi8IKjPbNBM6lV6+5pLP5l494TcyU=
github.com/go-openapi/strfmt v0.19.0/go.mod h1:+uW+93UVvGGq2qGaZxdDeJqSAqBqBdl+ZPMF/cC8nDY=
github.com/go-openapi/strfmt v0.19.3/go.mod h1:0yX7dbo8mKIvc3XSKp7MNfxw4JytCfCD6+bY1AVL9LU=
github.com/go-openapi/swag v0.0.0-20160704191624-1d0bd113de87/go.mod h1:DXUve3Dpr1UfpPtxFw+EFuQ41HhCWZfha5jSVRG7C7I=
github.com/go-openapi/swag v0.17.0/go.mod h1:AByQ+nYG6gQg71GINrmuDXCPWdL640yX49/kXLo40Tg=
github.com/go-openapi/swag v0.18.0/go.mod h1:AByQ+nYG6gQg71GINrmuDXCPWdL640yX49/kXLo40Tg=
@@ -359,6 +363,7 @@ github.com/go-openapi/swag v0.19.5 h1:lTz6Ys4CmqqCQmZPBlbQENR1/GucA2bzYTE12Pw4tF
github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
github.com/go-openapi/validate v0.18.0/go.mod h1:Uh4HdOzKt19xGIGm1qHf/ofbX1YQ4Y+MYsct2VUrAJ4=
github.com/go-openapi/validate v0.19.2/go.mod h1:1tRCw7m3jtI8eNWEEliiAqUIcBztB2KDnRCRMUi7GTA=
github.com/go-openapi/validate v0.19.5/go.mod h1:8DJv2CVJQ6kGNpFW6eV9N3JviE1C85nY1c2z52x1Gk4=
github.com/go-sql-driver/mysql v1.4.1 h1:g24URVg0OFbNUTx9qqY1IRZ9D9z3iPyi5zKhQZpNwpA=
github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
@@ -395,6 +400,7 @@ github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y=
github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8=
github.com/godbus/dbus v0.0.0-20190422162347-ade71ed3457e/go.mod h1:bBOAhwG1umN6/6ZUMtDFBMQR8jRg9O75tm9K00oMsK4=
github.com/gofrs/flock v0.0.0-20190320160742-5135e617513b/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14jxHU=
github.com/gofrs/flock v0.7.1 h1:DP+LD/t0njgoPBvT5MJLeliUIVQR03hiKR6vezdwHlc=
github.com/gofrs/flock v0.7.1/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14jxHU=
github.com/gofrs/uuid v3.2.0+incompatible h1:y12jRkkFxsd7GpqdSZ+/KCs/fJbqpEXSGd4+jfEaewE=
github.com/gofrs/uuid v3.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
@@ -413,12 +419,10 @@ github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfU
github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/groupcache v0.0.0-20191027212112-611e8accdfc9/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7 h1:5ZkaAPbicIKTF2I64qf5Fh8Aa83Q/dnOafMYV0OMwjA=
github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e h1:1r7pUrabqp18hOBcwBwiTsbnFeTZHV9eER/QT5JVZxY=
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:tluoj9z5200jBnyusfRPU2LqT6J+DAorxEvtC7LHB+E=
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
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=
@@ -498,36 +502,35 @@ github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+
github.com/googleapis/gax-go/v2 v2.0.5 h1:sjZBwGj9Jlw33ImPtvFviGYvseOtDM7hkSKB7+Tv3SM=
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
github.com/googleapis/gnostic v0.0.0-20170729233727-0c5108395e2d/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY=
github.com/googleapis/gnostic v0.3.0 h1:CcQijm0XKekKjP/YCz28LXVSpgguuB+nCxaSjCe09y0=
github.com/googleapis/gnostic v0.3.0/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY=
github.com/googleapis/gnostic v0.3.1 h1:WeAefnSUHlBb0iJKwxFDZdbfGwkd7xRNuV+IpXMJhYk=
github.com/googleapis/gnostic v0.3.1/go.mod h1:on+2t9HRStVgn95RSsFWFz+6Q0Snyqv1awfrALZdbtU=
github.com/gophercloud/gophercloud v0.1.0/go.mod h1:vxM41WHh5uqHVBMZHzuwNOHh8XEoIEcSTewFxm1c5g8=
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8=
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg=
github.com/gorilla/handlers v1.4.0 h1:XulKRWSQK5uChr4pEgSE4Tc/OcmnU9GJuSwdog/tZsA=
github.com/gorilla/handlers v1.4.0/go.mod h1:Qkdc/uu4tH4g6mTK6auzZ766c4CA0Ng8+o/OAirnOIQ=
github.com/gorilla/handlers v0.0.0-20150720190736-60c7bfde3e33 h1:893HsJqtxp9z1SF76gg6hY70hRY1wVlTSnC/h1yUDCo=
github.com/gorilla/handlers v0.0.0-20150720190736-60c7bfde3e33/go.mod h1:Qkdc/uu4tH4g6mTK6auzZ766c4CA0Ng8+o/OAirnOIQ=
github.com/gorilla/mux v0.0.0-20170217192616-94e7d24fd285/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
github.com/gorilla/mux v1.7.0/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
github.com/gorilla/mux v1.7.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
github.com/gorilla/mux v1.7.3 h1:gnP5JzjVOuiZD07fKKToCAOjS0yOpj/qPETTXCCS6hw=
github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
github.com/gosimple/slug v1.9.0 h1:r5vDcYrFz9BmfIAMC829un9hq7hKM4cHUrsv36LbEqs=
github.com/gosimple/slug v1.9.0/go.mod h1:AMZ+sOVe65uByN3kgEyf9WEBKBCSS+dJjMX9x4vDJbg=
github.com/gostaticanalysis/analysisutil v0.0.0-20190318220348-4088753ea4d3/go.mod h1:eEOZF4jCKGi+aprrirO9e7WKB3beBRtWgqGunKl6pKE=
github.com/gosuri/uitable v0.0.1 h1:M9sMNgSZPyAu1FJZJLpJ16ofL8q5ko2EDUkICsynvlY=
github.com/gosuri/uitable v0.0.1/go.mod h1:tKR86bXuXPZazfOTG1FIzvjIdXzd0mo4Vtn16vt0PJo=
github.com/gosuri/uitable v0.0.4 h1:IG2xLKRvErL3uhY6e1BylFzG+aJiwQviDDTfOKeKTpY=
github.com/gosuri/uitable v0.0.4/go.mod h1:tKR86bXuXPZazfOTG1FIzvjIdXzd0mo4Vtn16vt0PJo=
github.com/gotestyourself/gotestyourself v2.2.0+incompatible/go.mod h1:zZKM6oeNM8k+FRljX1mnzVYeS8wiGgQyvST1/GafPbY=
github.com/gregjones/httpcache v0.0.0-20170728041850-787624de3eb7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA=
github.com/gregjones/httpcache v0.0.0-20181110185634-c63ab54fda8f h1:ShTPMJQes6tubcjzGMODIVG5hlrCeImaBnZzKF2N8SM=
github.com/gregjones/httpcache v0.0.0-20181110185634-c63ab54fda8f/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA=
github.com/grpc-ecosystem/go-grpc-middleware v0.0.0-20190222133341-cfaf5686ec79/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7 h1:pdN6V1QBWetyv/0+wjACpqVH+eVULgEjkurDLq3goeM=
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/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
github.com/grpc-ecosystem/grpc-gateway v1.3.0/go.mod h1:RSKVYQBd5MCa4OVpNdGskqpgL2+G+NZTnrVHpWWfpdw=
github.com/grpc-ecosystem/grpc-gateway v1.8.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
github.com/grpc-ecosystem/grpc-gateway v1.9.2/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
github.com/hairyhenderson/gomplate/v3 v3.6.0 h1:EryWG7cCxvZ2awoZ957B3AMAd20Zy0uRXeZ7TXXMIp0=
github.com/hairyhenderson/gomplate/v3 v3.6.0/go.mod h1:RbEC6Y14nNTHCtNWpBAkwqDP4ICFUrAH0S8PUFa0qT4=
github.com/hairyhenderson/toml v0.3.1-0.20191004034452-2a4f3b6160f2 h1:Dc4YWWuY02jqhCnErAH++juCTwEPLstAOOVhyPXeE7Q=
@@ -625,6 +628,7 @@ github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJS
github.com/jinzhu/copier v0.0.0-20190924061706-b57f9002281a h1:zPPuIq2jAWWPTrGt70eK/BSch+gFAGrNzecsoENgu2o=
github.com/jinzhu/copier v0.0.0-20190924061706-b57f9002281a/go.mod h1:yL958EeXv8Ylng6IfnvG4oflryUi3vgA3xPs9hmII1s=
github.com/jmespath/go-jmespath v0.0.0-20160202185014-0b12d6b521d8/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
github.com/jmespath/go-jmespath v0.0.0-20160803190731-bd40a432e4c7/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
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/johannesboyne/gofakes3 v0.0.0-20191029185751-e238f04965fe h1:9kkgzfTjcHQqS6wGlEhJBJmAMI75lKyHX69w/ii+5So=
@@ -636,13 +640,14 @@ github.com/json-iterator/go v0.0.0-20180612202835-f2b4162afba3/go.mod h1:+SdeFBv
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
github.com/json-iterator/go v1.1.7 h1:KfgG9LzI+pYjr4xvmz/5H4FXjokeP+rlHLhv3iH62Fo=
github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
github.com/json-iterator/go v1.1.8 h1:QiWkFLKq0T7mpzwOTu6BzNDbfTE8OLrYhVKYMLF46Ok=
github.com/json-iterator/go v1.1.8/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
github.com/jstemmer/go-junit-report v0.9.1 h1:6QPYqodiu3GuPL+7mfx+NwDdp2eTkp9IfEUpgAwUN0o=
github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo=
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/kardianos/osext v0.0.0-20170510131534-ae77be60afb1/go.mod h1:1NbS8ALrpOvjt0rHPNLyCIeMtbizbir8U//inJ+zuB8=
github.com/kardianos/osext v0.0.0-20190222173326-2bc1f35cddc0 h1:iQTw/8FWTuc7uiaSepXwyf3o52HaUYcV+Tu66S3F5GA=
github.com/kardianos/osext v0.0.0-20190222173326-2bc1f35cddc0/go.mod h1:1NbS8ALrpOvjt0rHPNLyCIeMtbizbir8U//inJ+zuB8=
github.com/kevinburke/ssh_config v0.0.0-20190725054713-01f96b0aa0cd h1:Coekwdh0v2wtGp9Gmz1Ze3eVRAWJMLokvN3QjdzCHLY=
@@ -674,6 +679,7 @@ github.com/kr/pty v1.1.5/go.mod h1:9r2w37qlBe7rQ6e1fg1S/9xpWHSnaqNdHD3WcMdbPDA=
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/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/lib/pq v1.1.1/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
github.com/lib/pq v1.2.0 h1:LXpIM/LZ5xGFhOpXAQUIMM1HdyqzVYM13zNdjCEEcA0=
@@ -681,7 +687,10 @@ github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de h1:9TO3cAIGXtEhnIaL+V+BEER86oLrvS+kWobKpbJuye0=
github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de/go.mod h1:zAbeS9B/r2mtpb6U+EI2rYA5OAXxsYw6wTamcNW+zcE=
github.com/lithammer/dedent v1.1.0/go.mod h1:jrXYCQtgg0nJiN+StA2KgR7w6CiQNv9Fd/Z9BP0jIOc=
github.com/logrusorgru/aurora v0.0.0-20181002194514-a7b3b318ed4e h1:9MlwzLdW7QSDrhDjFlsEYmxpFyIoXmYRon3dt0io31k=
github.com/logrusorgru/aurora v0.0.0-20181002194514-a7b3b318ed4e/go.mod h1:7rIyQOR62GCctdiQpZ/zOJlFyk6y+94wXzv6RNZgaR4=
github.com/logrusorgru/aurora v0.0.0-20200102142835-e9ef32dff381 h1:bqDmpDG49ZRnB5PcgP0RXtQvnMSgIF14M7CBd2shtXs=
github.com/logrusorgru/aurora v0.0.0-20200102142835-e9ef32dff381/go.mod h1:7rIyQOR62GCctdiQpZ/zOJlFyk6y+94wXzv6RNZgaR4=
github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
github.com/magiconair/properties v1.8.1 h1:ZC2Vc7/ZFkGmsVC9KvOjumD+G5lXy2RtTKyzRKO2BQ4=
github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
@@ -692,6 +701,7 @@ github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN
github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
github.com/mailru/easyjson v0.7.0 h1:aizVhC/NAAcKWb+5QsU1iNOZb4Yws5UO2I+aIprQITM=
github.com/mailru/easyjson v0.7.0/go.mod h1:KAzv3t3aY1NaHWoQz1+4F1ccyAH66Jk7yos7ldAVICs=
github.com/marstr/guid v1.1.0/go.mod h1:74gB1z2wpxxInTG6yaqA7KrtM0NZ+RbrcqDvYHefzho=
github.com/matoous/godox v0.0.0-20190911065817-5d6d842e92eb/go.mod h1:1BELzlh859Sh1c6+90blK8lbYy0kwQf1bYlBhBysy1s=
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
@@ -706,14 +716,13 @@ github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNx
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
github.com/mattn/go-isatty v0.0.10 h1:qxFzApOv4WsAL965uUPIsXzAKCZxN2p9UqdhFS4ZW10=
github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84=
github.com/mattn/go-runewidth v0.0.4 h1:2BvfKmzob6Bmd4YsL0zygOqfdFnK7GR4QL06Do4/p7Y=
github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
github.com/mattn/go-runewidth v0.0.6 h1:V2iyH+aX9C5fsYCpK60U8BYIvmhqxuOL3JZcqc1NB7k=
github.com/mattn/go-runewidth v0.0.6/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
github.com/mattn/go-shellwords v1.0.5/go.mod h1:3xCvwCdWdlDJUrvuMn7Wuy9eWs4pE8vqg+NOMyg4B2o=
github.com/mattn/go-shellwords v1.0.6 h1:9Jok5pILi5S1MnDirGVTufYGtksUs/V2BWUP3ZkeUUI=
github.com/mattn/go-shellwords v1.0.6/go.mod h1:3xCvwCdWdlDJUrvuMn7Wuy9eWs4pE8vqg+NOMyg4B2o=
github.com/mattn/go-shellwords v1.0.9 h1:eaB5JspOwiKKcHdqcjbfe5lA9cNn/4NRRtddXJCimqk=
github.com/mattn/go-shellwords v1.0.9/go.mod h1:EZzvwXDESEeg03EKmM+RmDnNOPKG4lLtQsUlTZDWQ8Y=
github.com/mattn/go-tty v0.0.3 h1:5OfyWorkyO7xP52Mq7tB36ajHDG5OHrmBGIS/DtakQI=
github.com/mattn/go-tty v0.0.3/go.mod h1:ihxohKRERHTVzN+aSVRwACLCeqIoZAWpoICkkvrWyR0=
github.com/mattn/goveralls v0.0.2/go.mod h1:8d1ZMHsd7fW6IRPKQh46F2WRpyib5/X4FOpevwGNQEw=
@@ -721,7 +730,6 @@ github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0j
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
github.com/mholt/archiver/v3 v3.3.0 h1:vWjhY8SQp5yzM9P6OJ/eZEkmi3UAbRrxCq48MxjAzig=
github.com/mholt/archiver/v3 v3.3.0/go.mod h1:YnQtqsp+94Rwd0D/rk5cnLrxusUBUXg+08Ebtr1Mqao=
github.com/miekg/dns v0.0.0-20181005163659-0d29b283ac0f/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
github.com/miekg/dns v1.0.14 h1:9jZdLNd/P4+SfEJ0TNyxYpsK8N4GtfylBLqtbYN1sbA=
github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
github.com/mistifyio/go-zfs v2.1.1+incompatible h1:gAMO1HM9xBRONLHHYnu5iFsOJUiJdNZo6oqSENd4eW8=
@@ -747,6 +755,7 @@ github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0Qu
github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE=
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
github.com/mitchellh/osext v0.0.0-20151018003038-5e2d6d41470f/go.mod h1:OkQIRizQZAeMln+1tSwduZz7+Af5oFlKirV/MSYes2A=
github.com/mitchellh/reflectwalk v1.0.0 h1:9D+8oIskB4VJBN5SFlmc27fSlIBZaov1Wpk/IfikLNY=
github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw=
github.com/moby/moby v0.7.3-0.20190826074503-38ab9da00309 h1:cvy4lBOYN3gKfKj8Lzz5Q9TfviP+L7koMHY7SvkyTKs=
@@ -758,34 +767,37 @@ github.com/modern-go/reflect2 v0.0.0-20180320133207-05fbef0ca5da/go.mod h1:bx2lN
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI=
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
github.com/morikuni/aec v0.0.0-20170113033406-39771216ff4c/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc=
github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A=
github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc=
github.com/mozilla/tls-observatory v0.0.0-20190404164649-a3c1b6cfecfd/go.mod h1:SrKMQvPiws7F7iqYp8/TX+IhxCYhzr6N/1yb8cwHsGk=
github.com/mtrmac/gpgme v0.0.0-20170102180018-b2432428689c h1:xa+eQWKuJ9MbB9FBL/eoNvDFvveAkz2LQoz8PzX7Q/4=
github.com/mtrmac/gpgme v0.0.0-20170102180018-b2432428689c/go.mod h1:GhAqVMEWnTcW2dxoD/SO3n2enrgWl3y6Dnx4m59GvcA=
github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw=
github.com/nbutton23/zxcvbn-go v0.0.0-20180912185939-ae427f1e4c1d/go.mod h1:o96djdrsSGy3AWPyBgZMAGfxZNfgntdJG+11KU4QvbU=
github.com/ncw/swift v1.0.47/go.mod h1:23YIA4yWVnGwv2dQlN4bB7egfYX6YLn0Yo/S6zZO/ZM=
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs=
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
github.com/nwaples/rardecode v1.0.0 h1:r7vGuS5akxOnR4JQSkko62RJ1ReCMXxQRPtxsiFMBOs=
github.com/nwaples/rardecode v1.0.0/go.mod h1:5DzqNKiOdpKKBH87u8VlvAnPZMXcGRhxWkRpHbbfGS0=
github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA=
github.com/oklog/ulid v1.3.1 h1:EGfNDEx6MqHz8B3uNV6QAib1UR2Lm97sHi3ocA6ESJ4=
github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo=
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.8.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.10.1 h1:q/mM8GF/n0shIN8SaAZ0V+jnLPzen6WIVZdiwrRlMlo=
github.com/onsi/ginkgo v1.10.1/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA=
github.com/onsi/gomega v1.5.0/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/opencontainers/go-digest v0.0.0-20170106003457-a6d0ee40d420/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s=
github.com/opencontainers/go-digest v0.0.0-20180430190053-c9281466c8b2/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s=
github.com/opencontainers/go-digest v1.0.0-rc1 h1:WzifXhOVOEOuFYOJAW6aQqW0TooG2iki3E3Ii+WN7gQ=
github.com/opencontainers/go-digest v1.0.0-rc1/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s=
github.com/opencontainers/image-spec v1.0.0/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0=
github.com/opencontainers/image-spec v1.0.1 h1:JMemWkRwHx4Zj+fVxWoMCFm/8sYGGrUVojFA6h/TRcI=
github.com/opencontainers/image-spec v1.0.1/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0=
github.com/opencontainers/image-spec v1.0.2-0.20190823105129-775207bd45b6 h1:yN8BPXVwMBAm3Cuvh1L5XE8XpvYRMdsVLd82ILprhUU=
@@ -818,8 +830,8 @@ github.com/pelletier/go-toml v1.2.0 h1:T5zMGML61Wp+FlcbWjRDT7yAxhJNAiPPLOFECq181
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
github.com/peterbourgon/diskv v2.0.1+incompatible h1:UBdAOUP5p4RWqPBg048CAvpKN+vxiaj6gdUUzhl4XmI=
github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU=
github.com/phayes/freeport v0.0.0-20171002181615-b8543db493a5 h1:rZQtoozkfsiNs36c7Tdv/gyGNzD1X1XWKO8rptVNZuM=
github.com/phayes/freeport v0.0.0-20171002181615-b8543db493a5/go.mod h1:iIss55rKnNBTvrwdmkUpLnDpZoAHvWaiq5+iMmen4AE=
github.com/phayes/freeport v0.0.0-20180830031419-95f893ade6f2 h1:JhzVVoYvbOACxoUmOs6V/G4D5nPVUW73rKvXxP4XUJc=
github.com/phayes/freeport v0.0.0-20180830031419-95f893ade6f2/go.mod h1:iIss55rKnNBTvrwdmkUpLnDpZoAHvWaiq5+iMmen4AE=
github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=
github.com/pierrec/lz4 v2.3.0+incompatible h1:CZzRn4Ut9GbUkHlQ7jqBXeZQV41ZSKWFc302ZU6lUTk=
github.com/pierrec/lz4 v2.3.0+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=
@@ -829,6 +841,8 @@ github.com/pkg/errors v0.8.1-0.20171018195549-f15c970de5b7 h1:RcqIXZDN7Vz5lgK7+0
github.com/pkg/errors v0.8.1-0.20171018195549-f15c970de5b7/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v0.0.0-20151028094244-d8ed2627bdf0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
@@ -837,31 +851,29 @@ github.com/pquerna/cachecontrol v0.0.0-20171018203845-0dec1b30a021/go.mod h1:prY
github.com/pquerna/ffjson v0.0.0-20181028064349-e517b90714f7/go.mod h1:YARuvh7BUWHNhzDq2OM5tzR2RiCcN2D7sapiKyCel/M=
github.com/pquerna/ffjson v0.0.0-20190813045741-dac163c6c0a9 h1:kyf9snWXHvQc+yxE9imhdI8YAm4oKeZISlaAR+x73zs=
github.com/pquerna/ffjson v0.0.0-20190813045741-dac163c6c0a9/go.mod h1:YARuvh7BUWHNhzDq2OM5tzR2RiCcN2D7sapiKyCel/M=
github.com/prometheus/client_golang v0.0.0-20180209125602-c332b6f63c06/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
github.com/prometheus/client_golang v0.9.2/go.mod h1:OsXs2jCmiKlQ1lTBmv21f2mNfw4xf/QclQDMrYNZzcM=
github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso=
github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo=
github.com/prometheus/client_golang v1.1.0 h1:BQ53HtBmfOitExawJ6LokA4x8ov/z0SYYb0+HxJfRI8=
github.com/prometheus/client_golang v1.1.0/go.mod h1:I1FGZT9+L76gKKOs5djB6ezCbFQP1xR9D75/vuwEF3g=
github.com/prometheus/client_golang v1.2.1 h1:JnMpQc6ppsNgw9QPAGF6Dod479itz7lvlsMzzNayLOI=
github.com/prometheus/client_golang v1.2.1/go.mod h1:XMU6Z2MjaRKVu/dC1qupJI9SiNkDYzz3xecMgSW/F+U=
github.com/prometheus/client_model v0.0.0-20171117100541-99fa1f4be8e5/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90 h1:S/YWwWx/RA8rT8tKFRuGUZhuA90OyIBpPCXkcbwU8DE=
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4 h1:gQz4mCbXsO+nc9n1hCxHcGA3Zx3Eo+UHZoInFGUIXNM=
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/common v0.0.0-20180110214958-89604d197083/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
github.com/prometheus/common v0.0.0-20181126121408-4724e9255275/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
github.com/prometheus/common v0.2.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
github.com/prometheus/common v0.6.0 h1:kRhiuYSXR3+uv2IbVbZhUxK5zVD/2pp3Gd2PpvPkpEo=
github.com/prometheus/common v0.6.0/go.mod h1:eBmuwkDJBwy6iBfxCBob6t6dR6ENT/y+J+Zk0j9GMYc=
github.com/prometheus/common v0.7.0 h1:L+1lyG48J1zAQXA3RBX/nG/B3gjlHq0zTt2tlbJLyCY=
github.com/prometheus/common v0.7.0/go.mod h1:DjGbpBbp5NYNiECxcL/VnbXCCaQpKd3tt26CguLLsqA=
github.com/prometheus/procfs v0.0.0-20180125133057-cb4147076ac7/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
github.com/prometheus/procfs v0.0.0-20181204211112-1dc9a6cbc91a/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
github.com/prometheus/procfs v0.0.0-20190129233650-316cf8ccfec5/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
github.com/prometheus/procfs v0.0.3 h1:CTwfnzjQ+8dS6MhHHu4YswVAD99sL2wjPqP+VkURmKE=
@@ -869,14 +881,10 @@ github.com/prometheus/procfs v0.0.3/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDa
github.com/prometheus/procfs v0.0.5 h1:3+auTFlqw+ZaQYJARz6ArODtkaIwtvBTx3N2NehQlL8=
github.com/prometheus/procfs v0.0.5/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ=
github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU=
github.com/qlik-oss/k-apis v0.0.39 h1:fIGCC7f9kU7319VTSJKr3fLoA9E4MjusRFmOjX3ypis=
github.com/qlik-oss/k-apis v0.0.39/go.mod h1:yoYGgPJ/H0t9H3NSq64dWfyQY6QWi2L9c+hCJoVO03U=
github.com/qlik-oss/k-apis v0.1.0 h1:uMl1316SNYy5Hm6jy1U7wiCMkut0tKqdP8mBpSuXXp8=
github.com/qlik-oss/k-apis v0.1.0/go.mod h1:yoYGgPJ/H0t9H3NSq64dWfyQY6QWi2L9c+hCJoVO03U=
github.com/qlik-oss/k-apis v0.1.1 h1:aZ4eTMB3mSn03Kuj7+RI0eFLkjK9+0qxADBioRb3qVA=
github.com/qlik-oss/k-apis v0.1.1/go.mod h1:yoYGgPJ/H0t9H3NSq64dWfyQY6QWi2L9c+hCJoVO03U=
github.com/qlik-oss/kustomize/api v0.3.3-0.20200402170547-2e8140160c36 h1:BuT+cnXPQ6mcOWTDS1S8GXy65LAEMdPuNQCC36rMq28=
github.com/qlik-oss/kustomize/api v0.3.3-0.20200402170547-2e8140160c36/go.mod h1:tSQaDZ4Jt9KwYvD7LlMUPi5nkiGOno3PAKl5/XqEfxs=
github.com/qlik-oss/kustomize/api v0.3.3-0.20200424070349-b0312eb71568 h1:wHOUCGfnmgYqW3aCjuP3fXmB2T/uZXMvltO+F3us83E=
github.com/qlik-oss/kustomize/api v0.3.3-0.20200424070349-b0312eb71568/go.mod h1:Yg8bqX8Mq/eSgXfcenxCxhZuSXg+NCsKq6NBdch/oUc=
github.com/quasilyte/go-consistent v0.0.0-20190521200055-c6f3937de18c/go.mod h1:5STLWrekHfjyYwxBRVRXNOSewLJ3PWfDJd1VyTS21fI=
github.com/rainycape/unidecode v0.0.0-20150907023854-cb7f23ec59be h1:ta7tUOvsPHVHGom5hKW5VXNc2xZIkfCKP8iaqOyYtUQ=
github.com/rainycape/unidecode v0.0.0-20150907023854-cb7f23ec59be/go.mod h1:MIDFMn7db1kT65GmV94GzpX9Qdi7N/pQlwb+AN8wh+Q=
@@ -901,6 +909,7 @@ github.com/ryanuber/go-glob v1.0.0 h1:iQh3xXAumdQ+4Ufa5b25cRpC5TYKlno6hsv6Cb3pkB
github.com/ryanuber/go-glob v1.0.0/go.mod h1:807d1WSdnB0XRJzKNil9Om6lcp/3a0v4qIHxIXzX/Yc=
github.com/ryszard/goskiplist v0.0.0-20150312221310-2dfbae5fcf46 h1:GHRpF1pTW19a8tTFrMLUcfWwyC0pnifVo2ClaLq+hP8=
github.com/ryszard/goskiplist v0.0.0-20150312221310-2dfbae5fcf46/go.mod h1:uAQ5PCi+MFsC7HjREoAz1BU+Mq60+05gifQSsHSDG/8=
github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529 h1:nn5Wsu0esKSJiIVhscUtVbo7ada43DJhG55ua/hjS5I=
github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
github.com/securego/gosec v0.0.0-20191002120514-e680875ea14d/go.mod h1:w5+eXa0mYznDkHaMCXA4XYffjlH+cy1oyKbfzJXa2Do=
@@ -925,10 +934,10 @@ github.com/sirupsen/logrus v1.4.2 h1:SPIRibHv4MatM3XXNO2BJeFLZwZ2LvZgfQ5+UNI2im4
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM=
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
github.com/smartystreets/goconvey v0.0.0-20190330032615-68dc04aab96a/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
github.com/smartystreets/goconvey v0.0.0-20190731233626-505e41936337/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIKYqbNC9s=
github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
github.com/soheilhy/cmux v0.1.3/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
github.com/sourcegraph/go-diff v0.5.1/go.mod h1:j2dHj3m8aZgQO8lMTcTnBcXkRRRqi34cd2MNlA9u1mE=
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
@@ -950,6 +959,7 @@ github.com/spf13/jwalterweatherman v1.0.0 h1:XHEdyB+EcvlqZamSM4ZOMGlc93t6AcsBEu9
github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
github.com/spf13/pflag v0.0.0-20170130214245-9ff6c6923cff/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
github.com/spf13/pflag v1.0.1-0.20171106142849-4c012f6dcd95/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
github.com/spf13/pflag v1.0.3 h1:zPAT6CGy6wXeQ7NtTnaTerfKOsV6V6F8agHXFiazDkg=
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=
@@ -960,8 +970,6 @@ github.com/spf13/viper v1.6.1 h1:VPZzIkznI1YhVMRi6vNFLHSwhnhReBfgTxIPccpfdZk=
github.com/spf13/viper v1.6.1/go.mod h1:t3iDnF5Jlj76alVNuyFBk5oUMCvsrkbvZK0WQdfDi5k=
github.com/src-d/gcfg v1.4.0 h1:xXbNR5AlLSA315x2UO+fTSSAXCDf+Ar38/6oyGbDKQ4=
github.com/src-d/gcfg v1.4.0/go.mod h1:p/UMsR43ujA89BJY9duynAwIpvqEujIH/jFlfL7jWoI=
github.com/src-d/go-git v4.7.0+incompatible h1:IYSSnbAHeKmsfbQFi9ozbid+KNh0bKjlorMfQehQbcE=
github.com/src-d/go-git v4.7.0+incompatible/go.mod h1:1bQciz+hn0jzPQNsYj0hDFZHLJBdV7gXE2mWhC7EkFk=
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=
@@ -977,11 +985,10 @@ github.com/syndtr/gocapability v0.0.0-20180916011248-d98352740cb2 h1:b6uOv7YOFK0
github.com/syndtr/gocapability v0.0.0-20180916011248-d98352740cb2/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww=
github.com/tchap/go-patricia v2.3.0+incompatible h1:GkY4dP3cEfEASBPPkWd+AmjYxhmDkqO9/zg7R0lSQRs=
github.com/tchap/go-patricia v2.3.0+incompatible/go.mod h1:bmLyhP68RS6kStMGxByiQ23RP/odRBOTVjwp2cDyi6I=
github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk=
github.com/timakin/bodyclose v0.0.0-20190930140734-f7f2e9bca95e/go.mod h1:Qimiffbc6q9tBWlVV6x0P9sat/ao1xEkREYPPj9hphk=
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/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
github.com/ttacon/chalk v0.0.0-20160626202418-22c06c80ed31 h1:OXcKh35JaYsGMRzpvFkLv/MEyPuL49CThT1pZ8aSml4=
github.com/ttacon/chalk v0.0.0-20160626202418-22c06c80ed31/go.mod h1:onvgF043R+lC5RZ8IT9rBXDaEDnpnw/Cl+HFiw+v/7Q=
github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM=
github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc=
github.com/ugorji/go v1.1.7 h1:/68gy2h+1mWMrwZFeD1kQialdSzAb432dtpeJ42ovdo=
@@ -995,6 +1002,7 @@ github.com/ulikunitz/xz v0.5.6/go.mod h1:2bypXElzHzzJZwzH67Y6wb67pO62Rzfn7BSiF4A
github.com/ultraware/funlen v0.0.2/go.mod h1:Dp4UiAus7Wdb9KUZsYWZEWiRzGuM2kXM1lPbfaF6xhA=
github.com/ultraware/whitespace v0.0.4/go.mod h1:aVMh/gQve5Maj9hQ/hg+F75lr/X5A89uZnzAmWSineA=
github.com/urfave/cli v0.0.0-20171014202726-7bc6a0acffa5/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA=
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/uudashr/gocognit v0.0.0-20190926065955-1655d0de0517/go.mod h1:j44Ayx2KW4+oB6SWMv8KsmHzZrOInQav7D3cQMJ5JUM=
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
@@ -1005,6 +1013,7 @@ github.com/vbatts/tar-split v0.11.1 h1:0Odu65rhcZ3JZaPHxl7tCI3V/C/Q9Zf82UFravl02
github.com/vbatts/tar-split v0.11.1/go.mod h1:LEuURwDEiWjRjwu46yU3KVGuUdVv/dcnpcEPSzR8z6g=
github.com/vbauerster/mpb/v4 v4.11.1 h1:ZOYQSVHgmeanXsbyC44aDg76tBGCS/54Rk8VkL8dJGA=
github.com/vbauerster/mpb/v4 v4.11.1/go.mod h1:vMLa1J/ZKC83G2lB/52XpqT+ZZtFG4aZOdKhmpRL1uM=
github.com/vektah/gqlparser v1.1.2/go.mod h1:1ycwN7Ij5njmMkPPAOaRFY4rET2Enx7IkVv3vaXspKw=
github.com/xanzy/ssh-agent v0.2.1 h1:TCbipTQL2JiiCprBWx9frJ2eJlCYT00NmctrHxVAr70=
github.com/xanzy/ssh-agent v0.2.1/go.mod h1:mLlQY/MoOhWBj+gOGMQkOeiEvkx+8pJSI+0Bx9h2kr4=
github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
@@ -1016,20 +1025,17 @@ github.com/xeipuuv/gojsonschema v0.0.0-20180618132009-1d523034197f/go.mod h1:5yf
github.com/xeipuuv/gojsonschema v0.0.0-20190816131739-be0936907f66/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y=
github.com/xeipuuv/gojsonschema v1.1.0 h1:ngVtJC9TY/lg0AA/1k48FYhBrhRoFlEmWzsehpNAaZg=
github.com/xeipuuv/gojsonschema v1.1.0/go.mod h1:5yf86TLmAcydyeJq5YvxkGPE2fm/u4myDekKRoLuqhs=
github.com/xenolf/lego v0.0.0-20160613233155-a9d8cec0e656/go.mod h1:fwiGnfsIjG7OHPfOvgK7Y/Qo6+2Ox0iozjNTkZICKbY=
github.com/xenolf/lego v0.3.2-0.20160613233155-a9d8cec0e656 h1:BTvU+npm3/yjuBd53EvgiFLl5+YLikf2WvHsjRQ4KrY=
github.com/xenolf/lego v0.3.2-0.20160613233155-a9d8cec0e656/go.mod h1:fwiGnfsIjG7OHPfOvgK7Y/Qo6+2Ox0iozjNTkZICKbY=
github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8 h1:nIPpBwaJSVYIxUFsDv3M8ofmx9yWTog9BfvIu0q41lo=
github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8/go.mod h1:HUYIGzjTL3rfEspMxjDjgmT5uz5wzYJKVo23qUhYTos=
github.com/xiang90/probing v0.0.0-20160813154853-07dd2e8dfe18/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
github.com/xlab/handysort v0.0.0-20150421192137-fb3537ed64a1/go.mod h1:QcJo0QPSfTONNIgpN5RA8prR7fF8nkF6cTWTcNerRO8=
github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=
github.com/yujunz/go-getter v1.4.1-lite h1:FhvNc94AXMZkfqUwfMKhnQEC9phkphSGdPTL7tIdhOM=
github.com/yujunz/go-getter v1.4.1-lite/go.mod h1:sbmqxXjyLunH1PkF3n7zSlnVeMvmYUuIl9ZVs/7NyCc=
github.com/yvasiyarov/go-metrics v0.0.0-20150112132944-c25f46c4b940 h1:p7OofyZ509h8DmPLh8Hn+EIIZm/xYhdZHJ9GnXHdr6U=
github.com/yvasiyarov/go-metrics v0.0.0-20150112132944-c25f46c4b940/go.mod h1:aX5oPXxHm3bOH+xeAttToC8pqch2ScQN/JoXYupl6xs=
github.com/yvasiyarov/gorelic v0.0.6 h1:qMJQYPNdtJ7UNYHjX38KXZtltKTqimMuoQjNnSVIuJg=
github.com/yvasiyarov/gorelic v0.0.6/go.mod h1:NUSPSUX/bi6SeDMUh6brw0nXpxHnc96TguQh0+r/ssA=
github.com/yvasiyarov/go-metrics v0.0.0-20140926110328-57bccd1ccd43 h1:+lm10QQTNSBd8DVTNGHx7o/IKu9HYDvLMffDhbyLccI=
github.com/yvasiyarov/go-metrics v0.0.0-20140926110328-57bccd1ccd43/go.mod h1:aX5oPXxHm3bOH+xeAttToC8pqch2ScQN/JoXYupl6xs=
github.com/yvasiyarov/gorelic v0.0.0-20141212073537-a9bba5b9ab50 h1:hlE8//ciYMztlGpl/VA+Zm1AcTPHYkHJPbHqE6WJUXE=
github.com/yvasiyarov/gorelic v0.0.0-20141212073537-a9bba5b9ab50/go.mod h1:NUSPSUX/bi6SeDMUh6brw0nXpxHnc96TguQh0+r/ssA=
github.com/yvasiyarov/newrelic_platform_go v0.0.0-20140908184405-b21fdbd4370f h1:ERexzlUfuTvpE74urLSbIQW0Z/6hF9t8U4NsJLaioAY=
github.com/yvasiyarov/newrelic_platform_go v0.0.0-20140908184405-b21fdbd4370f/go.mod h1:GlGEuHIJweS1mbCqG+7vt2nvWLzLLnRHbXz5JKd/Qbg=
github.com/zealic/xignore v0.3.3 h1:EpLXUgZY/JEzFkTc+Y/VYypzXtNz+MSOMVCGW5Q4CKQ=
@@ -1038,17 +1044,19 @@ go.etcd.io/bbolt v1.3.2 h1:Z/90sZLPOeCy2PwprqkFa25PdkusRzaj9P8zm/KNyvk=
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=
go.etcd.io/etcd v0.0.0-20191023171146-3cf2f69b5738/go.mod h1:dnLIgRNXwCJa5e+c6mIZCrds/GIG4ncV9HhK5PX7jPg=
go.mongodb.org/mongo-driver v1.0.3/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM=
go.mongodb.org/mongo-driver v1.1.1/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM=
go.mongodb.org/mongo-driver v1.1.2/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM=
go.opencensus.io v0.15.0/go.mod h1:UffZAU+4sDEINUGP/B7UfBBkq4fqLu9zXAX7ke6CHW0=
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
go.opencensus.io v0.22.0 h1:C9hSCOW830chIVkdja34wa6Ky+IzWllkUinR+BtRZd4=
go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
go.opencensus.io v0.22.2 h1:75k/FF0Q2YM8QYo07VPddOLBslDt1MZOdEslOHvmzAs=
go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
go.uber.org/atomic v0.0.0-20181018215023-8dc6146f7569/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
go.uber.org/multierr v0.0.0-20180122172545-ddea229ff1df/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
go.uber.org/zap v0.0.0-20180814183419-67bc79d13d15/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
gocloud.dev v0.18.0 h1:HX6uFZYZs9tUP87jzoWgB8dl4ihsRpiAsBDKTthiApY=
gocloud.dev v0.18.0/go.mod h1:lhLOb91+9tKB8RnNlsx+weJGEd0AHM94huK1bmrhPwM=
@@ -1064,15 +1072,16 @@ golang.org/x/crypto v0.0.0-20190320223903-b7391e95e576/go.mod h1:djNgcEr1/C05ACk
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190617133340-57b3e21c3d56/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190621222207-cc06ce4a13d4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4 h1:HuIa8hRrWRSrqYzx1qI49NNxhdi2PrY7gxVSq1JjLDc=
golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4 h1:HuIa8hRrWRSrqYzx1qI49NNxhdi2PrY7gxVSq1JjLDc=
golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/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=
golang.org/x/crypto v0.0.0-20190911031432-227b76d455e7/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190923035154-9ee001bba392/go.mod h1:/lpIB1dKB+9EgE3H3cr1v9wB50oz8l4C4h62xy7jSTY=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20191028145041-f83a4685e152/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20191112222119-e1110fd1c708/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20191122220453-ac88ee75c92c/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20200128174031-69ecbb4d6d5d h1:9FCpayM9Egr1baVnV1SX0H87m+XB0B8S0hAMi99X/3U=
@@ -1095,7 +1104,6 @@ golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u0
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
golang.org/x/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
@@ -1123,7 +1131,6 @@ golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73r
golang.org/x/net v0.0.0-20180911220305-26e67e76b6c3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181005035420-146acd28ed58/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181106065722-10aee1819953/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
@@ -1145,10 +1152,10 @@ golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLL
golang.org/x/net v0.0.0-20190628185345-da137c7871d7/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-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190812203447-cdfb69ac37fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20191028085509-fe3aa8a45271/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-20191112182307-2180aed22343/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553 h1:efeOvDhwQ29Dj3SdAV/MJf8oukgn+8D8WgaCaRMchF8=
golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
@@ -1189,6 +1196,7 @@ golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3
golang.org/x/text v0.3.1-0.20181227161524-e6919f6577db/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
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/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 h1:SvFZT6jyqRaOeXpc5h/JSfZenJ2O330aBsf7JfSUXmQ=
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
@@ -1196,13 +1204,13 @@ golang.org/x/time v0.0.0-20191024005414-555d28b269f0 h1:/5xXl8Y5W96D+TtHSlonuFqG
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20180525024113-a5b4c53f6e8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20181011042414-1f849cf54d09/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20181117154741-2ddaf7f79a09/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190110163146-51295c7ec13a/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190125232054-d66bd3c5d5a6/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190206041539-40960b6deb8e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
golang.org/x/tools v0.0.0-20190308174544-00c44ba9c14f/go.mod h1:25r3+/G6/xytQM8iWZKq3Hn0kr0rgFKPUNVEL/dr3z4=
@@ -1222,6 +1230,7 @@ golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBn
golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190614205625-5aca471b1d59/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190617190820-da514acc4774/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
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=
@@ -1231,6 +1240,7 @@ golang.org/x/tools v0.0.0-20190729092621-ff9f1409240a/go.mod h1:jcCCGcm9btYwXyDq
golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20190910044552-dd2b5c81c578/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-20190920225731-5eefd052ad72/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20190930201159-7c411dea38b0/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191004055002-72853e10c5a3/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191010075000-0337d82405ff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
@@ -1254,6 +1264,7 @@ golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8T
gonum.org/v1/gonum v0.0.0-20190331200053-3d26580ed485/go.mod h1:2ltnJ7xHfj0zHS40VVPYEAAMTa3ZGguvHGBSJeRWqE0=
gonum.org/v1/netlib v0.0.0-20190313105609-8cb42192e0e0/go.mod h1:wa6Ws7BG/ESfp6dHfk7C6KdzKA7wR7u/rKwOGE66zvw=
gonum.org/v1/netlib v0.0.0-20190331212654-76723241ea4e/go.mod h1:kS+toOQn6AQKjmKJ7gzohV1XkqsFehRA2FbsbkopSuQ=
google.golang.org/api v0.0.0-20160322025152-9bf6e6e569ff/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0=
google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
google.golang.org/api v0.5.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
@@ -1276,9 +1287,9 @@ google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww
google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0=
google.golang.org/appengine v1.6.5 h1:tycE03LOZYQNhDpS27tcQdAzLCVMaj7QT2SXxebnpCM=
google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
google.golang.org/cloud v0.0.0-20151119220103-975617b05ea8/go.mod h1:0H1ncTHf11KCFhTc/+EFRbzSCOZx+VUbRMk55Yv5MYk=
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8 h1:Nw54tB0rB7hY/N0NQvRW8DG4Yk3Q6T9cu9RcFQDu1tc=
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
google.golang.org/genproto v0.0.0-20190128161407-8ac453e89fca/go.mod h1:L3J43x8/uS+qIUoksaLKe6OS3nUKxOKuIFz1sl2/jx4=
google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/genproto v0.0.0-20190404172233-64821d5d2107/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
@@ -1292,8 +1303,6 @@ google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55 h1:gSJIx1SDwno+2ElGhA4+qG2zF97qiUzTM+rQ0klBOcE=
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8=
google.golang.org/genproto v0.0.0-20191028173616-919d9bdd9fe6 h1:UXl+Zk3jqqcbEVV7ace5lrt4YdA4tXiz3f/KbmD29Vo=
google.golang.org/genproto v0.0.0-20191028173616-919d9bdd9fe6/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
@@ -1301,8 +1310,8 @@ google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvx
google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
google.golang.org/genproto v0.0.0-20200128133413-58ce757ed39b h1:c8OBoXP3kTbDWWB/oVE3FkR851p4iZ3MPadz7zXEIPU=
google.golang.org/genproto v0.0.0-20200128133413-58ce757ed39b/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
google.golang.org/grpc v0.0.0-20160317175043-d3ddb4469d5a/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw=
google.golang.org/grpc v1.14.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw=
google.golang.org/grpc v1.16.0/go.mod h1:0JHn/cJsOMiMfNA9+DeHDlAU7KAAB5GDlYFpa9MZMio=
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
google.golang.org/grpc v1.21.0 h1:G+97AoqBnmZIT91cLG/EkCoK9NSelj64P8bOHHNmGn0=
@@ -1310,6 +1319,7 @@ google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ij
google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
google.golang.org/grpc v1.22.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
google.golang.org/grpc v1.23.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
google.golang.org/grpc v1.24.0 h1:vb/1TCsVn3DcJlQ0Gs1yB1pKI6Do2/QNwxdKqmc/b0s=
google.golang.org/grpc v1.24.0/go.mod h1:XDChyiUovWa60DnaeDeZmSW86xtLtjtZbwvSiRnRtcA=
google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
@@ -1319,16 +1329,18 @@ gopkg.in/airbrake/gobrake.v2 v2.0.9/go.mod h1:/h5ZAUhDkGaJfjzjKLSjv6zCL6O0LLBxU4
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
gopkg.in/asn1-ber.v1 v1.0.0-20181015200546-f715ec2f112d/go.mod h1:cuepJuh7vyXfUyUwEgHQXw849cJrilpS5NeIjOWESAw=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20141024133853-64131543e789/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU=
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/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/gemnasium/logrus-airbrake-hook.v2 v2.1.2/go.mod h1:Xk6kEKp8OKb+X14hQBKWaSkCsqBpgog8nAV2xsGOxlo=
gopkg.in/inf.v0 v0.9.0/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc=
gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
gopkg.in/ini.v1 v1.51.0 h1:AQvPpx3LzTDM0AjnIRlVFwFFGC+npRopjZxLJj6gdno=
@@ -1336,8 +1348,6 @@ gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/mgo.v2 v2.0.0-20180705113604-9856a29383ce/go.mod h1:yeKp02qBN3iKW1OzL3MGk2IdtZzaj7SFntXj72NppTA=
gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k=
gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
gopkg.in/square/go-jose.v1 v1.1.2 h1:/5jmADZB+RiKtZGr4HxsEFOEfbfsjTKsVnqpThUpE30=
gopkg.in/square/go-jose.v1 v1.1.2/go.mod h1:QpYS+a4WhS+DTlyQIi6Ka7MS3SuR9a055rgXNEe6EiA=
gopkg.in/square/go-jose.v2 v2.2.2/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI=
gopkg.in/square/go-jose.v2 v2.3.1 h1:SK5KegNXmKmqE342YYN2qPHEnUYeoMiXXl1poUlI+o4=
gopkg.in/square/go-jose.v2 v2.3.1/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI=
@@ -1365,9 +1375,8 @@ gotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo=
gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw=
gotest.tools/v3 v3.0.0 h1:d+tVGRu6X0ZBQ+kyAR8JKi6AXhTP2gmQaoIYaGFz634=
gotest.tools/v3 v3.0.0/go.mod h1:TUP+/YtXl/dp++T+SZ5v2zUmLVBHmptSb/ajDLCJ+3c=
helm.sh/helm/v3 v3.0.2 h1:BggvLisIMrAc+Is5oAHVrlVxgwOOrMN8nddfQbm5gKo=
helm.sh/helm/v3 v3.0.2/go.mod h1:KBxE6XWO57XSNA1PA9CvVLYRY0zWqYQTad84bNXp1lw=
honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
helm.sh/helm/v3 v3.1.2 h1:VpNzaNv2DX4aRnOCcV7v5Of+XT2SZrJ8iOQ25AGKOos=
helm.sh/helm/v3 v3.1.2/go.mod h1:WYsFJuMASa/4XUqLyv54s0U/f3mlAaRErGmyy4z921g=
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
@@ -1375,38 +1384,40 @@ honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWh
honnef.co/go/tools v0.0.1-2019.2.3 h1:3JgtbtFHMiCmsznwGVTUWbgGov+pVqnlf1dEJTNAXeM=
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
k8s.io/api v0.0.0-20191016110408-35e52d86657a/go.mod h1:/L5qH+AD540e7Cetbui1tuJeXdmNhO8jM6VkXeDdDhQ=
k8s.io/api v0.0.0-20191214185829-ca1d04f8b0d3/go.mod h1:itOjKREfmUTvcjantxOsyYU5mbFsU7qUnyUuRfF5+5M=
k8s.io/api v0.17.0 h1:H9d/lw+VkZKEVIUc8F3wgiQ+FUXTTr21M87jXLU7yqM=
k8s.io/api v0.17.0/go.mod h1:npsyOePkeP0CPwyGfXDHxvypiYMJxBWAMpQxCaJ4ZxI=
k8s.io/apiextensions-apiserver v0.0.0-20191016113550-5357c4baaf65 h1:kThoiqgMsSwBdMK/lPgjtYTsEjbUU9nXCA9DyU3feok=
k8s.io/apiextensions-apiserver v0.0.0-20191016113550-5357c4baaf65/go.mod h1:5BINdGqggRXXKnDgpwoJ7PyQH8f+Ypp02fvVNcIFy9s=
k8s.io/apimachinery v0.0.0-20191004115801-a2eda9f80ab8 h1:Iieh/ZEgT3BWwbLD5qEKcY06jKuPEl6zC7gPSehoLw4=
k8s.io/apimachinery v0.0.0-20191004115801-a2eda9f80ab8/go.mod h1:llRdnznGEAqC3DcNm6yEj472xaFVfLM7hnYofMb12tQ=
k8s.io/apiserver v0.0.0-20191016112112-5190913f932d/go.mod h1:7OqfAolfWxUM/jJ/HBLyE+cdaWFBUoo5Q5pHgJVj2ws=
k8s.io/cli-runtime v0.0.0-20191016114015-74ad18325ed5 h1:8ZfMjkMBzcXEawLsYHg9lDM7aLEVso3NiVKfUTnN56A=
k8s.io/cli-runtime v0.0.0-20191016114015-74ad18325ed5/go.mod h1:sDl6WKSQkDM6zS1u9F49a0VooQ3ycYFBFLqd2jf2Xfo=
k8s.io/client-go v0.0.0-20191016111102-bec269661e48 h1:C2XVy2z0dV94q9hSSoCuTPp1KOG7IegvbdXuz9VGxoU=
k8s.io/client-go v0.0.0-20191016111102-bec269661e48/go.mod h1:hrwktSwYGI4JK+TJA3dMaFyyvHVi/aLarVHpbs8bgCU=
k8s.io/code-generator v0.0.0-20191004115455-8e001e5d1894/go.mod h1:mJUgkl06XV4kstAnLHAIzJPVCOzVR+ZcfPIv4fUsFCY=
k8s.io/component-base v0.0.0-20191016111319-039242c015a9/go.mod h1:SuWowIgd/dtU/m/iv8OD9eOxp3QZBBhTIiWMsBQvKjI=
k8s.io/api v0.17.2 h1:NF1UFXcKN7/OOv1uxdRz3qfra8AHsPav5M93hlV9+Dc=
k8s.io/api v0.17.2/go.mod h1:BS9fjjLc4CMuqfSO8vgbHPKMt5+SF0ET6u/RVDihTo4=
k8s.io/apiextensions-apiserver v0.17.2 h1:cP579D2hSZNuO/rZj9XFRzwJNYb41DbNANJb6Kolpss=
k8s.io/apiextensions-apiserver v0.17.2/go.mod h1:4KdMpjkEjjDI2pPfBA15OscyNldHWdBCfsWMDWAmSTs=
k8s.io/apimachinery v0.17.0 h1:xRBnuie9rXcPxUkDizUsGvPf1cnlZCFu210op7J7LJo=
k8s.io/apimachinery v0.17.0/go.mod h1:b9qmWdKlLuU9EBh+06BtLcSf/Mu89rWL33naRxs1uZg=
k8s.io/apiserver v0.17.2/go.mod h1:lBmw/TtQdtxvrTk0e2cgtOxHizXI+d0mmGQURIHQZlo=
k8s.io/cli-runtime v0.0.0-20191214191754-e6dc6d5c8724/go.mod h1:wzlq80lvjgHW9if6MlE4OIGC86MDKsy5jtl9nxz/IYY=
k8s.io/cli-runtime v0.17.2 h1:YH4txSplyGudvxjhAJeHEtXc7Tr/16clKGfN076ydGk=
k8s.io/cli-runtime v0.17.2/go.mod h1:aa8t9ziyQdbkuizkNLAw3qe3srSyWh9zlSB7zTqRNPI=
k8s.io/client-go v0.17.0 h1:8QOGvUGdqDMFrm9sD6IUFl256BcffynGoe80sxgTEDg=
k8s.io/client-go v0.17.0/go.mod h1:TYgR6EUHs6k45hb6KWjVD6jFZvJV4gHDikv/It0xz+k=
k8s.io/code-generator v0.0.0-20191214185510-0b9b3c99f9f2/go.mod h1:BjGKcoq1MRUmcssvHiSxodCco1T6nVIt4YeCT5CMSao=
k8s.io/code-generator v0.17.2/go.mod h1:DVmfPQgxQENqDIzVR2ddLXMH34qeszkKSdH/N+s+38s=
k8s.io/component-base v0.0.0-20191214190519-d868452632e2/go.mod h1:wupxkh1T/oUDqyTtcIjiEfpbmIHGm8By/vqpSKC6z8c=
k8s.io/component-base v0.17.2 h1:0XHf+cerTvL9I5Xwn9v+0jmqzGAZI7zNydv4tL6Cw6A=
k8s.io/component-base v0.17.2/go.mod h1:zMPW3g5aH7cHJpKYQ/ZsGMcgbsA/VyhEugF3QT1awLs=
k8s.io/gengo v0.0.0-20190128074634-0689ccc1d7d6/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0=
k8s.io/gengo v0.0.0-20190822140433-26a664648505/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0=
k8s.io/klog v0.0.0-20181102134211-b9b56d5dfc92/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk=
k8s.io/klog v0.3.0/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk=
k8s.io/klog v0.4.0/go.mod h1:4Bi6QPql/J/LkTDqv7R/cd3hPo4k2DG6Ptcz060Ez5I=
k8s.io/klog v1.0.0 h1:Pt+yjF5aB1xDSVbau4VsWe+dQNzA0qv1LlXdC2dF6Q8=
k8s.io/klog v1.0.0/go.mod h1:4Bi6QPql/J/LkTDqv7R/cd3hPo4k2DG6Ptcz060Ez5I=
k8s.io/kube-openapi v0.0.0-20190816220812-743ec37842bf/go.mod h1:1TqjTSzOxsLGIKfj0lK8EeCP7K1iUG65v09OM0/WG5E=
k8s.io/kube-openapi v0.0.0-20190918143330-0270cf2f1c1d/go.mod h1:1TqjTSzOxsLGIKfj0lK8EeCP7K1iUG65v09OM0/WG5E=
k8s.io/kube-openapi v0.0.0-20191107075043-30be4d16710a h1:UcxjrRMyNx/i/y8G7kPvLyy7rfbeuf1PYyBf973pgyU=
k8s.io/kube-openapi v0.0.0-20191107075043-30be4d16710a/go.mod h1:1TqjTSzOxsLGIKfj0lK8EeCP7K1iUG65v09OM0/WG5E=
k8s.io/kubectl v0.0.0-20191016120415-2ed914427d51 h1:RBkTKVMF+xsNsSOVc0+HdC0B5gD1sr6s6Cu5w9qNbuQ=
k8s.io/kubectl v0.0.0-20191016120415-2ed914427d51/go.mod h1:gL826ZTIfD4vXTGlmzgTbliCAT9NGiqpCqK2aNYv5MQ=
k8s.io/kubectl v0.0.0-20191219154910-1528d4eea6dd h1:nZX5+wEqTu/EBIYjrZlFOA63z4+Zcy96lDkCZPU9a9c=
k8s.io/kubectl v0.0.0-20191219154910-1528d4eea6dd/go.mod h1:9ehGcuUGjXVZh0qbYSB0vvofQw2JQe6c6cO0k4wu/Oo=
k8s.io/kubernetes v1.13.0/go.mod h1:ocZa8+6APFNC2tX1DZASIbocyYT5jHzqFVsY5aoB7Jk=
k8s.io/metrics v0.0.0-20191016113814-3b1a734dba6e/go.mod h1:ve7/vMWeY5lEBkZf6Bt5TTbGS3b8wAxwGbdXAsufjRs=
k8s.io/utils v0.0.0-20190801114015-581e00157fb1/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew=
k8s.io/utils v0.0.0-20191010214722-8d271d903fe4 h1:Gi+/O1saihwDqnlmC8Vhv1M5Sp4+rbOmK9TbsLn8ZEA=
k8s.io/utils v0.0.0-20191010214722-8d271d903fe4/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew=
k8s.io/metrics v0.0.0-20191214191643-6b1944c9f765/go.mod h1:5V7rewilItwK0cz4nomU0b3XCcees2Ka5EBYWS1HBeM=
k8s.io/utils v0.0.0-20191114184206-e782cd3c129f h1:GiPwtSzdP43eI1hpPCbROQCCIgCuiMMNF8YUVLF3vJo=
k8s.io/utils v0.0.0-20191114184206-e782cd3c129f/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew=
modernc.org/cc v1.0.0/go.mod h1:1Sk4//wdnYJiUIxnW8ddKpaOJCF37yAdqYnkxUpaYxw=
modernc.org/golex v1.0.0/go.mod h1:b/QX9oBD/LhixY6NDh+IdGv17hgB+51fET1i2kPSmvk=
modernc.org/mathutil v1.0.0/go.mod h1:wU0vUrJsVWBZ4P6e7xtFJEhFSNsfRLJ8H458uRjg03k=
@@ -1417,12 +1428,13 @@ mvdan.cc/lint v0.0.0-20170908181259-adc824a0674b/go.mod h1:2odslEg/xrtNQqCYg2/jC
mvdan.cc/unparam v0.0.0-20190720180237-d51796306d8f/go.mod h1:4G1h5nDURzA3bwVMZIVpwbkw+04kSxk3rAtzlimaUJw=
pack.ag/amqp v0.11.2/go.mod h1:4/cbmt4EJXSKlG6LCfWHoqmN0uFdy5i/+YFz+fTfhV4=
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
rsc.io/letsencrypt v0.0.1 h1:DV0d09Ne9E7UUa9ZqWktZ9L2VmybgTgfq7xlfFR/bbU=
rsc.io/letsencrypt v0.0.1/go.mod h1:buyQKZ6IXrRnB7TdkHP0RyEybLx18HHyOSoTyoOLqNY=
rsc.io/letsencrypt v0.0.3 h1:H7xDfhkaFFSYEJlKeq38RwX2jYcnTeHuDQyT+mMNMwM=
rsc.io/letsencrypt v0.0.3/go.mod h1:buyQKZ6IXrRnB7TdkHP0RyEybLx18HHyOSoTyoOLqNY=
sigs.k8s.io/kustomize v2.0.3+incompatible h1:JUufWFNlI44MdtnjUqVnvh29rR37PQFzPbLXqhyOyX0=
sigs.k8s.io/kustomize v2.0.3+incompatible/go.mod h1:MkjgH3RdOWrievjo6c9T245dYlB5QeXV4WCbnt/PEpU=
sigs.k8s.io/structured-merge-diff v0.0.0-20190525122527-15d366b2352e/go.mod h1:wWxsB5ozmmv/SG7nM11ayaAW51xMvak/t1r0CSlcokI=
sigs.k8s.io/structured-merge-diff v0.0.0-20190817042607-6149e4549fca/go.mod h1:IIgPezJWb76P0hotTxzDbWsMYB8APh18qZnxkomBpxA=
sigs.k8s.io/structured-merge-diff v1.0.1-0.20191108220359-b1b620dd3f06/go.mod h1:/ULNhyfzRopfcjskuui0cTITekDduZ7ycKN3oUT9R18=
sigs.k8s.io/yaml v1.1.0 h1:4A07+ZFc2wgJwo8YNlQpr1rVlgUDlxXHhPJciaPY5gs=
sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o=
sourcegraph.com/sqs/pbtypes v0.0.0-20180604144634-d3ebe8f20ae4/go.mod h1:ketZ/q3QxT9HOBeFhu6RdvsftgpsbFHBF5Cas6cDKZ0=
vbom.ml/util v0.0.0-20160121211510-db5cfe13f5cc/go.mod h1:so/NYdZXCz+E3ZpW0uAoCj6uzU2+8OWDFv/HxUSs7kI=

View File

@@ -1,4 +1,4 @@
site_name: Qlik Sense installer
site_name: Qlik Sense on Kubernetes CLI
repo_url: 'https://github.com/qlik-oss/sense-installer'
strict: true
theme:
@@ -19,6 +19,5 @@ nav:
- getting_started.md
- command_reference.md
- concepts.md
- preflight_checks.md
- air_gap.md
- Releases ⧉: https://github.com/qlik-oss/sense-installer/releases

View File

@@ -109,6 +109,7 @@ func ReadFromFile(content interface{}, sourceFile string) error {
if e != nil {
return e
}
defer file.Close()
return ReadFromStream(content, file)
}

View File

@@ -15,12 +15,20 @@ func KubectlApply(manifests, namespace string) error {
return kubectlOperation(manifests, "apply", namespace)
}
func KubectlApplyVerbose(manifests, namespace string, verbose bool) error {
return kubectlOperationVerbose(manifests, "apply", namespace, verbose)
}
// KubectlDelete delete resoruces in the provided namespace,
// if namespace="" then use whatever the kubectl default is
func KubectlDelete(manifests, namespace string) error {
return kubectlOperation(manifests, "delete", namespace)
}
func KubectlDeleteVerbose(manifests, namespace string, verbose bool) error {
return kubectlOperationVerbose(manifests, "delete", namespace, verbose)
}
func GetKubectlNamespace() string {
namespace := ""
cmd := exec.Command("kubectl", "config", "current-context")
@@ -61,6 +69,10 @@ func SetKubectlNamespace(ns string) {
}
func kubectlOperation(manifests string, oprName string, namespace string) error {
return kubectlOperationVerbose(manifests, oprName, namespace, true)
}
func kubectlOperationVerbose(manifests string, oprName string, namespace string, verbose bool) error {
tempYaml, err := ioutil.TempFile("", "")
if err != nil {
fmt.Println("cannot create file ", err)
@@ -88,12 +100,16 @@ func kubectlOperation(manifests string, oprName string, namespace string) error
}
sterrBuffer := &bytes.Buffer{}
cmd.Stdout = os.Stdout
stoutBuffer := &bytes.Buffer{}
cmd.Stdout = stoutBuffer
cmd.Stderr = sterrBuffer
err = cmd.Run()
if err != nil {
return fmt.Errorf("kubectl %v failed with: %v, %v, temp k8s yaml file:%v\n", oprName, err, sterrBuffer.String(), tempYaml.Name())
}
if verbose {
fmt.Println(stoutBuffer.String())
}
os.Remove(tempYaml.Name())
return nil
}

View File

@@ -46,7 +46,7 @@ func DirExists(dirname string) bool {
// LogDebugMessage logs a debug message
func LogDebugMessage(strMessage string, args ...interface{}) {
if os.Getenv("QLIKSENSE_DEBUG") == "true" {
log.Printf(strMessage, args...)
fmt.Printf(strMessage, args...)
}
}

View File

@@ -2,106 +2,110 @@ package preflight
import (
"fmt"
. "github.com/logrusorgru/aurora"
ansi "github.com/mattn/go-colorable"
"github.com/pkg/errors"
)
func (qp *QliksensePreflight) RunAllPreflightChecks(namespace string, kubeConfigContents []byte, mongodbUrl string) {
func (qp *QliksensePreflight) RunAllPreflightChecks(kubeConfigContents []byte, namespace string, preflightOpts *PreflightOptions) error {
checkCount := 0
totalCount := 0
out := ansi.NewColorableStdout()
// Preflight minimum kuberenetes version check
fmt.Printf("\nPreflight kubernetes minimum version check\n")
fmt.Println("------------------------------------------")
if err := qp.CheckK8sVersion(namespace, kubeConfigContents); err != nil {
fmt.Printf("Preflight kubernetes minimum version check: FAILED\n")
fmt.Fprintf(out, "%s\n", Red("Preflight kubernetes minimum version check FAILED"))
fmt.Printf("Error: %v\n\n", err)
} else {
fmt.Fprintf(out, "%s\n\n", Green("Preflight kubernetes minimum version check PASSED"))
checkCount++
}
totalCount++
// Preflight deployment check
fmt.Printf("\nPreflight deployment check\n")
fmt.Println("--------------------------")
if err := qp.CheckDeployment(namespace, kubeConfigContents); err != nil {
fmt.Printf("Preflight deployment check: FAILED\n")
if err := qp.CheckDeployment(namespace, kubeConfigContents, false); err != nil {
fmt.Fprintf(out, "%s\n", Red("Preflight deployment check FAILED"))
fmt.Printf("Error: %v\n\n", err)
} else {
fmt.Fprintf(out, "%s\n\n", Green("Preflight deployment check PASSED"))
checkCount++
}
totalCount++
// Preflight service check
fmt.Printf("\nPreflight service check\n")
fmt.Println("-----------------------")
if err := qp.CheckService(namespace, kubeConfigContents); err != nil {
fmt.Printf("Preflight service check: FAILED\n")
if err := qp.CheckService(namespace, kubeConfigContents, false); err != nil {
fmt.Fprintf(out, "%s\n", Red("Preflight service check FAILED"))
fmt.Printf("Error: %v\n\n", err)
} else {
fmt.Fprintf(out, "%s\n\n", Green("Preflight service check PASSED"))
checkCount++
}
totalCount++
// Preflight pod check
fmt.Printf("\nPreflight pod check\n")
fmt.Println("-----------------------")
if err := qp.CheckPod(namespace, kubeConfigContents); err != nil {
fmt.Printf("Preflight pod check: FAILED\n")
if err := qp.CheckPod(namespace, kubeConfigContents, false); err != nil {
fmt.Fprintf(out, "%s\n", Red("Preflight pod check FAILED"))
fmt.Printf("Error: %v\n\n", err)
} else {
fmt.Fprintf(out, "%s\n\n", Green("Preflight pod check PASSED"))
checkCount++
}
totalCount++
// Preflight role check
fmt.Printf("\nPreflight role check\n")
fmt.Println("--------------------------")
if err := qp.CheckCreateRole(namespace); err != nil {
fmt.Printf("Preflight role check: FAILED\n")
if err := qp.CheckCreateRole(namespace, false); err != nil {
fmt.Fprintf(out, "%s\n", Red("Preflight role check FAILED"))
fmt.Printf("Error: %v\n\n", err)
} else {
fmt.Fprintf(out, "%s\n\n", Green("Preflight role check PASSED"))
checkCount++
}
totalCount++
// Preflight rolebinding check
fmt.Printf("\nPreflight rolebinding check\n")
fmt.Println("---------------------------------")
if err := qp.CheckCreateRoleBinding(namespace); err != nil {
fmt.Printf("Preflight rolebinding check: FAILED\n")
if err := qp.CheckCreateRoleBinding(namespace, false); err != nil {
fmt.Fprintf(out, "%s\n", Red(" Preflight rolebinding check FAILED"))
fmt.Printf("Error: %v\n\n", err)
} else {
fmt.Fprintf(out, "%s\n\n", Green("Preflight rolebinding check PASSED"))
checkCount++
}
totalCount++
// Preflight serviceaccount check
fmt.Printf("\nPreflight serviceaccount check\n")
fmt.Println("------------------------------------")
if err := qp.CheckCreateServiceAccount(namespace); err != nil {
fmt.Printf("Preflight serviceaccount check: FAILED\n")
if err := qp.CheckCreateServiceAccount(namespace, false); err != nil {
fmt.Fprintf(out, "%s\n", Red(" Preflight serviceaccount check FAILED"))
fmt.Printf("Error: %v\n\n", err)
} else {
fmt.Fprintf(out, "%s\n\n", Green("Preflight serviceaccount check PASSED"))
checkCount++
}
totalCount++
// Preflight mongo check
fmt.Printf("\nPreflight mongo check\n")
fmt.Println("---------------------")
if err := qp.CheckMongo(kubeConfigContents, namespace, mongodbUrl); err != nil {
fmt.Printf("Preflight mongo check: FAILED\n")
if err := qp.CheckMongo(kubeConfigContents, namespace, preflightOpts, false); err != nil {
fmt.Fprintf(out, "%s\n", Red(" Preflight mongo check FAILED"))
fmt.Printf("Error: %v\n\n", err)
} else {
fmt.Fprintf(out, "%s\n\n", Green("Preflight mongo check PASSED"))
checkCount++
}
totalCount++
// Preflight DNS check
fmt.Printf("\nPreflight DNS check\n")
fmt.Println("-------------------")
if err := qp.CheckDns(namespace, kubeConfigContents); err != nil {
fmt.Printf("Preflight DNS check: FAILED\n")
if err := qp.CheckDns(namespace, kubeConfigContents, false); err != nil {
fmt.Fprintf(out, "%s\n", Red(" Preflight DNS check FAILED"))
fmt.Printf("Error: %v\n\n", err)
} else {
fmt.Fprintf(out, "%s\n\n", Green("Preflight DNS check PASSED"))
checkCount++
}
totalCount++
if checkCount == totalCount {
fmt.Printf("\nAll preflight checks have PASSED\n")
} else {
fmt.Printf("\n1 or more preflight checks have FAILED\n")
// All preflight checks were successful
return nil
}
fmt.Println("Completed running all preflight checks")
return errors.New("1 or more preflight checks have FAILED")
}

View File

@@ -6,123 +6,151 @@ import (
"k8s.io/client-go/kubernetes"
)
func (qp *QliksensePreflight) CheckDeployment(namespace string, kubeConfigContents []byte) error {
func (qp *QliksensePreflight) CheckDeployment(namespace string, kubeConfigContents []byte, cleanup bool) error {
clientset, _, err := getK8SClientSet(kubeConfigContents, "")
if err != nil {
err = fmt.Errorf("Kube config error: %v\n", err)
fmt.Print(err)
return err
}
// Deployment check
fmt.Printf("Preflight deployment check: \n")
err = qp.checkPfDeployment(clientset, namespace, "deployment-preflight-check")
if !cleanup {
qp.P.LogVerboseMessage("Preflight deployment check: \n")
qp.P.LogVerboseMessage("--------------------------- \n")
}
err = qp.checkPfDeployment(clientset, namespace, cleanup)
if err != nil {
fmt.Println("Preflight Deployment check: FAILED")
qp.P.LogVerboseMessage("Preflight Deployment check: FAILED\n")
return err
}
fmt.Println("Completed preflight deployment check")
if !cleanup {
qp.P.LogVerboseMessage("Completed preflight deployment check\n")
}
return nil
}
func (qp *QliksensePreflight) CheckService(namespace string, kubeConfigContents []byte) error {
func (qp *QliksensePreflight) CheckService(namespace string, kubeConfigContents []byte, cleanup bool) error {
clientset, _, err := getK8SClientSet(kubeConfigContents, "")
if err != nil {
err = fmt.Errorf("error: unable to create a kubernetes client: %v\n", err)
fmt.Println(err)
err = fmt.Errorf("unable to create a kubernetes client: %v\n", err)
return err
}
// Service check
fmt.Printf("\nPreflight service check: \n")
err = checkPfService(clientset, namespace)
if !cleanup {
qp.P.LogVerboseMessage("Preflight service check: \n")
qp.P.LogVerboseMessage("------------------------ \n")
}
err = qp.checkPfService(clientset, namespace, cleanup)
if err != nil {
fmt.Println("Preflight Service check: FAILED")
qp.P.LogVerboseMessage("Preflight Service check: FAILED\n")
return err
}
fmt.Println("Completed preflight service check")
if !cleanup {
qp.P.LogVerboseMessage("Completed preflight service check\n")
}
return nil
}
func (qp *QliksensePreflight) CheckPod(namespace string, kubeConfigContents []byte) error {
func (qp *QliksensePreflight) CheckPod(namespace string, kubeConfigContents []byte, cleanup bool) error {
clientset, _, err := getK8SClientSet(kubeConfigContents, "")
if err != nil {
err = fmt.Errorf("error: unable to create a kubernetes client: %v\n", err)
fmt.Print(err)
return err
}
// Pod check
fmt.Printf("\nPreflight pod check: \n")
err = qp.checkPfPod(clientset, namespace)
if !cleanup {
qp.P.LogVerboseMessage("Preflight pod check: \n")
qp.P.LogVerboseMessage("-------------------- \n")
}
err = qp.checkPfPod(clientset, namespace, cleanup)
if err != nil {
fmt.Println("Preflight Pod check: FAILED")
qp.P.LogVerboseMessage("Preflight Pod check: FAILED\n")
return err
}
fmt.Println("Completed preflight pod check")
if !cleanup {
qp.P.LogVerboseMessage("Completed preflight pod check\n")
}
return nil
}
func (qp *QliksensePreflight) checkPfPod(clientset *kubernetes.Clientset, namespace string) error {
// create a pod
func (qp *QliksensePreflight) checkPfPod(clientset *kubernetes.Clientset, namespace string, cleanup bool) error {
// delete the pod we are going to create, if it already exists in the cluster
podName := "pod-pf-check"
qp.deletePod(clientset, namespace, podName)
if cleanup {
return nil
}
commandToRun := []string{}
imageName, err := qp.GetPreflightConfigObj().GetImageName(nginx, true)
if err != nil {
return err
}
pod, err := createPreflightTestPod(clientset, namespace, podName, imageName, commandToRun)
// create a pod
pod, err := qp.createPreflightTestPod(clientset, namespace, podName, imageName, nil, commandToRun)
if err != nil {
err = fmt.Errorf("error: unable to create pod %s - %v\n", podName, err)
err = fmt.Errorf("unable to create pod - %v\n", err)
return err
}
defer deletePod(clientset, namespace, podName)
defer qp.deletePod(clientset, namespace, podName)
if err := waitForPod(clientset, namespace, pod); err != nil {
return err
}
fmt.Println("Preflight pod creation check: PASSED")
fmt.Println("Cleaning up resources...")
qp.P.LogVerboseMessage("Preflight pod creation check: PASSED\n")
qp.P.LogVerboseMessage("Cleaning up resources...\n")
return nil
}
func checkPfService(clientset *kubernetes.Clientset, namespace string) error {
// creating service
func (qp *QliksensePreflight) checkPfService(clientset *kubernetes.Clientset, namespace string, cleanup bool) error {
// delete the service we are going to create, if it already exists in the cluster
serviceName := "svc-pf-check"
pfService, err := createPreflightTestService(clientset, namespace, serviceName)
qp.deleteService(clientset, namespace, serviceName)
if cleanup {
return nil
}
// creating service
pfService, err := qp.createPreflightTestService(clientset, namespace, serviceName)
if err != nil {
err = fmt.Errorf("error: unable to create service : %s\n", serviceName)
err = fmt.Errorf("unable to create service - %v\n", err)
return err
}
defer deleteService(clientset, namespace, serviceName)
defer qp.deleteService(clientset, namespace, serviceName)
_, err = getService(clientset, namespace, pfService.GetName())
if err != nil {
err = fmt.Errorf("error: unable to retrieve service: %s\n", serviceName)
err = fmt.Errorf("unable to retrieve service - %v\n", err)
return err
}
fmt.Println("Preflight service creation check: PASSED")
fmt.Println("Cleaning up resources...")
qp.P.LogVerboseMessage("Preflight service creation check: PASSED\n")
qp.P.LogVerboseMessage("Cleaning up resources...\n")
return nil
}
func (qp *QliksensePreflight) checkPfDeployment(clientset *kubernetes.Clientset, namespace, depName string) error {
func (qp *QliksensePreflight) checkPfDeployment(clientset *kubernetes.Clientset, namespace string, cleanup bool) error {
// delete the deployment we are going to create, if it already exists in the cluster
depName := "deployment-preflight-check"
qp.deleteDeployment(clientset, namespace, depName)
if cleanup {
return nil
}
// check if we are able to create a deployment
imageName, err := qp.GetPreflightConfigObj().GetImageName(nginx, true)
if err != nil {
return err
}
pfDeployment, err := createPreflightTestDeployment(clientset, namespace, depName, imageName)
pfDeployment, err := qp.createPreflightTestDeployment(clientset, namespace, depName, imageName)
if err != nil {
err = fmt.Errorf("error: unable to create deployment: %v\n", err)
err = fmt.Errorf("unable to create deployment - %v\n", err)
return err
}
defer deleteDeployment(clientset, namespace, depName)
defer qp.deleteDeployment(clientset, namespace, depName)
if err := waitForDeployment(clientset, namespace, pfDeployment); err != nil {
return err
}
fmt.Println("Preflight Deployment check: PASSED")
fmt.Println("Cleaning up resources...")
qp.P.LogVerboseMessage("Preflight Deployment check: PASSED\n")
qp.P.LogVerboseMessage("Cleaning up resources...\n")
return nil
}

View File

@@ -3,6 +3,8 @@ package preflight
import (
"fmt"
"strings"
"k8s.io/client-go/kubernetes"
)
const (
@@ -10,62 +12,72 @@ const (
netcat = "netcat"
)
func (qp *QliksensePreflight) CheckDns(namespace string, kubeConfigContents []byte) error {
func (qp *QliksensePreflight) CheckDns(namespace string, kubeConfigContents []byte, cleanup bool) error {
depName := "dep-dns-preflight-check"
serviceName := "svc-dns-pf-check"
podName := "pf-pod-1"
if !cleanup {
qp.P.LogVerboseMessage("Preflight DNS check: \n")
qp.P.LogVerboseMessage("------------------- \n")
}
clientset, _, err := getK8SClientSet(kubeConfigContents, "")
if err != nil {
err = fmt.Errorf("error: unable to create a kubernetes client: %v\n", err)
fmt.Println(err)
err = fmt.Errorf("unable to create a kubernetes client: %v\n", err)
return err
}
// delete the deployment we are going to create, if it already exists in the cluster
qp.runDNSCleanup(clientset, namespace, podName, serviceName, depName)
if cleanup {
return nil
}
// creating deployment
depName := "dep-dns-preflight-check"
nginxImageName, err := qp.GetPreflightConfigObj().GetImageName(nginx, true)
if err != nil {
return err
}
dnsDeployment, err := createPreflightTestDeployment(clientset, namespace, depName, nginxImageName)
dnsDeployment, err := qp.createPreflightTestDeployment(clientset, namespace, depName, nginxImageName)
if err != nil {
err = fmt.Errorf("error: unable to create deployment: %v\n", err)
fmt.Println(err)
err = fmt.Errorf("unable to create deployment: %v\n", err)
return err
}
defer deleteDeployment(clientset, namespace, depName)
defer qp.deleteDeployment(clientset, namespace, depName)
if err := waitForDeployment(clientset, namespace, dnsDeployment); err != nil {
return err
}
// creating service
serviceName := "svc-dns-pf-check"
dnsService, err := createPreflightTestService(clientset, namespace, serviceName)
dnsService, err := qp.createPreflightTestService(clientset, namespace, serviceName)
if err != nil {
err = fmt.Errorf("error: unable to create service : %s\n", serviceName)
err = fmt.Errorf("unable to create service : %s, %s\n", serviceName, err)
return err
}
defer deleteService(clientset, namespace, serviceName)
defer qp.deleteService(clientset, namespace, serviceName)
// create a pod
podName := "pf-pod-1"
commandToRun := []string{"sh", "-c", "sleep 10; nc -z -v -w 1 " + dnsService.Name + " 80"}
netcatImageName, err := qp.GetPreflightConfigObj().GetImageName(netcat, true)
if err != nil {
return err
}
dnsPod, err := createPreflightTestPod(clientset, namespace, podName, netcatImageName, commandToRun)
if err != nil {
err = fmt.Errorf("error: unable to create pod : %s\n", podName)
err = fmt.Errorf("unable to retrieve image : %v\n", err)
return err
}
defer deletePod(clientset, namespace, podName)
dnsPod, err := qp.createPreflightTestPod(clientset, namespace, podName, netcatImageName, nil, commandToRun)
if err != nil {
err = fmt.Errorf("unable to create pod : %s, %s\n", podName, err)
return err
}
defer qp.deletePod(clientset, namespace, podName)
if err := waitForPod(clientset, namespace, dnsPod); err != nil {
return err
}
if len(dnsPod.Spec.Containers) == 0 {
err := fmt.Errorf("error: there are no containers in the pod")
fmt.Println(err)
err := fmt.Errorf("there are no containers in the pod")
return err
}
@@ -73,20 +85,26 @@ func (qp *QliksensePreflight) CheckDns(namespace string, kubeConfigContents []by
logStr, err := getPodLogs(clientset, dnsPod)
if err != nil {
err = fmt.Errorf("error: unable to execute dns check in the cluster: %v", err)
fmt.Println(err)
err = fmt.Errorf("unable to execute dns check in the cluster: %v", err)
return err
}
if strings.HasSuffix(strings.TrimSpace(logStr), "succeeded!") {
fmt.Println("Preflight DNS check: PASSED")
qp.P.LogVerboseMessage("Preflight DNS check: PASSED\n")
} else {
err = fmt.Errorf("Expected response not found\n")
return err
}
fmt.Println("Completed preflight DNS check")
fmt.Println("Cleaning up resources...")
if !cleanup {
qp.P.LogVerboseMessage("Completed preflight DNS check\n")
qp.P.LogVerboseMessage("Cleaning up resources...\n")
}
return nil
}
func (qp *QliksensePreflight) runDNSCleanup(clientset *kubernetes.Clientset, namespace, podName, serviceName, depName string) {
qp.deleteDeployment(clientset, namespace, depName)
qp.deletePod(clientset, namespace, podName)
qp.deleteService(clientset, namespace, serviceName)
}

View File

@@ -2,21 +2,27 @@ package preflight
import (
"fmt"
"io/ioutil"
"strings"
"github.com/qlik-oss/sense-installer/pkg/api"
qapi "github.com/qlik-oss/sense-installer/pkg/api"
apiv1 "k8s.io/api/core/v1"
"k8s.io/client-go/kubernetes"
)
const (
mongo = "mongo"
)
func (qp *QliksensePreflight) CheckMongo(kubeConfigContents []byte, namespace, mongodbUrl string) error {
fmt.Printf("Preflight mongodb check: \n")
if mongodbUrl == "" {
func (qp *QliksensePreflight) CheckMongo(kubeConfigContents []byte, namespace string, preflightOpts *PreflightOptions, cleanup bool) error {
if !cleanup {
qp.P.LogVerboseMessage("Preflight mongodb check: \n")
qp.P.LogVerboseMessage("------------------------ \n")
}
if preflightOpts != nil && preflightOpts.MongoOptions.MongodbUrl == "" && !cleanup {
// infer mongoDbUrl from currentCR
fmt.Println("MongoDbUri is empty, infer from CR")
qp.P.LogVerboseMessage("MongoDbUri is empty, infer from CR\n")
qConfig := qapi.NewQConfig(qp.Q.QliksenseHome)
var currentCR *qapi.QliksenseCR
@@ -24,64 +30,145 @@ func (qp *QliksensePreflight) CheckMongo(kubeConfigContents []byte, namespace, m
qConfig.SetNamespace(namespace)
currentCR, err = qConfig.GetCurrentCR()
if err != nil {
fmt.Printf("Unable to retrieve current CR: %v\n", err)
qp.P.LogVerboseMessage("Unable to retrieve current CR: %v\n", err)
return err
}
decryptedCR, err := qConfig.GetDecryptedCr(currentCR)
mongodbUrl = decryptedCR.Spec.GetFromSecrets("qliksense", "mongoDbUri")
if err != nil {
qp.P.LogVerboseMessage("An error occurred while retrieving mongodbUrl from current CR: %v\n", err)
return err
}
preflightOpts.MongoOptions.MongodbUrl = decryptedCR.Spec.GetFromSecrets("qliksense", "mongoDbUri")
}
fmt.Printf("mongodbUrl: %s\n", mongodbUrl)
if err := qp.mongoConnCheck(kubeConfigContents, namespace, mongodbUrl); err != nil {
if !cleanup {
qp.P.LogVerboseMessage("MongodbUrl: %s\n", preflightOpts.MongoOptions.MongodbUrl)
}
if err := qp.mongoConnCheck(kubeConfigContents, namespace, preflightOpts, cleanup); err != nil {
return err
}
fmt.Println("Completed preflight mongodb check")
if !cleanup {
qp.P.LogVerboseMessage("Completed preflight mongodb check\n")
}
return nil
}
func (qp *QliksensePreflight) mongoConnCheck(kubeConfigContents []byte, namespace, mongodbUrl string) error {
func (qp *QliksensePreflight) mongoConnCheck(kubeConfigContents []byte, namespace string, preflightOpts *PreflightOptions, cleanup bool) error {
caCertSecretName := "preflight-mongo-test-cacert"
clientCertSecretName := "preflight-mongo-test-clientcert"
mongoPodName := "pf-mongo-pod"
clientset, _, err := getK8SClientSet(kubeConfigContents, "")
if err != nil {
err = fmt.Errorf("error: unable to create a kubernetes client: %v\n", err)
fmt.Println(err)
err = fmt.Errorf("unable to create a kubernetes client: %v\n", err)
return err
}
// cleanup before starting check
qp.runMongoCleanup(clientset, namespace, mongoPodName, caCertSecretName, clientCertSecretName)
if cleanup {
return nil
}
var secrets []string
if preflightOpts.MongoOptions.CaCertFile != "" {
caCertSecret, err := qp.createSecret(clientset, namespace, preflightOpts.MongoOptions.CaCertFile, caCertSecretName)
if err != nil {
err = fmt.Errorf("unable to create a ca cert kubernetes secret: %v\n", err)
return err
}
defer qp.deleteK8sSecret(clientset, namespace, caCertSecret.Name)
secrets = append(secrets, caCertSecretName)
}
if preflightOpts.MongoOptions.ClientCertFile != "" {
clientCertSecret, err := qp.createSecret(clientset, namespace, preflightOpts.MongoOptions.ClientCertFile, clientCertSecretName)
if err != nil {
err = fmt.Errorf("unable to create a client cert kubernetes secret: %v\n", err)
return err
}
defer qp.deleteK8sSecret(clientset, namespace, clientCertSecret.Name)
secrets = append(secrets, clientCertSecretName)
}
mongoCommand := strings.Builder{}
mongoCommand.WriteString(fmt.Sprintf("sleep 10;mongo %s", preflightOpts.MongoOptions.MongodbUrl))
if preflightOpts.MongoOptions.Username != "" {
mongoCommand.WriteString(fmt.Sprintf(" --username %s", preflightOpts.MongoOptions.Username))
api.LogDebugMessage("Adding username: Mongo command: %s\n", mongoCommand.String())
}
if preflightOpts.MongoOptions.Password != "" {
mongoCommand.WriteString(fmt.Sprintf(" --password %s", preflightOpts.MongoOptions.Password))
api.LogDebugMessage("Adding username and password\n")
}
if preflightOpts.MongoOptions.Tls || preflightOpts.MongoOptions.CaCertFile != "" || preflightOpts.MongoOptions.ClientCertFile != "" {
mongoCommand.WriteString(" --tls")
api.LogDebugMessage("Adding --tls: Mongo command: %s\n", mongoCommand.String())
}
if preflightOpts.MongoOptions.CaCertFile != "" {
mongoCommand.WriteString(fmt.Sprintf(" --tlsCAFile=/etc/ssl/%s/%[1]s", caCertSecretName))
api.LogDebugMessage("Adding caCertFile: Mongo command: %s\n", mongoCommand.String())
}
if preflightOpts.MongoOptions.ClientCertFile != "" {
mongoCommand.WriteString(fmt.Sprintf(" --tlsCertificateKeyFile=/etc/ssl/%s/%[1]s", clientCertSecretName))
api.LogDebugMessage("Adding clientCertFile: Mongo command: %s\n", mongoCommand.String())
}
mongoCommand.WriteString(` --eval "print(\"connected to mongo\")"`)
commandToRun := []string{"sh", "-c", mongoCommand.String()}
api.LogDebugMessage("Mongo command: %s\n", strings.Join(commandToRun, " "))
// create a pod
podName := "pf-mongo-pod"
commandToRun := []string{"sh", "-c", "sleep 10;mongo " + mongodbUrl}
imageName, err := qp.GetPreflightConfigObj().GetImageName(mongo, true)
if err != nil {
err = fmt.Errorf("unable to retrieve image : %v\n", err)
return err
}
mongoPod, err := createPreflightTestPod(clientset, namespace, podName, imageName, commandToRun)
mongoPod, err := qp.createPreflightTestPod(clientset, namespace, mongoPodName, imageName, secrets, commandToRun)
if err != nil {
err = fmt.Errorf("error: unable to create pod : %v\n", err)
err = fmt.Errorf("unable to create pod : %v\n", err)
return err
}
defer deletePod(clientset, namespace, podName)
defer qp.deletePod(clientset, namespace, mongoPodName)
if err := waitForPod(clientset, namespace, mongoPod); err != nil {
return err
}
if len(mongoPod.Spec.Containers) == 0 {
err := fmt.Errorf("error: there are no containers in the pod- %v\n", err)
fmt.Println(err)
err := fmt.Errorf("there are no containers in the pod- %v\n", err)
return err
}
waitForPodToDie(clientset, namespace, mongoPod)
logStr, err := getPodLogs(clientset, mongoPod)
if err != nil {
err = fmt.Errorf("error: unable to execute mongo check in the cluster: %v\n", err)
fmt.Println(err)
err = fmt.Errorf("unable to execute mongo check in the cluster: %v\n", err)
return err
}
stringToCheck := "Implicit session:"
if strings.Contains(logStr, stringToCheck) {
fmt.Println("Preflight mongo check: PASSED")
qp.P.LogVerboseMessage("Preflight mongo check: PASSED\n")
} else {
err = fmt.Errorf("Expected response not found\n")
err = fmt.Errorf("Connection failed: %s\n", logStr)
return err
}
return nil
}
func (qp *QliksensePreflight) createSecret(clientset *kubernetes.Clientset, namespace, certFile, certSecretName string) (*apiv1.Secret, error) {
certBytes, err := ioutil.ReadFile(certFile)
if err != nil {
return nil, err
}
certSecret, err := qp.createPreflightTestSecret(clientset, namespace, certSecretName, certBytes)
if err != nil {
err = fmt.Errorf("unable to create secret with ca cert : %v\n", err)
return nil, err
}
return certSecret, nil
}
func (qp *QliksensePreflight) runMongoCleanup(clientset *kubernetes.Clientset, namespace, mongoPodName, caCertSecretName, clientCertSecretName string) {
qp.deletePod(clientset, namespace, mongoPodName)
qp.deleteK8sSecret(clientset, namespace, caCertSecretName)
qp.deleteK8sSecret(clientset, namespace, clientCertSecretName)
}

View File

@@ -6,6 +6,7 @@ import (
"io"
"io/ioutil"
"log"
"os"
"path/filepath"
"strings"
"time"
@@ -26,10 +27,32 @@ import (
"k8s.io/client-go/util/retry"
)
type PreflightOptions struct {
Verbose bool
MongoOptions *MongoOptions
}
// LogVerboseMessage logs a verbose message
func (p *PreflightOptions) LogVerboseMessage(strMessage string, args ...interface{}) {
if p.Verbose || os.Getenv("QLIKSENSE_DEBUG") == "true" {
fmt.Printf(strMessage, args...)
}
}
type MongoOptions struct {
MongodbUrl string
Username string
Password string
CaCertFile string
ClientCertFile string
Tls bool
}
var gracePeriod int64 = 0
type QliksensePreflight struct {
Q *qliksense.Qliksense
P *PreflightOptions
}
func (qp *QliksensePreflight) GetPreflightConfigObj() *api.PreflightConfig {
@@ -93,14 +116,12 @@ func getK8SClientSet(kubeconfig []byte, contextName string) (*kubernetes.Clients
clientConfig, err = rest.InClusterConfig()
if err != nil {
err = errors.Wrap(err, "Unable to load in-cluster kubeconfig")
fmt.Println(err)
return nil, nil, err
}
} else {
config, err := clientcmd.Load(kubeconfig)
if err != nil {
err = errors.Wrap(err, "Unable to load kubeconfig")
fmt.Println(err)
return nil, nil, err
}
if contextName != "" {
@@ -109,20 +130,18 @@ func getK8SClientSet(kubeconfig []byte, contextName string) (*kubernetes.Clients
clientConfig, err = clientcmd.NewDefaultClientConfig(*config, &clientcmd.ConfigOverrides{}).ClientConfig()
if err != nil {
err = errors.Wrap(err, "Unable to create client config from config")
fmt.Println(err)
return nil, nil, err
}
}
clientset, err := kubernetes.NewForConfig(clientConfig)
if err != nil {
err = errors.Wrap(err, "Unable to create clientset")
fmt.Println(err)
return nil, nil, err
}
return clientset, clientConfig, nil
}
func createPreflightTestDeployment(clientset *kubernetes.Clientset, namespace string, depName string, imageName string) (*appsv1.Deployment, error) {
func (qp *QliksensePreflight) createPreflightTestDeployment(clientset *kubernetes.Clientset, namespace string, depName string, imageName string) (*appsv1.Deployment, error) {
deploymentsClient := clientset.AppsV1().Deployments(namespace)
deployment := &appsv1.Deployment{
ObjectMeta: v1.ObjectMeta{
@@ -167,11 +186,10 @@ func createPreflightTestDeployment(clientset *kubernetes.Clientset, namespace st
result, err = deploymentsClient.Create(deployment)
return err
}); err != nil {
err = errors.Wrapf(err, "error: unable to create deployments in the %s namespace", namespace)
fmt.Println(err)
err = errors.Wrapf(err, "unable to create deployments in the %s namespace", namespace)
return nil, err
}
fmt.Printf("Created deployment %q\n", result.GetObjectMeta().GetName())
qp.P.LogVerboseMessage("Created deployment %q\n", result.GetObjectMeta().GetName())
return deployment, nil
}
@@ -183,14 +201,14 @@ func getDeployment(clientset *kubernetes.Clientset, namespace, depName string) (
deployment, err = deploymentsClient.Get(depName, v1.GetOptions{})
return err
}); err != nil {
err = errors.Wrapf(err, "error: unable to get deployments in the %s namespace", namespace)
err = errors.Wrapf(err, "unable to get deployments in the %s namespace", namespace)
api.LogDebugMessage("%v\n", err)
return nil, err
}
return deployment, nil
}
func deleteDeployment(clientset *kubernetes.Clientset, namespace, name string) error {
func (qp *QliksensePreflight) deleteDeployment(clientset *kubernetes.Clientset, namespace, name string) error {
deploymentsClient := clientset.AppsV1().Deployments(namespace)
// Create Deployment
deletePolicy := v1.DeletePropagationForeground
@@ -202,17 +220,16 @@ func deleteDeployment(clientset *kubernetes.Clientset, namespace, name string) e
if err := retryOnError(func() (err error) {
return deploymentsClient.Delete(name, &deleteOptions)
}); err != nil {
fmt.Println(err)
return err
}
if err := waitForDeploymentToDelete(clientset, namespace, name); err != nil {
return err
}
fmt.Printf("Deleted deployment: %s\n", name)
qp.P.LogVerboseMessage("Deleted deployment: %s\n", name)
return nil
}
func createPreflightTestService(clientset *kubernetes.Clientset, namespace string, svcName string) (*apiv1.Service, error) {
func (qp *QliksensePreflight) createPreflightTestService(clientset *kubernetes.Clientset, namespace string, svcName string) (*apiv1.Service, error) {
iptr := int32Ptr(80)
servicesClient := clientset.CoreV1().Services(namespace)
service := &apiv1.Service{
@@ -240,10 +257,9 @@ func createPreflightTestService(clientset *kubernetes.Clientset, namespace strin
result, err = servicesClient.Create(service)
return err
}); err != nil {
fmt.Println(err)
return nil, err
}
fmt.Printf("Created service %q\n", result.GetObjectMeta().GetName())
qp.P.LogVerboseMessage("Created service %q\n", result.GetObjectMeta().GetName())
return service, nil
}
@@ -256,14 +272,13 @@ func getService(clientset *kubernetes.Clientset, namespace, svcName string) (*ap
return err
}); err != nil {
err = errors.Wrapf(err, "unable to get services in the %s namespace", namespace)
fmt.Println(err)
return nil, err
}
return svc, nil
}
func deleteService(clientset *kubernetes.Clientset, namespace, name string) error {
func (qp *QliksensePreflight) deleteService(clientset *kubernetes.Clientset, namespace, name string) error {
servicesClient := clientset.CoreV1().Services(namespace)
// Create Deployment
deletePolicy := v1.DeletePropagationForeground
@@ -273,14 +288,13 @@ func deleteService(clientset *kubernetes.Clientset, namespace, name string) erro
if err := retryOnError(func() (err error) {
return servicesClient.Delete(name, &deleteOptions)
}); err != nil {
fmt.Println(err)
return err
}
fmt.Printf("Deleted service: %s\n", name)
qp.P.LogVerboseMessage("Deleted service: %s\n", name)
return nil
}
func deletePod(clientset *kubernetes.Clientset, namespace, name string) error {
func (qp *QliksensePreflight) deletePod(clientset *kubernetes.Clientset, namespace, name string) error {
podsClient := clientset.CoreV1().Pods(namespace)
deletePolicy := v1.DeletePropagationForeground
@@ -291,17 +305,16 @@ func deletePod(clientset *kubernetes.Clientset, namespace, name string) error {
if err := retryOnError(func() (err error) {
return podsClient.Delete(name, &deleteOptions)
}); err != nil {
fmt.Println(err)
return err
}
if err := waitForPodToDelete(clientset, namespace, name); err != nil {
return err
}
fmt.Printf("Deleted pod: %s\n", name)
qp.P.LogVerboseMessage("Deleted pod: %s\n", name)
return nil
}
func createPreflightTestPod(clientset *kubernetes.Clientset, namespace string, podName string, imageName string, commandToRun []string) (*apiv1.Pod, error) {
func (qp *QliksensePreflight) createPreflightTestPod(clientset *kubernetes.Clientset, namespace, podName, imageName string, secretNames []string, commandToRun []string) (*apiv1.Pod, error) {
// build the pod definition we want to deploy
pod := &apiv1.Pod{
ObjectMeta: v1.ObjectMeta{
@@ -323,16 +336,40 @@ func createPreflightTestPod(clientset *kubernetes.Clientset, namespace string, p
},
},
}
if len(secretNames) > 0 {
for _, secretName := range secretNames {
pod.Spec.Volumes = append(pod.Spec.Volumes, apiv1.Volume{
Name: secretName,
VolumeSource: apiv1.VolumeSource{
Secret: &apiv1.SecretVolumeSource{
SecretName: secretName,
Items: []apiv1.KeyToPath{
{
Key: secretName,
Path: secretName,
},
},
},
},
})
if len(pod.Spec.Containers) > 0 {
pod.Spec.Containers[0].VolumeMounts = append(pod.Spec.Containers[0].VolumeMounts, apiv1.VolumeMount{
Name: secretName,
MountPath: "/etc/ssl/" + secretName,
ReadOnly: true,
})
}
}
}
// now create the pod in kubernetes cluster using the clientset
if err := retryOnError(func() (err error) {
pod, err = clientset.CoreV1().Pods(namespace).Create(pod)
return err
}); err != nil {
fmt.Println(err)
return nil, err
}
fmt.Printf("Created pod: %s\n", pod.Name)
qp.P.LogVerboseMessage("Created pod: %s\n", pod.Name)
return pod, nil
}
@@ -397,8 +434,7 @@ func waitForDeployment(clientset *kubernetes.Clientset, namespace string, pfDepl
checkFunc := func() (interface{}, error) {
pfDeployment, err = getDeployment(clientset, namespace, depName)
if err != nil {
err = fmt.Errorf("error: unable to retrieve deployment: %s\n", depName)
fmt.Println(err)
err = fmt.Errorf("unable to retrieve deployment: %s\n", depName)
return nil, err
}
return pfDeployment, nil
@@ -411,8 +447,7 @@ func waitForDeployment(clientset *kubernetes.Clientset, namespace string, pfDepl
return err
}
if int(pfDeployment.Status.ReadyReplicas) == 0 {
err = fmt.Errorf("error: deployment took longer than expected to spin up pods")
fmt.Println(err)
err = fmt.Errorf("deployment took longer than expected to spin up pods")
return err
}
return nil
@@ -421,16 +456,14 @@ func waitForDeployment(clientset *kubernetes.Clientset, namespace string, pfDepl
func waitForPod(clientset *kubernetes.Clientset, namespace string, pod *apiv1.Pod) error {
var err error
if len(pod.Spec.Containers) == 0 {
err = fmt.Errorf("error: there are no containers in the pod")
fmt.Println(err)
err = fmt.Errorf("there are no containers in the pod")
return err
}
podName := pod.Name
checkFunc := func() (interface{}, error) {
pod, err = getPod(clientset, namespace, podName)
if err != nil {
err = fmt.Errorf("error: unable to retrieve %s pod by name", podName)
fmt.Println(err)
err = fmt.Errorf("unable to retrieve %s pod by name", podName)
return nil, err
}
return pod, nil
@@ -444,8 +477,7 @@ func waitForPod(clientset *kubernetes.Clientset, namespace string, pod *apiv1.Po
return err
}
if len(pod.Status.ContainerStatuses) == 0 || !pod.Status.ContainerStatuses[0].Ready {
err = fmt.Errorf("error: container is taking much longer than expected")
fmt.Println(err)
err = fmt.Errorf("container is taking much longer than expected")
return err
}
return nil
@@ -456,8 +488,7 @@ func waitForPodToDie(clientset *kubernetes.Clientset, namespace string, pod *api
checkFunc := func() (interface{}, error) {
po, err := getPod(clientset, namespace, podName)
if err != nil {
err = fmt.Errorf("error: unable to retrieve %s pod by name", podName)
fmt.Println(err)
err = fmt.Errorf("unable to retrieve %s pod by name", podName)
return nil, err
}
api.LogDebugMessage("pod status: %v\n", po.Status.Phase)
@@ -487,8 +518,7 @@ func waitForPodToDelete(clientset *kubernetes.Clientset, namespace, podName stri
if err := waitForResource(checkFunc, validateFunc); err != nil {
return nil
}
err := fmt.Errorf("error: delete pod is taking unusually long")
fmt.Println(err)
err := fmt.Errorf("delete pod is taking unusually long")
return err
}
@@ -506,12 +536,11 @@ func waitForDeploymentToDelete(clientset *kubernetes.Clientset, namespace, deplo
if err := waitForResource(checkFunc, validateFunc); err != nil {
return nil
}
err := fmt.Errorf("error: delete deployment is taking unusually long")
fmt.Println(err)
err := fmt.Errorf("delete deployment is taking unusually long")
return err
}
func createPfRole(clientset *kubernetes.Clientset, namespace, roleName string) (*v1beta1.Role, error) {
func (qp *QliksensePreflight) createPfRole(clientset *kubernetes.Clientset, namespace, roleName string) (*v1beta1.Role, error) {
// build the role defination we want to create
var role *v1beta1.Role
roleSpec := &v1beta1.Role{
@@ -530,30 +559,31 @@ func createPfRole(clientset *kubernetes.Clientset, namespace, roleName string) (
role, err = clientset.RbacV1beta1().Roles(namespace).Create(roleSpec)
return err
}); err != nil {
fmt.Println(err)
return nil, err
}
fmt.Printf("Created role: %s\n", role.Name)
qp.P.LogVerboseMessage("Created role: %s\n", role.Name)
return role, nil
}
func deleteRole(clientset *kubernetes.Clientset, namespace string, role *v1beta1.Role) {
func (qp *QliksensePreflight) deleteRole(clientset *kubernetes.Clientset, namespace string, roleName string) error {
rolesClient := clientset.RbacV1beta1().Roles(namespace)
deletePolicy := v1.DeletePropagationForeground
deleteOptions := v1.DeleteOptions{
PropagationPolicy: &deletePolicy,
}
err := rolesClient.Delete(role.GetName(), &deleteOptions)
err := rolesClient.Delete(roleName, &deleteOptions)
if err != nil {
log.Fatal(err)
log.Printf("Error: %v\n", err)
return err
}
fmt.Printf("Deleted role: %s\n\n", role.Name)
qp.P.LogVerboseMessage("Deleted role: %s\n\n", roleName)
return nil
}
func createPfRoleBinding(clientset *kubernetes.Clientset, namespace, roleBindingName string) (*v1beta1.RoleBinding, error) {
func (qp *QliksensePreflight) createPfRoleBinding(clientset *kubernetes.Clientset, namespace, roleBindingName string) (*v1beta1.RoleBinding, error) {
var roleBinding *v1beta1.RoleBinding
// build the rolebinding defination we want to create
roleBindingSpec := &v1beta1.RoleBinding{
@@ -561,7 +591,7 @@ func createPfRoleBinding(clientset *kubernetes.Clientset, namespace, roleBinding
Name: roleBindingName,
Namespace: namespace,
Labels: map[string]string{
"app": "demo",
"app": "preflight",
},
},
Subjects: []v1beta1.Subject{
@@ -584,28 +614,29 @@ func createPfRoleBinding(clientset *kubernetes.Clientset, namespace, roleBinding
roleBinding, err = clientset.RbacV1beta1().RoleBindings(namespace).Create(roleBindingSpec)
return err
}); err != nil {
fmt.Println(err)
return nil, err
}
fmt.Printf("Created RoleBinding: %s\n", roleBindingSpec.Name)
qp.P.LogVerboseMessage("Created RoleBinding: %s\n", roleBindingSpec.Name)
return roleBinding, nil
}
func deleteRoleBinding(clientset *kubernetes.Clientset, namespace string, roleBinding *v1beta1.RoleBinding) {
func (qp *QliksensePreflight) deleteRoleBinding(clientset *kubernetes.Clientset, namespace string, roleBindingName string) error {
roleBindingClient := clientset.RbacV1beta1().RoleBindings(namespace)
deletePolicy := v1.DeletePropagationForeground
deleteOptions := v1.DeleteOptions{
PropagationPolicy: &deletePolicy,
}
err := roleBindingClient.Delete(roleBinding.GetName(), &deleteOptions)
err := roleBindingClient.Delete(roleBindingName, &deleteOptions)
if err != nil {
log.Fatal(err)
log.Printf("Error: %v\n", err)
return err
}
fmt.Printf("Deleted RoleBinding: %s\n\n", roleBinding.Name)
qp.P.LogVerboseMessage("Deleted RoleBinding: %s\n\n", roleBindingName)
return nil
}
func createPfServiceAccount(clientset *kubernetes.Clientset, namespace, serviceAccountName string) (*apiv1.ServiceAccount, error) {
func (qp *QliksensePreflight) createPfServiceAccount(clientset *kubernetes.Clientset, namespace, serviceAccountName string) (*apiv1.ServiceAccount, error) {
var serviceAccount *apiv1.ServiceAccount
// build the serviceAccount defination we want to create
serviceAccountSpec := &apiv1.ServiceAccount{
@@ -613,7 +644,7 @@ func createPfServiceAccount(clientset *kubernetes.Clientset, namespace, serviceA
Name: "preflight-check-test-serviceaccount",
Namespace: namespace,
Labels: map[string]string{
"app": "demo",
"app": "preflight",
},
},
}
@@ -623,23 +654,92 @@ func createPfServiceAccount(clientset *kubernetes.Clientset, namespace, serviceA
serviceAccount, err = clientset.CoreV1().ServiceAccounts(namespace).Create(serviceAccountSpec)
return err
}); err != nil {
fmt.Println(err)
return nil, err
}
fmt.Printf("Created Service Account: %s\n", serviceAccountSpec.Name)
qp.P.LogVerboseMessage("Created Service Account: %s\n", serviceAccountSpec.Name)
return serviceAccount, nil
}
func deleteServiceAccount(clientset *kubernetes.Clientset, namespace string, serviceAccount *apiv1.ServiceAccount) {
func (qp *QliksensePreflight) deleteServiceAccount(clientset *kubernetes.Clientset, namespace string, serviceAccountName string) error {
serviceAccountClient := clientset.CoreV1().ServiceAccounts(namespace)
deletePolicy := v1.DeletePropagationForeground
deleteOptions := v1.DeleteOptions{
PropagationPolicy: &deletePolicy,
}
err := serviceAccountClient.Delete(serviceAccount.GetName(), &deleteOptions)
err := serviceAccountClient.Delete(serviceAccountName, &deleteOptions)
if err != nil {
log.Fatal(err)
log.Printf("Error: %v\n", err)
return err
}
fmt.Printf("Deleted ServiceAccount: %s\n\n", serviceAccount.Name)
qp.P.LogVerboseMessage("Deleted ServiceAccount: %s\n\n", serviceAccountName)
return nil
}
func (qp *QliksensePreflight) createPreflightTestSecret(clientset *kubernetes.Clientset, namespace, secretName string, secretData []byte) (*apiv1.Secret, error) {
var secret *apiv1.Secret
var err error
// build the secret defination we want to create
secretSpec := &apiv1.Secret{
ObjectMeta: v1.ObjectMeta{
Name: secretName,
Namespace: namespace,
Labels: map[string]string{
"app": "preflight",
},
},
Data: map[string][]byte{
secretName: secretData,
},
}
// now create the secret in kubernetes cluster using the clientset
if err = retryOnError(func() (err error) {
secret, err = clientset.CoreV1().Secrets(namespace).Create(secretSpec)
return err
}); err != nil {
return nil, err
}
qp.P.LogVerboseMessage("Created Secret: %s\n", secret.Name)
return secret, nil
}
func (qp *QliksensePreflight) deleteK8sSecret(clientset *kubernetes.Clientset, namespace string, secretName string) error {
secretClient := clientset.CoreV1().Secrets(namespace)
deletePolicy := v1.DeletePropagationForeground
deleteOptions := v1.DeleteOptions{
PropagationPolicy: &deletePolicy,
}
err := secretClient.Delete(secretName, &deleteOptions)
if err != nil {
return err
}
qp.P.LogVerboseMessage("Deleted Secret: %s\n", secretName)
return nil
}
func (qp *QliksensePreflight) Cleanup(namespace string, kubeConfigContents []byte) error {
qp.P.LogVerboseMessage("Preflight clean\n")
qp.P.LogVerboseMessage("----------------\n")
qp.P.LogVerboseMessage("Removing deployment...\n")
qp.CheckDeployment(namespace, kubeConfigContents, true)
qp.P.LogVerboseMessage("Removing service...\n")
qp.CheckService(namespace, kubeConfigContents, true)
qp.P.LogVerboseMessage("Removing pod...\n")
qp.CheckPod(namespace, kubeConfigContents, true)
qp.P.LogVerboseMessage("Removing role...\n")
qp.CheckCreateRole(namespace, true)
qp.P.LogVerboseMessage("Removing rolebinding...\n")
qp.CheckCreateRoleBinding(namespace, true)
qp.P.LogVerboseMessage("Removing serviceaccount...\n")
qp.CheckCreateServiceAccount(namespace, true)
qp.P.LogVerboseMessage("Removing DNS check components...\n")
qp.CheckDns(namespace, kubeConfigContents, true)
qp.P.LogVerboseMessage("Removing mongo check components...\n")
qp.CheckMongo(kubeConfigContents, namespace, &PreflightOptions{MongoOptions: &MongoOptions{}}, true)
return nil
}

View File

@@ -5,60 +5,75 @@ import (
"path/filepath"
"strings"
"github.com/pkg/errors"
"github.com/qlik-oss/sense-installer/pkg/api"
qapi "github.com/qlik-oss/sense-installer/pkg/api"
"github.com/qlik-oss/sense-installer/pkg/qliksense"
)
var resultYamlBytes = []byte("")
func (qp *QliksensePreflight) CheckCreateRole(namespace string) error {
func (qp *QliksensePreflight) CheckCreateRole(namespace string, cleanup bool) error {
// create a Role
fmt.Printf("Preflight role check: \n")
err := qp.checkCreateEntity(namespace, "Role")
if !cleanup {
qp.P.LogVerboseMessage("Preflight role check: \n")
qp.P.LogVerboseMessage("--------------------- \n")
}
err := qp.checkCreateEntity(namespace, "Role", cleanup)
if err != nil {
return err
}
fmt.Println("Completed preflight role check")
if !cleanup {
qp.P.LogVerboseMessage("Completed preflight role check\n")
}
return nil
}
func (qp *QliksensePreflight) CheckCreateRoleBinding(namespace string) error {
func (qp *QliksensePreflight) CheckCreateRoleBinding(namespace string, cleanup bool) error {
// create a RoleBinding
fmt.Printf("Preflight rolebinding check: \n")
err := qp.checkCreateEntity(namespace, "RoleBinding")
if !cleanup {
qp.P.LogVerboseMessage("Preflight rolebinding check: \n")
qp.P.LogVerboseMessage("---------------------------- \n")
}
err := qp.checkCreateEntity(namespace, "RoleBinding", cleanup)
if err != nil {
return err
}
fmt.Println("Completed preflight rolebinding check")
if !cleanup {
qp.P.LogVerboseMessage("Completed preflight rolebinding check\n")
}
return nil
}
func (qp *QliksensePreflight) CheckCreateServiceAccount(namespace string) error {
func (qp *QliksensePreflight) CheckCreateServiceAccount(namespace string, cleanup bool) error {
// create a service account
fmt.Printf("Preflight serviceaccount check: \n")
err := qp.checkCreateEntity(namespace, "ServiceAccount")
if !cleanup {
qp.P.LogVerboseMessage("Preflight serviceaccount check: \n")
qp.P.LogVerboseMessage("------------------------------- \n")
}
err := qp.checkCreateEntity(namespace, "ServiceAccount", cleanup)
if err != nil {
return err
}
fmt.Println("Completed preflight serviceaccount check")
if !cleanup {
qp.P.LogVerboseMessage("Completed preflight serviceaccount check\n")
}
return nil
}
func (qp *QliksensePreflight) checkCreateEntity(namespace, entityToTest string) error {
func (qp *QliksensePreflight) checkCreateEntity(namespace, entityToTest string, cleanup bool) error {
qConfig := qapi.NewQConfig(qp.Q.QliksenseHome)
var currentCR *qapi.QliksenseCR
mfroot := ""
kusDir := ""
resultYamlBytes := []byte("")
var err error
currentCR, err = qConfig.GetCurrentCR()
if err != nil {
fmt.Printf("Unable to retrieve current CR: %v\n", err)
qp.P.LogVerboseMessage("Unable to retrieve current CR: %v\n", err)
return err
}
if currentCR.IsRepoExist() {
mfroot = currentCR.Spec.GetManifestsRoot()
} else if tempDownloadedDir, err := qliksense.DownloadFromGitRepoToTmpDir(qliksense.QLIK_GIT_REPO, "master"); err != nil {
fmt.Printf("Unable to Download from git repo to tmp dir: %v\n", err)
qp.P.LogVerboseMessage("Unable to Download from git repo to tmp dir: %v\n", err)
return err
} else {
mfroot = tempDownloadedDir
@@ -72,7 +87,7 @@ func (qp *QliksensePreflight) checkCreateEntity(namespace, entityToTest string)
if len(resultYamlBytes) == 0 {
resultYamlBytes, err = qliksense.ExecuteKustomizeBuild(kusDir)
if err != nil {
fmt.Printf("Unable to retrieve manifests from executing kustomize: %v\n", err)
err := fmt.Errorf("Unable to retrieve manifests from executing kustomize: %s, error: %v", kusDir, err)
return err
}
}
@@ -80,58 +95,80 @@ func (qp *QliksensePreflight) checkCreateEntity(namespace, entityToTest string)
if sa != "" {
sa = strings.Replace(sa, "name: qliksense", "name: preflight", -1)
} else {
err := fmt.Errorf("Unable to retrieve yamls to apply on cluster")
fmt.Println(err)
err := fmt.Errorf("Unable to retrieve yamls to apply on cluster from dir: %s, error: %v", kusDir, err)
return err
}
namespace = "" // namespace is handled when generating the manifests
// check if entity already exists in the cluster, if so - delete it
api.KubectlDeleteVerbose(sa, namespace, qp.P.Verbose)
if cleanup {
return nil
}
defer func() {
fmt.Println("Cleaning up resources")
api.KubectlDelete(sa, namespace)
qp.P.LogVerboseMessage("Cleaning up resources...\n")
err := api.KubectlDeleteVerbose(sa, namespace, qp.P.Verbose)
if err != nil {
fmt.Println("Preflight cleanup failed!")
qp.P.LogVerboseMessage("Preflight cleanup failed!\n")
}
}()
err = api.KubectlApply(sa, namespace)
err = api.KubectlApplyVerbose(sa, namespace, qp.P.Verbose)
if err != nil {
err := fmt.Errorf("Failed to create entity on the cluster: %v", err)
fmt.Println(err)
return err
}
fmt.Printf("Preflight %s check: PASSED\n", entityToTest)
qp.P.LogVerboseMessage("Preflight %s check: PASSED\n", entityToTest)
return nil
}
func (qp *QliksensePreflight) CheckCreateRB(namespace string, kubeConfigContents []byte) error {
// create a role
fmt.Printf("Preflight createRole check: \n")
err := qp.checkCreateEntity(namespace, "Role")
if err != nil {
fmt.Println("Preflight role check: FAILED")
qp.P.LogVerboseMessage("Preflight createRole check: \n")
qp.P.LogVerboseMessage("--------------------------- \n")
errStr := strings.Builder{}
err1 := qp.checkCreateEntity(namespace, "Role", false)
if err1 != nil {
errStr.WriteString(err1.Error())
errStr.WriteString("\n")
qp.P.LogVerboseMessage("%v\n", err1)
qp.P.LogVerboseMessage("Preflight role check: FAILED\n")
}
fmt.Printf("Completed preflight role check\n\n")
qp.P.LogVerboseMessage("Completed preflight role check\n\n")
// create a roleBinding
fmt.Printf("Preflight rolebinding check: \n")
err = qp.checkCreateEntity(namespace, "RoleBinding")
if err != nil {
fmt.Println("Preflight rolebinding check: FAILED")
qp.P.LogVerboseMessage("Preflight rolebinding check: \n")
qp.P.LogVerboseMessage("---------------------------- \n")
err2 := qp.checkCreateEntity(namespace, "RoleBinding", false)
if err2 != nil {
errStr.WriteString(err2.Error())
errStr.WriteString("\n")
qp.P.LogVerboseMessage("%v\n", err2)
qp.P.LogVerboseMessage("Preflight rolebinding check: FAILED\n")
}
fmt.Printf("Completed preflight rolebinding check\n\n")
qp.P.LogVerboseMessage("Completed preflight rolebinding check\n\n")
// create a service account
fmt.Printf("Preflight serviceaccount check: \n")
err = qp.checkCreateEntity(namespace, "ServiceAccount")
if err != nil {
fmt.Println("Preflight serviceaccount check: FAILED")
qp.P.LogVerboseMessage("Preflight serviceaccount check: \n")
qp.P.LogVerboseMessage("------------------------------- \n")
err3 := qp.checkCreateEntity(namespace, "ServiceAccount", false)
if err3 != nil {
errStr.WriteString(err3.Error())
errStr.WriteString("\n")
qp.P.LogVerboseMessage("%v\n", err3)
qp.P.LogVerboseMessage("Preflight serviceaccount check: FAILED\n")
}
fmt.Printf("Completed preflight serviceaccount check\n\n")
qp.P.LogVerboseMessage("Completed preflight serviceaccount check\n\n")
fmt.Println("Preflight RB check: PASSED")
fmt.Println("Completed preflight CreateRB check")
if err1 != nil || err2 != nil || err3 != nil {
qp.P.LogVerboseMessage("Preflight authcheck: FAILED\n")
qp.P.LogVerboseMessage("Completed preflight authcheck\n")
return errors.New(errStr.String())
}
qp.P.LogVerboseMessage("Preflight authcheck: PASSED\n")
qp.P.LogVerboseMessage("Completed preflight authcheck\n")
return nil
}

View File

@@ -4,11 +4,13 @@ import (
"fmt"
"github.com/Masterminds/semver/v3"
"github.com/qlik-oss/sense-installer/pkg/api"
"k8s.io/apimachinery/pkg/version"
)
func (qp *QliksensePreflight) CheckK8sVersion(namespace string, kubeConfigContents []byte) error {
qp.P.LogVerboseMessage("Preflight kubernetes version check: \n")
qp.P.LogVerboseMessage("----------------------------------- \n")
var currentVersion *semver.Version
clientset, _, err := getK8SClientSet(kubeConfigContents, "")
@@ -22,35 +24,29 @@ func (qp *QliksensePreflight) CheckK8sVersion(namespace string, kubeConfigConten
return err
}); err != nil {
err = fmt.Errorf("Unable to get server version: %v\n", err)
//fmt.Println(err)
return err
}
fmt.Printf("Kubernetes API Server version: %s\n", serverVersion.String())
qp.P.LogVerboseMessage("Kubernetes API Server version: %s\n", serverVersion.String())
// Compare K8s version on the cluster with minimum supported k8s version
currentVersion, err = semver.NewVersion(serverVersion.String())
if err != nil {
err = fmt.Errorf("Unable to convert server version into semver version: %v\n", err)
//fmt.Println(err)
return err
}
//fmt.Printf("Current K8s Version: %v\n", currentVersion)
api.LogDebugMessage("Current Kubernetes Version: %v\n", currentVersion)
minK8sVersionSemver, err := semver.NewVersion(qp.GetPreflightConfigObj().GetMinK8sVersion())
if err != nil {
err = fmt.Errorf("Unable to convert minimum Kubernetes version into semver version:%v\n", err)
fmt.Println(err)
return err
}
if currentVersion.GreaterThan(minK8sVersionSemver) {
//fmt.Printf("\n\nCurrent %s Component version: %s is less than minimum required version:%s\n", component, currentComponentVersion, componentVersionFromDependenciesYaml)
fmt.Printf("Current %s is greater than minimum required version:%s\n", currentVersion, minK8sVersionSemver)
fmt.Println("Preflight minimum kubernetes version check: PASSED")
qp.P.LogVerboseMessage("Current Kubernetes API Server version %s is greater than or equal to minimum required version: %s\n", currentVersion, minK8sVersionSemver)
} else {
fmt.Printf("Current %s is less than minimum required version:%s\n", currentVersion, minK8sVersionSemver)
fmt.Println("Preflight minimum kubernetes version check: FAILED")
err = fmt.Errorf("Current Kubernetes API Server version %s is less than minimum required version: %s", currentVersion, minK8sVersionSemver)
return err
}
fmt.Printf("Completed Preflight kubernetes minimum version check\n")
return nil
}

View File

@@ -5,6 +5,7 @@ import (
"io/ioutil"
"os"
"path"
"path/filepath"
"reflect"
"testing"
@@ -234,11 +235,12 @@ func Test_About_getConfigDirectory(t *testing.T) {
verifyAsdBranch := func(configDir string) (ok bool, reason string) {
tmpDir := os.TempDir()
if (path.Clean(path.Dir(path.Dir(configDir))) != path.Clean(tmpDir)) || (path.Base(configDir) != "repo") {
configParentDir := filepath.Dir(configDir)
if (filepath.Clean(filepath.Dir(configParentDir)) != filepath.Clean(tmpDir)) || (filepath.Base(configDir) != "repo") {
return false, fmt.Sprintf("expected config directory path: %v to be under: %v and terminate with repo", configDir, tmpDir)
}
if info, err := os.Stat(path.Join(configDir, "asdczxc")); err != nil || !info.Mode().IsRegular() {
if info, err := os.Stat(filepath.Join(configDir, "asdczxc")); err != nil || !info.Mode().IsRegular() {
return false, fmt.Sprintf(`expected to find file: "asdczxc" under directory: %v`, configDir)
}
return true, ""
@@ -247,15 +249,16 @@ func Test_About_getConfigDirectory(t *testing.T) {
verifyMasterBranch := func(configDir string) (ok bool, reason string) {
tmpDir := os.TempDir()
if (path.Clean(path.Dir(path.Dir(configDir))) != path.Clean(tmpDir)) || (path.Base(configDir) != "repo") {
configParentDir := filepath.Dir(configDir)
if (filepath.Clean(filepath.Dir(configParentDir)) != filepath.Clean(tmpDir)) || (filepath.Base(configDir) != "repo") {
return false, fmt.Sprintf("expected config directory path: %v to be under: %v and terminate with repo", configDir, tmpDir)
}
if _, err := os.Stat(path.Join(configDir, "asdczxc")); err == nil || !os.IsNotExist(err) {
if _, err := os.Stat(filepath.Join(configDir, "asdczxc")); err == nil || !os.IsNotExist(err) {
return false, fmt.Sprintf(`expected to NOT find file: "asdczxc"" under directory: %v`, configDir)
}
if info, err := os.Stat(path.Join(configDir, "sad")); err != nil || !info.Mode().IsRegular() {
if info, err := os.Stat(filepath.Join(configDir, "sad")); err != nil || !info.Mode().IsRegular() {
return false, fmt.Sprintf(`expected to find file: "sad"" under directory: %v`, configDir)
}
return true, ""
@@ -305,7 +308,7 @@ func Test_About_getConfigDirectory(t *testing.T) {
cleanup: func(_ *Qliksense, configDir string) error {
if currentDirectory, err := os.Getwd(); err != nil {
return err
} else if err := os.RemoveAll(path.Join(currentDirectory, "manifests")); err != nil {
} else if err := os.RemoveAll(filepath.Join(currentDirectory, "manifests")); err != nil {
return err
}
return nil
@@ -320,7 +323,7 @@ func Test_About_getConfigDirectory(t *testing.T) {
}
profileEntered = "foo"
defaultProfilePath := path.Join(currentDirectory, "manifests", profileEntered)
defaultProfilePath := filepath.Join(currentDirectory, "manifests", profileEntered)
err = os.MkdirAll(defaultProfilePath, os.ModePerm)
if err != nil {
t.Fatalf("error making path: %v, err: %v\n", defaultProfilePath, err)
@@ -350,7 +353,7 @@ func Test_About_getConfigDirectory(t *testing.T) {
cleanup: func(_ *Qliksense, configDir string) error {
if currentDirectory, err := os.Getwd(); err != nil {
return err
} else if err := os.RemoveAll(path.Join(currentDirectory, "manifests")); err != nil {
} else if err := os.RemoveAll(filepath.Join(currentDirectory, "manifests")); err != nil {
return err
}
return nil
@@ -380,8 +383,8 @@ func Test_About_getConfigDirectory(t *testing.T) {
cleanup: func(_ *Qliksense, configDir string) error {
tmpDir := os.TempDir()
if path.Clean(path.Dir(path.Dir(configDir))) == path.Clean(tmpDir) && path.Base(configDir) == "repo" {
tmpTmpDir := path.Dir(configDir)
tmpTmpDir := filepath.Dir(configDir)
if filepath.Clean(filepath.Dir(tmpTmpDir)) == filepath.Clean(tmpDir) && filepath.Base(configDir) == "repo" {
if err := os.RemoveAll(tmpTmpDir); err != nil {
return err
}
@@ -413,8 +416,8 @@ func Test_About_getConfigDirectory(t *testing.T) {
cleanup: func(_ *Qliksense, configDir string) error {
tmpDir := os.TempDir()
if path.Clean(path.Dir(path.Dir(configDir))) == path.Clean(tmpDir) && path.Base(configDir) == "repo" {
tmpTmpDir := path.Dir(configDir)
tmpTmpDir := filepath.Dir(configDir)
if filepath.Clean(filepath.Dir(tmpTmpDir)) == filepath.Clean(tmpDir) && filepath.Base(configDir) == "repo" {
if err := os.RemoveAll(tmpTmpDir); err != nil {
return err
}
@@ -456,8 +459,9 @@ func Test_About_getConfigDirectory(t *testing.T) {
},
cleanup: func(q *Qliksense, configDir string) error {
tmpDir := os.TempDir()
if path.Clean(path.Dir(path.Dir(configDir))) == path.Clean(tmpDir) && path.Base(configDir) == "repo" {
tmpTmpDir := path.Dir(configDir)
tmpTmpDir := filepath.Dir(configDir)
if filepath.Clean(filepath.Dir(tmpTmpDir)) == filepath.Clean(tmpDir) && filepath.Base(configDir) == "repo" {
if err := os.RemoveAll(tmpTmpDir); err != nil {
return err
}
@@ -502,8 +506,9 @@ func Test_About_getConfigDirectory(t *testing.T) {
},
cleanup: func(q *Qliksense, configDir string) error {
tmpDir := os.TempDir()
if path.Clean(path.Dir(path.Dir(configDir))) == path.Clean(tmpDir) && path.Base(configDir) == "repo" {
tmpTmpDir := path.Dir(configDir)
tmpTmpDir := filepath.Dir(configDir)
if filepath.Clean(filepath.Dir(tmpTmpDir)) == filepath.Clean(tmpDir) && filepath.Base(configDir) == "repo" {
if err := os.RemoveAll(tmpTmpDir); err != nil {
return err
}

View File

@@ -1,12 +1,13 @@
package qliksense
import (
"fmt"
"io"
qapi "github.com/qlik-oss/sense-installer/pkg/api"
)
func (q *Qliksense) ApplyCRFromReader(r io.Reader, opts *InstallCommandOptions, keepPatchFiles, overwriteExistingContext bool) error {
func (q *Qliksense) ApplyCRFromReader(r io.Reader, opts *InstallCommandOptions, keepPatchFiles, overwriteExistingContext, pull, push bool) error {
if err := q.LoadCr(r, overwriteExistingContext); err != nil {
return err
}
@@ -15,19 +16,33 @@ func (q *Qliksense) ApplyCRFromReader(r io.Reader, opts *InstallCommandOptions,
if err != nil {
return err
}
version := cr.GetLabelFromCr("version")
if pull {
fmt.Println("Pulling images...")
if err := q.PullImages(version, ""); err != nil {
return err
}
}
if push {
fmt.Println("Pushing images...")
if err := q.PushImagesForCurrentCR(); err != nil {
return err
}
}
if IsQliksenseInstalled(cr.GetName()) {
// it is needed in case want to upgrade from one version to another
if cr.Spec.ManifestsRoot == "" && cr.Spec.Git == nil {
v := cr.GetLabelFromCr("version")
if !qConfig.IsRepoExistForCurrent(v) {
if err := q.FetchQK8s(v); err != nil {
if !qConfig.IsRepoExistForCurrent(version) {
if err := q.FetchQK8s(version); err != nil {
return err
}
}
}
return q.UpgradeQK8s(keepPatchFiles)
}
return q.InstallQK8s(cr.GetLabelFromCr("version"), opts, keepPatchFiles)
return q.InstallQK8s(version, opts, keepPatchFiles)
}
func IsQliksenseInstalled(crName string) bool {

View File

@@ -0,0 +1,24 @@
package qliksense
import (
"fmt"
"log"
"strings"
)
func AskForConfirmation(s string) bool {
for {
fmt.Printf("%s [y/n]: ", s)
var response string
_, err := fmt.Scanln(&response)
if err != nil {
log.Fatal(err)
}
if strings.EqualFold(response, "y") || strings.EqualFold(response, "yes") {
return true
} else if strings.EqualFold(response, "n") || strings.EqualFold(response, "no") {
return false
}
}
}

View File

@@ -20,10 +20,10 @@ import (
ansi "github.com/mattn/go-colorable"
"github.com/qlik-oss/sense-installer/pkg/api"
"github.com/ttacon/chalk"
_ "gopkg.in/yaml.v2"
v1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
. "github.com/logrusorgru/aurora"
)
const (
@@ -257,7 +257,7 @@ func (q *Qliksense) SetOtherConfigs(args []string) error {
return err
}
}
fmt.Println(chalk.Green.Color("Successfully added to Custom Resource Spec"))
fmt.Println(Green("Successfully added to Custom Resource Spec"))
}
// write modified content into context.yaml
@@ -388,7 +388,7 @@ func (q *Qliksense) ListContextConfigs() error {
}
out := ansi.NewColorableStdout()
w := tabwriter.NewWriter(out, 5, 8, 0, '\t', 0)
fmt.Fprintln(w, chalk.Underline.TextStyle("Context Name"), "\t", chalk.Underline.TextStyle("CR File Location"))
fmt.Fprintln(w, Underline("Context Name"), "\t", Underline("CR File Location"))
w.Flush()
if len(qliksenseConfig.Spec.Contexts) > 0 {
for _, cont := range qliksenseConfig.Spec.Contexts {
@@ -396,14 +396,14 @@ func (q *Qliksense) ListContextConfigs() error {
}
w.Flush()
fmt.Fprintln(out, "")
fmt.Fprintln(out, chalk.Bold.TextStyle("Current Context : "), qliksenseConfig.Spec.CurrentContext)
fmt.Fprintln(out, Bold("Current Context : "), qliksenseConfig.Spec.CurrentContext)
} else {
fmt.Fprintln(out, "No Contexts Available")
}
return nil
}
func (q *Qliksense) DeleteContextConfig(args []string) error {
func (q *Qliksense) DeleteContextConfig(args []string, flag bool) error {
if len(args) == 1 {
qliksenseConfigFile := filepath.Join(q.QliksenseHome, QliksenseConfigFile)
var qliksenseConfig api.QliksenseConfig
@@ -411,11 +411,11 @@ func (q *Qliksense) DeleteContextConfig(args []string) error {
out := ansi.NewColorableStdout()
switch args[0] {
case qliksenseConfig.Spec.CurrentContext:
fmt.Fprintln(out, chalk.Yellow.Color("Please switch contexts to be able to delete this context."))
err := fmt.Errorf(chalk.Red.Color("Cannot delete current context - %s"), chalk.White.Color(chalk.Bold.TextStyle(qliksenseConfig.Spec.CurrentContext)))
fmt.Fprintln(out,Yellow("Please switch contexts to be able to delete this context."))
err := fmt.Errorf(Red("Cannot delete current context - %s").String(), White(Bold(qliksenseConfig.Spec.CurrentContext)))
return err
case DefaultQliksenseContext:
err := fmt.Errorf(chalk.Red.Color("Cannot delete default qliksense context"))
err := fmt.Errorf(Red("Cannot delete default qliksense context").String())
return err
default:
qliksenseContextsDir1 := filepath.Join(q.QliksenseHome, QliksenseContextsDir)
@@ -445,11 +445,19 @@ func (q *Qliksense) DeleteContextConfig(args []string) error {
}
newLength := len(qliksenseConfig.Spec.Contexts)
if currentLength != newLength {
api.WriteToFile(&qliksenseConfig, qliksenseConfigFile)
fmt.Fprintln(out, chalk.Yellow.Color(chalk.Underline.TextStyle("Warning: Active resources may still be running in-cluster")))
fmt.Fprintln(out, chalk.Green.Color("Successfully deleted context: "), chalk.Bold.TextStyle(args[0]))
ans := flag
if ans == false {
ans = AskForConfirmation("Are You Sure? ")
}
if ans == true {
api.WriteToFile(&qliksenseConfig, qliksenseConfigFile)
fmt.Fprintln(out, Yellow(Underline("Warning: Active resources may still be running in-cluster")))
fmt.Fprintln(out, Green("Successfully deleted context: "),Bold(args[0]))
} else {
return nil
}
} else {
err := fmt.Errorf(chalk.Red.Color("Context not found"))
err := fmt.Errorf(Red("Context not found").String())
return err
}
}

View File

@@ -855,9 +855,10 @@ func TestDeleteContexts(t *testing.T) {
q := New(tt.args.qlikSenseHome)
var arg []string
arg = append(arg, tt.args.contextName)
if err := q.DeleteContextConfig(arg); (err != nil) != tt.wantErr {
if err := q.DeleteContextConfig(arg, true); (err != nil) != tt.wantErr {
t.Errorf("DeleteContext() error = %v, wantErr %v", err, tt.wantErr)
}
})
}

View File

@@ -46,8 +46,8 @@ func (q *Qliksense) PullImages(version, profile string) error {
}
if profile != "" {
qcr.Spec.Profile = profile
if e := qConfig.WriteCR(qcr); e != nil {
return e
if err := qConfig.WriteCR(qcr); err != nil {
return err
}
}
return q.PullImagesForCurrentCR()
@@ -155,7 +155,6 @@ func pullImage(image, imagesDir string) error {
return nil
}
// TagAndPushImages ...
func (q *Qliksense) PushImagesForCurrentCR() error {
qConfig := qapi.NewQConfig(q.QliksenseHome)
qcr, err := qConfig.GetCurrentCR()

View File

@@ -80,9 +80,14 @@ func fetchAndUpdateCR(qConfig *qapi.QliksenseConfig, version string) error {
}
if version == "" {
if qcr.GetLabelFromCr("version") == "" {
return errors.New("Cannot find gitref/tag/branch/version to fetch")
if encKey, err := qConfig.GetEncryptionKeyFor(qcr.GetName()); err != nil {
return err
} else if version, err = getLatestTag(qcr.GetFetchUrl(), qcr.GetFetchAccessToken(encKey)); err != nil {
return err
}
} else {
version = qcr.GetLabelFromCr("version")
}
version = qcr.GetLabelFromCr("version")
}
encKey, err := qConfig.GetEncryptionKeyFor(qcr.GetName())
if err != nil {

View File

@@ -32,4 +32,19 @@ func TestFetchAndUpdateCR(t *testing.T) {
t.Log("actual path: " + cr.Spec.ManifestsRoot + ", expected path: contexts/test1/qlik-k8s/v0.0.2")
t.FailNow()
}
//testing latest tag is fetched
cr.AddLabelToCr("version", "")
qConfig.WriteCR(cr)
err := fetchAndUpdateCR(qConfig, "")
if err != nil {
t.Log(err)
t.Fail()
}
cr = &qapi.QliksenseCR{}
qapi.ReadFromFile(cr, actualCrFile)
v := cr.GetLabelFromCr("version")
if v == "" || v == "v0.0.2" {
t.Log("should get latest but got version: " + v)
t.Fail()
}
}

View File

@@ -4,6 +4,7 @@ import (
"errors"
"fmt"
"github.com/Masterminds/semver/v3"
"github.com/qlik-oss/k-apis/pkg/git"
qapi "github.com/qlik-oss/sense-installer/pkg/api"
)
@@ -86,3 +87,69 @@ func (q *Qliksense) GetInstallableVersions(opts *LsRemoteCmdOptions) error {
return nil
}
func getLatestTag(repoUrl, accessToken string) (string, error) {
if repoUrl == "" {
return "", errors.New("repo url is empty")
}
repoPath, err := fetchToTempDir(repoUrl, "master", accessToken)
if err != nil {
return "", err
}
r, err := git.OpenRepository(repoPath)
if err != nil {
return "", err
}
remoteRefsList, err := git.GetRemoteRefs(r, nil,
&git.RemoteRefConstraints{
Include: true,
Sort: true,
SortOrder: git.RefSortOrderDescending,
},
&git.RemoteRefConstraints{
Include: false,
Sort: true,
SortOrder: git.RefSortOrderAscending,
})
if err != nil {
return "", err
}
if len(remoteRefsList) < 1 {
return "", errors.New("cannot find git remote information in the config repository")
}
var originRemoteRefs *git.RemoteRefs
for _, remoteRefs := range remoteRefsList {
if remoteRefs.Name == "origin" {
originRemoteRefs = remoteRefs
break
}
}
if originRemoteRefs == nil {
return "", errors.New(`cannot find git remote called "origin" in the config repository`)
}
tags := originRemoteRefs.Tags
if len(tags) == 0 {
return "", errors.New(("no tags exists in the repo: " + repoPath))
}
maxSem, _ := semver.NewVersion(tags[0])
for _, sv := range tags[1:] {
if sv == "" {
continue
}
v, err := semver.NewVersion(sv)
if err != nil {
// it may happen, in the repo some tags may not conform to semver
fmt.Print("Unconform tags: " + sv)
continue
}
if maxSem == nil || maxSem.LessThan(v) {
maxSem = v
}
}
return maxSem.Original(), nil
}

View File

@@ -0,0 +1,25 @@
package qliksense
import (
"testing"
"github.com/Masterminds/semver/v3"
)
func TestGetLatestTag(t *testing.T) {
s, err := getLatestTag(defaultConfigRepoGitUrl, "")
if s == "" || err != nil {
t.Log(err)
t.Fail()
}
sv, err := semver.NewVersion(s)
if err != nil {
t.Log(err)
t.Log(sv)
}
baseV, _ := semver.NewVersion("v0.0.7")
if !sv.GreaterThan(baseV) {
t.Log("Expected greater than v0.0.7, but got: " + s)
t.Fail()
}
}

View File

@@ -3,6 +3,8 @@ package qliksense
import (
"errors"
"fmt"
"io/ioutil"
"os"
"path"
"path/filepath"
@@ -107,11 +109,16 @@ func (q *Qliksense) InstallQK8s(version string, opts *InstallCommandOptions, kee
if dcr, err := qConfig.GetDecryptedCr(qcr); err != nil {
return err
} else if err := q.applyConfigToK8s(dcr); err != nil {
fmt.Println("cannot do kubectl apply on manifests")
return err
} else {
return q.applyCR(dcr)
if IsQliksenseInstalled(dcr.GetName()) {
return q.UpgradeQK8s(keepPatchFiles)
}
if err := q.applyConfigToK8s(dcr); err != nil {
fmt.Println("cannot do kubectl apply on manifests")
return err
} else {
return q.applyCR(dcr)
}
}
}
@@ -146,10 +153,15 @@ func installOrRemoveImagePullSecret(qConfig *qapi.QliksenseConfig) error {
}
func kustomizeForImageRegistry(resources, dockerConfigJsonSecretName, name, newName string) (string, error) {
fSys := filesys.MakeFsInMemory()
if err := fSys.WriteFile("/resources.yaml", []byte(resources)); err != nil {
dir, err := ioutil.TempDir("", "")
if err != nil {
return "", err
} else if err := fSys.WriteFile("/addImagePullSecrets.yaml", []byte(fmt.Sprintf(`
}
defer os.RemoveAll(dir)
if err := ioutil.WriteFile(filepath.Join(dir, "resources.yaml"), []byte(resources), os.ModePerm); err != nil {
return "", err
} else if err := ioutil.WriteFile(filepath.Join(dir, "addImagePullSecrets.yaml"), []byte(fmt.Sprintf(`
apiVersion: builtin
kind: PatchTransformer
metadata:
@@ -158,9 +170,9 @@ patch: '[{"op": "add", "path": "/spec/template/spec/imagePullSecrets", "value":
target:
name: .*-operator
kind: Deployment
`, dockerConfigJsonSecretName))); err != nil {
`, dockerConfigJsonSecretName)), os.ModePerm); err != nil {
return "", err
} else if err := fSys.WriteFile("/kustomization.yaml", []byte(fmt.Sprintf(`
} else if err := ioutil.WriteFile(filepath.Join(dir, "kustomization.yaml"), []byte(fmt.Sprintf(`
resources:
- resources.yaml
transformers:
@@ -168,9 +180,9 @@ transformers:
images:
- name: %s
newName: %s
`, name, newName))); err != nil {
`, name, newName)), os.ModePerm); err != nil {
return "", err
} else if out, err := executeKustomizeBuildForFileSystem("/", fSys); err != nil {
} else if out, err := executeKustomizeBuildForFileSystem(dir, filesys.MakeFsOnDisk()); err != nil {
return "", err
} else {
return string(out), nil

View File

@@ -130,7 +130,6 @@ spec:
}
originalOperatorString := q.GetOperatorControllerString()
processedOperatorString, err := q.getProcessedOperatorControllerString(qcr)
if err != nil {
t.Fatalf("unexpected error: %v", err)

View File

@@ -3,13 +3,24 @@ package qliksense
import (
"bytes"
"encoding/base64"
"fmt"
"io"
"io/ioutil"
"log"
"os"
"path"
"path/filepath"
"regexp"
"strings"
"sync"
"sync/atomic"
"testing"
"time"
"sigs.k8s.io/kustomize/api/k8sdeps/kunstruct"
"sigs.k8s.io/kustomize/api/resid"
"sigs.k8s.io/kustomize/api/resmap"
"sigs.k8s.io/kustomize/api/resource"
"sigs.k8s.io/kustomize/api/types"
"gopkg.in/yaml.v3"
@@ -27,7 +38,7 @@ func Test_ExecuteKustomizeBuild(t *testing.T) {
}
defer os.RemoveAll(tmpDir)
kustomizationYamlFilePath := path.Join(tmpDir, "kustomization.yaml")
kustomizationYamlFilePath := filepath.Join(tmpDir, "kustomization.yaml")
kustomizationYaml := `
generatorOptions:
disableNameSuffixHash: true
@@ -58,6 +69,203 @@ metadata:
}
}
func Test_executeKustomizeBuild_onQlikConfig_withConcurrency(t *testing.T) {
if testing.Short() {
t.Skip("Skipping parallel kustomize test in short mode")
}
tmpDir, err := ioutil.TempDir("", "")
if err != nil {
t.Fatalf("unexpected error: %v\n", err)
}
defer os.RemoveAll(tmpDir)
configPath := filepath.Join(tmpDir, "config")
if repo, err := kapis_git.CloneRepository(configPath, defaultConfigRepoGitUrl, nil); err != nil {
t.Fatalf("unexpected error: %v\n", err)
} else if err := kapis_git.Checkout(repo, "v0.0.8", "v0.0.8", nil); err != nil {
t.Fatalf("unexpected error: %v\n", err)
}
configsDir := filepath.Join(configPath, "manifests", "base", "manifests")
shouldSkipDir := func(dirName string) bool {
skipMap := map[string]bool{
"sense-client": true,
}
_, ok := skipMap[dirName]
return ok
}
insertConcatenationKuzYaml := func(dir string) error {
concatenatedMap := map[string]interface{}{}
concatenatedMap["apiVersion"] = "kustomize.config.k8s.io/v1beta1"
concatenatedMap["kind"] = "Kustomization"
resources := make([]string, 0)
infos, err := ioutil.ReadDir(dir)
if err != nil {
return err
}
for _, info := range infos {
if !info.IsDir() {
resources = append(resources, info.Name())
}
}
concatenatedMap["resources"] = resources
if concatenatedMapBytes, err := yaml.Marshal(&concatenatedMap); err != nil {
return err
} else if err := ioutil.WriteFile(filepath.Join(dir, "kustomization.yaml"), concatenatedMapBytes, os.ModePerm); err != nil {
return err
}
return nil
}
//sequential test:
sequentialManifestsDir := filepath.Join(tmpDir, "sequential")
if err := os.RemoveAll(sequentialManifestsDir); err != nil {
t.Fatalf("unexpected error: %v\n", err)
} else if err := os.MkdirAll(sequentialManifestsDir, os.ModePerm); err != nil {
t.Fatalf("unexpected error: %v\n", err)
} else if err := os.RemoveAll(filepath.Join(os.TempDir(), "dotHelm")); err != nil {
t.Fatalf("unexpected error: %v\n", err)
} else if err := os.RemoveAll(filepath.Join(os.TempDir(), ".chartcache")); err != nil {
t.Fatalf("unexpected error: %v\n", err)
}
infos, err := ioutil.ReadDir(configsDir)
if err != nil {
t.Fatalf("unexpected error: %v\n", err)
}
fmt.Print("running a sequential execution test...\n")
t1 := time.Now()
for _, info := range infos {
if shouldSkipDir(info.Name()) {
continue
}
if info.IsDir() {
if yamlResources, err := ExecuteKustomizeBuild(filepath.Join(configsDir, info.Name())); err != nil {
t.Fatalf("unexpected error kustomizing: %v, error: %v\n", info.Name(), err)
} else if err := ioutil.WriteFile(filepath.Join(sequentialManifestsDir, fmt.Sprintf("%v.yaml", info.Name())), yamlResources, os.ModePerm); err != nil {
t.Fatalf("unexpected error: %v\n", err)
}
}
}
t2 := time.Now()
fmt.Printf("sequential execution test took: %vs\n", t2.Sub(t1).Seconds())
if err := insertConcatenationKuzYaml(sequentialManifestsDir); err != nil {
t.Fatalf("unexpected error: %v\n", err)
}
concatenatedSequentialManifests, err := ExecuteKustomizeBuild(sequentialManifestsDir)
if err != nil {
t.Fatalf("unexpected error: %v\n", err)
}
//concurrent tests:
numConcurrentTests := 5
concatenatedConcurrentManifestsList := make([][]byte, 0)
for i := 0; i < numConcurrentTests; i++ {
concurrentManifestsDir := filepath.Join(tmpDir, fmt.Sprintf("concurrent-%v", i))
if err := os.RemoveAll(concurrentManifestsDir); err != nil {
t.Fatalf("unexpected error: %v\n", err)
} else if err := os.MkdirAll(concurrentManifestsDir, os.ModePerm); err != nil {
t.Fatalf("unexpected error: %v\n", err)
} else if err := os.RemoveAll(filepath.Join(os.TempDir(), "dotHelm")); err != nil {
t.Fatalf("unexpected error: %v\n", err)
} else if err := os.RemoveAll(filepath.Join(os.TempDir(), ".chartcache")); err != nil {
t.Fatalf("unexpected error: %v\n", err)
}
var wg sync.WaitGroup
var concurrentErrorCounter int32
osStderrBackup := os.Stderr
tmpStdErrFile, err := ioutil.TempFile("", "")
if err != nil {
t.Fatalf("unexpected error: %v\n", err)
}
os.Stderr = tmpStdErrFile
fmt.Print("running a concurrent execution test...\n")
t1 = time.Now()
for _, fi := range infos {
wg.Add(1)
go func(info os.FileInfo) {
defer wg.Done()
if shouldSkipDir(info.Name()) {
return
}
if info.IsDir() {
if yamlResources, err := ExecuteKustomizeBuild(filepath.Join(configsDir, info.Name())); err != nil {
fmt.Printf("unexpected error: %v\n", err)
atomic.AddInt32(&concurrentErrorCounter, 1)
} else if err := ioutil.WriteFile(filepath.Join(concurrentManifestsDir, fmt.Sprintf("%v.yaml", info.Name())), yamlResources, os.ModePerm); err != nil {
fmt.Printf("unexpected error: %v\n", err)
atomic.AddInt32(&concurrentErrorCounter, 1)
}
}
}(fi)
}
wg.Wait()
t2 = time.Now()
os.Stderr = osStderrBackup
os.Remove(tmpStdErrFile.Name())
if concurrentErrorCounter > 0 {
t.Fatalf("there were %v errors during the concurrent execution", concurrentErrorCounter)
}
fmt.Printf("concurrent execution test took: %vs\n", t2.Sub(t1).Seconds())
if err := insertConcatenationKuzYaml(concurrentManifestsDir); err != nil {
t.Fatalf("unexpected error: %v\n", err)
}
concatenatedConcurrentManifests, err := ExecuteKustomizeBuild(concurrentManifestsDir)
if err != nil {
t.Fatalf("unexpected error: %v\n", err)
}
concatenatedConcurrentManifestsList = append(concatenatedConcurrentManifestsList, concatenatedConcurrentManifests)
}
getResMapBytesAdjustedForCaCertsJobName := func(resBytes []byte) ([]byte, error) {
resMapFactory := resmap.NewFactory(resource.NewFactory(kunstruct.NewKunstructuredFactoryImpl()), nil)
if resMap, err := resMapFactory.NewResMapFromBytes(resBytes); err != nil {
return nil, err
} else if resources, err := resMap.Select(types.Selector{
Gvk: resid.Gvk{
Group: "batch",
Version: "v1",
Kind: "Job",
},
}); err != nil {
return nil, err
} else if re, err := regexp.Compile(`^.+-ca-certificates-[a-z]{5}$`); err != nil {
return nil, err
} else {
for _, res := range resources {
res.SetName(re.ReplaceAllString(res.GetName(), "qliksense-ca-certificates"))
}
return resMap.AsYaml()
}
}
sequentialFinalManifest, err := getResMapBytesAdjustedForCaCertsJobName(concatenatedSequentialManifests)
if err != nil {
t.Fatalf("unexpected error: %v\n", err)
}
concurrentFinalManifestsList := make([][]byte, 0)
for _, concatenatedConcurrentManifest := range concatenatedConcurrentManifestsList {
if concurrentFinalManifest, err := getResMapBytesAdjustedForCaCertsJobName(concatenatedConcurrentManifest); err != nil {
t.Fatalf("unexpected error: %v\n", err)
} else {
concurrentFinalManifestsList = append(concurrentFinalManifestsList, concurrentFinalManifest)
}
}
for _, concurrentFinalManifest := range concurrentFinalManifestsList {
if !bytes.Equal(concurrentFinalManifest, sequentialFinalManifest) {
t.Fatalf("expected the concatenated concurrent manifest to equal the concatenated sequential manifest, but they didn't..."+
"\nconcurrent:\n%v\nsequential:\n%v", string(concurrentFinalManifest), string(sequentialFinalManifest))
}
}
}
func Test_executeKustomizeBuild_onQlikConfig_regenerateKeys(t *testing.T) {
tmpDir, err := ioutil.TempDir("", "")
if err != nil {
@@ -65,10 +273,10 @@ func Test_executeKustomizeBuild_onQlikConfig_regenerateKeys(t *testing.T) {
}
defer os.RemoveAll(tmpDir)
configPath := path.Join(tmpDir, "config")
configPath := filepath.Join(tmpDir, "config")
if repo, err := kapis_git.CloneRepository(configPath, defaultConfigRepoGitUrl, nil); err != nil {
t.Fatalf("unexpected error: %v\n", err)
} else if err := kapis_git.Checkout(repo, "v1.21.23-edge", "", nil); err != nil {
} else if err := kapis_git.Checkout(repo, "e38df644e759abf0b5941c1511d1a2cd5e3c42fa", "", nil); err != nil {
t.Fatalf("unexpected error: %v\n", err)
}
@@ -86,7 +294,7 @@ func Test_executeKustomizeBuild_onQlikConfig_regenerateKeys(t *testing.T) {
generateKeys(cr, "won't-use")
yamlResources, err := ExecuteKustomizeBuild(path.Join(configPath, "manifests", "base", "resources", "users"))
yamlResources, err := ExecuteKustomizeBuild(filepath.Join(configPath, "manifests", "base", "resources", "users"))
if err != nil {
t.Fatalf("unexpected kustomize error: %v\n", err)
}
@@ -127,7 +335,7 @@ func generateKeys(cr *config.CRSpec, defaultKeyDir string) {
log.Printf("error generating application keys: %v\n", err)
} else if err := os.MkdirAll(keyDir, os.ModePerm); err != nil {
log.Printf("error makeing sure private key storage directory: %v exists, error: %v\n", keyDir, err)
} else if err := ioutil.WriteFile(path.Join(keyDir, ejsonPublicKey), []byte(ejsonPrivateKey), os.ModePerm); err != nil {
} else if err := ioutil.WriteFile(filepath.Join(keyDir, ejsonPublicKey), []byte(ejsonPrivateKey), os.ModePerm); err != nil {
log.Printf("error storing ejson private key: %v\n", err)
}
}
@@ -147,8 +355,8 @@ func Test_GetYamlDocKindFromMultiDoc(t *testing.T) {
}
defer os.RemoveAll(tmpDir)
kustomizationYamlFilePath := path.Join(tmpDir, "kustomization.yaml")
testResFileYamlFilePath := path.Join(tmpDir, "test-file.yaml")
kustomizationYamlFilePath := filepath.Join(tmpDir, "kustomization.yaml")
testResFileYamlFilePath := filepath.Join(tmpDir, "test-file.yaml")
kustomizationYaml := `
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization

View File

@@ -6,16 +6,24 @@ import (
qapi "github.com/qlik-oss/sense-installer/pkg/api"
)
func (q *Qliksense) UninstallQK8s(contextName string) error {
qConfig := qapi.NewQConfig(q.QliksenseHome)
if contextName == "" {
contextName = qConfig.Spec.CurrentContext
} else if !qConfig.IsContextExist(contextName) {
return errors.New("context name [ " + contextName + " ] not found")
func (q *Qliksense) UninstallQK8s(contextName string, skipConfirmation bool) error {
ans := skipConfirmation
if ans == false {
ans = AskForConfirmation("Are You Sure? ")
}
str, err := q.getCRString(contextName)
if err != nil {
return err
if ans == true {
qConfig := qapi.NewQConfig(q.QliksenseHome)
if contextName == "" {
contextName = qConfig.Spec.CurrentContext
} else if !qConfig.IsContextExist(contextName) {
return errors.New("context name [ " + contextName + " ] not found")
}
str, err := q.getCRString(contextName)
if err != nil {
return err
}
return qapi.KubectlDelete(str, "")
}
return qapi.KubectlDelete(str, "")
return nil
}