Compare commits
64 Commits
random-fix
...
export_fun
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
02b8692d7f | ||
|
|
02f7b2006a | ||
|
|
ae676258ac | ||
|
|
dbe5639fd0 | ||
|
|
8255fe0971 | ||
|
|
65040f9fb6 | ||
|
|
d9bea9b0fd | ||
|
|
0dd136f07b | ||
|
|
9ec9801bea | ||
|
|
d48212ec8f | ||
|
|
546a2caf3e | ||
|
|
0c26d8bb46 | ||
|
|
92cdcf2b84 | ||
|
|
2eae380287 | ||
|
|
5dd6a08e65 | ||
|
|
ed7e97332b | ||
|
|
4b7674261c | ||
|
|
2ea4366653 | ||
|
|
eb7517f88d | ||
|
|
ea048f1b5f | ||
|
|
0992286e23 | ||
|
|
6d87fadae0 | ||
|
|
04e2cc5b22 | ||
|
|
7b7cd7b4bf | ||
|
|
7a0bbcd5d8 | ||
|
|
6b6ef14fb1 | ||
|
|
fa0c6528e4 | ||
|
|
e6070a33c2 | ||
|
|
0c9f264ed2 | ||
|
|
22b9b902a9 | ||
|
|
3a49745622 | ||
|
|
5795988d01 | ||
|
|
e9b359c1bd | ||
|
|
9ab2478aba | ||
|
|
044e00afc5 | ||
|
|
2f718649f4 | ||
|
|
c6fe7084f5 | ||
|
|
e60ce7d62d | ||
|
|
0d2e436639 | ||
|
|
6093552ba9 | ||
|
|
449642e6f4 | ||
|
|
97b6cf21a7 | ||
|
|
14b6447154 | ||
|
|
1c60ce4cc0 | ||
|
|
7a8926773f | ||
|
|
0b868732a7 | ||
|
|
4f2581cde2 | ||
|
|
ca15145499 | ||
|
|
3274ebd12a | ||
|
|
505b4ef4ce | ||
|
|
a4e2b0dfe6 | ||
|
|
7cf2b00f0b | ||
|
|
d94454b832 | ||
|
|
f4d0bd87f6 | ||
|
|
645d1496d4 | ||
|
|
65ce074981 | ||
|
|
323014d137 | ||
|
|
31262df504 | ||
|
|
a15fe75b6c | ||
|
|
a59bf2d015 | ||
|
|
b36b8917da | ||
|
|
eed4d49665 | ||
|
|
34d35909a4 | ||
|
|
cb78b4da9f |
41
.github/workflows/build.yml
vendored
41
.github/workflows/build.yml
vendored
@@ -4,24 +4,43 @@ on: [pull_request]
|
|||||||
|
|
||||||
jobs:
|
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:
|
build:
|
||||||
name: Build
|
name: Build
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
needs: test
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Set up Go 1.13
|
- name: Set up Go 1.13
|
||||||
uses: actions/setup-go@v1
|
uses: actions/setup-go@v2-beta
|
||||||
with:
|
with:
|
||||||
go-version: 1.13
|
go-version: 1.13
|
||||||
|
|
||||||
- uses: actions/checkout@v2
|
- 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 build
|
|
||||||
|
- run: make xbuild-all
|
||||||
|
|||||||
9
.github/workflows/release.yml
vendored
9
.github/workflows/release.yml
vendored
@@ -12,19 +12,12 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Set up Go 1.13
|
- name: Set up Go 1.13
|
||||||
uses: actions/setup-go@v1
|
uses: actions/setup-go@v2-beta
|
||||||
with:
|
with:
|
||||||
go-version: 1.13
|
go-version: 1.13
|
||||||
|
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v2
|
||||||
- run: git fetch --depth=1 origin +refs/tags/*:refs/tags/* # Needed in makefile for versioning
|
- 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 test
|
||||||
- run: make xbuild-all
|
- run: make xbuild-all
|
||||||
|
|||||||
49
Makefile
49
Makefile
@@ -39,21 +39,29 @@ endif
|
|||||||
|
|
||||||
.PHONY: build
|
.PHONY: build
|
||||||
build: clean generate
|
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)
|
go build -ldflags '$(LDFLAGS)' -tags "$(BUILDTAGS)" -o $(BINDIR)/$(MIXIN)$(FILE_EXT) ./cmd/$(MIXIN)
|
||||||
$(MAKE) clean
|
$(MAKE) clean
|
||||||
|
|
||||||
.PHONY: test
|
.PHONY: test-setup
|
||||||
test: clean generate
|
test-setup: clean generate
|
||||||
ifeq ($(shell ${WHICH} docker-registry 2>${DEVNUL}),)
|
ifeq ($(shell ${WHICH} docker-registry 2>${DEVNUL}),)
|
||||||
$(eval TMP-docker-distribution := $(shell mktemp -d))
|
$(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
|
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
|
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
|
go run _make_support/copy/do.go --src "$(TMP-docker-distribution)/docker-distribution/bin/registry" --dst pkg/qliksense/docker-registry$(FILE_EXT)
|
||||||
-rm -rf $(TMP-docker-distribution)
|
go run _make_support/remove_all/do.go "$(TMP-docker-distribution)"
|
||||||
endif
|
endif
|
||||||
go test -short -count=1 -tags "$(BUILDTAGS)" -v ./...
|
|
||||||
$(MAKE) clean
|
.PHONY: test-short
|
||||||
|
test-short: test-setup
|
||||||
|
go test -count 1 -p 1 -tags "$(BUILDTAGS)" -v -short ./...
|
||||||
|
"$(MAKE)" clean
|
||||||
|
|
||||||
|
.PHONY: test
|
||||||
|
test: test-setup
|
||||||
|
go test -count 1 -p 1 -tags "$(BUILDTAGS)" -v ./...
|
||||||
|
"$(MAKE)" clean
|
||||||
|
|
||||||
xbuild-all: clean generate
|
xbuild-all: clean generate
|
||||||
$(foreach OS, $(SUPPORTED_PLATFORMS), \
|
$(foreach OS, $(SUPPORTED_PLATFORMS), \
|
||||||
@@ -78,6 +86,7 @@ endif
|
|||||||
|
|
||||||
generate: get-crds packr2
|
generate: get-crds packr2
|
||||||
go generate ./...
|
go generate ./...
|
||||||
|
go run _make_support/remove_all/do.go pkg/qliksense/crds
|
||||||
|
|
||||||
packr2:
|
packr2:
|
||||||
ifeq ($(shell ${WHICH} packr2 2>${DEVNUL}),)
|
ifeq ($(shell ${WHICH} packr2 2>${DEVNUL}),)
|
||||||
@@ -85,22 +94,22 @@ ifeq ($(shell ${WHICH} packr2 2>${DEVNUL}),)
|
|||||||
endif
|
endif
|
||||||
|
|
||||||
clean: clean-packr
|
clean: clean-packr
|
||||||
-rm -fr pkg/qliksense/crds
|
go run _make_support/remove_all/do.go pkg/qliksense/crds
|
||||||
|
|
||||||
clean-packr: packr2
|
clean-packr: packr2
|
||||||
cd pkg/qliksense && packr2 clean
|
cd pkg/qliksense && packr2 clean
|
||||||
|
|
||||||
get-crds:
|
get-crds:
|
||||||
ifeq ($(QLIKSENSE_OPERATOR_DIR),)
|
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
|
git clone https://github.com/qlik-oss/qliksense-operator.git -b master $(TMP-operator)/operator
|
||||||
$(MAKE) QLIKSENSE_OPERATOR_DIR=$(TMP-operator)/operator get-crds
|
"$(MAKE)" QLIKSENSE_OPERATOR_DIR="$(TMP-operator)/operator" get-crds
|
||||||
-rm -rf $(TMP-operator)
|
go run _make_support/remove_all/do.go "$(TMP-operator)"
|
||||||
else
|
else
|
||||||
mkdir -p pkg/qliksense/crds/cr
|
go run _make_support/mkdir_all/do.go pkg/qliksense/crds/cr
|
||||||
mkdir -p pkg/qliksense/crds/crd
|
go run _make_support/mkdir_all/do.go pkg/qliksense/crds/crd
|
||||||
mkdir -p pkg/qliksense/crds/crd-deploy
|
go run _make_support/mkdir_all/do.go pkg/qliksense/crds/crd-deploy
|
||||||
cp $(QLIKSENSE_OPERATOR_DIR)/deploy/*.yaml 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
|
||||||
cp $(QLIKSENSE_OPERATOR_DIR)/deploy/crds/*_crd.yaml pkg/qliksense/crds/crd
|
go run _make_support/copy/do.go --src-pattern "$(QLIKSENSE_OPERATOR_DIR)/deploy/crds/*_crd.yaml" --dst pkg/qliksense/crds/crd
|
||||||
cp $(QLIKSENSE_OPERATOR_DIR)/deploy/crds/*_cr.yaml pkg/qliksense/crds/cr
|
go run _make_support/copy/do.go --src-pattern "$(QLIKSENSE_OPERATOR_DIR)/deploy/crds/*_cr.yaml" --dst pkg/qliksense/crds/cr
|
||||||
endif
|
endif
|
||||||
|
|||||||
10
README.md
10
README.md
@@ -1,16 +1,12 @@
|
|||||||
# (WIP) Qlik Sense installation and operations CLI
|
# (WIP) Qlik Sense on Kubernetes installation and operations CLI
|
||||||
|
|
||||||
## Documentation
|
## 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
|
## 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:
|
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).
|
||||||
|
|
||||||
- installation of QSEoK
|
|
||||||
- installation of qliksense operator to manage QSEoK
|
|
||||||
- air gapped installation of QSEoK
|
|
||||||
|
|
||||||
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.
|
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
109
_make_support/copy/do.go
Normal 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
|
||||||
|
}
|
||||||
5
_make_support/copy/go.mod
Normal file
5
_make_support/copy/go.mod
Normal 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
|
||||||
8
_make_support/copy/go.sum
Normal file
8
_make_support/copy/go.sum
Normal 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=
|
||||||
14
_make_support/get_tmp_dir/do.go
Normal file
14
_make_support/get_tmp_dir/do.go
Normal 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)
|
||||||
|
}
|
||||||
|
}
|
||||||
3
_make_support/get_tmp_dir/go.mod
Normal file
3
_make_support/get_tmp_dir/go.mod
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
module github.com/qlik-oss/sense-installer/_make_support/get_tmp_dir
|
||||||
|
|
||||||
|
go 1.13
|
||||||
11
_make_support/mkdir_all/do.go
Normal file
11
_make_support/mkdir_all/do.go
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
if err := os.MkdirAll(os.Args[1], os.ModePerm); err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
3
_make_support/mkdir_all/go.mod
Normal file
3
_make_support/mkdir_all/go.mod
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
module github.com/qlik-oss/sense-installer/_make_support/mkdir_all
|
||||||
|
|
||||||
|
go 1.13
|
||||||
11
_make_support/remove_all/do.go
Normal file
11
_make_support/remove_all/do.go
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
if err := os.RemoveAll(os.Args[1]); err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
3
_make_support/remove_all/go.mod
Normal file
3
_make_support/remove_all/go.mod
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
module github.com/qlik-oss/sense-installer/_make_support/remove_all
|
||||||
|
|
||||||
|
go 1.13
|
||||||
@@ -39,7 +39,7 @@ qliksense about --profile=test
|
|||||||
then get version information based on the default profile in the qliksense-k8s repo master
|
then get version information based on the default profile in the qliksense-k8s repo master
|
||||||
`,
|
`,
|
||||||
RunE: func(cmd *cobra.Command, args []string) error {
|
RunE: func(cmd *cobra.Command, args []string) error {
|
||||||
if gitRef, err := getAboutCommandGitRef(args); err != nil {
|
if gitRef, err := getSingleArg(args); err != nil {
|
||||||
return err
|
return err
|
||||||
} else if vout, err := q.About(gitRef, opts.Profile); err != nil {
|
} else if vout, err := q.About(gitRef, opts.Profile); err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -56,7 +56,7 @@ qliksense about --profile=test
|
|||||||
return c
|
return c
|
||||||
}
|
}
|
||||||
|
|
||||||
func getAboutCommandGitRef(args []string) (string, error) {
|
func getSingleArg(args []string) (string, error) {
|
||||||
if len(args) > 1 {
|
if len(args) > 1 {
|
||||||
return "", errors.New("too many arguments, only 1 expected")
|
return "", errors.New("too many arguments, only 1 expected")
|
||||||
} else if len(args) == 1 {
|
} else if len(args) == 1 {
|
||||||
|
|||||||
@@ -1,7 +1,11 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"io"
|
"bytes"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
qapi "github.com/qlik-oss/sense-installer/pkg/api"
|
||||||
|
|
||||||
"github.com/qlik-oss/sense-installer/pkg/qliksense"
|
"github.com/qlik-oss/sense-installer/pkg/qliksense"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
@@ -10,15 +14,21 @@ import (
|
|||||||
func applyCmd(q *qliksense.Qliksense) *cobra.Command {
|
func applyCmd(q *qliksense.Qliksense) *cobra.Command {
|
||||||
opts := &qliksense.InstallCommandOptions{}
|
opts := &qliksense.InstallCommandOptions{}
|
||||||
filePath := ""
|
filePath := ""
|
||||||
keepPatchFiles := false
|
keepPatchFiles, pull, push := false, false, false
|
||||||
c := &cobra.Command{
|
c := &cobra.Command{
|
||||||
Use: "apply",
|
Use: "apply",
|
||||||
Short: "install qliksense based on provided cr file",
|
Short: "install qliksense based on provided cr file",
|
||||||
Long: `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 -`,
|
Example: `qliksense apply -f file_name or cat cr_file | qliksense apply -f -`,
|
||||||
RunE: func(cmd *cobra.Command, args []string) error {
|
RunE: func(cmd *cobra.Command, args []string) error {
|
||||||
return runLoadOrApplyCommandE(cmd, func(reader io.Reader) error {
|
return runLoadOrApplyCommandE(cmd, func(crBytes []byte) error {
|
||||||
return q.ApplyCRFromReader(reader, opts, keepPatchFiles, true)
|
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.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.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.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
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package main
|
|||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"os"
|
||||||
|
|
||||||
qapi "github.com/qlik-oss/sense-installer/pkg/api"
|
qapi "github.com/qlik-oss/sense-installer/pkg/api"
|
||||||
|
|
||||||
@@ -68,18 +69,30 @@ func setConfigsCmd(q *qliksense.Qliksense) *cobra.Command {
|
|||||||
var (
|
var (
|
||||||
cmd *cobra.Command
|
cmd *cobra.Command
|
||||||
)
|
)
|
||||||
|
base64Encoded := false
|
||||||
cmd = &cobra.Command{
|
cmd = &cobra.Command{
|
||||||
Use: "set-configs",
|
Use: "set-configs",
|
||||||
Short: "set configurations into the qliksense context as key-value pairs",
|
Short: "set configurations into the qliksense context as key-value pairs",
|
||||||
Example: `
|
Example: `
|
||||||
qliksense config set-configs <service_name>.<attribute>="<value>"
|
qliksense config set-configs <service_name>.<attribute>="<value>"
|
||||||
- The above configuration will be displayed in the CR
|
- The above configuration will be displayed in the CR
|
||||||
|
qliksense config set-configs <service_name>.<attribute>="<value" --base64
|
||||||
|
- if the value is base64 encoded
|
||||||
|
echo "something" | base64 | qliksense config set-configs <service_name>.<attribute> --base64
|
||||||
|
- value is coming from input pipe as base64 encoded
|
||||||
|
echo "something" | qliksense config set-configs <service_name>.<attribute>
|
||||||
|
- value is coming from input pipe
|
||||||
|
|
||||||
`,
|
`,
|
||||||
RunE: func(cmd *cobra.Command, args []string) error {
|
RunE: func(cmd *cobra.Command, args []string) error {
|
||||||
return q.SetConfigs(args)
|
if isInputFromPipe() && len(args) == 1 {
|
||||||
|
return q.SetConfigFromReader(args[0], os.Stdin, base64Encoded)
|
||||||
|
}
|
||||||
|
return q.SetConfigs(args, base64Encoded)
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
f := cmd.Flags()
|
||||||
|
f.BoolVarP(&base64Encoded, "base64", "", false, "if the arguments value is base64 encoded")
|
||||||
return cmd
|
return cmd
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -88,7 +101,7 @@ func setSecretsCmd(q *qliksense.Qliksense) *cobra.Command {
|
|||||||
cmd *cobra.Command
|
cmd *cobra.Command
|
||||||
secret bool
|
secret bool
|
||||||
)
|
)
|
||||||
|
base64Encoded := false
|
||||||
cmd = &cobra.Command{
|
cmd = &cobra.Command{
|
||||||
Use: "set-secrets",
|
Use: "set-secrets",
|
||||||
Short: "set secrets configurations into the qliksense context as key-value pairs",
|
Short: "set secrets configurations into the qliksense context as key-value pairs",
|
||||||
@@ -101,13 +114,24 @@ qliksense config set-secrets <service_name>.<attribute>="<value>" --secret=true
|
|||||||
qliksense config set-secrets <service_name>.<attribute>="<value>" --secret=false
|
qliksense config set-secrets <service_name>.<attribute>="<value>" --secret=false
|
||||||
- Encrypt the secret value and display it in the current context
|
- Encrypt the secret value and display it in the current context
|
||||||
- No secret resource is created
|
- No secret resource is created
|
||||||
- The above configuration will be displayed in the CR `,
|
- The above configuration will be displayed in the CR
|
||||||
|
qliksense config set-secrets <service_name>.<attribute>="<value>" --base64
|
||||||
|
- the <value> is base64 encoded
|
||||||
|
echo "something" | base64 | qliksense config set-secrets <service_name>.<attribute> --base64
|
||||||
|
- value coming from input pipe as base64 encoded
|
||||||
|
echo "something" | qliksense config set-secrets <service_name>.<attribute>
|
||||||
|
- value coming from input pipe`,
|
||||||
RunE: func(cmd *cobra.Command, args []string) error {
|
RunE: func(cmd *cobra.Command, args []string) error {
|
||||||
return q.SetSecrets(args, secret)
|
if isInputFromPipe() && len(args) == 1 {
|
||||||
|
return q.SetSecretsFromReader(args[0], os.Stdin, secret, base64Encoded)
|
||||||
|
}
|
||||||
|
return q.SetSecrets(args, secret, base64Encoded)
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
f := cmd.Flags()
|
f := cmd.Flags()
|
||||||
f.BoolVar(&secret, "secret", false, "Whether secrets should be encrypted as a Kubernetes Secret resource")
|
f.BoolVar(&secret, "secret", false, "Whether secrets should be encrypted as a Kubernetes Secret resource")
|
||||||
|
f.BoolVarP(&base64Encoded, "base64", "", false, "if the arguments value is base64 encoded")
|
||||||
|
|
||||||
return cmd
|
return cmd
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -115,15 +139,18 @@ func deleteContextConfigCmd(q *qliksense.Qliksense) *cobra.Command {
|
|||||||
var (
|
var (
|
||||||
cmd *cobra.Command
|
cmd *cobra.Command
|
||||||
)
|
)
|
||||||
|
skipConfirmation := false
|
||||||
cmd = &cobra.Command{
|
cmd = &cobra.Command{
|
||||||
Use: "delete-context",
|
Use: "delete-context",
|
||||||
Short: "deletes a specific context locally (not in-cluster)",
|
Short: "deletes a specific context locally (not in-cluster)",
|
||||||
Example: `qliksense config delete-contexts <context_name>`,
|
Example: `qliksense config delete-contexts <context_name>`,
|
||||||
RunE: func(cmd *cobra.Command, args []string) error {
|
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
|
return cmd
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -48,13 +48,14 @@ var eulaPreRunHooks = eulaPreRunHooksT{
|
|||||||
}
|
}
|
||||||
|
|
||||||
func commandAlwaysRequiresEulaAcceptance(commandName string) bool {
|
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) {
|
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 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 {
|
if eulaAccepted, err := eulaPreRunHook(cmd, q); err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
} else if !eulaAccepted {
|
} else if !eulaAccepted {
|
||||||
@@ -70,7 +71,7 @@ func globalEulaPreRun(cmd *cobra.Command, q *qliksense.Qliksense) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func globalEulaPostRun(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 {
|
if err := q.SetEulaAccepted(); err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|||||||
27
cmd/qliksense/export.go
Normal file
27
cmd/qliksense/export.go
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/qlik-oss/sense-installer/pkg/qliksense"
|
||||||
|
"github.com/spf13/cobra"
|
||||||
|
)
|
||||||
|
|
||||||
|
func exportCmd(q *qliksense.Qliksense) *cobra.Command {
|
||||||
|
filePath := q.QliksenseHome
|
||||||
|
c := &cobra.Command{
|
||||||
|
Use: "export",
|
||||||
|
Short: "export files for corresponding context",
|
||||||
|
Long: `exports all context files in zip format`,
|
||||||
|
Example: `qliksense export <context_name>`,
|
||||||
|
RunE: func(cmd *cobra.Command, args []string) error {
|
||||||
|
|
||||||
|
if len(args) != 0 {
|
||||||
|
context := args[0]
|
||||||
|
return q.ExportContext(context, filePath)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
}
|
||||||
|
f := c.Flags()
|
||||||
|
f.StringVarP(&filePath, "output", "o", "", "Output Directory")
|
||||||
|
return c
|
||||||
|
}
|
||||||
@@ -1,26 +1,30 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
|
||||||
"github.com/qlik-oss/sense-installer/pkg/qliksense"
|
"github.com/qlik-oss/sense-installer/pkg/qliksense"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
)
|
)
|
||||||
|
|
||||||
func fetchCmd(q *qliksense.Qliksense) *cobra.Command {
|
func fetchCmd(q *qliksense.Qliksense) *cobra.Command {
|
||||||
|
opts := &qliksense.FetchCommandOptions{}
|
||||||
c := &cobra.Command{
|
c := &cobra.Command{
|
||||||
Use: "fetch",
|
Use: "fetch",
|
||||||
Short: "fetch a release from qliksense-k8s repo",
|
Short: "fetch a release from qliksense-k8s repo, if version not supplied, will use from context",
|
||||||
Long: `fetch a release from qliksense-k8s repo`,
|
Long: `fetch a release from qliksense-k8s repo, if version not supplied, will use from context`,
|
||||||
Example: `qliksense fetch <version>`,
|
Example: `qliksense fetch [version]`,
|
||||||
Args: func(cmd *cobra.Command, args []string) error {
|
|
||||||
if len(args) != 1 {
|
|
||||||
return errors.New("requires a version (i.e. v1.0.0)")
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
},
|
|
||||||
RunE: func(cmd *cobra.Command, args []string) error {
|
RunE: func(cmd *cobra.Command, args []string) error {
|
||||||
return q.FetchQK8s(args[0])
|
if len(args) == 1 {
|
||||||
|
opts.Version = args[0]
|
||||||
|
}
|
||||||
|
return q.FetchK8sWithOpts(opts)
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
f := c.Flags()
|
||||||
|
f.StringVarP(&opts.GitUrl, "url", "", "", "git url from where configuration will be pulled")
|
||||||
|
f.StringVarP(&opts.AccessToken, "accessToken", "", "", "access token for git url")
|
||||||
|
f.StringVarP(&opts.SecretName, "secretName", "", "", "kubernetes secret name where a key name accessToken exist")
|
||||||
|
f.BoolVarP(&opts.Overwrite, "overwrite", "", false, "Ovewrite previously fetched veersion as well as local chagnes")
|
||||||
|
|
||||||
return c
|
return c
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,32 +1,95 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
qapi "github.com/qlik-oss/sense-installer/pkg/api"
|
||||||
|
|
||||||
"github.com/qlik-oss/sense-installer/pkg/qliksense"
|
"github.com/qlik-oss/sense-installer/pkg/qliksense"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
)
|
)
|
||||||
|
|
||||||
func installCmd(q *qliksense.Qliksense) *cobra.Command {
|
func installCmd(q *qliksense.Qliksense) *cobra.Command {
|
||||||
opts := &qliksense.InstallCommandOptions{}
|
opts := &qliksense.InstallCommandOptions{}
|
||||||
keepPatchFiles := false
|
filePath := ""
|
||||||
|
keepPatchFiles, pull, push := false, false, false
|
||||||
c := &cobra.Command{
|
c := &cobra.Command{
|
||||||
Use: "install",
|
Use: "install",
|
||||||
Short: "install a qliksense release",
|
Short: "install a qliksense release",
|
||||||
Long: `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`,
|
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 {
|
RunE: func(cmd *cobra.Command, args []string) error {
|
||||||
|
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 := ""
|
version := ""
|
||||||
if len(args) != 0 {
|
if len(args) != 0 {
|
||||||
version = 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 := c.Flags()
|
||||||
f.StringVarP(&opts.StorageClass, "storageClass", "s", "", "Storage class for qliksense")
|
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.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.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.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
|
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
|
||||||
|
}
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ package main
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"io"
|
"fmt"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"os"
|
"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`,
|
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 -`,
|
Example: `qliksense load -f file_name or cat cr_file | qliksense load -f -`,
|
||||||
RunE: func(cmd *cobra.Command, args []string) error {
|
RunE: func(cmd *cobra.Command, args []string) error {
|
||||||
return runLoadOrApplyCommandE(cmd, func(reader io.Reader) error {
|
return runLoadOrApplyCommandE(cmd, func(buffer []byte) error {
|
||||||
return q.LoadCr(reader, overwriteExistingContext)
|
return q.LoadCr(bytes.NewReader(buffer), overwriteExistingContext)
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@@ -30,7 +30,7 @@ func loadCrFile(q *qliksense.Qliksense) *cobra.Command {
|
|||||||
c.MarkFlagRequired("file")
|
c.MarkFlagRequired("file")
|
||||||
f.BoolVarP(&overwriteExistingContext, "overwrite", "o", overwriteExistingContext, "Overwrite any existing contexts with the same name")
|
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
|
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 {
|
if crBytes := eulaPreRunHooks.getPostValidationArtifact("CR"); crBytes != nil {
|
||||||
return callBack(bytes.NewBuffer(crBytes.([]byte)))
|
return callBack(crBytes.([]byte))
|
||||||
} else {
|
} else {
|
||||||
file, err := getCrFileFromFlag(cmd, "file")
|
file, err := getCrFileFromFlag(cmd, "file")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
defer file.Close()
|
defer file.Close()
|
||||||
return callBack(file)
|
if crBytes, err := ioutil.ReadAll(file); err != nil {
|
||||||
|
return err
|
||||||
|
} else {
|
||||||
|
return callBack(crBytes)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,9 +2,10 @@ package main
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
|
||||||
|
|
||||||
|
ansi "github.com/mattn/go-colorable"
|
||||||
"github.com/qlik-oss/sense-installer/pkg/preflight"
|
"github.com/qlik-oss/sense-installer/pkg/preflight"
|
||||||
|
. "github.com/logrusorgru/aurora"
|
||||||
|
|
||||||
"github.com/qlik-oss/sense-installer/pkg/qliksense"
|
"github.com/qlik-oss/sense-installer/pkg/qliksense"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
@@ -21,312 +22,417 @@ func preflightCmd(q *qliksense.Qliksense) *cobra.Command {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func pfDnsCheckCmd(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{
|
var preflightDnsCmd = &cobra.Command{
|
||||||
Use: "dns",
|
Use: "dns",
|
||||||
Short: "perform preflight dns check",
|
Short: "perform preflight dns check",
|
||||||
Long: `perform preflight dns check to check DNS connectivity status in the cluster`,
|
Long: `perform preflight dns check to check DNS connectivity status in the cluster`,
|
||||||
Example: `qliksense preflight dns`,
|
Example: `qliksense preflight dns`,
|
||||||
RunE: func(cmd *cobra.Command, args []string) error {
|
RunE: func(cmd *cobra.Command, args []string) error {
|
||||||
qp := &preflight.QliksensePreflight{Q: q}
|
qp := &preflight.QliksensePreflight{Q: q, P: preflightOpts}
|
||||||
|
|
||||||
// Preflight DNS check
|
// Preflight DNS check
|
||||||
fmt.Printf("Preflight DNS check\n")
|
|
||||||
fmt.Println("---------------------")
|
|
||||||
namespace, kubeConfigContents, err := preflight.InitPreflight()
|
namespace, kubeConfigContents, err := preflight.InitPreflight()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Printf("Preflight DNS check FAILED\n")
|
fmt.Fprintf(out, "%s\n", Red("Preflight DNS check FAILED"))
|
||||||
log.Fatal(err)
|
fmt.Printf("Error: %v\n", err)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
if namespace == "" {
|
||||||
|
namespace = "default"
|
||||||
}
|
}
|
||||||
if err = qp.CheckDns(namespace, kubeConfigContents); err != nil {
|
if err = qp.CheckDns(namespace, kubeConfigContents); err != nil {
|
||||||
fmt.Println(err)
|
fmt.Fprintf(out, "%s\n", Red("Preflight DNS check FAILED"))
|
||||||
fmt.Print("Preflight DNS check FAILED\n")
|
fmt.Printf("Error: %v\n", err)
|
||||||
log.Fatal()
|
return nil
|
||||||
}
|
}
|
||||||
|
fmt.Fprintf(out, "%s\n", Green("Preflight DNS check PASSED"))
|
||||||
return nil
|
return nil
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
f := preflightDnsCmd.Flags()
|
||||||
|
f.BoolVarP(&preflightOpts.Verbose, "verbose", "v", false, "verbose mode")
|
||||||
return preflightDnsCmd
|
return preflightDnsCmd
|
||||||
}
|
}
|
||||||
|
|
||||||
func pfK8sVersionCheckCmd(q *qliksense.Qliksense) *cobra.Command {
|
func pfK8sVersionCheckCmd(q *qliksense.Qliksense) *cobra.Command {
|
||||||
|
out := ansi.NewColorableStdout()
|
||||||
|
preflightOpts := &preflight.PreflightOptions{
|
||||||
|
MongoOptions: &preflight.MongoOptions{},
|
||||||
|
}
|
||||||
|
|
||||||
var preflightCheckK8sVersionCmd = &cobra.Command{
|
var preflightCheckK8sVersionCmd = &cobra.Command{
|
||||||
Use: "kube-version",
|
Use: "kube-version",
|
||||||
Short: "check kubernetes version",
|
Short: "check kubernetes version",
|
||||||
Long: `check minimum valid kubernetes version on the cluster`,
|
Long: `check minimum valid kubernetes version on the cluster`,
|
||||||
Example: `qliksense preflight kube-version`,
|
Example: `qliksense preflight kube-version`,
|
||||||
RunE: func(cmd *cobra.Command, args []string) error {
|
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
|
// Preflight Kubernetes minimum version check
|
||||||
fmt.Printf("Preflight kubernetes minimum version check\n")
|
|
||||||
fmt.Println("------------------------------------------")
|
|
||||||
namespace, kubeConfigContents, err := preflight.InitPreflight()
|
namespace, kubeConfigContents, err := preflight.InitPreflight()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Printf("Preflight kubernetes minimum version check FAILED\n")
|
fmt.Fprintf(out, "%s\n", Red("Preflight kubernetes minimum version check FAILED"))
|
||||||
log.Fatal(err)
|
fmt.Printf("Error: %v\n", err)
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
if err = qp.CheckK8sVersion(namespace, kubeConfigContents); err != nil {
|
if err = qp.CheckK8sVersion(namespace, kubeConfigContents); err != nil {
|
||||||
fmt.Println(err)
|
fmt.Fprintf(out, "%s\n", Red("Preflight kubernetes minimum version check FAILED"))
|
||||||
fmt.Printf("Preflight kubernetes minimum version check FAILED\n")
|
fmt.Printf("Error: %v\n", err)
|
||||||
log.Fatal()
|
return nil
|
||||||
}
|
}
|
||||||
|
fmt.Fprintf(out, "%s\n", Green("Preflight kubernetes minimum version check PASSED"))
|
||||||
return nil
|
return nil
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
f := preflightCheckK8sVersionCmd.Flags()
|
||||||
|
f.BoolVarP(&preflightOpts.Verbose, "verbose", "v", false, "verbose mode")
|
||||||
|
|
||||||
return preflightCheckK8sVersionCmd
|
return preflightCheckK8sVersionCmd
|
||||||
}
|
}
|
||||||
|
|
||||||
func pfAllChecksCmd(q *qliksense.Qliksense) *cobra.Command {
|
func pfAllChecksCmd(q *qliksense.Qliksense) *cobra.Command {
|
||||||
var mongodbUrl string
|
out := ansi.NewColorableStdout()
|
||||||
|
preflightOpts := &preflight.PreflightOptions{
|
||||||
|
MongoOptions: &preflight.MongoOptions{},
|
||||||
|
}
|
||||||
|
|
||||||
var preflightAllChecksCmd = &cobra.Command{
|
var preflightAllChecksCmd = &cobra.Command{
|
||||||
Use: "all",
|
Use: "all",
|
||||||
Short: "perform all checks",
|
Short: "perform all checks",
|
||||||
Long: `perform all preflight checks on the target cluster`,
|
Long: `perform all preflight checks on the target cluster`,
|
||||||
Example: `qliksense preflight all`,
|
Example: `qliksense preflight all`,
|
||||||
RunE: func(cmd *cobra.Command, args []string) error {
|
RunE: func(cmd *cobra.Command, args []string) error {
|
||||||
qp := &preflight.QliksensePreflight{Q: q}
|
qp := &preflight.QliksensePreflight{Q: q, P: preflightOpts}
|
||||||
|
|
||||||
// Preflight run all checks
|
// Preflight run all checks
|
||||||
fmt.Printf("Running all preflight checks\n")
|
fmt.Printf("Running all preflight checks...\n\n")
|
||||||
namespace, kubeConfigContents, err := preflight.InitPreflight()
|
namespace, kubeConfigContents, err := preflight.InitPreflight()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println(err)
|
fmt.Fprintf(out, "%s\n", Red("Unable to run the preflight checks suite"))
|
||||||
fmt.Printf("Running preflight check suite has FAILED...\n")
|
fmt.Printf("Error: %v\n", err)
|
||||||
log.Fatal()
|
return nil
|
||||||
}
|
}
|
||||||
qp.RunAllPreflightChecks(namespace, kubeConfigContents, mongodbUrl)
|
if namespace == "" {
|
||||||
|
namespace = "default"
|
||||||
|
}
|
||||||
|
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
|
return nil
|
||||||
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
f := preflightAllChecksCmd.Flags()
|
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
|
return preflightAllChecksCmd
|
||||||
}
|
}
|
||||||
|
|
||||||
func pfDeploymentCheckCmd(q *qliksense.Qliksense) *cobra.Command {
|
func pfDeploymentCheckCmd(q *qliksense.Qliksense) *cobra.Command {
|
||||||
|
out := ansi.NewColorableStdout()
|
||||||
|
preflightOpts := &preflight.PreflightOptions{
|
||||||
|
MongoOptions: &preflight.MongoOptions{},
|
||||||
|
}
|
||||||
var pfDeploymentCheckCmd = &cobra.Command{
|
var pfDeploymentCheckCmd = &cobra.Command{
|
||||||
Use: "deployment",
|
Use: "deployment",
|
||||||
Short: "perform preflight deploymwnt check",
|
Short: "perform preflight deploymwnt check",
|
||||||
Long: `perform preflight deployment check to ensure that we can create deployments in the cluster`,
|
Long: `perform preflight deployment check to ensure that we can create deployments in the cluster`,
|
||||||
Example: `qliksense preflight deployment`,
|
Example: `qliksense preflight deployment`,
|
||||||
RunE: func(cmd *cobra.Command, args []string) error {
|
RunE: func(cmd *cobra.Command, args []string) error {
|
||||||
qp := &preflight.QliksensePreflight{Q: q}
|
qp := &preflight.QliksensePreflight{Q: q, P: preflightOpts}
|
||||||
|
|
||||||
// Preflight deployments check
|
// Preflight deployments check
|
||||||
fmt.Printf("Preflight deployment check\n")
|
|
||||||
fmt.Println("--------------------------")
|
|
||||||
namespace, kubeConfigContents, err := preflight.InitPreflight()
|
namespace, kubeConfigContents, err := preflight.InitPreflight()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Printf("Preflight deployment check FAILED\n")
|
fmt.Fprintf(out, "%s\n", Red("Preflight deployment check FAILED"))
|
||||||
log.Fatal(err)
|
fmt.Printf("Error: %v\n", err)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
if namespace == "" {
|
||||||
|
namespace = "default"
|
||||||
}
|
}
|
||||||
if err = qp.CheckDeployment(namespace, kubeConfigContents); err != nil {
|
if err = qp.CheckDeployment(namespace, kubeConfigContents); err != nil {
|
||||||
fmt.Println(err)
|
fmt.Fprintf(out, "%s\n", Red("Preflight deployment check FAILED"))
|
||||||
fmt.Print("Preflight deploy check FAILED\n")
|
fmt.Printf("Error: %v\n", err)
|
||||||
log.Fatal()
|
return nil
|
||||||
}
|
}
|
||||||
|
fmt.Fprintf(out, "%s\n", Green("Preflight deployment check PASSED"))
|
||||||
return nil
|
return nil
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
f := pfDeploymentCheckCmd.Flags()
|
||||||
|
f.BoolVarP(&preflightOpts.Verbose, "verbose", "v", false, "verbose mode")
|
||||||
return pfDeploymentCheckCmd
|
return pfDeploymentCheckCmd
|
||||||
}
|
}
|
||||||
|
|
||||||
func pfServiceCheckCmd(q *qliksense.Qliksense) *cobra.Command {
|
func pfServiceCheckCmd(q *qliksense.Qliksense) *cobra.Command {
|
||||||
|
out := ansi.NewColorableStdout()
|
||||||
|
preflightOpts := &preflight.PreflightOptions{
|
||||||
|
MongoOptions: &preflight.MongoOptions{},
|
||||||
|
}
|
||||||
|
|
||||||
var pfServiceCheckCmd = &cobra.Command{
|
var pfServiceCheckCmd = &cobra.Command{
|
||||||
Use: "service",
|
Use: "service",
|
||||||
Short: "perform preflight service check",
|
Short: "perform preflight service check",
|
||||||
Long: `perform preflight service check to ensure that we are able to create services in the cluster`,
|
Long: `perform preflight service check to ensure that we are able to create services in the cluster`,
|
||||||
Example: `qliksense preflight service`,
|
Example: `qliksense preflight service`,
|
||||||
RunE: func(cmd *cobra.Command, args []string) error {
|
RunE: func(cmd *cobra.Command, args []string) error {
|
||||||
qp := &preflight.QliksensePreflight{Q: q}
|
qp := &preflight.QliksensePreflight{Q: q, P: preflightOpts}
|
||||||
|
|
||||||
// Preflight service check
|
// Preflight service check
|
||||||
fmt.Printf("Preflight service check\n")
|
|
||||||
fmt.Println("-----------------------")
|
|
||||||
namespace, kubeConfigContents, err := preflight.InitPreflight()
|
namespace, kubeConfigContents, err := preflight.InitPreflight()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Printf("Preflight service check FAILED\n")
|
fmt.Fprintf(out, "%s\n", Red("Preflight service check FAILED"))
|
||||||
log.Fatal(err)
|
fmt.Printf("Error: %v\n", err)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if namespace == "" {
|
||||||
|
namespace = "default"
|
||||||
}
|
}
|
||||||
if err = qp.CheckService(namespace, kubeConfigContents); err != nil {
|
if err = qp.CheckService(namespace, kubeConfigContents); err != nil {
|
||||||
fmt.Println(err)
|
fmt.Fprintf(out, "%s\n", Red("Preflight service check FAILED"))
|
||||||
fmt.Print("Preflight service check FAILED\n")
|
fmt.Printf("Error: %v\n", err)
|
||||||
log.Fatal()
|
return nil
|
||||||
}
|
}
|
||||||
|
fmt.Fprintf(out, "%s\n", Green("Preflight service check PASSED"))
|
||||||
return nil
|
return nil
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
f := pfServiceCheckCmd.Flags()
|
||||||
|
f.BoolVarP(&preflightOpts.Verbose, "verbose", "v", false, "verbose mode")
|
||||||
return pfServiceCheckCmd
|
return pfServiceCheckCmd
|
||||||
}
|
}
|
||||||
|
|
||||||
func pfPodCheckCmd(q *qliksense.Qliksense) *cobra.Command {
|
func pfPodCheckCmd(q *qliksense.Qliksense) *cobra.Command {
|
||||||
|
out := ansi.NewColorableStdout()
|
||||||
|
preflightOpts := &preflight.PreflightOptions{
|
||||||
|
MongoOptions: &preflight.MongoOptions{},
|
||||||
|
}
|
||||||
|
|
||||||
var pfPodCheckCmd = &cobra.Command{
|
var pfPodCheckCmd = &cobra.Command{
|
||||||
Use: "pod",
|
Use: "pod",
|
||||||
Short: "perform preflight pod check",
|
Short: "perform preflight pod check",
|
||||||
Long: `perform preflight pod check to ensure we can create pods in the cluster`,
|
Long: `perform preflight pod check to ensure we can create pods in the cluster`,
|
||||||
Example: `qliksense preflight pod`,
|
Example: `qliksense preflight pod`,
|
||||||
RunE: func(cmd *cobra.Command, args []string) error {
|
RunE: func(cmd *cobra.Command, args []string) error {
|
||||||
qp := &preflight.QliksensePreflight{Q: q}
|
qp := &preflight.QliksensePreflight{Q: q, P: preflightOpts}
|
||||||
|
|
||||||
// Preflight pod check
|
// Preflight pod check
|
||||||
fmt.Printf("Preflight pod check\n")
|
|
||||||
fmt.Println("--------------------")
|
|
||||||
namespace, kubeConfigContents, err := preflight.InitPreflight()
|
namespace, kubeConfigContents, err := preflight.InitPreflight()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Printf("Preflight pod check FAILED\n")
|
fmt.Fprintf(out, "%s\n", Red("Preflight pod check FAILED"))
|
||||||
log.Fatal(err)
|
fmt.Printf("Error: %v\n", err)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
if namespace == "" {
|
||||||
|
namespace = "default"
|
||||||
}
|
}
|
||||||
if err = qp.CheckPod(namespace, kubeConfigContents); err != nil {
|
if err = qp.CheckPod(namespace, kubeConfigContents); err != nil {
|
||||||
fmt.Println(err)
|
fmt.Fprintf(out, "%s\n", Red("Preflight pod check FAILED"))
|
||||||
fmt.Print("Preflight pod check FAILED\n")
|
fmt.Printf("Error: %v\n", err)
|
||||||
log.Fatal()
|
return nil
|
||||||
}
|
}
|
||||||
|
fmt.Fprintf(out, "%s\n", Green("Preflight pod check PASSED"))
|
||||||
return nil
|
return nil
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
f := pfPodCheckCmd.Flags()
|
||||||
|
f.BoolVarP(&preflightOpts.Verbose, "verbose", "v", false, "verbose mode")
|
||||||
return pfPodCheckCmd
|
return pfPodCheckCmd
|
||||||
}
|
}
|
||||||
|
|
||||||
func pfCreateRoleCheckCmd(q *qliksense.Qliksense) *cobra.Command {
|
func pfCreateRoleCheckCmd(q *qliksense.Qliksense) *cobra.Command {
|
||||||
|
out := ansi.NewColorableStdout()
|
||||||
|
preflightOpts := &preflight.PreflightOptions{
|
||||||
|
MongoOptions: &preflight.MongoOptions{},
|
||||||
|
}
|
||||||
|
|
||||||
var preflightRoleCmd = &cobra.Command{
|
var preflightRoleCmd = &cobra.Command{
|
||||||
Use: "role",
|
Use: "role",
|
||||||
Short: "preflight create role check",
|
Short: "preflight create role check",
|
||||||
Long: `perform preflight role check to ensure we are able to create a role in the cluster`,
|
Long: `perform preflight role check to ensure we are able to create a role in the cluster`,
|
||||||
Example: `qliksense preflight createRole`,
|
Example: `qliksense preflight createRole`,
|
||||||
RunE: func(cmd *cobra.Command, args []string) error {
|
RunE: func(cmd *cobra.Command, args []string) error {
|
||||||
qp := &preflight.QliksensePreflight{Q: q}
|
qp := &preflight.QliksensePreflight{Q: q, P: preflightOpts}
|
||||||
|
|
||||||
// Preflight role check
|
// Preflight role check
|
||||||
fmt.Printf("Preflight role check\n")
|
|
||||||
fmt.Println("---------------------------")
|
|
||||||
namespace, _, err := preflight.InitPreflight()
|
namespace, _, err := preflight.InitPreflight()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Printf("Preflight role check FAILED\n")
|
fmt.Fprintf(out, "%s\n", Red("Preflight role check FAILED"))
|
||||||
log.Fatal(err)
|
fmt.Printf("Error: %v\n", err)
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
if err = qp.CheckCreateRole(namespace); err != nil {
|
if err = qp.CheckCreateRole(namespace); err != nil {
|
||||||
fmt.Println(err)
|
fmt.Fprintf(out, "%s\n", Red("Preflight role check FAILED"))
|
||||||
fmt.Print("Preflight role FAILED\n")
|
fmt.Printf("Error: %v\n", err)
|
||||||
log.Fatal()
|
return nil
|
||||||
}
|
}
|
||||||
|
fmt.Fprintf(out, "%s\n", Green("Preflight role check PASSED"))
|
||||||
return nil
|
return nil
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
f := preflightRoleCmd.Flags()
|
||||||
|
f.BoolVarP(&preflightOpts.Verbose, "verbose", "v", false, "verbose mode")
|
||||||
return preflightRoleCmd
|
return preflightRoleCmd
|
||||||
}
|
}
|
||||||
|
|
||||||
func pfCreateRoleBindingCheckCmd(q *qliksense.Qliksense) *cobra.Command {
|
func pfCreateRoleBindingCheckCmd(q *qliksense.Qliksense) *cobra.Command {
|
||||||
|
out := ansi.NewColorableStdout()
|
||||||
|
preflightOpts := &preflight.PreflightOptions{
|
||||||
|
MongoOptions: &preflight.MongoOptions{},
|
||||||
|
}
|
||||||
|
|
||||||
var preflightRoleBindingCmd = &cobra.Command{
|
var preflightRoleBindingCmd = &cobra.Command{
|
||||||
Use: "rolebinding",
|
Use: "rolebinding",
|
||||||
Short: "preflight create rolebinding check",
|
Short: "preflight create rolebinding check",
|
||||||
Long: `perform preflight rolebinding check to ensure we are able to create a rolebinding in the cluster`,
|
Long: `perform preflight rolebinding check to ensure we are able to create a rolebinding in the cluster`,
|
||||||
Example: `qliksense preflight rolebinding`,
|
Example: `qliksense preflight rolebinding`,
|
||||||
RunE: func(cmd *cobra.Command, args []string) error {
|
RunE: func(cmd *cobra.Command, args []string) error {
|
||||||
qp := &preflight.QliksensePreflight{Q: q}
|
qp := &preflight.QliksensePreflight{Q: q, P: preflightOpts}
|
||||||
|
|
||||||
// Preflight createRoleBinding check
|
// Preflight createRoleBinding check
|
||||||
fmt.Printf("Preflight rolebinding check\n")
|
|
||||||
fmt.Println("---------------------------")
|
|
||||||
namespace, _, err := preflight.InitPreflight()
|
namespace, _, err := preflight.InitPreflight()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Printf("Preflight rolebinding check FAILED\n")
|
fmt.Fprintf(out, "%s\n", Red("Preflight rolebinding check FAILED"))
|
||||||
log.Fatal(err)
|
fmt.Printf("Error: %v\n", err)
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
if err = qp.CheckCreateRoleBinding(namespace); err != nil {
|
if err = qp.CheckCreateRoleBinding(namespace); err != nil {
|
||||||
fmt.Println(err)
|
fmt.Fprintf(out, "%s\n", Red("Preflight rolebinding check FAILED"))
|
||||||
fmt.Print("Preflight rolebinding check FAILED\n")
|
fmt.Printf("Error: %v\n", err)
|
||||||
log.Fatal()
|
return nil
|
||||||
}
|
}
|
||||||
|
fmt.Fprintf(out, "%s\n", Green("Preflight rolebinding check PASSED"))
|
||||||
return nil
|
return nil
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
f := preflightRoleBindingCmd.Flags()
|
||||||
|
f.BoolVarP(&preflightOpts.Verbose, "verbose", "v", false, "verbose mode")
|
||||||
return preflightRoleBindingCmd
|
return preflightRoleBindingCmd
|
||||||
}
|
}
|
||||||
|
|
||||||
func pfCreateServiceAccountCheckCmd(q *qliksense.Qliksense) *cobra.Command {
|
func pfCreateServiceAccountCheckCmd(q *qliksense.Qliksense) *cobra.Command {
|
||||||
|
out := ansi.NewColorableStdout()
|
||||||
|
preflightOpts := &preflight.PreflightOptions{
|
||||||
|
MongoOptions: &preflight.MongoOptions{},
|
||||||
|
}
|
||||||
|
|
||||||
var preflightServiceAccountCmd = &cobra.Command{
|
var preflightServiceAccountCmd = &cobra.Command{
|
||||||
Use: "serviceaccount",
|
Use: "serviceaccount",
|
||||||
Short: "preflight create ServiceAccount check",
|
Short: "preflight create ServiceAccount check",
|
||||||
Long: `perform preflight serviceaccount check to ensure we are able to create a service account in the cluster`,
|
Long: `perform preflight serviceaccount check to ensure we are able to create a service account in the cluster`,
|
||||||
Example: `qliksense preflight serviceaccount`,
|
Example: `qliksense preflight serviceaccount`,
|
||||||
RunE: func(cmd *cobra.Command, args []string) error {
|
RunE: func(cmd *cobra.Command, args []string) error {
|
||||||
qp := &preflight.QliksensePreflight{Q: q}
|
qp := &preflight.QliksensePreflight{Q: q, P: preflightOpts}
|
||||||
|
|
||||||
// Preflight createServiceAccount check
|
// Preflight createServiceAccount check
|
||||||
fmt.Printf("Preflight ServiceAccount check\n")
|
|
||||||
fmt.Println("-------------------------------------")
|
|
||||||
namespace, _, err := preflight.InitPreflight()
|
namespace, _, err := preflight.InitPreflight()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Printf("Preflight serviceaccount check FAILED\n")
|
fmt.Fprintf(out, "%s\n", Red("Preflight ServiceAccount check FAILED"))
|
||||||
log.Fatal(err)
|
fmt.Printf("Error: %v\n", err)
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
if err = qp.CheckCreateServiceAccount(namespace); err != nil {
|
if err = qp.CheckCreateServiceAccount(namespace); err != nil {
|
||||||
fmt.Println(err)
|
fmt.Fprintf(out, "%s\n", Red("Preflight ServiceAccount check FAILED"))
|
||||||
fmt.Print("Preflight serviceaccount check FAILED\n")
|
fmt.Printf("Error: %v\n", err)
|
||||||
log.Fatal()
|
return nil
|
||||||
}
|
}
|
||||||
|
fmt.Fprintf(out, "%s\n", Green("Preflight ServiceAccount check PASSED"))
|
||||||
return nil
|
return nil
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
f := preflightServiceAccountCmd.Flags()
|
||||||
|
f.BoolVarP(&preflightOpts.Verbose, "verbose", "v", false, "verbose mode")
|
||||||
return preflightServiceAccountCmd
|
return preflightServiceAccountCmd
|
||||||
}
|
}
|
||||||
|
|
||||||
func pfCreateRBCheckCmd(q *qliksense.Qliksense) *cobra.Command {
|
func pfCreateAuthCheckCmd(q *qliksense.Qliksense) *cobra.Command {
|
||||||
var preflightCreateRBCmd = &cobra.Command{
|
out := ansi.NewColorableStdout()
|
||||||
|
preflightOpts := &preflight.PreflightOptions{
|
||||||
|
MongoOptions: &preflight.MongoOptions{},
|
||||||
|
}
|
||||||
|
var preflightCreateAuthCmd = &cobra.Command{
|
||||||
Use: "authcheck",
|
Use: "authcheck",
|
||||||
Short: "preflight authcheck",
|
Short: "preflight authcheck",
|
||||||
Long: `perform preflight authcheck that combines the role, rolebinding and serviceaccount checks`,
|
Long: `perform preflight authcheck that combines the role, rolebinding and serviceaccount checks`,
|
||||||
Example: `qliksense preflight authcheck`,
|
Example: `qliksense preflight authcheck`,
|
||||||
RunE: func(cmd *cobra.Command, args []string) error {
|
RunE: func(cmd *cobra.Command, args []string) error {
|
||||||
qp := &preflight.QliksensePreflight{Q: q}
|
qp := &preflight.QliksensePreflight{Q: q, P: preflightOpts}
|
||||||
|
|
||||||
// Preflight authcheck
|
// Preflight authcheck
|
||||||
fmt.Printf("Preflight authcheck\n")
|
|
||||||
fmt.Println("------------------------")
|
|
||||||
namespace, kubeConfigContents, err := preflight.InitPreflight()
|
namespace, kubeConfigContents, err := preflight.InitPreflight()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Printf("Preflight authcheck FAILED\n")
|
fmt.Fprintf(out, "%s\n", Red("Preflight authcheck FAILED"))
|
||||||
log.Fatal(err)
|
fmt.Printf("Error: %v\n", err)
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
if err = qp.CheckCreateRB(namespace, kubeConfigContents); err != nil {
|
if err = qp.CheckCreateRB(namespace, kubeConfigContents); err != nil {
|
||||||
fmt.Println(err)
|
fmt.Fprintf(out, "%s\n", Red("Preflight authcheck FAILED"))
|
||||||
fmt.Print("Preflight authcheck FAILED\n")
|
fmt.Printf("Error: %v\n", err)
|
||||||
log.Fatal()
|
return nil
|
||||||
}
|
}
|
||||||
|
fmt.Fprintf(out, "%s\n", Green("Preflight authcheck PASSED"))
|
||||||
return nil
|
return nil
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
return preflightCreateRBCmd
|
f := preflightCreateAuthCmd.Flags()
|
||||||
|
f.BoolVarP(&preflightOpts.Verbose, "verbose", "v", false, "verbose mode")
|
||||||
|
return preflightCreateAuthCmd
|
||||||
}
|
}
|
||||||
|
|
||||||
func pfMongoCheckCmd(q *qliksense.Qliksense) *cobra.Command {
|
func pfMongoCheckCmd(q *qliksense.Qliksense) *cobra.Command {
|
||||||
var mongodbUrl string
|
out := ansi.NewColorableStdout()
|
||||||
|
preflightOpts := &preflight.PreflightOptions{
|
||||||
|
MongoOptions: &preflight.MongoOptions{},
|
||||||
|
}
|
||||||
|
|
||||||
var preflightMongoCmd = &cobra.Command{
|
var preflightMongoCmd = &cobra.Command{
|
||||||
Use: "mongo",
|
Use: "mongo",
|
||||||
Short: "preflight mongo OR preflight mongo --url=<url>",
|
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`,
|
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>`,
|
Example: `qliksense preflight mongo OR preflight mongo --url=<url>`,
|
||||||
RunE: func(cmd *cobra.Command, args []string) error {
|
RunE: func(cmd *cobra.Command, args []string) error {
|
||||||
qp := &preflight.QliksensePreflight{Q: q}
|
qp := &preflight.QliksensePreflight{Q: q, P: preflightOpts}
|
||||||
|
|
||||||
// Preflight mongo check
|
// Preflight mongo check
|
||||||
fmt.Printf("Preflight mongo check\n")
|
|
||||||
fmt.Println("-------------------------------------")
|
|
||||||
namespace, kubeConfigContents, err := preflight.InitPreflight()
|
namespace, kubeConfigContents, err := preflight.InitPreflight()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Printf("Preflight mongo check FAILED\n")
|
fmt.Fprintf(out, "%s\n", Red("Preflight mongo check FAILED"))
|
||||||
log.Fatal(err)
|
fmt.Printf("Error: %v\n", err)
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
if err = qp.CheckMongo(kubeConfigContents, namespace, mongodbUrl); err != nil {
|
if namespace == "" {
|
||||||
fmt.Println(err)
|
namespace = "default"
|
||||||
fmt.Print("Preflight mongo check FAILED\n")
|
|
||||||
log.Fatal()
|
|
||||||
}
|
}
|
||||||
|
if err = qp.CheckMongo(kubeConfigContents, namespace, preflightOpts); 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
|
return nil
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
f := preflightMongoCmd.Flags()
|
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
|
return preflightMongoCmd
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ func pullQliksenseImages(q *qliksense.Qliksense) *cobra.Command {
|
|||||||
Short: "Pull docker images for offline install",
|
Short: "Pull docker images for offline install",
|
||||||
Example: `qliksense pull`,
|
Example: `qliksense pull`,
|
||||||
RunE: func(cmd *cobra.Command, args []string) error {
|
RunE: func(cmd *cobra.Command, args []string) error {
|
||||||
version, err := getAboutCommandGitRef(args)
|
version, err := getSingleArg(args)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -34,11 +34,8 @@ func pushQliksenseImages(q *qliksense.Qliksense) *cobra.Command {
|
|||||||
Short: "Push docker images for offline install",
|
Short: "Push docker images for offline install",
|
||||||
Example: `qliksense push`,
|
Example: `qliksense push`,
|
||||||
RunE: func(cmd *cobra.Command, args []string) error {
|
RunE: func(cmd *cobra.Command, args []string) error {
|
||||||
qConfig := qapi.NewQConfig(q.QliksenseHome)
|
if err := ensureImageRegistrySetInCR(q); err != nil {
|
||||||
if qcr, err := qConfig.GetCurrentCR(); err != nil {
|
|
||||||
return err
|
return err
|
||||||
} else if registry := qcr.GetImageRegistry(); registry == "" {
|
|
||||||
return errors.New("no image registry in config")
|
|
||||||
} else {
|
} else {
|
||||||
return q.PushImagesForCurrentCR()
|
return q.PushImagesForCurrentCR()
|
||||||
}
|
}
|
||||||
@@ -46,3 +43,13 @@ func pushQliksenseImages(q *qliksense.Qliksense) *cobra.Command {
|
|||||||
}
|
}
|
||||||
return cmd
|
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
|
||||||
|
}
|
||||||
|
|||||||
@@ -12,11 +12,10 @@ import (
|
|||||||
"github.com/mitchellh/go-homedir"
|
"github.com/mitchellh/go-homedir"
|
||||||
"github.com/qlik-oss/sense-installer/pkg"
|
"github.com/qlik-oss/sense-installer/pkg"
|
||||||
"github.com/qlik-oss/sense-installer/pkg/api"
|
"github.com/qlik-oss/sense-installer/pkg/api"
|
||||||
"github.com/qlik-oss/sense-installer/pkg/preflight"
|
|
||||||
"github.com/qlik-oss/sense-installer/pkg/qliksense"
|
"github.com/qlik-oss/sense-installer/pkg/qliksense"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
"github.com/spf13/viper"
|
"github.com/spf13/viper"
|
||||||
"github.com/ttacon/chalk"
|
. "github.com/logrusorgru/aurora"
|
||||||
)
|
)
|
||||||
|
|
||||||
// To run this project in debug mode, run:
|
// To run this project in debug mode, run:
|
||||||
@@ -28,6 +27,13 @@ const (
|
|||||||
qlikSenseDirVar = ".qliksense"
|
qlikSenseDirVar = ".qliksense"
|
||||||
keepPatchFilesFlagName = "keep-config-repo-patches"
|
keepPatchFilesFlagName = "keep-config-repo-patches"
|
||||||
keepPatchFilesFlagUsage = "Keep config repo patch files (for debugging)"
|
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 {
|
func initAndExecute() error {
|
||||||
@@ -86,22 +92,25 @@ var versionCmd = &cobra.Command{
|
|||||||
}
|
}
|
||||||
|
|
||||||
func commandUsesContext(commandName string) bool {
|
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 {
|
func getRootCmd(p *qliksense.Qliksense) *cobra.Command {
|
||||||
cmd := &cobra.Command{
|
cmd := &cobra.Command{
|
||||||
Use: "qliksense",
|
Use: rootCommandName,
|
||||||
Short: "Qliksense cli tool",
|
Short: "Qliksense cli tool",
|
||||||
Long: `qliksense cli tool provides functionality to perform operations on qliksense-k8s, qliksense operator, and kubernetes cluster`,
|
Long: `qliksense cli tool provides functionality to perform operations on qliksense-k8s, qliksense operator, and kubernetes cluster`,
|
||||||
Args: cobra.ArbitraryArgs,
|
Args: cobra.ArbitraryArgs,
|
||||||
PersistentPreRun: func(cmd *cobra.Command, args []string) {
|
PersistentPreRun: func(cmd *cobra.Command, args []string) {
|
||||||
if commandUsesContext(cmd.Name()) {
|
if commandUsesContext(cmd.CommandPath()) {
|
||||||
globalEulaPreRun(cmd, p)
|
globalEulaPreRun(cmd, p)
|
||||||
if err := p.SetUpQliksenseDefaultContext(); err != nil {
|
if err := p.SetUpQliksenseDefaultContext(); err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
pf := preflight.NewPreflightConfig(p.QliksenseHome)
|
pf := api.NewPreflightConfig(p.QliksenseHome)
|
||||||
if err := pf.Initialize(); err != nil {
|
if err := pf.Initialize(); err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
@@ -109,14 +118,14 @@ func getRootCmd(p *qliksense.Qliksense) *cobra.Command {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
PersistentPostRun: func(cmd *cobra.Command, args []string) {
|
PersistentPostRun: func(cmd *cobra.Command, args []string) {
|
||||||
if commandUsesContext(cmd.Name()) {
|
if commandUsesContext(cmd.CommandPath()) {
|
||||||
globalEulaPostRun(cmd, p)
|
globalEulaPostRun(cmd, p)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
origHelpFunc := cmd.HelpFunc()
|
origHelpFunc := cmd.HelpFunc()
|
||||||
cmd.SetHelpFunc(func(cmd *cobra.Command, args []string) {
|
cmd.SetHelpFunc(func(cmd *cobra.Command, args []string) {
|
||||||
if !commandUsesContext(cmd.Name()) {
|
if !commandUsesContext(cmd.CommandPath()) {
|
||||||
cmd.Flags().MarkHidden("acceptEULA")
|
cmd.Flags().MarkHidden("acceptEULA")
|
||||||
}
|
}
|
||||||
origHelpFunc(cmd, args)
|
origHelpFunc(cmd, args)
|
||||||
@@ -163,9 +172,6 @@ func rootCmd(p *qliksense.Qliksense) *cobra.Command {
|
|||||||
|
|
||||||
viper.SetEnvKeyReplacer(strings.NewReplacer("-", "_"))
|
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
|
// add the set-context config command as a sub-command to the app config command
|
||||||
configCmd.AddCommand(setContextConfigCmd(p))
|
configCmd.AddCommand(setContextConfigCmd(p))
|
||||||
|
|
||||||
@@ -190,11 +196,15 @@ func rootCmd(p *qliksense.Qliksense) *cobra.Command {
|
|||||||
// add clean-config-repo-patches command as a sub-command to the app config sub-command
|
// add clean-config-repo-patches command as a sub-command to the app config sub-command
|
||||||
configCmd.AddCommand(cleanConfigRepoPatchesCmd(p))
|
configCmd.AddCommand(cleanConfigRepoPatchesCmd(p))
|
||||||
|
|
||||||
|
|
||||||
// open editor for config
|
// open editor for config
|
||||||
configCmd.AddCommand(configEditCmd(p))
|
configCmd.AddCommand(configEditCmd(p))
|
||||||
// add uninstall command
|
// add uninstall command
|
||||||
cmd.AddCommand(uninstallCmd(p))
|
cmd.AddCommand(uninstallCmd(p))
|
||||||
|
|
||||||
|
// add export command
|
||||||
|
cmd.AddCommand(exportCmd(p))
|
||||||
|
|
||||||
// add crds
|
// add crds
|
||||||
cmd.AddCommand(crdsCmd)
|
cmd.AddCommand(crdsCmd)
|
||||||
crdsCmd.AddCommand(crdsViewCmd(p))
|
crdsCmd.AddCommand(crdsViewCmd(p))
|
||||||
@@ -212,7 +222,7 @@ func rootCmd(p *qliksense.Qliksense) *cobra.Command {
|
|||||||
preflightCmd.AddCommand(pfCreateRoleCheckCmd(p))
|
preflightCmd.AddCommand(pfCreateRoleCheckCmd(p))
|
||||||
preflightCmd.AddCommand(pfCreateRoleBindingCheckCmd(p))
|
preflightCmd.AddCommand(pfCreateRoleBindingCheckCmd(p))
|
||||||
preflightCmd.AddCommand(pfCreateServiceAccountCheckCmd(p))
|
preflightCmd.AddCommand(pfCreateServiceAccountCheckCmd(p))
|
||||||
preflightCmd.AddCommand(pfCreateRBCheckCmd(p))
|
preflightCmd.AddCommand(pfCreateAuthCheckCmd(p))
|
||||||
|
|
||||||
cmd.AddCommand(preflightCmd)
|
cmd.AddCommand(preflightCmd)
|
||||||
cmd.AddCommand(loadCrFile(p))
|
cmd.AddCommand(loadCrFile(p))
|
||||||
@@ -261,7 +271,7 @@ func levenstein(cmd *cobra.Command) {
|
|||||||
if !strings.EqualFold(arg[1], suggest[0]) {
|
if !strings.EqualFold(arg[1], suggest[0]) {
|
||||||
arg[1] = suggest[0]
|
arg[1] = suggest[0]
|
||||||
out := ansi.NewColorableStdout()
|
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, " ")), "?")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func uninstallCmd(q *qliksense.Qliksense) *cobra.Command {
|
func uninstallCmd(q *qliksense.Qliksense) *cobra.Command {
|
||||||
|
skipConfirmation := false
|
||||||
c := &cobra.Command{
|
c := &cobra.Command{
|
||||||
Use: "uninstall",
|
Use: "uninstall",
|
||||||
Short: "Uninstall the deployed qliksense.",
|
Short: "Uninstall the deployed qliksense.",
|
||||||
@@ -13,10 +14,15 @@ func uninstallCmd(q *qliksense.Qliksense) *cobra.Command {
|
|||||||
Example: `qliksense uninstall <context-name>`,
|
Example: `qliksense uninstall <context-name>`,
|
||||||
RunE: func(cmd *cobra.Command, args []string) error {
|
RunE: func(cmd *cobra.Command, args []string) error {
|
||||||
if len(args) > 0 {
|
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
|
return c
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
|
|
||||||
}
|
|
||||||
@@ -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`
|
- `qliksense apply -f cr-file.yaml`
|
||||||
- `cat cr-file.yaml | qliksense apply -f -`
|
- `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
|
```yaml
|
||||||
apiVersion: qlik.com/v1
|
apiVersion: qlik.com/v1
|
||||||
@@ -27,33 +61,26 @@ spec:
|
|||||||
value: mongodb://qlik-test-mongodb:27017/qliksense?ssl=false
|
value: mongodb://qlik-test-mongodb:27017/qliksense?ssl=false
|
||||||
profile: docker-desktop
|
profile: docker-desktop
|
||||||
rotateKeys: "yes"
|
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`
|
For example, running the following command will show information about default profile for `1.0.0` tag
|
||||||
- `cat cr-file.yaml | qliksense load -f -`
|
|
||||||
|
|
||||||
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.
|
Using other supported commands user might have built the CR into the location `~/.qliksense/myqliksense.yaml`
|
||||||
|
|
||||||
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`
|
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
apiVersion: qlik.com/v1
|
apiVersion: qlik.com/v1
|
||||||
@@ -62,7 +89,7 @@ metadata:
|
|||||||
name: myqliksense
|
name: myqliksense
|
||||||
spec:
|
spec:
|
||||||
profile: docker-desktop
|
profile: docker-desktop
|
||||||
manifestsRoot: /Usr/ddd/my-k8-repo/manifests
|
manifestsRoot: /Usr/xyz/my-k8-repo/manifests
|
||||||
namespace: myqliksense
|
namespace: myqliksense
|
||||||
storageClassName: efs
|
storageClassName: efs
|
||||||
configs:
|
configs:
|
||||||
@@ -77,31 +104,30 @@ spec:
|
|||||||
valueFromKey: messagingPassword
|
valueFromKey: messagingPassword
|
||||||
```
|
```
|
||||||
|
|
||||||
In that case the command would be
|
In this case, the result of `qliksense about` command would display information from:
|
||||||
|
|
||||||
- `qliksense about`
|
- `/Usr/xyz/my-k8-repo/manifests/docker-desktop` location, or
|
||||||
- display from `/Usr/ddd/my-k8-repo/manifests/docker-desktop` location
|
- Pull and show information from `master` branch if the directory is invalid or empty
|
||||||
- pull from `master` if directory invalid/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 apply` - generate the patches and apply manifests to K8s
|
||||||
- `qliksense config list-contexts` - retrieves the contexts and lists them
|
- `qliksense config list-contexts` - get and list contexts
|
||||||
- `qliksense config set` - configure a key value pair into the current context
|
- `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-configs` - set configurations into 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-context` - sets the Kubernetes context where resources are located
|
||||||
- `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=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 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 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 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
|
```yaml
|
||||||
apiVersion: config.qlik.com/v1
|
apiVersion: config.qlik.com/v1
|
||||||
kind: QliksenseConfig
|
kind: QliksenseConfig
|
||||||
@@ -110,10 +136,10 @@ metadata:
|
|||||||
spec:
|
spec:
|
||||||
contexts:
|
contexts:
|
||||||
- name: qlik-default
|
- 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
|
- name: myqliksense
|
||||||
crFile: /Users/fff/.qliksense/contexts/myqliksense/myqliksense.yaml
|
crFile: /Users/xyz/.qliksense/contexts/myqliksense/myqliksense.yaml
|
||||||
- name: hello
|
- name: hello
|
||||||
crFile: /Users/fff/.qliksense/contexts/hello/hello.yaml
|
crFile: /Users/xyz/.qliksense/contexts/hello/hello.yaml
|
||||||
currentContext: hello
|
currentContext: hello
|
||||||
```
|
```
|
||||||
@@ -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:
|
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.
|
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
|
`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
|
- 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
|
## With a git repo
|
||||||
|
|
||||||
@@ -94,4 +94,3 @@ spec:
|
|||||||
image: qlik-docker-oss.bintray.io/qliksense-repo-watcher
|
image: qlik-docker-oss.bintray.io/qliksense-repo-watcher
|
||||||
....
|
....
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
- Kubernetes cluster (Docker Desktop with enabled Kubernetes)
|
- 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_
|
- `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`
|
Download the executable for your platform from [releases page](https://github.com/qlik-oss/sense-installer/releases) and rename it to `qliksense`
|
||||||
|
|
||||||
|
|||||||
@@ -1,22 +1,15 @@
|
|||||||
# Overview
|
# 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 QSEoK
|
||||||
- Installation of qliksense operator to manage QSEoK
|
- Installation of qliksense operator to manage QSEoK
|
||||||
- Air gapped installation of QSEoK
|
- Air gapped installation of QSEoK
|
||||||
|
|
||||||
!!! info ""
|
!!! 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 ""
|
!!! info ""
|
||||||
See QlikSense [edge releases on qliksense-k8s](https://github.com/qlik-oss/qliksense-k8s/releases) repository
|
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
|
|
||||||
|
|||||||
@@ -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.
|
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.
|
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:
|
Run the following command to view help about the commands supported by preflight at any moment:
|
||||||
```console
|
```shell
|
||||||
$ qliksense preflight
|
$ qliksense preflight
|
||||||
perform preflight checks on the cluster
|
perform preflight checks on the cluster
|
||||||
|
|
||||||
@@ -26,7 +27,7 @@ Flags:
|
|||||||
### DNS check
|
### 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.
|
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.
|
The expected output should be similar to the one shown below.
|
||||||
```console
|
```shell
|
||||||
$ qliksense preflight dns
|
$ qliksense preflight dns
|
||||||
|
|
||||||
Preflight DNS check
|
Preflight DNS check
|
||||||
@@ -49,7 +50,7 @@ Deleted deployment: dep-dns-preflight-check
|
|||||||
### Kubernetes version 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.
|
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:
|
The command to run this check and the expected similar output are as shown below:
|
||||||
```console
|
```shell
|
||||||
$ qliksense preflight k8s-version
|
$ qliksense preflight k8s-version
|
||||||
|
|
||||||
Preflight kubernetes minimum version check
|
Preflight kubernetes minimum version check
|
||||||
@@ -64,7 +65,7 @@ Completed Preflight kubernetes minimum version check
|
|||||||
|
|
||||||
### Service check
|
### Service check
|
||||||
We use the commmand below to test if we are able to create a service in the cluster.
|
We use the commmand below to test if we are able to create a service in the cluster.
|
||||||
```console
|
```shell
|
||||||
$ qliksense preflight service
|
$ qliksense preflight service
|
||||||
|
|
||||||
Preflight service check
|
Preflight service check
|
||||||
@@ -80,7 +81,7 @@ Completed preflight service check
|
|||||||
|
|
||||||
### Deployment 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.
|
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
|
$ qliksense preflight deployment
|
||||||
|
|
||||||
Preflight deployment check
|
Preflight deployment check
|
||||||
@@ -95,7 +96,7 @@ Completed preflight deployment check
|
|||||||
|
|
||||||
### Pod check
|
### Pod check
|
||||||
We use the commmand below to test if we are able to create a pod in the cluster.
|
We use the commmand below to test if we are able to create a pod in the cluster.
|
||||||
```console
|
```shell
|
||||||
$ qliksense preflight pod
|
$ qliksense preflight pod
|
||||||
|
|
||||||
Preflight pod check
|
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
|
```shell
|
||||||
qliksense preflight mongo --url=<url> OR
|
qliksense preflight mongo --url=<url> OR
|
||||||
qliksense preflight mongo
|
qliksense preflight mongo
|
||||||
|
qliksense preflight mongo --url=<mongo-server url> --ca-cert=<path to ca-cert file>
|
||||||
|
|
||||||
|
|
||||||
Preflight mongo check
|
Preflight mongo check
|
||||||
---------------------
|
---------------------
|
||||||
@@ -204,7 +207,7 @@ Preflight mongodb check:
|
|||||||
Created pod: pf-mongo-pod
|
Created pod: pf-mongo-pod
|
||||||
stdout: MongoDB shell version v4.2.5
|
stdout: MongoDB shell version v4.2.5
|
||||||
connecting to: <url>/?compressors=disabled&gssapiServiceName=mongodb
|
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
|
MongoDB server version: 4.2.5
|
||||||
bye
|
bye
|
||||||
stderr:
|
stderr:
|
||||||
@@ -217,9 +220,9 @@ Completed preflight mongodb check
|
|||||||
|
|
||||||
### Running all checks
|
### Running all checks
|
||||||
Run the command shown below to execute all preflight checks.
|
Run the command shown below to execute all preflight checks.
|
||||||
```console
|
```shell
|
||||||
$ qliksense preflight all --mongodb-url=<url> OR
|
$ 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
|
Running all preflight checks
|
||||||
|
|
||||||
|
|||||||
34
go.mod
34
go.mod
@@ -6,11 +6,11 @@ replace (
|
|||||||
github.com/docker/docker => github.com/moby/moby v0.7.3-0.20190826074503-38ab9da00309
|
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
|
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/apimachinery => k8s.io/apimachinery v0.17.0
|
||||||
k8s.io/client-go => k8s.io/client-go v0.0.0-20191016111102-bec269661e48
|
k8s.io/client-go => k8s.io/client-go v0.17.0
|
||||||
k8s.io/kubectl => k8s.io/kubectl v0.0.0-20191016120415-2ed914427d51
|
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 (
|
require (
|
||||||
@@ -20,47 +20,43 @@ require (
|
|||||||
github.com/Shopify/ejson v1.2.1
|
github.com/Shopify/ejson v1.2.1
|
||||||
github.com/aws/aws-sdk-go v1.28.9 // indirect
|
github.com/aws/aws-sdk-go v1.28.9 // indirect
|
||||||
github.com/bugsnag/bugsnag-go v1.5.3 // 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/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/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/envy v1.9.0 // indirect
|
||||||
github.com/gobuffalo/logger v1.0.3 // indirect
|
github.com/gobuffalo/logger v1.0.3 // indirect
|
||||||
github.com/gobuffalo/packd v1.0.0 // indirect
|
github.com/gobuffalo/packd v1.0.0 // indirect
|
||||||
github.com/gobuffalo/packr/v2 v2.7.1
|
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/groupcache v0.0.0-20200121045136-8c9f03a8e57e // indirect
|
||||||
github.com/golang/protobuf v1.3.3 // indirect
|
github.com/golang/protobuf v1.3.3 // indirect
|
||||||
github.com/google/uuid v1.1.1
|
|
||||||
github.com/gorilla/mux v1.7.3 // indirect
|
github.com/gorilla/mux v1.7.3 // indirect
|
||||||
github.com/hashicorp/golang-lru v0.5.4 // indirect
|
github.com/hashicorp/golang-lru v0.5.4 // indirect
|
||||||
github.com/jinzhu/copier v0.0.0-20190924061706-b57f9002281a
|
github.com/jinzhu/copier v0.0.0-20190924061706-b57f9002281a
|
||||||
github.com/kardianos/osext v0.0.0-20190222173326-2bc1f35cddc0 // indirect
|
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-colorable v0.1.4
|
||||||
github.com/mattn/go-tty v0.0.3
|
github.com/mattn/go-tty v0.0.3
|
||||||
github.com/mitchellh/go-homedir v1.1.0
|
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.0.34
|
github.com/qlik-oss/k-apis v0.1.1
|
||||||
github.com/robfig/cron/v3 v3.0.1
|
github.com/robfig/cron/v3 v3.0.1
|
||||||
github.com/rogpeppe/go-internal v1.5.2 // indirect
|
github.com/rogpeppe/go-internal v1.5.2 // indirect
|
||||||
github.com/spf13/cobra v0.0.6
|
github.com/spf13/cobra v0.0.6
|
||||||
github.com/spf13/viper v1.6.1
|
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/crypto v0.0.0-20200311171314-f7b00557c8c4 // indirect
|
||||||
golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a // indirect
|
golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a // indirect
|
||||||
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b
|
golang.org/x/net v0.0.0-20200301022130-244492dfa37a
|
||||||
golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527 // indirect
|
|
||||||
golang.org/x/tools v0.0.0-20200312194400-c312e98713c2 // indirect
|
golang.org/x/tools v0.0.0-20200312194400-c312e98713c2 // indirect
|
||||||
google.golang.org/genproto v0.0.0-20200128133413-58ce757ed39b // 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.v2 v2.2.8
|
||||||
gopkg.in/yaml.v3 v3.0.0-20190924164351-c8b7dadae555
|
gopkg.in/yaml.v3 v3.0.0-20190924164351-c8b7dadae555
|
||||||
k8s.io/api v0.17.0
|
k8s.io/api v0.17.2
|
||||||
k8s.io/apimachinery v0.17.0
|
k8s.io/apimachinery v0.17.2
|
||||||
k8s.io/client-go v11.0.0+incompatible
|
k8s.io/client-go v11.0.0+incompatible
|
||||||
k8s.io/kubectl v0.0.0-20191016120415-2ed914427d51
|
|
||||||
sigs.k8s.io/kustomize/api v0.3.2
|
sigs.k8s.io/kustomize/api v0.3.2
|
||||||
sigs.k8s.io/yaml v1.1.0
|
sigs.k8s.io/yaml v1.1.0
|
||||||
)
|
)
|
||||||
|
|||||||
293
go.sum
293
go.sum
@@ -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-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 h1:OLBdZJ3yvOn2MezlWvbrBMTEUQC72zAftRZOMdj5HYo=
|
||||||
github.com/Azure/azure-pipeline-go v0.2.1/go.mod h1:UGSo8XybXnIGZ3epmeBw7Jdz+HiUVpqIlpz/HKHylF4=
|
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 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 h1:HyYPft8wXpxMd0kfLtXo6etWcO+XuPbLkcgx9g2cqxU=
|
||||||
github.com/Azure/azure-sdk-for-go v30.1.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc=
|
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/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 h1:w+iIsaOQNcT7OZ575w+acHgRric5iCyQh+xv+KJ4HB8=
|
||||||
github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8=
|
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 h1:x0sVyfVo0Qw9jcgVHuKIAiTHGRvQ9PsJP+43TVPV/DM=
|
||||||
github.com/Azure/go-autorest v12.1.0+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24=
|
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=
|
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/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/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/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-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 h1:zukEsf/1JZwCMgHiK3GZftabmxiCw4apj3a28RPBiVg=
|
||||||
github.com/Masterminds/goutils v1.1.0/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU=
|
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 h1:znjIyLfpXEDQjOIEWh+ehwpTU14UzUPub3c3sm36u14=
|
||||||
github.com/Masterminds/semver/v3 v3.0.3/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs=
|
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 h1:wz22D0CiSctrliXiI9ZO3HoNApweeRGftyDN+BQa3B8=
|
||||||
github.com/Masterminds/sprig/v3 v3.0.2/go.mod h1:oesJ8kPONMONaZgtiHNzUShJbksypC5kWczhZAf6+aU=
|
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/Masterminds/vcs v1.13.1/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/Microsoft/go-winio v0.4.15-0.20190919025122-fc70bd9a86b5 h1:ygIc8M6trr62pF5DucadTWGdEB4mEyvzi0e2nbcmcyA=
|
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/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 h1:ptnOoufxGSzauVTsdE+wMYnCWA301PdoN4xg5oRdZpg=
|
||||||
github.com/Microsoft/hcsshim v0.8.7/go.mod h1:OHd7sQqRFrYd3RmSgbgji+ctCwkbq2wbEYNSzOYtcBQ=
|
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=
|
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/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 h1:MnEK4VOv6n0RSY4vtRe3h11qjxL3+t0B8yOL8iMXdcM=
|
||||||
github.com/VividCortex/ewma v1.1.1/go.mod h1:2Tkkvm3sRDVXaiyucHiACn4cqf7DpdyLvmxzcbUokwA=
|
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 h1:uSoVVbwJiQipAclBbw+8quDsfcvFjOpI5iCf4p/cqCs=
|
||||||
github.com/alcortesm/tgz v0.0.0-20161220082320-9c5fe88206d7/go.mod h1:6zEj6s6u/ghQa61ZWa/C2Aw3RkjiTBOix7dkqa1VLIs=
|
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-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-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 h1:bZ28Hqta7TFAK3Q08CMvv8y3/8ATaEqv2nGoc6yff6c=
|
||||||
github.com/andybalholm/brotli v0.0.0-20190621154722-5f990b63d2d6/go.mod h1:+lx6/Aqd1kLJ1GQfkvOnaZ1WGmLpMpbprPuIOOZX30U=
|
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=
|
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-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 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-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.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.17.4/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
|
||||||
github.com/aws/aws-sdk-go v1.19.18/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.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 h1:grIuBQc+p3dTRXerh5+2OxSuWFi0iXuxbFdTSg0jaW0=
|
||||||
github.com/aws/aws-sdk-go v1.28.9/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
|
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 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.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
|
||||||
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
|
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/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 h1:pgAtgj+A31JBVtEHu2uHuEx0n+2ukqUJnS2vVe5pQNA=
|
||||||
github.com/bshuster-repo/logrus-logstash-hook v0.4.1/go.mod h1:zsTqEiSzDgAa/8GZR7E1qaXrhYNDKBYy5/dWPTIflbk=
|
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 h1:yeRUT3mUE13jL1tGwvoQsKdVbAsQx9AJ+fqahKveP04=
|
||||||
github.com/bugsnag/bugsnag-go v1.5.3/go.mod h1:2oa8nejYd4cQ/b0hMIopN0lCRxU0bueqREvZLWFrtK8=
|
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/osext v0.0.0-20130617224835-0dd3f918b21b h1:otBG+dV+YK+Soembjv71DPz3uX/V/6MMlSyD9JBQ6kQ=
|
||||||
github.com/bugsnag/panicwrap v1.2.0/go.mod h1:D/8v3kj0zr8ZAKg1AQ6crr+5VwKN5eIywRkfhyM/+dE=
|
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.0/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
||||||
github.com/census-instrumentation/opencensus-proto v0.2.1/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 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko=
|
||||||
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
|
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/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/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
|
||||||
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
|
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/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/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I=
|
||||||
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
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 h1:tSNMc+rJDfmYntojat8lljbt1mgKNpTxUZJsSzJ9Y1s=
|
||||||
github.com/containerd/cgroups v0.0.0-20190919134610-bf292b21730f/go.mod h1:OApqhQ4XNSNC13gXIwDjhOQxjWa/NxkwZXJ1EvqT0ko=
|
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/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.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-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 h1:ForxmXkA6tPIvffbrDAcPUIB32QgXkt2XFj+F0UxetA=
|
||||||
github.com/containerd/containerd v1.3.2/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA=
|
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-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-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-20200107194136-26c1120b8d41 h1:kIFnQBO7rQ0XkMe6xEwbybYHBEaWmh/f++laI6Emt7M=
|
||||||
github.com/containerd/continuity v0.0.0-20191214063359-1097c8bae83b/go.mod h1:Dq467ZllaHgAtVp4p1xUQWBrFXR9s/wyoTpG8zOJGkY=
|
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/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/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=
|
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/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 h1:+lFSQZnnKUFyUEtguIgdoQLJfWSuYz+j/wg5GxLtsN4=
|
||||||
github.com/containers/storage v1.15.3/go.mod h1:v0lq/3f+cXH3Y/HiDaFYRR0zilwDve7I4W7U5xQxvF8=
|
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/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.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-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-oidc v2.1.0+incompatible/go.mod h1:CgnwVTmzoESiwO9qyAFEMiHoZ1nMCKZlZ9V6mm3/LKc=
|
||||||
github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
|
github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
|
||||||
@@ -201,12 +199,14 @@ 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-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 h1:Wf6HqHfScWJN9/ZjdUKyjop4mf3Qdd+1TvvltAvM3m8=
|
||||||
github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
|
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-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/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
|
||||||
github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE=
|
github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE=
|
||||||
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
|
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
|
||||||
github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
|
github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
|
||||||
github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY=
|
github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY=
|
||||||
|
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
||||||
github.com/cyphar/filepath-securejoin v0.2.2 h1:jCwT2GTP+PY5nBz3c/YL5PAIbusElVrPujOBSCj8xRg=
|
github.com/cyphar/filepath-securejoin v0.2.2 h1:jCwT2GTP+PY5nBz3c/YL5PAIbusElVrPujOBSCj8xRg=
|
||||||
github.com/cyphar/filepath-securejoin v0.2.2/go.mod h1:FpkQEhXnPnOthhzymB7CGsFk2G9VLXONKD9G7QGMM+4=
|
github.com/cyphar/filepath-securejoin v0.2.2/go.mod h1:FpkQEhXnPnOthhzymB7CGsFk2G9VLXONKD9G7QGMM+4=
|
||||||
github.com/davecgh/go-spew v0.0.0-20151105211317-5215b55f46b2/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v0.0.0-20151105211317-5215b55f46b2/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
@@ -214,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 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
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/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.8.1 h1:If674KraJVpujYR00rzdi0QAmW4BxzMJPVAZJKuhQ0c=
|
||||||
github.com/deislabs/oras v0.7.0/go.mod h1:sqMKPG3tMyIX9xwXUBRLhZ24o+uT4y6jgBD2RzUTKDM=
|
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/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 h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM=
|
||||||
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
|
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/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/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/dnaeon/go-vcr v1.0.1/go.mod h1:aBB1+wY4s93YsC3HHjMBMrwTj2R9FHDzUr9KyGc8n1E=
|
||||||
github.com/docker/cli v0.0.0-20191212191748-ebca1413117a h1:rgpgmLocRiSIM3zdtVgJcyvH7S2cSiIPtL7LvFY8K/0=
|
github.com/docker/cli v0.0.0-20200130152716-5d0cf8839492 h1:FwssHbCDJD025h+BchanCwE1Q8fyMgqDr2mOQAWOLGw=
|
||||||
github.com/docker/cli v0.0.0-20191212191748-ebca1413117a/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8=
|
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 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 h1:a5mlkVzth6W5A4fOsS3D2EO5BUmsJpcB+cRlLU7cSug=
|
||||||
github.com/docker/distribution v2.7.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
|
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 h1:zI2p9+1NQYdnG6sMU26EX4aVGlqbInSQxQXLvzJ4RPQ=
|
||||||
github.com/docker/docker-credential-helpers v0.6.3/go.mod h1:WRaJzqw3CTB9bk10avuGsjVBZsD05qeibJ1/TYlvc0Y=
|
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.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 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ=
|
||||||
github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec=
|
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 h1:AgB/0SvBxihN0X8OR4SjsblXkbMvalQ8cjmtKQ2rQV8=
|
||||||
github.com/docker/go-metrics v0.0.1/go.mod h1:cG1hvH2utMXtqgqqYE9plW6lDxS3/5ayHzueweSI3Vw=
|
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=
|
github.com/docker/go-units v0.3.3/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
|
||||||
@@ -242,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/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 h1:PNXYaftMVCFS5CmnDtDWTg3wbBO61Q/cEo3KX1oKxto=
|
||||||
github.com/docker/libkv v0.2.1/go.mod h1:r5hEwHwW8dr0TFBYGCarMNbrQOiwL1xoqDYZ/JqoTK0=
|
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 h1:UhxFibDNY/bfvqU5CAUmr9zpesgbU6SWc8/B4mflAE4=
|
||||||
github.com/docker/libtrust v0.0.0-20160708172513-aabc10ec26b7/go.mod h1:cyGadeNEkKy96OOhEzfZl+yxihPEzKnqJwvfuSUqbZE=
|
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-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 h1:PlZu0n3Tuv04TzpfPbrnI0HW/YwodEXDS+oPKahKF0Q=
|
||||||
github.com/dsnet/compress v0.0.1/go.mod h1:Aw8dCMJ7RioblQeTqt88akK31OvO8Dhf5JflhBbQEHo=
|
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/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 h1:qk/FSDDxo05wdJH28W+p5yivv7LuLYLRXPPD8KQCtZs=
|
||||||
github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
|
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 h1:Qk76DOWdOp+GlyDKBAG3Klr9cn7N+LcYc82AZ2S7+cA=
|
||||||
github.com/dustin/gojson v0.0.0-20160307161227-2e71ec9dd5ad/go.mod h1:mPKfmRa823oBIgl2r20LeMSpTAteW5j7FLkc0vjmzyQ=
|
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 h1:p1yVGRW3nmb85p1Sh1ZJSDm4A4iKLS5QNbvUHMgGu/M=
|
||||||
github.com/elazarl/goproxy v0.0.0-20170405201442-c4fc26588b6e/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc=
|
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 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.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 h1:QAUIPSaCu4G+POclxeqb3F+WPpdKqFGlw36+yOzGlrg=
|
||||||
github.com/emirpasic/gods v1.12.0/go.mod h1:YfzfFFoVP/catgzJb4IKIqXjX78Ha8FMSDh3ymbK86o=
|
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=
|
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
||||||
@@ -287,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/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 h1:RDBNVkRviHZtvDvId8XSGPu3rmpmSe+wKRcEWNgsfWU=
|
||||||
github.com/fullsailor/pkcs7 v0.0.0-20190404230743-d7302db945fa/go.mod h1:KnogPXtdwXqoenmZCw6S+25EAm2MkxbG0deNDu4cbSA=
|
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 v0.0.0-20150301180006-535138d7bcd7 h1:LofdAjjjqCSXMwLGgOgnE+rdPuvX9DxCqaHwKy7i/ko=
|
||||||
github.com/garyburd/redigo v1.6.0/go.mod h1:NR3MbYisc3/PwhQ00EMzDiPmrwpPxAn5GI05/YaO1SY=
|
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-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-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 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk=
|
||||||
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
|
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
|
||||||
github.com/gliderlabs/ssh v0.2.2 h1:6zsha5zo/TWhRhwqCD3+EarCAgZ2yN28ipRnGPnwkI0=
|
github.com/gliderlabs/ssh v0.2.2 h1:6zsha5zo/TWhRhwqCD3+EarCAgZ2yN28ipRnGPnwkI0=
|
||||||
@@ -299,11 +298,18 @@ github.com/gliderlabs/ssh v0.2.2/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aev
|
|||||||
github.com/globalsign/mgo v0.0.0-20180905125535-1ca0a4f7cbcb/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q=
|
github.com/globalsign/mgo v0.0.0-20180905125535-1ca0a4f7cbcb/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q=
|
||||||
github.com/globalsign/mgo v0.0.0-20181015135952-eeefdecb41b8/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q=
|
github.com/globalsign/mgo v0.0.0-20181015135952-eeefdecb41b8/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q=
|
||||||
github.com/go-critic/go-critic v0.3.5-0.20190904082202-d79a9f0c64db/go.mod h1:+sE8vrLDS2M0pZkBk0wy6+nLdKexVDrl/jBqQOTDThA=
|
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=
|
||||||
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
|
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
|
||||||
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
|
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-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.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-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-lintpack/lintpack v0.5.2/go.mod h1:NwZuYi2nUHho8XEIZ6SIxihrnPoqBTDqfpXvXAN0sXM=
|
||||||
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
|
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
|
||||||
@@ -314,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.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.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.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.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.18.0/go.mod h1:LcZQpmvG4wyF5j4IhA73wkLFQg+QJXOQHVjmcZxhka0=
|
||||||
github.com/go-openapi/errors v0.19.2/go.mod h1:qX0BLWsyaKfvhluLejVpVNwNRdXZhEbTA4kxxpKBC94=
|
github.com/go-openapi/errors v0.19.2/go.mod h1:qX0BLWsyaKfvhluLejVpVNwNRdXZhEbTA4kxxpKBC94=
|
||||||
@@ -333,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.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.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.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.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.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.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.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.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.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 h1:ixzUSnHTd6hCemgtAJgluaTSGYpLNpJY4mA2DIkdOAo=
|
||||||
github.com/go-openapi/spec v0.19.4/go.mod h1:FpwSN1ksY1eteniUU7X0N/BgJ7a4WvBFVA8Lj9mJglo=
|
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.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.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.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.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.17.0/go.mod h1:AByQ+nYG6gQg71GINrmuDXCPWdL640yX49/kXLo40Tg=
|
||||||
github.com/go-openapi/swag v0.18.0/go.mod h1:AByQ+nYG6gQg71GINrmuDXCPWdL640yX49/kXLo40Tg=
|
github.com/go-openapi/swag v0.18.0/go.mod h1:AByQ+nYG6gQg71GINrmuDXCPWdL640yX49/kXLo40Tg=
|
||||||
@@ -352,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/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.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.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 h1:g24URVg0OFbNUTx9qqY1IRZ9D9z3iPyi5zKhQZpNwpA=
|
||||||
github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
|
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=
|
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
|
||||||
@@ -388,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/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/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.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/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 h1:y12jRkkFxsd7GpqdSZ+/KCs/fJbqpEXSGd4+jfEaewE=
|
||||||
github.com/gofrs/uuid v3.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
|
github.com/gofrs/uuid v3.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
|
||||||
@@ -406,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-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-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-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 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-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 h1:1r7pUrabqp18hOBcwBwiTsbnFeTZHV9eER/QT5JVZxY=
|
||||||
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
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.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=
|
github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||||
@@ -491,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 h1:sjZBwGj9Jlw33ImPtvFviGYvseOtDM7hkSKB7+Tv3SM=
|
||||||
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
|
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.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.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/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 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8=
|
||||||
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
|
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/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg=
|
||||||
github.com/gorilla/handlers v1.4.0 h1:XulKRWSQK5uChr4pEgSE4Tc/OcmnU9GJuSwdog/tZsA=
|
github.com/gorilla/handlers v0.0.0-20150720190736-60c7bfde3e33 h1:893HsJqtxp9z1SF76gg6hY70hRY1wVlTSnC/h1yUDCo=
|
||||||
github.com/gorilla/handlers v1.4.0/go.mod h1:Qkdc/uu4tH4g6mTK6auzZ766c4CA0Ng8+o/OAirnOIQ=
|
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 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 h1:gnP5JzjVOuiZD07fKKToCAOjS0yOpj/qPETTXCCS6hw=
|
||||||
github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
|
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/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 h1:r5vDcYrFz9BmfIAMC829un9hq7hKM4cHUrsv36LbEqs=
|
||||||
github.com/gosimple/slug v1.9.0/go.mod h1:AMZ+sOVe65uByN3kgEyf9WEBKBCSS+dJjMX9x4vDJbg=
|
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/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.4 h1:IG2xLKRvErL3uhY6e1BylFzG+aJiwQviDDTfOKeKTpY=
|
||||||
github.com/gosuri/uitable v0.0.1/go.mod h1:tKR86bXuXPZazfOTG1FIzvjIdXzd0mo4Vtn16vt0PJo=
|
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/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-20180305231024-9cad4c3443a7 h1:pdN6V1QBWetyv/0+wjACpqVH+eVULgEjkurDLq3goeM=
|
||||||
github.com/gregjones/httpcache v0.0.0-20181110185634-c63ab54fda8f h1:ShTPMJQes6tubcjzGMODIVG5hlrCeImaBnZzKF2N8SM=
|
github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA=
|
||||||
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/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
|
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/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.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.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.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 h1:EryWG7cCxvZ2awoZ957B3AMAd20Zy0uRXeZ7TXXMIp0=
|
||||||
github.com/hairyhenderson/gomplate/v3 v3.6.0/go.mod h1:RbEC6Y14nNTHCtNWpBAkwqDP4ICFUrAH0S8PUFa0qT4=
|
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=
|
github.com/hairyhenderson/toml v0.3.1-0.20191004034452-2a4f3b6160f2 h1:Dc4YWWuY02jqhCnErAH++juCTwEPLstAOOVhyPXeE7Q=
|
||||||
@@ -618,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 h1:zPPuIq2jAWWPTrGt70eK/BSch+gFAGrNzecsoENgu2o=
|
||||||
github.com/jinzhu/copier v0.0.0-20190924061706-b57f9002281a/go.mod h1:yL958EeXv8Ylng6IfnvG4oflryUi3vgA3xPs9hmII1s=
|
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-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 h1:pmfjZENx5imkbgOkpRUYLnmbU7UEFbjtDA2hxJ1ichM=
|
||||||
github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
|
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=
|
github.com/johannesboyne/gofakes3 v0.0.0-20191029185751-e238f04965fe h1:9kkgzfTjcHQqS6wGlEhJBJmAMI75lKyHX69w/ii+5So=
|
||||||
@@ -629,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.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 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.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.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 h1:6QPYqodiu3GuPL+7mfx+NwDdp2eTkp9IfEUpgAwUN0o=
|
||||||
github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
|
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 h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo=
|
||||||
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
|
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
|
||||||
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
|
github.com/julienschmidt/httprouter v1.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 h1:iQTw/8FWTuc7uiaSepXwyf3o52HaUYcV+Tu66S3F5GA=
|
||||||
github.com/kardianos/osext v0.0.0-20190222173326-2bc1f35cddc0/go.mod h1:1NbS8ALrpOvjt0rHPNLyCIeMtbizbir8U//inJ+zuB8=
|
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=
|
github.com/kevinburke/ssh_config v0.0.0-20190725054713-01f96b0aa0cd h1:Coekwdh0v2wtGp9Gmz1Ze3eVRAWJMLokvN3QjdzCHLY=
|
||||||
@@ -667,13 +679,18 @@ 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/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 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
|
||||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
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.1.1/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
|
||||||
github.com/lib/pq v1.2.0 h1:LXpIM/LZ5xGFhOpXAQUIMM1HdyqzVYM13zNdjCEEcA0=
|
github.com/lib/pq v1.2.0 h1:LXpIM/LZ5xGFhOpXAQUIMM1HdyqzVYM13zNdjCEEcA0=
|
||||||
github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
|
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 h1:9TO3cAIGXtEhnIaL+V+BEER86oLrvS+kWobKpbJuye0=
|
||||||
github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de/go.mod h1:zAbeS9B/r2mtpb6U+EI2rYA5OAXxsYw6wTamcNW+zcE=
|
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/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-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.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
|
||||||
github.com/magiconair/properties v1.8.1 h1:ZC2Vc7/ZFkGmsVC9KvOjumD+G5lXy2RtTKyzRKO2BQ4=
|
github.com/magiconair/properties v1.8.1 h1:ZC2Vc7/ZFkGmsVC9KvOjumD+G5lXy2RtTKyzRKO2BQ4=
|
||||||
github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
|
github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
|
||||||
@@ -684,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.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 h1:aizVhC/NAAcKWb+5QsU1iNOZb4Yws5UO2I+aIprQITM=
|
||||||
github.com/mailru/easyjson v0.7.0/go.mod h1:KAzv3t3aY1NaHWoQz1+4F1ccyAH66Jk7yos7ldAVICs=
|
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/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=
|
||||||
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=
|
||||||
@@ -698,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.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 h1:qxFzApOv4WsAL965uUPIsXzAKCZxN2p9UqdhFS4ZW10=
|
||||||
github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84=
|
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.2/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.4/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 h1:V2iyH+aX9C5fsYCpK60U8BYIvmhqxuOL3JZcqc1NB7k=
|
||||||
github.com/mattn/go-runewidth v0.0.6/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
|
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 h1:9Jok5pILi5S1MnDirGVTufYGtksUs/V2BWUP3ZkeUUI=
|
||||||
github.com/mattn/go-shellwords v1.0.6/go.mod h1:3xCvwCdWdlDJUrvuMn7Wuy9eWs4pE8vqg+NOMyg4B2o=
|
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 h1:5OfyWorkyO7xP52Mq7tB36ajHDG5OHrmBGIS/DtakQI=
|
||||||
github.com/mattn/go-tty v0.0.3/go.mod h1:ihxohKRERHTVzN+aSVRwACLCeqIoZAWpoICkkvrWyR0=
|
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=
|
github.com/mattn/goveralls v0.0.2/go.mod h1:8d1ZMHsd7fW6IRPKQh46F2WRpyib5/X4FOpevwGNQEw=
|
||||||
@@ -713,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/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 h1:vWjhY8SQp5yzM9P6OJ/eZEkmi3UAbRrxCq48MxjAzig=
|
||||||
github.com/mholt/archiver/v3 v3.3.0/go.mod h1:YnQtqsp+94Rwd0D/rk5cnLrxusUBUXg+08Ebtr1Mqao=
|
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 h1:9jZdLNd/P4+SfEJ0TNyxYpsK8N4GtfylBLqtbYN1sbA=
|
||||||
github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
|
github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
|
||||||
github.com/mistifyio/go-zfs v2.1.1+incompatible h1:gAMO1HM9xBRONLHHYnu5iFsOJUiJdNZo6oqSENd4eW8=
|
github.com/mistifyio/go-zfs v2.1.1+incompatible h1:gAMO1HM9xBRONLHHYnu5iFsOJUiJdNZo6oqSENd4eW8=
|
||||||
@@ -739,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 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 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE=
|
||||||
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
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 h1:9D+8oIskB4VJBN5SFlmc27fSlIBZaov1Wpk/IfikLNY=
|
||||||
github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw=
|
github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw=
|
||||||
github.com/moby/moby v0.7.3-0.20190826074503-38ab9da00309 h1:cvy4lBOYN3gKfKj8Lzz5Q9TfviP+L7koMHY7SvkyTKs=
|
github.com/moby/moby v0.7.3-0.20190826074503-38ab9da00309 h1:cvy4lBOYN3gKfKj8Lzz5Q9TfviP+L7koMHY7SvkyTKs=
|
||||||
@@ -750,33 +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 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 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI=
|
||||||
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
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 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A=
|
||||||
github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc=
|
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/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 h1:xa+eQWKuJ9MbB9FBL/eoNvDFvveAkz2LQoz8PzX7Q/4=
|
||||||
github.com/mtrmac/gpgme v0.0.0-20170102180018-b2432428689c/go.mod h1:GhAqVMEWnTcW2dxoD/SO3n2enrgWl3y6Dnx4m59GvcA=
|
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-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/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/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/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 h1:r7vGuS5akxOnR4JQSkko62RJ1ReCMXxQRPtxsiFMBOs=
|
||||||
github.com/nwaples/rardecode v1.0.0/go.mod h1:5DzqNKiOdpKKBH87u8VlvAnPZMXcGRhxWkRpHbbfGS0=
|
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/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 h1:EGfNDEx6MqHz8B3uNV6QAib1UR2Lm97sHi3ocA6ESJ4=
|
||||||
github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
|
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 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.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 h1:q/mM8GF/n0shIN8SaAZ0V+jnLPzen6WIVZdiwrRlMlo=
|
||||||
github.com/onsi/ginkgo v1.10.1/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
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 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 h1:XPnZz8VVBHjVsy1vzJmRwIcSwiUO+JFfrv/xGiigmME=
|
||||||
github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
|
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 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 h1:WzifXhOVOEOuFYOJAW6aQqW0TooG2iki3E3Ii+WN7gQ=
|
||||||
github.com/opencontainers/go-digest v1.0.0-rc1/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s=
|
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 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.1/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0=
|
||||||
github.com/opencontainers/image-spec v1.0.2-0.20190823105129-775207bd45b6 h1:yN8BPXVwMBAm3Cuvh1L5XE8XpvYRMdsVLd82ILprhUU=
|
github.com/opencontainers/image-spec v1.0.2-0.20190823105129-775207bd45b6 h1:yN8BPXVwMBAm3Cuvh1L5XE8XpvYRMdsVLd82ILprhUU=
|
||||||
@@ -792,6 +813,14 @@ github.com/opencontainers/selinux v1.3.0 h1:xsI95WzPZu5exzA6JzkLSfdr/DilzOhCJOqG
|
|||||||
github.com/opencontainers/selinux v1.3.0/go.mod h1:+BLncwf63G4dgOzykXAxcmnFlUaOlkDdmw/CqsW6pjs=
|
github.com/opencontainers/selinux v1.3.0/go.mod h1:+BLncwf63G4dgOzykXAxcmnFlUaOlkDdmw/CqsW6pjs=
|
||||||
github.com/ostreedev/ostree-go v0.0.0-20190702140239-759a8c1ac913 h1:TnbXhKzrTOyuvWrjI8W6pcoI9XPbLHFXCdN2dtUw7Rw=
|
github.com/ostreedev/ostree-go v0.0.0-20190702140239-759a8c1ac913 h1:TnbXhKzrTOyuvWrjI8W6pcoI9XPbLHFXCdN2dtUw7Rw=
|
||||||
github.com/ostreedev/ostree-go v0.0.0-20190702140239-759a8c1ac913/go.mod h1:J6OG6YJVEWopen4avK3VNQSnALmmjvniMmni/YFYAwc=
|
github.com/ostreedev/ostree-go v0.0.0-20190702140239-759a8c1ac913/go.mod h1:J6OG6YJVEWopen4avK3VNQSnALmmjvniMmni/YFYAwc=
|
||||||
|
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=
|
||||||
github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
|
github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
|
||||||
github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY=
|
github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY=
|
||||||
github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
|
github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
|
||||||
@@ -801,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/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 h1:UBdAOUP5p4RWqPBg048CAvpKN+vxiaj6gdUUzhl4XmI=
|
||||||
github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU=
|
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-20180830031419-95f893ade6f2 h1:JhzVVoYvbOACxoUmOs6V/G4D5nPVUW73rKvXxP4XUJc=
|
||||||
github.com/phayes/freeport v0.0.0-20171002181615-b8543db493a5/go.mod h1:iIss55rKnNBTvrwdmkUpLnDpZoAHvWaiq5+iMmen4AE=
|
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.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 h1:CZzRn4Ut9GbUkHlQ7jqBXeZQV41ZSKWFc302ZU6lUTk=
|
||||||
github.com/pierrec/lz4 v2.3.0+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=
|
github.com/pierrec/lz4 v2.3.0+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=
|
||||||
@@ -812,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-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 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
|
||||||
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
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 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 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
@@ -820,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-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 h1:kyf9snWXHvQc+yxE9imhdI8YAm4oKeZISlaAR+x73zs=
|
||||||
github.com/pquerna/ffjson v0.0.0-20190813045741-dac163c6c0a9/go.mod h1:YARuvh7BUWHNhzDq2OM5tzR2RiCcN2D7sapiKyCel/M=
|
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.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.2/go.mod h1:OsXs2jCmiKlQ1lTBmv21f2mNfw4xf/QclQDMrYNZzcM=
|
||||||
github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso=
|
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.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 h1:BQ53HtBmfOitExawJ6LokA4x8ov/z0SYYb0+HxJfRI8=
|
||||||
github.com/prometheus/client_golang v1.1.0/go.mod h1:I1FGZT9+L76gKKOs5djB6ezCbFQP1xR9D75/vuwEF3g=
|
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_model v0.0.0-20171117100541-99fa1f4be8e5/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
|
||||||
github.com/prometheus/client_golang v1.2.1/go.mod h1:XMU6Z2MjaRKVu/dC1qupJI9SiNkDYzz3xecMgSW/F+U=
|
|
||||||
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/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 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-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 h1:gQz4mCbXsO+nc9n1hCxHcGA3Zx3Eo+UHZoInFGUIXNM=
|
||||||
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
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-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
|
||||||
github.com/prometheus/common v0.0.0-20181126121408-4724e9255275/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.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
|
||||||
github.com/prometheus/common v0.4.1/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 h1:kRhiuYSXR3+uv2IbVbZhUxK5zVD/2pp3Gd2PpvPkpEo=
|
||||||
github.com/prometheus/common v0.6.0/go.mod h1:eBmuwkDJBwy6iBfxCBob6t6dR6ENT/y+J+Zk0j9GMYc=
|
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/procfs v0.0.0-20180125133057-cb4147076ac7/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
|
||||||
github.com/prometheus/common v0.7.0/go.mod h1:DjGbpBbp5NYNiECxcL/VnbXCCaQpKd3tt26CguLLsqA=
|
|
||||||
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/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-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.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.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
|
||||||
github.com/prometheus/procfs v0.0.3 h1:CTwfnzjQ+8dS6MhHHu4YswVAD99sL2wjPqP+VkURmKE=
|
github.com/prometheus/procfs v0.0.3 h1:CTwfnzjQ+8dS6MhHHu4YswVAD99sL2wjPqP+VkURmKE=
|
||||||
@@ -852,12 +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 h1:3+auTFlqw+ZaQYJARz6ArODtkaIwtvBTx3N2NehQlL8=
|
||||||
github.com/prometheus/procfs v0.0.5/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ=
|
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/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU=
|
||||||
github.com/qlik-oss/k-apis v0.0.34 h1:lOC21wz/nNZNmSfTXZSJCOm1BulaZfdg7tAuYb7knAE=
|
github.com/qlik-oss/k-apis v0.1.1 h1:aZ4eTMB3mSn03Kuj7+RI0eFLkjK9+0qxADBioRb3qVA=
|
||||||
github.com/qlik-oss/k-apis v0.0.34/go.mod h1:DNiWYqCqPIN216l7+1rccArNIYPb1Le7kYDcPSyNp+Q=
|
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.20200401055330-fa528324112a h1:Vzod5XB+e25ENy5Lse0pXNmSYSDFxSEYhH/6Sj7twPg=
|
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.20200401055330-fa528324112a/go.mod h1:tSQaDZ4Jt9KwYvD7LlMUPi5nkiGOno3PAKl5/XqEfxs=
|
github.com/qlik-oss/kustomize/api v0.3.3-0.20200424070349-b0312eb71568/go.mod h1:Yg8bqX8Mq/eSgXfcenxCxhZuSXg+NCsKq6NBdch/oUc=
|
||||||
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/quasilyte/go-consistent v0.0.0-20190521200055-c6f3937de18c/go.mod h1:5STLWrekHfjyYwxBRVRXNOSewLJ3PWfDJd1VyTS21fI=
|
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 h1:ta7tUOvsPHVHGom5hKW5VXNc2xZIkfCKP8iaqOyYtUQ=
|
||||||
github.com/rainycape/unidecode v0.0.0-20150907023854-cb7f23ec59be/go.mod h1:MIDFMn7db1kT65GmV94GzpX9Qdi7N/pQlwb+AN8wh+Q=
|
github.com/rainycape/unidecode v0.0.0-20150907023854-cb7f23ec59be/go.mod h1:MIDFMn7db1kT65GmV94GzpX9Qdi7N/pQlwb+AN8wh+Q=
|
||||||
@@ -882,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/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 h1:GHRpF1pTW19a8tTFrMLUcfWwyC0pnifVo2ClaLq+hP8=
|
||||||
github.com/ryszard/goskiplist v0.0.0-20150312221310-2dfbae5fcf46/go.mod h1:uAQ5PCi+MFsC7HjREoAz1BU+Mq60+05gifQSsHSDG/8=
|
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 h1:nn5Wsu0esKSJiIVhscUtVbo7ada43DJhG55ua/hjS5I=
|
||||||
github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
|
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=
|
github.com/securego/gosec v0.0.0-20191002120514-e680875ea14d/go.mod h1:w5+eXa0mYznDkHaMCXA4XYffjlH+cy1oyKbfzJXa2Do=
|
||||||
@@ -906,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/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 h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM=
|
||||||
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
|
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 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 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIKYqbNC9s=
|
||||||
github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
|
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/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
|
||||||
github.com/sourcegraph/go-diff v0.5.1/go.mod h1:j2dHj3m8aZgQO8lMTcTnBcXkRRRqi34cd2MNlA9u1mE=
|
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=
|
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
|
||||||
@@ -931,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/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 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-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 h1:zPAT6CGy6wXeQ7NtTnaTerfKOsV6V6F8agHXFiazDkg=
|
||||||
github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
|
github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
|
||||||
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
|
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
|
||||||
@@ -956,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/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 h1:GkY4dP3cEfEASBPPkWd+AmjYxhmDkqO9/zg7R0lSQRs=
|
||||||
github.com/tchap/go-patricia v2.3.0+incompatible/go.mod h1:bmLyhP68RS6kStMGxByiQ23RP/odRBOTVjwp2cDyi6I=
|
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/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-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/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/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.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc=
|
||||||
github.com/ugorji/go v1.1.7 h1:/68gy2h+1mWMrwZFeD1kQialdSzAb432dtpeJ42ovdo=
|
github.com/ugorji/go v1.1.7 h1:/68gy2h+1mWMrwZFeD1kQialdSzAb432dtpeJ42ovdo=
|
||||||
@@ -974,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/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/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 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/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/uudashr/gocognit v0.0.0-20190926065955-1655d0de0517/go.mod h1:j44Ayx2KW4+oB6SWMv8KsmHzZrOInQav7D3cQMJ5JUM=
|
||||||
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
|
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
|
||||||
@@ -984,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/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 h1:ZOYQSVHgmeanXsbyC44aDg76tBGCS/54Rk8VkL8dJGA=
|
||||||
github.com/vbauerster/mpb/v4 v4.11.1/go.mod h1:vMLa1J/ZKC83G2lB/52XpqT+ZZtFG4aZOdKhmpRL1uM=
|
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 h1:TCbipTQL2JiiCprBWx9frJ2eJlCYT00NmctrHxVAr70=
|
||||||
github.com/xanzy/ssh-agent v0.2.1/go.mod h1:mLlQY/MoOhWBj+gOGMQkOeiEvkx+8pJSI+0Bx9h2kr4=
|
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=
|
github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
|
||||||
@@ -995,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 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 h1:ngVtJC9TY/lg0AA/1k48FYhBrhRoFlEmWzsehpNAaZg=
|
||||||
github.com/xeipuuv/gojsonschema v1.1.0/go.mod h1:5yf86TLmAcydyeJq5YvxkGPE2fm/u4myDekKRoLuqhs=
|
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 h1:nIPpBwaJSVYIxUFsDv3M8ofmx9yWTog9BfvIu0q41lo=
|
||||||
github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8/go.mod h1:HUYIGzjTL3rfEspMxjDjgmT5uz5wzYJKVo23qUhYTos=
|
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/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/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 h1:FhvNc94AXMZkfqUwfMKhnQEC9phkphSGdPTL7tIdhOM=
|
||||||
github.com/yujunz/go-getter v1.4.1-lite/go.mod h1:sbmqxXjyLunH1PkF3n7zSlnVeMvmYUuIl9ZVs/7NyCc=
|
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-20140926110328-57bccd1ccd43 h1:+lm10QQTNSBd8DVTNGHx7o/IKu9HYDvLMffDhbyLccI=
|
||||||
github.com/yvasiyarov/go-metrics v0.0.0-20150112132944-c25f46c4b940/go.mod h1:aX5oPXxHm3bOH+xeAttToC8pqch2ScQN/JoXYupl6xs=
|
github.com/yvasiyarov/go-metrics v0.0.0-20140926110328-57bccd1ccd43/go.mod h1:aX5oPXxHm3bOH+xeAttToC8pqch2ScQN/JoXYupl6xs=
|
||||||
github.com/yvasiyarov/gorelic v0.0.6 h1:qMJQYPNdtJ7UNYHjX38KXZtltKTqimMuoQjNnSVIuJg=
|
github.com/yvasiyarov/gorelic v0.0.0-20141212073537-a9bba5b9ab50 h1:hlE8//ciYMztlGpl/VA+Zm1AcTPHYkHJPbHqE6WJUXE=
|
||||||
github.com/yvasiyarov/gorelic v0.0.6/go.mod h1:NUSPSUX/bi6SeDMUh6brw0nXpxHnc96TguQh0+r/ssA=
|
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 h1:ERexzlUfuTvpE74urLSbIQW0Z/6hF9t8U4NsJLaioAY=
|
||||||
github.com/yvasiyarov/newrelic_platform_go v0.0.0-20140908184405-b21fdbd4370f/go.mod h1:GlGEuHIJweS1mbCqG+7vt2nvWLzLLnRHbXz5JKd/Qbg=
|
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=
|
github.com/zealic/xignore v0.3.3 h1:EpLXUgZY/JEzFkTc+Y/VYypzXtNz+MSOMVCGW5Q4CKQ=
|
||||||
@@ -1017,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.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
|
||||||
go.etcd.io/bbolt v1.3.3 h1:MUGmc65QhB3pIlaQ5bB4LwqSj6GIonVJXpZiaKNyaKk=
|
go.etcd.io/bbolt v1.3.3 h1:MUGmc65QhB3pIlaQ5bB4LwqSj6GIonVJXpZiaKNyaKk=
|
||||||
go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
|
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.15.0/go.mod h1:UffZAU+4sDEINUGP/B7UfBBkq4fqLu9zXAX7ke6CHW0=
|
||||||
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
|
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 h1:C9hSCOW830chIVkdja34wa6Ky+IzWllkUinR+BtRZd4=
|
||||||
go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
|
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 h1:75k/FF0Q2YM8QYo07VPddOLBslDt1MZOdEslOHvmzAs=
|
||||||
go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
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/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/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=
|
go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
|
||||||
gocloud.dev v0.18.0 h1:HX6uFZYZs9tUP87jzoWgB8dl4ihsRpiAsBDKTthiApY=
|
gocloud.dev v0.18.0 h1:HX6uFZYZs9tUP87jzoWgB8dl4ihsRpiAsBDKTthiApY=
|
||||||
gocloud.dev v0.18.0/go.mod h1:lhLOb91+9tKB8RnNlsx+weJGEd0AHM94huK1bmrhPwM=
|
gocloud.dev v0.18.0/go.mod h1:lhLOb91+9tKB8RnNlsx+weJGEd0AHM94huK1bmrhPwM=
|
||||||
@@ -1043,19 +1072,21 @@ 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-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-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-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-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 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-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-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-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-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-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-20191122220453-ac88ee75c92c/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||||
golang.org/x/crypto v0.0.0-20200128174031-69ecbb4d6d5d h1:9FCpayM9Egr1baVnV1SX0H87m+XB0B8S0hAMi99X/3U=
|
golang.org/x/crypto v0.0.0-20200128174031-69ecbb4d6d5d h1:9FCpayM9Egr1baVnV1SX0H87m+XB0B8S0hAMi99X/3U=
|
||||||
golang.org/x/crypto v0.0.0-20200128174031-69ecbb4d6d5d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
golang.org/x/crypto v0.0.0-20200128174031-69ecbb4d6d5d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||||
|
golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||||
golang.org/x/crypto v0.0.0-20200311171314-f7b00557c8c4 h1:QmwruyY+bKbDDL0BaglrbZABEali68eoMFhTZpCjYVA=
|
golang.org/x/crypto v0.0.0-20200311171314-f7b00557c8c4 h1:QmwruyY+bKbDDL0BaglrbZABEali68eoMFhTZpCjYVA=
|
||||||
golang.org/x/crypto v0.0.0-20200311171314-f7b00557c8c4/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
golang.org/x/crypto v0.0.0-20200311171314-f7b00557c8c4/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||||
@@ -1073,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-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/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-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-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
|
||||||
golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||||
@@ -1101,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-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-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-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-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-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
@@ -1123,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-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-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-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-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-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 h1:efeOvDhwQ29Dj3SdAV/MJf8oukgn+8D8WgaCaRMchF8=
|
||||||
golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
@@ -1136,6 +1165,8 @@ golang.org/x/net v0.0.0-20200202094626-16171245cfb2 h1:CCH4IOTTfewWjGOlSp+zGcjut
|
|||||||
golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b h1:0mm1VjtFUOIlE1SbDlwjYaDxZVDP2S5ou6y0gSgXHu8=
|
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b h1:0mm1VjtFUOIlE1SbDlwjYaDxZVDP2S5ou6y0gSgXHu8=
|
||||||
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
|
golang.org/x/net v0.0.0-20200301022130-244492dfa37a h1:GuSPYbZzB5/dcLNCwLQLsg3obCJtX9IJhpXkvY7kzk0=
|
||||||
|
golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||||
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421 h1:Wo7BWFiOk0QRFMLYMqJGFMd9CgUAcGx7V+qEg/h5IBI=
|
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421 h1:Wo7BWFiOk0QRFMLYMqJGFMd9CgUAcGx7V+qEg/h5IBI=
|
||||||
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||||
@@ -1165,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.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 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
|
||||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
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-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 h1:SvFZT6jyqRaOeXpc5h/JSfZenJ2O330aBsf7JfSUXmQ=
|
||||||
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||||
@@ -1172,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/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-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-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-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-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-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-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-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-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-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-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
|
||||||
golang.org/x/tools v0.0.0-20190308174544-00c44ba9c14f/go.mod h1:25r3+/G6/xytQM8iWZKq3Hn0kr0rgFKPUNVEL/dr3z4=
|
golang.org/x/tools v0.0.0-20190308174544-00c44ba9c14f/go.mod h1:25r3+/G6/xytQM8iWZKq3Hn0kr0rgFKPUNVEL/dr3z4=
|
||||||
@@ -1198,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-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-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-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=
|
golang.org/x/tools v0.0.0-20190624222133-a101b041ded4/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||||
@@ -1207,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-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-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-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-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-20191004055002-72853e10c5a3/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||||
golang.org/x/tools v0.0.0-20191010075000-0337d82405ff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
golang.org/x/tools v0.0.0-20191010075000-0337d82405ff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||||
@@ -1230,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/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-20190313105609-8cb42192e0e0/go.mod h1:wa6Ws7BG/ESfp6dHfk7C6KdzKA7wR7u/rKwOGE66zvw=
|
||||||
gonum.org/v1/netlib v0.0.0-20190331212654-76723241ea4e/go.mod h1:kS+toOQn6AQKjmKJ7gzohV1XkqsFehRA2FbsbkopSuQ=
|
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.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=
|
google.golang.org/api v0.5.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
|
||||||
@@ -1252,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.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0=
|
||||||
google.golang.org/appengine v1.6.5 h1:tycE03LOZYQNhDpS27tcQdAzLCVMaj7QT2SXxebnpCM=
|
google.golang.org/appengine v1.6.5 h1:tycE03LOZYQNhDpS27tcQdAzLCVMaj7QT2SXxebnpCM=
|
||||||
google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
|
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 h1:Nw54tB0rB7hY/N0NQvRW8DG4Yk3Q6T9cu9RcFQDu1tc=
|
||||||
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
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-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-20190404172233-64821d5d2107/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||||
google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||||
@@ -1268,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 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-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-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-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-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
||||||
google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
||||||
@@ -1277,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-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 h1:c8OBoXP3kTbDWWB/oVE3FkR851p4iZ3MPadz7zXEIPU=
|
||||||
google.golang.org/genproto v0.0.0-20200128133413-58ce757ed39b/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
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.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.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||||
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
|
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
|
||||||
google.golang.org/grpc v1.21.0 h1:G+97AoqBnmZIT91cLG/EkCoK9NSelj64P8bOHHNmGn0=
|
google.golang.org/grpc v1.21.0 h1:G+97AoqBnmZIT91cLG/EkCoK9NSelj64P8bOHHNmGn0=
|
||||||
@@ -1286,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.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
|
||||||
google.golang.org/grpc v1.22.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
|
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.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 h1:vb/1TCsVn3DcJlQ0Gs1yB1pKI6Do2/QNwxdKqmc/b0s=
|
||||||
google.golang.org/grpc v1.24.0/go.mod h1:XDChyiUovWa60DnaeDeZmSW86xtLtjtZbwvSiRnRtcA=
|
google.golang.org/grpc v1.24.0/go.mod h1:XDChyiUovWa60DnaeDeZmSW86xtLtjtZbwvSiRnRtcA=
|
||||||
google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
|
google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
|
||||||
@@ -1295,15 +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/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/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 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 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-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 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-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/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 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4=
|
||||||
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
|
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/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 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc=
|
||||||
gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
|
gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
|
||||||
gopkg.in/ini.v1 v1.51.0 h1:AQvPpx3LzTDM0AjnIRlVFwFFGC+npRopjZxLJj6gdno=
|
gopkg.in/ini.v1 v1.51.0 h1:AQvPpx3LzTDM0AjnIRlVFwFFGC+npRopjZxLJj6gdno=
|
||||||
@@ -1311,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/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/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/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.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 h1:SK5KegNXmKmqE342YYN2qPHEnUYeoMiXXl1poUlI+o4=
|
||||||
gopkg.in/square/go-jose.v2 v2.3.1/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI=
|
gopkg.in/square/go-jose.v2 v2.3.1/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI=
|
||||||
@@ -1340,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 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 h1:d+tVGRu6X0ZBQ+kyAR8JKi6AXhTP2gmQaoIYaGFz634=
|
||||||
gotest.tools/v3 v3.0.0/go.mod h1:TUP+/YtXl/dp++T+SZ5v2zUmLVBHmptSb/ajDLCJ+3c=
|
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.1.2 h1:VpNzaNv2DX4aRnOCcV7v5Of+XT2SZrJ8iOQ25AGKOos=
|
||||||
helm.sh/helm/v3 v3.0.2/go.mod h1:KBxE6XWO57XSNA1PA9CvVLYRY0zWqYQTad84bNXp1lw=
|
helm.sh/helm/v3 v3.1.2/go.mod h1:WYsFJuMASa/4XUqLyv54s0U/f3mlAaRErGmyy4z921g=
|
||||||
honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
|
||||||
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
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-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||||
honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||||
@@ -1350,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 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=
|
||||||
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 h1:H9d/lw+VkZKEVIUc8F3wgiQ+FUXTTr21M87jXLU7yqM=
|
||||||
k8s.io/api v0.17.0/go.mod h1:npsyOePkeP0CPwyGfXDHxvypiYMJxBWAMpQxCaJ4ZxI=
|
k8s.io/api v0.17.0/go.mod h1:npsyOePkeP0CPwyGfXDHxvypiYMJxBWAMpQxCaJ4ZxI=
|
||||||
k8s.io/apiextensions-apiserver v0.0.0-20191016113550-5357c4baaf65 h1:kThoiqgMsSwBdMK/lPgjtYTsEjbUU9nXCA9DyU3feok=
|
k8s.io/api v0.17.2 h1:NF1UFXcKN7/OOv1uxdRz3qfra8AHsPav5M93hlV9+Dc=
|
||||||
k8s.io/apiextensions-apiserver v0.0.0-20191016113550-5357c4baaf65/go.mod h1:5BINdGqggRXXKnDgpwoJ7PyQH8f+Ypp02fvVNcIFy9s=
|
k8s.io/api v0.17.2/go.mod h1:BS9fjjLc4CMuqfSO8vgbHPKMt5+SF0ET6u/RVDihTo4=
|
||||||
k8s.io/apimachinery v0.0.0-20191004115801-a2eda9f80ab8 h1:Iieh/ZEgT3BWwbLD5qEKcY06jKuPEl6zC7gPSehoLw4=
|
k8s.io/apiextensions-apiserver v0.17.2 h1:cP579D2hSZNuO/rZj9XFRzwJNYb41DbNANJb6Kolpss=
|
||||||
k8s.io/apimachinery v0.0.0-20191004115801-a2eda9f80ab8/go.mod h1:llRdnznGEAqC3DcNm6yEj472xaFVfLM7hnYofMb12tQ=
|
k8s.io/apiextensions-apiserver v0.17.2/go.mod h1:4KdMpjkEjjDI2pPfBA15OscyNldHWdBCfsWMDWAmSTs=
|
||||||
k8s.io/apiserver v0.0.0-20191016112112-5190913f932d/go.mod h1:7OqfAolfWxUM/jJ/HBLyE+cdaWFBUoo5Q5pHgJVj2ws=
|
k8s.io/apimachinery v0.17.0 h1:xRBnuie9rXcPxUkDizUsGvPf1cnlZCFu210op7J7LJo=
|
||||||
k8s.io/cli-runtime v0.0.0-20191016114015-74ad18325ed5 h1:8ZfMjkMBzcXEawLsYHg9lDM7aLEVso3NiVKfUTnN56A=
|
k8s.io/apimachinery v0.17.0/go.mod h1:b9qmWdKlLuU9EBh+06BtLcSf/Mu89rWL33naRxs1uZg=
|
||||||
k8s.io/cli-runtime v0.0.0-20191016114015-74ad18325ed5/go.mod h1:sDl6WKSQkDM6zS1u9F49a0VooQ3ycYFBFLqd2jf2Xfo=
|
k8s.io/apiserver v0.17.2/go.mod h1:lBmw/TtQdtxvrTk0e2cgtOxHizXI+d0mmGQURIHQZlo=
|
||||||
k8s.io/client-go v0.0.0-20191016111102-bec269661e48 h1:C2XVy2z0dV94q9hSSoCuTPp1KOG7IegvbdXuz9VGxoU=
|
k8s.io/cli-runtime v0.0.0-20191214191754-e6dc6d5c8724/go.mod h1:wzlq80lvjgHW9if6MlE4OIGC86MDKsy5jtl9nxz/IYY=
|
||||||
k8s.io/client-go v0.0.0-20191016111102-bec269661e48/go.mod h1:hrwktSwYGI4JK+TJA3dMaFyyvHVi/aLarVHpbs8bgCU=
|
k8s.io/cli-runtime v0.17.2 h1:YH4txSplyGudvxjhAJeHEtXc7Tr/16clKGfN076ydGk=
|
||||||
k8s.io/code-generator v0.0.0-20191004115455-8e001e5d1894/go.mod h1:mJUgkl06XV4kstAnLHAIzJPVCOzVR+ZcfPIv4fUsFCY=
|
k8s.io/cli-runtime v0.17.2/go.mod h1:aa8t9ziyQdbkuizkNLAw3qe3srSyWh9zlSB7zTqRNPI=
|
||||||
k8s.io/component-base v0.0.0-20191016111319-039242c015a9/go.mod h1:SuWowIgd/dtU/m/iv8OD9eOxp3QZBBhTIiWMsBQvKjI=
|
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-20190128074634-0689ccc1d7d6/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0=
|
||||||
k8s.io/gengo v0.0.0-20190822140433-26a664648505/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.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.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 h1:Pt+yjF5aB1xDSVbau4VsWe+dQNzA0qv1LlXdC2dF6Q8=
|
||||||
k8s.io/klog v1.0.0/go.mod h1:4Bi6QPql/J/LkTDqv7R/cd3hPo4k2DG6Ptcz060Ez5I=
|
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 h1:UcxjrRMyNx/i/y8G7kPvLyy7rfbeuf1PYyBf973pgyU=
|
||||||
k8s.io/kube-openapi v0.0.0-20191107075043-30be4d16710a/go.mod h1:1TqjTSzOxsLGIKfj0lK8EeCP7K1iUG65v09OM0/WG5E=
|
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-20191219154910-1528d4eea6dd h1:nZX5+wEqTu/EBIYjrZlFOA63z4+Zcy96lDkCZPU9a9c=
|
||||||
k8s.io/kubectl v0.0.0-20191016120415-2ed914427d51/go.mod h1:gL826ZTIfD4vXTGlmzgTbliCAT9NGiqpCqK2aNYv5MQ=
|
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/kubernetes v1.13.0/go.mod h1:ocZa8+6APFNC2tX1DZASIbocyYT5jHzqFVsY5aoB7Jk=
|
||||||
k8s.io/metrics v0.0.0-20191016113814-3b1a734dba6e/go.mod h1:ve7/vMWeY5lEBkZf6Bt5TTbGS3b8wAxwGbdXAsufjRs=
|
k8s.io/metrics v0.0.0-20191214191643-6b1944c9f765/go.mod h1:5V7rewilItwK0cz4nomU0b3XCcees2Ka5EBYWS1HBeM=
|
||||||
k8s.io/utils v0.0.0-20190801114015-581e00157fb1/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew=
|
k8s.io/utils v0.0.0-20191114184206-e782cd3c129f h1:GiPwtSzdP43eI1hpPCbROQCCIgCuiMMNF8YUVLF3vJo=
|
||||||
k8s.io/utils v0.0.0-20191010214722-8d271d903fe4 h1:Gi+/O1saihwDqnlmC8Vhv1M5Sp4+rbOmK9TbsLn8ZEA=
|
k8s.io/utils v0.0.0-20191114184206-e782cd3c129f/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew=
|
||||||
k8s.io/utils v0.0.0-20191010214722-8d271d903fe4/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew=
|
|
||||||
modernc.org/cc v1.0.0/go.mod h1:1Sk4//wdnYJiUIxnW8ddKpaOJCF37yAdqYnkxUpaYxw=
|
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/golex v1.0.0/go.mod h1:b/QX9oBD/LhixY6NDh+IdGv17hgB+51fET1i2kPSmvk=
|
||||||
modernc.org/mathutil v1.0.0/go.mod h1:wU0vUrJsVWBZ4P6e7xtFJEhFSNsfRLJ8H458uRjg03k=
|
modernc.org/mathutil v1.0.0/go.mod h1:wU0vUrJsVWBZ4P6e7xtFJEhFSNsfRLJ8H458uRjg03k=
|
||||||
@@ -1392,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=
|
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=
|
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/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.3 h1:H7xDfhkaFFSYEJlKeq38RwX2jYcnTeHuDQyT+mMNMwM=
|
||||||
rsc.io/letsencrypt v0.0.1/go.mod h1:buyQKZ6IXrRnB7TdkHP0RyEybLx18HHyOSoTyoOLqNY=
|
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 h1:JUufWFNlI44MdtnjUqVnvh29rR37PQFzPbLXqhyOyX0=
|
||||||
sigs.k8s.io/kustomize v2.0.3+incompatible/go.mod h1:MkjgH3RdOWrievjo6c9T245dYlB5QeXV4WCbnt/PEpU=
|
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-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 h1:4A07+ZFc2wgJwo8YNlQpr1rVlgUDlxXHhPJciaPY5gs=
|
||||||
sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o=
|
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=
|
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=
|
||||||
|
|||||||
@@ -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'
|
repo_url: 'https://github.com/qlik-oss/sense-installer'
|
||||||
strict: true
|
strict: true
|
||||||
theme:
|
theme:
|
||||||
@@ -19,6 +19,5 @@ nav:
|
|||||||
- getting_started.md
|
- getting_started.md
|
||||||
- command_reference.md
|
- command_reference.md
|
||||||
- concepts.md
|
- concepts.md
|
||||||
- preflight_checks.md
|
|
||||||
- air_gap.md
|
- air_gap.md
|
||||||
- Releases ⧉: https://github.com/qlik-oss/sense-installer/releases
|
- Releases ⧉: https://github.com/qlik-oss/sense-installer/releases
|
||||||
|
|||||||
153
pkg/api/apis.go
153
pkg/api/apis.go
@@ -1,11 +1,9 @@
|
|||||||
package api
|
package api
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"crypto/rsa"
|
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"log"
|
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
@@ -23,6 +21,7 @@ const (
|
|||||||
qliksenseContextsDirName = "contexts"
|
qliksenseContextsDirName = "contexts"
|
||||||
qliksenseSecretsDirName = "secrets"
|
qliksenseSecretsDirName = "secrets"
|
||||||
qliksenseEjsonDirName = "ejson"
|
qliksenseEjsonDirName = "ejson"
|
||||||
|
QLIK_GIT_REPO = "https://github.com/qlik-oss/qliksense-k8s"
|
||||||
)
|
)
|
||||||
|
|
||||||
// NewQConfig create QliksenseConfig object from file ~/.qliksense/config.yaml
|
// NewQConfig create QliksenseConfig object from file ~/.qliksense/config.yaml
|
||||||
@@ -144,6 +143,66 @@ func (cr *QliksenseCR) IsRepoExist() bool {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (cr *QliksenseCR) GetFetchUrl() string {
|
||||||
|
if cr.Spec.FetchSource == nil || cr.Spec.FetchSource.Repository == "" {
|
||||||
|
return QLIK_GIT_REPO
|
||||||
|
}
|
||||||
|
return cr.Spec.FetchSource.Repository
|
||||||
|
}
|
||||||
|
|
||||||
|
func (cr *QliksenseCR) GetFetchAccessToken(encryptionKey string) string {
|
||||||
|
if cr.Spec.FetchSource == nil {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
if tok, err := cr.Spec.FetchSource.GetAccessToken(); err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
return ""
|
||||||
|
} else {
|
||||||
|
by, _ := b64.StdEncoding.DecodeString(tok)
|
||||||
|
res, err := DecryptData(by, encryptionKey)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
return string(res)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (cr *QliksenseCR) SetFetchUrl(url string) {
|
||||||
|
if cr.Spec.FetchSource == nil {
|
||||||
|
cr.Spec.FetchSource = &config.Repo{}
|
||||||
|
}
|
||||||
|
cr.Spec.FetchSource.Repository = url
|
||||||
|
}
|
||||||
|
|
||||||
|
func (cr *QliksenseCR) SetFetchAccessToken(token, encryptionKey string) error {
|
||||||
|
if cr.Spec.FetchSource == nil {
|
||||||
|
cr.Spec.FetchSource = &config.Repo{}
|
||||||
|
}
|
||||||
|
res, err := EncryptData([]byte(token), encryptionKey)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
cr.Spec.FetchSource.AccessToken = b64.StdEncoding.EncodeToString(res)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (cr *QliksenseCR) SetFetchAccessSecretName(sec string) {
|
||||||
|
if cr.Spec.FetchSource == nil {
|
||||||
|
cr.Spec.FetchSource = &config.Repo{}
|
||||||
|
}
|
||||||
|
cr.Spec.FetchSource.SecretName = sec
|
||||||
|
}
|
||||||
|
|
||||||
|
//DeleteRepo delete the manifest repo and unset manifestsRoot
|
||||||
|
func (cr *QliksenseCR) DeleteRepo() error {
|
||||||
|
if err := os.RemoveAll(cr.Spec.ManifestsRoot); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
cr.Spec.ManifestsRoot = ""
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func (qc *QliksenseConfig) IsRepoExist(contextName, version string) bool {
|
func (qc *QliksenseConfig) IsRepoExist(contextName, version string) bool {
|
||||||
if _, err := os.Lstat(qc.BuildRepoPathForContext(contextName, version)); err != nil {
|
if _, err := os.Lstat(qc.BuildRepoPathForContext(contextName, version)); err != nil {
|
||||||
return false
|
return false
|
||||||
@@ -158,6 +217,11 @@ func (qc *QliksenseConfig) IsRepoExistForCurrent(version string) bool {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (qc *QliksenseConfig) DeleteRepoForCurrent(version string) error {
|
||||||
|
path := qc.BuildRepoPath(version)
|
||||||
|
return os.RemoveAll(path)
|
||||||
|
}
|
||||||
|
|
||||||
func (qc *QliksenseConfig) BuildRepoPath(version string) string {
|
func (qc *QliksenseConfig) BuildRepoPath(version string) string {
|
||||||
return qc.BuildRepoPathForContext(qc.Spec.CurrentContext, version)
|
return qc.BuildRepoPathForContext(qc.Spec.CurrentContext, version)
|
||||||
}
|
}
|
||||||
@@ -258,9 +322,9 @@ func (qc *QliksenseConfig) GetCurrentContextSecretsDir() (string, error) {
|
|||||||
func (qc *QliksenseConfig) setDockerConfigJsonSecret(filename string, dockerConfigJsonSecret *DockerConfigJsonSecret) error {
|
func (qc *QliksenseConfig) setDockerConfigJsonSecret(filename string, dockerConfigJsonSecret *DockerConfigJsonSecret) error {
|
||||||
if secretsDir, err := qc.GetCurrentContextSecretsDir(); err != nil {
|
if secretsDir, err := qc.GetCurrentContextSecretsDir(); err != nil {
|
||||||
return err
|
return err
|
||||||
} else if publicKey, _, err := qc.GetCurrentContextEncryptionKeyPair(); err != nil {
|
} else if encryptionKey, err := qc.GetEncryptionKeyForCurrent(); err != nil {
|
||||||
return err
|
return err
|
||||||
} else if dockerConfigJsonSecretYaml, err := dockerConfigJsonSecret.ToYaml(publicKey); err != nil {
|
} else if dockerConfigJsonSecretYaml, err := dockerConfigJsonSecret.ToYaml(encryptionKey); err != nil {
|
||||||
return err
|
return err
|
||||||
} else if err := os.MkdirAll(secretsDir, os.ModePerm); err != nil {
|
} else if err := os.MkdirAll(secretsDir, os.ModePerm); err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -307,9 +371,9 @@ func (qc *QliksenseConfig) getDockerConfigJsonSecret(name string) (*DockerConfig
|
|||||||
return nil, err
|
return nil, err
|
||||||
} else if dockerConfigJsonSecretYaml, err := ioutil.ReadFile(filepath.Join(secretsDir, name)); err != nil {
|
} else if dockerConfigJsonSecretYaml, err := ioutil.ReadFile(filepath.Join(secretsDir, name)); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
} else if _, privateKey, err := qc.GetCurrentContextEncryptionKeyPair(); err != nil {
|
} else if encryptionKey, err := qc.GetEncryptionKeyForCurrent(); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
} else if err := dockerConfigJsonSecret.FromYaml(dockerConfigJsonSecretYaml, privateKey); err != nil {
|
} else if err := dockerConfigJsonSecret.FromYaml(dockerConfigJsonSecretYaml, encryptionKey); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return dockerConfigJsonSecret, nil
|
return dockerConfigJsonSecret, nil
|
||||||
@@ -320,11 +384,11 @@ func (qc *QliksenseConfig) getCurrentContextEncryptionKeyPairLocation() (string,
|
|||||||
if qcr, err := qc.GetCurrentCR(); err != nil {
|
if qcr, err := qc.GetCurrentCR(); err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
} else {
|
} else {
|
||||||
return qc.getContextEncryptionKeyPairLocation(qcr.GetName())
|
return qc.getContextEncryptionKeyLocation(qcr.GetName())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (qc *QliksenseConfig) getContextEncryptionKeyPairLocation(contextName string) (string, error) {
|
func (qc *QliksenseConfig) getContextEncryptionKeyLocation(contextName string) (string, error) {
|
||||||
// Check env var: QLIKSENSE_KEY_LOCATION to determine location to store keypair
|
// Check env var: QLIKSENSE_KEY_LOCATION to determine location to store keypair
|
||||||
var secretKeyPairLocation string
|
var secretKeyPairLocation string
|
||||||
if os.Getenv("QLIKSENSE_KEY_LOCATION") != "" {
|
if os.Getenv("QLIKSENSE_KEY_LOCATION") != "" {
|
||||||
@@ -334,9 +398,9 @@ func (qc *QliksenseConfig) getContextEncryptionKeyPairLocation(contextName strin
|
|||||||
// QLIKSENSE_KEY_LOCATION has not been set, hence storing key pair in default location:
|
// QLIKSENSE_KEY_LOCATION has not been set, hence storing key pair in default location:
|
||||||
// /.qliksense/secrets/contexts/<current-context>/secrets/
|
// /.qliksense/secrets/contexts/<current-context>/secrets/
|
||||||
secretKeyPairLocation = filepath.Join(qc.QliksenseHomePath, qliksenseSecretsDirName, qliksenseContextsDirName, contextName, qliksenseSecretsDirName)
|
secretKeyPairLocation = filepath.Join(qc.QliksenseHomePath, qliksenseSecretsDirName, qliksenseContextsDirName, contextName, qliksenseSecretsDirName)
|
||||||
|
|
||||||
}
|
}
|
||||||
return secretKeyPairLocation, nil
|
|
||||||
|
return secretKeyPairLocation, os.MkdirAll(secretKeyPairLocation, os.ModePerm)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (qc *QliksenseConfig) GetCurrentContextEjsonKeyDir() (string, error) {
|
func (qc *QliksenseConfig) GetCurrentContextEjsonKeyDir() (string, error) {
|
||||||
@@ -351,52 +415,25 @@ func (qc *QliksenseConfig) GetCurrentContextEjsonKeyDir() (string, error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (qc *QliksenseConfig) GetCurrentContextEncryptionKeyPair() (*rsa.PublicKey, *rsa.PrivateKey, error) {
|
func (qc *QliksenseConfig) GetEncryptionKeyForCurrent() (string, error) {
|
||||||
if qcr, err := qc.GetCurrentCR(); err != nil {
|
if qcr, err := qc.GetCurrentCR(); err != nil {
|
||||||
return nil, nil, err
|
return "", err
|
||||||
} else {
|
} else {
|
||||||
return qc.GetContextEncryptionKeyPair(qcr.GetName())
|
return qc.GetEncryptionKeyFor(qcr.GetName())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (qc *QliksenseConfig) GetContextEncryptionKeyPair(contextName string) (*rsa.PublicKey, *rsa.PrivateKey, error) {
|
func (qc *QliksenseConfig) GetEncryptionKeyFor(contextName string) (string, error) {
|
||||||
secretKeyPairLocation, err := qc.getContextEncryptionKeyPairLocation(contextName)
|
secretKeyLocation, err := qc.getContextEncryptionKeyLocation(contextName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return "", err
|
||||||
}
|
}
|
||||||
|
key, err := LoadSecretKey(secretKeyLocation)
|
||||||
publicKeyFilePath := filepath.Join(secretKeyPairLocation, QliksensePublicKey)
|
if key != "" {
|
||||||
privateKeyFilePath := filepath.Join(secretKeyPairLocation, QliksensePrivateKey)
|
return key, nil
|
||||||
// try to create the dir if it doesn't exist
|
|
||||||
if !FileExists(publicKeyFilePath) || !FileExists(privateKeyFilePath) {
|
|
||||||
LogDebugMessage("Qliksense secretKeyLocation dir does not exist, creating it now: %s", secretKeyPairLocation)
|
|
||||||
if err := os.MkdirAll(secretKeyPairLocation, os.ModePerm); err != nil {
|
|
||||||
err = fmt.Errorf("Not able to create %s dir: %v", secretKeyPairLocation, err)
|
|
||||||
log.Println(err)
|
|
||||||
return nil, nil, err
|
|
||||||
}
|
|
||||||
// generating and storing key-pair
|
|
||||||
err1 := GenerateAndStoreSecretKeypair(secretKeyPairLocation)
|
|
||||||
if err1 != nil {
|
|
||||||
err1 = fmt.Errorf("Not able to generate and store key pair for encryption")
|
|
||||||
log.Println(err1)
|
|
||||||
return nil, nil, err1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if publicKeyBytes, err := ReadKeys(publicKeyFilePath); err != nil {
|
|
||||||
LogDebugMessage("Not able to read public key")
|
|
||||||
return nil, nil, err
|
|
||||||
} else if privateKeyBytes, err := ReadKeys(privateKeyFilePath); err != nil {
|
|
||||||
LogDebugMessage("Not able to read private key")
|
|
||||||
return nil, nil, err
|
|
||||||
} else if rsaPublicKey, err := DecodeToPublicKey(publicKeyBytes); err != nil {
|
|
||||||
return nil, nil, err
|
|
||||||
} else if rsaPrivateKey, err := DecodeToPrivateKey(privateKeyBytes); err != nil {
|
|
||||||
return nil, nil, err
|
|
||||||
} else {
|
|
||||||
return rsaPublicKey, rsaPrivateKey, nil
|
|
||||||
}
|
}
|
||||||
|
fmt.Println("Generating new encryption key for the context: " + contextName)
|
||||||
|
return GenerateAndStoreSecretKey(secretKeyLocation)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cr *QliksenseCR) AddLabelToCr(key, value string) {
|
func (cr *QliksenseCR) AddLabelToCr(key, value string) {
|
||||||
@@ -421,17 +458,6 @@ func (cr *QliksenseCR) GetString() (string, error) {
|
|||||||
return string(out), nil
|
return string(out), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cr *QliksenseCR) GetImageRegistry() string {
|
|
||||||
for _, nameValues := range cr.Spec.Configs {
|
|
||||||
for _, nameValue := range nameValues {
|
|
||||||
if nameValue.Name == "imageRegistry" {
|
|
||||||
return nameValue.Value
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
func (cr *QliksenseCR) GetK8sSecretsFolder(qlikSenseHomeDir string) string {
|
func (cr *QliksenseCR) GetK8sSecretsFolder(qlikSenseHomeDir string) string {
|
||||||
return filepath.Join(qlikSenseHomeDir, qliksenseContextsDirName, cr.GetName(), qliksenseSecretsDirName)
|
return filepath.Join(qlikSenseHomeDir, qliksenseContextsDirName, cr.GetName(), qliksenseSecretsDirName)
|
||||||
}
|
}
|
||||||
@@ -469,7 +495,7 @@ func (cr *QliksenseCR) GetCustomCrdsPath() string {
|
|||||||
func (qc *QliksenseConfig) GetDecryptedCr(cr *QliksenseCR) (*QliksenseCR, error) {
|
func (qc *QliksenseConfig) GetDecryptedCr(cr *QliksenseCR) (*QliksenseCR, error) {
|
||||||
newCr := &QliksenseCR{}
|
newCr := &QliksenseCR{}
|
||||||
copier.Copy(newCr, cr)
|
copier.Copy(newCr, cr)
|
||||||
_, rsaPrivateKey, err := qc.GetCurrentContextEncryptionKeyPair()
|
encryptionKey, err := qc.GetEncryptionKeyFor(cr.GetName())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -482,7 +508,7 @@ func (qc *QliksenseConfig) GetDecryptedCr(cr *QliksenseCR) (*QliksenseCR, error)
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
db, err := Decrypt(b, rsaPrivateKey)
|
db, err := DecryptData(b, encryptionKey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -495,6 +521,11 @@ func (qc *QliksenseConfig) GetDecryptedCr(cr *QliksenseCR) (*QliksenseCR, error)
|
|||||||
finalSecrets[k] = newNvs
|
finalSecrets[k] = newNvs
|
||||||
}
|
}
|
||||||
newCr.Spec.Secrets = finalSecrets
|
newCr.Spec.Secrets = finalSecrets
|
||||||
|
|
||||||
|
if newCr.Spec.FetchSource != nil && newCr.Spec.FetchSource.AccessToken != "" {
|
||||||
|
decData := cr.GetFetchAccessToken(encryptionKey)
|
||||||
|
newCr.Spec.FetchSource.AccessToken = decData
|
||||||
|
}
|
||||||
return newCr, nil
|
return newCr, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package api
|
package api
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
b64 "encoding/base64"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"log"
|
"log"
|
||||||
@@ -52,12 +53,6 @@ spec:
|
|||||||
qliksense:
|
qliksense:
|
||||||
- name: acceptEULA
|
- name: acceptEULA
|
||||||
value: "yes"
|
value: "yes"
|
||||||
secrets:
|
|
||||||
qliksense:
|
|
||||||
- name: mongoDbUri
|
|
||||||
# this is rsa encrypted value, the pub and pri keys are in setuPublicAndPrivateKey() method
|
|
||||||
# actual value: mongodb://qlik-default-mongodb:27017/qliksense?ssl=false
|
|
||||||
value: n/pDi7Z/A3i16cAHFFwMp19/egNKc8WZxm6MKHLT/B1DMv3U6pDXWyXT5fYYDV1wDTO3Vk43yECST1UgZYmMpgUOwgSfGgqTVi2VqS0JQsnwI+Twwhnvha8RJANX8b/XIoSFVWaOgy7+RP35ZkvOqHdCfC2aT8JMIHgBQqqCbsNgimCuRSxi0klR000ic/Tp5PYSz5mD+WLrkPw2FbS0OVBsQ/hIp5GZrmVpvEOZdbT63Sz+n/G4Br6GTv2LkZcU7JBuKQm2wfB+mRjJmJnNrPawLfn2UZ89Rz0BLwIy+6b24/RoIUgoNowfGkJreGiwItGK8fjCcx11oavK/yAo6pYZXCcru46pmHbxxle1OlkdTKkG6EVtJuKjSZXtVmBHZYRFzsR7HnAiXnL7QzSEcS7ieZlQvTmNLfpidJhK199oSbyKREqXGl2S8DzPKM9RLccVbQTy6X8qWimP3MYCnO4K0KoQnNQAgfuV8ZxnvdDecByLDPIpmFMGy0Xm9pUZWxmSoDBq+p5WBI2HdCX2gCYVv5yxS2iBqO5SMKo8iOglHtPI9NIMvloERdN1vZtxSRkY5uDEfrU9ysYwfayEXxvXmdWv0HxlotcgUinP02j7k+OfIapTmY/jGfvF4euyCGRKuJ9JlSD9pIiRdAcekjL6hCxXLJLdajCV4sL/YDo=
|
|
||||||
`
|
`
|
||||||
ctx1Dir := filepath.Join(homeDir, "contexts", "contx1")
|
ctx1Dir := filepath.Join(homeDir, "contexts", "contx1")
|
||||||
crFile := filepath.Join(ctx1Dir, "contx1.yaml")
|
crFile := filepath.Join(ctx1Dir, "contx1.yaml")
|
||||||
@@ -106,13 +101,16 @@ func TestGetDecryptedCr(t *testing.T) {
|
|||||||
t.Fail()
|
t.Fail()
|
||||||
t.Log(e)
|
t.Log(e)
|
||||||
}
|
}
|
||||||
qcr, err := qct.GetCurrentCR()
|
|
||||||
if err != nil {
|
|
||||||
t.Fail()
|
|
||||||
t.Log(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
setuPublicAndPrivateKey(dir)
|
qcr, err := qct.GetCurrentCR()
|
||||||
|
|
||||||
|
key, _ := setupGenerateKey(dir)
|
||||||
|
ecn, _ := EncryptData([]byte("mongodb://qlik-default-mongodb:27017/qliksense?ssl=false"), key)
|
||||||
|
b := b64.StdEncoding.EncodeToString(ecn)
|
||||||
|
qcr.Spec.AddToSecrets("qliksense", "mongoDbUri", b, "")
|
||||||
|
|
||||||
|
qcr.SetFetchAccessToken("mytoken", key)
|
||||||
|
|
||||||
newCr, err := qct.GetDecryptedCr(qcr)
|
newCr, err := qct.GetDecryptedCr(qcr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fail()
|
t.Fail()
|
||||||
@@ -129,77 +127,12 @@ func TestGetDecryptedCr(t *testing.T) {
|
|||||||
if decryptedValue == orignalValue {
|
if decryptedValue == orignalValue {
|
||||||
t.Fail()
|
t.Fail()
|
||||||
}
|
}
|
||||||
|
if newCr.Spec.FetchSource.AccessToken != "mytoken" {
|
||||||
|
t.Fail()
|
||||||
|
}
|
||||||
td()
|
td()
|
||||||
}
|
}
|
||||||
func setuPublicAndPrivateKey(homeDir string) ([]byte, []byte, error) {
|
func setupGenerateKey(homeDir string) (string, error) {
|
||||||
privKeyBytes := []byte(`-----BEGIN RSA PRIVATE KEY-----
|
|
||||||
MIIJJwIBAAKCAgEAwUCimKCidbF3UxEHPy8K+hvhklRB9JYhj5sJy0if4lTVibkK
|
|
||||||
1MrYCykOnmC40pPU9GLY1b8HxAg9tvyRn0YHUxOra6vVQaVcOVJhTM8D18d+lSr3
|
|
||||||
Lp1yiX+UGT4nzWI9+R1CCbwXrqeQVoZs6QZKynEXMkFI9/wNMOwPOvQFOSTuoEoC
|
|
||||||
O+zyTyUWEkNbUq825ELUQdIsjgmlWUOONudxsAr7ESRXW9QTHVh6uWmr3VRKZHby
|
|
||||||
1JdU3I/wjdlGg5M2dDuXy5nQO9w/nYLjJXiw+zzOetZ/+t7/VOkOpNTeJQhwTM1W
|
|
||||||
F7Y2VLetbi9FHgyzHatrduh07+XEiTbgDf3GIx2bp2p6oh0G3N2zpiLcK/aZj8ro
|
|
||||||
uWWydfFfsU3MZ4FfJDP8I6b9awxjmKYqIr6hiPQCJaLBED8mwK+I5evIbnKv6E6u
|
|
||||||
K+BApWA/R7ElragoFYbqQ1VpvntVMtJt9Dy5ZrI+IQARdXD3bb34oh0IPBhClnvv
|
|
||||||
MUc1cWxDoXEX6oJ4I+LzxE87Zkwnan9qOwengolMVKFwPx1o37qrbmrXID21kKt7
|
|
||||||
FL6xN4HxHLkItr1fKzdyWDFRHgASTAWfx5BIwvPuUW0vZHkvO80VyV2L63whVhPn
|
|
||||||
PASmFkbviomrBttYfpr2aGQqF/qR1Nlxe834MFxk1pS9LMa/WnzvFr0gWakCAwEA
|
|
||||||
AQKCAgARSp9B2N2wejibDiL/3E23I1eDqFZedDB8kPrHXbAwqDaTJCN79spt9TaB
|
|
||||||
pVXkQaYEV/Pe7EDdoX8kKGU/QxzUqiXkdHOYdBtUZbKfFMbbP9ZrsnR7j0r4UpoF
|
|
||||||
yDH3hprU93E5PcNAtW2M0GpeT1nR01yn+n908PCdOAIE3GC7RDq1zOl2QzVLL55R
|
|
||||||
9ATv2Q2oTvJ/ETc7XlGVMx4+e2cIwXLFjeLjLI6pSYlxnarrGuetJZeEviWxto9n
|
|
||||||
odFVZI6yx8JFTXX8ZTCr/1IjwDDVyhMPmrHI2Lsv9cqBpSpbVe32cUkKxhsGaYjz
|
|
||||||
GvesQKamOPhco2ATNxPm0yopFlPsGKMfVl0BK0J6BqFh1BvU/SYJmXfnFuUNO3vV
|
|
||||||
4u2Saa0q1iddxV0rXDwIqUfn+S6rwzK0G7y8bH2yvpB2VwiG3TFPnULep4wsefNq
|
|
||||||
Fj92kqFBjacGpQLEEslUY0CMgeZ2+NuBQSUTscP3wBRsottMR6YXJtINdvfHBx+e
|
|
||||||
EcN71z8D00w3mYqIQ7qb4Ml6HOqknunn58g43L9sACMUMTlEBXa9pUnScNYgWBAz
|
|
||||||
W2q2mH37cIydM2JRZPpA8B4yTHt5ugJmChwyNFM7941arjKrebH+6AzLkofGedOP
|
|
||||||
zg+vZQuPEXWs+3MBBnkWoyJW3Y0fbQdjsuQTtnd+7iyoxoBroQKCAQEA4dIiFlIS
|
|
||||||
MDfRhQQWSiDvaw9aneDEJ3uo63ZRH5tm/IynLgtjYgEm/ZxlBCQgqRKLYELBxhu8
|
|
||||||
SaF0uPK8pmpFJt0mIwSlsdeVhuE2obQeKUCczaqrKeaHS3PdWLjTlwph81BGRkHy
|
|
||||||
qfqtNylyyMxrdEbnR51EtsWgFq6anTUAui1Q09JMuMNZRMOzDs1F4gExgD22rc0V
|
|
||||||
c9YQ+jHJRxBGtNKMpMEqc8cvaxBidbItrN9SMTSWog7uYPBuEuaJ6K9vpgyJMOzJ
|
|
||||||
SYcQEFGqgIqIDCg+ABE4d/4YROMKZ1DV/bJCind9brUHSx6XALsF0nC5c1Q9TnUL
|
|
||||||
qI2khOwts4KYKwKCAQEA2xRC6Az97Vkdzu7BjLJ1FKmx4S2nEEgVS12ds82U+5Xf
|
|
||||||
BHKAJnjqlqmmpzzJG+d77IYktz0+mey1QCNkqlm2fhuKs8LZMnpZRf0l8VcoBsUP
|
|
||||||
/xKz7wfiE7RRFZtLJhPp4hhe43GzX5/JFMWMnC6UykwQbj4t1E/GNM/Suqwvg12M
|
|
||||||
wktAJ6nqLgfhjQSO4xWo+nPzcbX+fNtrPCZVrBhYXihhcwRRNImWUCGJ6J4LMdPY
|
|
||||||
Y9Z59qhOvE9cReH/Xw1av46omyiSyAqlgPyZ/kzA2IJSqYCjiQR/2+RD/g13jpcJ
|
|
||||||
jatXLVZ8MJSL5OTS40G/HHTNNpNHbKKh0GOyxBA3ewKCAQBAn8UXhCcmW2L/YPsL
|
|
||||||
/b7mcX9qPP+FmRLvR23R0MQ5M/tH5wRq8I969n3GIJykJeVzB8eybQ+GNslTgEvS
|
|
||||||
iAkAJTubu+G7MkndTqg2wHf9MDtvdA8Fr646Po8yq7oJuHPtkKR7yLWsRUu6xIbP
|
|
||||||
xgheP0hCq1QVxhqZQyCGKrvpi7xc0gsYuPbcAfFFJCOCmPrUi1SzCkTAYJt9LjA+
|
|
||||||
wP6rErIjGBCRD4iXaBn1OqdtmH9KC5WsDP/VCBlIGWeQCly2NVIxiSHVg+xp7yUP
|
|
||||||
IhXq/L05gbQaSsIhPKQmivCiaJg4The8TdwneDqYf+0bmxzHT203/bD3bImPbJNr
|
|
||||||
ksz/AoIBAEwu4Y1cZzkQUmNRd5D7xecnk6ngfEYXKwCIT3zlMrfCSEl9n77BMaKu
|
|
||||||
4Dsr0iuX9eosQ7xM2eYhAG6LYEg05lc4MKWOToVVMpI6E+W3Dz47bPKgiF3I+f8s
|
|
||||||
Jz5CQIG/TwfGvciOE3hfUkec4ua09BzdEqGjkcBQ9XYMBxXPJr6h2379OBQS7FKR
|
|
||||||
fwfQ2/dv4tElXTTfut2kV8gU9Jnh5Wjo1epvR+XjKpg28YQo4W+0YX1magcyRB8L
|
|
||||||
4eSTUIC3XiVa8Jr0IwbZXPBb5xkdi7o+p4w2JahSHjxTRqmj+T1mnHXdbXVgq9Mg
|
|
||||||
9Pzl7cgFZvX4UBx4XtASRf73jITNtt0CggEADH9K+O7FrIOSQly0sMvsRCMtejp3
|
|
||||||
o+MDh1Q+vEg2kEgNXjS4ZFVljUpM2kg1OdUz7feS4dLXUJiIQ8ZWtZPedcq7wjHd
|
|
||||||
02he5+s06l0jPifN3tX1ADfXGpXg5R2fbkrIzakkPP5/RO/aDxIUo7qhklNsVTXO
|
|
||||||
VlGGfWLdk0ekA4upKm02Q1+YOlbIcAicEYYY8K7IffUwnohzKwL9yfuGi1VKTXpE
|
|
||||||
4fzdegsHI03FSqR7V+LvtBpIupQ7RO4kuBmCEyI4E9FVknchg4te4gO3qwd9y0rJ
|
|
||||||
Gu7HNIOrwOHzviI7J6Nd/l9MmeKqklHSgJvko/f5TmiXuQQ8xDZf84rcjQ==
|
|
||||||
-----END RSA PRIVATE KEY-----
|
|
||||||
`)
|
|
||||||
|
|
||||||
publicKeyBytes := []byte(`-----BEGIN RSA PUBLIC KEY-----
|
|
||||||
MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAwUCimKCidbF3UxEHPy8K
|
|
||||||
+hvhklRB9JYhj5sJy0if4lTVibkK1MrYCykOnmC40pPU9GLY1b8HxAg9tvyRn0YH
|
|
||||||
UxOra6vVQaVcOVJhTM8D18d+lSr3Lp1yiX+UGT4nzWI9+R1CCbwXrqeQVoZs6QZK
|
|
||||||
ynEXMkFI9/wNMOwPOvQFOSTuoEoCO+zyTyUWEkNbUq825ELUQdIsjgmlWUOONudx
|
|
||||||
sAr7ESRXW9QTHVh6uWmr3VRKZHby1JdU3I/wjdlGg5M2dDuXy5nQO9w/nYLjJXiw
|
|
||||||
+zzOetZ/+t7/VOkOpNTeJQhwTM1WF7Y2VLetbi9FHgyzHatrduh07+XEiTbgDf3G
|
|
||||||
Ix2bp2p6oh0G3N2zpiLcK/aZj8rouWWydfFfsU3MZ4FfJDP8I6b9awxjmKYqIr6h
|
|
||||||
iPQCJaLBED8mwK+I5evIbnKv6E6uK+BApWA/R7ElragoFYbqQ1VpvntVMtJt9Dy5
|
|
||||||
ZrI+IQARdXD3bb34oh0IPBhClnvvMUc1cWxDoXEX6oJ4I+LzxE87Zkwnan9qOwen
|
|
||||||
golMVKFwPx1o37qrbmrXID21kKt7FL6xN4HxHLkItr1fKzdyWDFRHgASTAWfx5BI
|
|
||||||
wvPuUW0vZHkvO80VyV2L63whVhPnPASmFkbviomrBttYfpr2aGQqF/qR1Nlxe834
|
|
||||||
MFxk1pS9LMa/WnzvFr0gWakCAwEAAQ==
|
|
||||||
-----END RSA PUBLIC KEY-----
|
|
||||||
`)
|
|
||||||
secretKeyPairDir := filepath.Join(homeDir, "secrets", "contexts", "contx1", "secrets")
|
secretKeyPairDir := filepath.Join(homeDir, "secrets", "contexts", "contx1", "secrets")
|
||||||
if err := os.MkdirAll(secretKeyPairDir, 0777); err != nil {
|
if err := os.MkdirAll(secretKeyPairDir, 0777); err != nil {
|
||||||
err = fmt.Errorf("Not able to create directories")
|
err = fmt.Errorf("Not able to create directories")
|
||||||
@@ -207,19 +140,33 @@ MFxk1pS9LMa/WnzvFr0gWakCAwEAAQ==
|
|||||||
}
|
}
|
||||||
os.Setenv("QLIKSENSE_KEY_LOCATION", secretKeyPairDir)
|
os.Setenv("QLIKSENSE_KEY_LOCATION", secretKeyPairDir)
|
||||||
|
|
||||||
privKeyFile := filepath.Join(secretKeyPairDir, "qliksensePriv")
|
key, _ := LoadSecretKey(secretKeyPairDir)
|
||||||
// construct and write priv key file into secretsDir location
|
|
||||||
err := ioutil.WriteFile(privKeyFile, privKeyBytes, 0777)
|
if key == "" {
|
||||||
if err != nil {
|
return GenerateAndStoreSecretKey(secretKeyPairDir)
|
||||||
log.Printf("Error while creating file: %v", err)
|
|
||||||
return nil, nil, err
|
|
||||||
}
|
}
|
||||||
pubKeyFile := filepath.Join(secretKeyPairDir, "qliksensePub")
|
return key, nil
|
||||||
// construct and write pub key file into secretsDir location
|
}
|
||||||
err = ioutil.WriteFile(pubKeyFile, publicKeyBytes, 0777)
|
|
||||||
if err != nil {
|
func Test_set_and_get_fetch_access_token(t *testing.T) {
|
||||||
log.Printf("Error while creating file: %v", err)
|
td, homeDir := setup()
|
||||||
return nil, nil, err
|
defer td()
|
||||||
}
|
createCRFile(homeDir)
|
||||||
return publicKeyBytes, privKeyBytes, nil
|
crFile := filepath.Join("contexts", "contx1", "contx1.yaml")
|
||||||
|
qConfig := NewQConfig(homeDir)
|
||||||
|
newQ, _ := qConfig.SetCrLocation("contx1", crFile)
|
||||||
|
newQ.Write()
|
||||||
|
qConfig = NewQConfig(homeDir)
|
||||||
|
qcr, _ := qConfig.GetCurrentCR()
|
||||||
|
key, _ := qConfig.GetEncryptionKeyFor(qcr.GetName())
|
||||||
|
if err := qcr.SetFetchAccessToken("mytokenbeforeencryption", key); err != nil {
|
||||||
|
t.Log(err)
|
||||||
|
t.FailNow()
|
||||||
|
}
|
||||||
|
tok := qcr.GetFetchAccessToken(key)
|
||||||
|
if tok != "mytokenbeforeencryption" {
|
||||||
|
t.Log("Expected: mytokenbeforeencryption, got: " + tok)
|
||||||
|
t.Fail()
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -109,6 +109,7 @@ func ReadFromFile(content interface{}, sourceFile string) error {
|
|||||||
if e != nil {
|
if e != nil {
|
||||||
return e
|
return e
|
||||||
}
|
}
|
||||||
|
defer file.Close()
|
||||||
return ReadFromStream(content, file)
|
return ReadFromStream(content, file)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
8
pkg/api/copy.go
Normal file
8
pkg/api/copy.go
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
package api
|
||||||
|
|
||||||
|
import "github.com/otiai10/copy"
|
||||||
|
|
||||||
|
//copy source directory to destination
|
||||||
|
func CopyDirectory(source string, dest string) error {
|
||||||
|
return copy.Copy(source, dest)
|
||||||
|
}
|
||||||
101
pkg/api/copy_test.go
Normal file
101
pkg/api/copy_test.go
Normal file
@@ -0,0 +1,101 @@
|
|||||||
|
package api
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io/ioutil"
|
||||||
|
"os"
|
||||||
|
"path"
|
||||||
|
"path/filepath"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
kapis_git "github.com/qlik-oss/k-apis/pkg/git"
|
||||||
|
"sigs.k8s.io/kustomize/api/filesys"
|
||||||
|
"sigs.k8s.io/kustomize/api/konfig"
|
||||||
|
"sigs.k8s.io/kustomize/api/krusty"
|
||||||
|
"sigs.k8s.io/kustomize/api/types"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestCopyDirectory(t *testing.T) {
|
||||||
|
src, _ := ioutil.TempDir("", "")
|
||||||
|
f1, _ := ioutil.TempFile(src, "")
|
||||||
|
ioutil.TempFile(src, "")
|
||||||
|
|
||||||
|
dest, _ := ioutil.TempDir("", "")
|
||||||
|
CopyDirectory(src, dest)
|
||||||
|
if _, err := os.Lstat(filepath.Join(dest, filepath.Base(f1.Name()))); err != nil {
|
||||||
|
t.Log(err)
|
||||||
|
t.Fail()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCopyDirectory_withGit_withKuz(t *testing.T) {
|
||||||
|
if testing.Short() {
|
||||||
|
t.Skip("Skipping in short test mode")
|
||||||
|
}
|
||||||
|
|
||||||
|
tmpDir1, err := ioutil.TempDir("", "")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unexpected error: %v", err)
|
||||||
|
}
|
||||||
|
defer os.RemoveAll(tmpDir1)
|
||||||
|
|
||||||
|
tmpDir2, err := ioutil.TempDir("", "")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unexpected error: %v", err)
|
||||||
|
}
|
||||||
|
defer os.RemoveAll(tmpDir2)
|
||||||
|
|
||||||
|
repoPath1 := path.Join(tmpDir1, "repo")
|
||||||
|
repo1, err := kapis_git.CloneRepository(repoPath1, "https://github.com/qlik-oss/qliksense-k8s", nil)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unexpected error: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := CopyDirectory(repoPath1, tmpDir2); err != nil {
|
||||||
|
t.Fatalf("unexpected error: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
repoPath2 := tmpDir2
|
||||||
|
repo2, err := kapis_git.OpenRepository(repoPath2)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unexpected error: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := kapis_git.Checkout(repo2, "v0.0.2", "", nil); err != nil {
|
||||||
|
t.Fatalf("unexpected error: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
repo2Manifest, err := kuz(path.Join(repoPath2, "manifests", "docker-desktop"))
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unexpected error: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := kapis_git.Checkout(repo1, "v0.0.2", "", nil); err != nil {
|
||||||
|
t.Fatalf("unexpected error: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
repo1Manifest, err := kuz(path.Join(repoPath1, "manifests", "docker-desktop"))
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unexpected error: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if string(repo2Manifest) != string(repo1Manifest) {
|
||||||
|
t.Logf("manifest generated on the original config:\n%v", string(repo1Manifest))
|
||||||
|
t.Logf("manifest generated on the copied config:\n%v", string(repo2Manifest))
|
||||||
|
t.Fatal("expected manifests to be equal, but they were not")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func kuz(directory string) ([]byte, error) {
|
||||||
|
options := &krusty.Options{
|
||||||
|
DoLegacyResourceSort: false,
|
||||||
|
LoadRestrictions: types.LoadRestrictionsNone,
|
||||||
|
DoPrune: false,
|
||||||
|
PluginConfig: konfig.DisabledPluginConfig(),
|
||||||
|
}
|
||||||
|
k := krusty.MakeKustomizer(filesys.MakeFsOnDisk(), options)
|
||||||
|
resMap, err := k.Run(directory)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return resMap.AsYaml()
|
||||||
|
}
|
||||||
@@ -1,7 +1,6 @@
|
|||||||
package api
|
package api
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"crypto/rsa"
|
|
||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
@@ -34,7 +33,7 @@ type DockerConfigJsonSecret struct {
|
|||||||
Email string
|
Email string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *DockerConfigJsonSecret) ToYaml(encryptionKey *rsa.PublicKey) ([]byte, error) {
|
func (d *DockerConfigJsonSecret) ToYaml(encryptionKey string) ([]byte, error) {
|
||||||
k8sDockerConfigJson := k8sDockerConfigJsonType{
|
k8sDockerConfigJson := k8sDockerConfigJsonType{
|
||||||
Username: d.Username,
|
Username: d.Username,
|
||||||
Password: d.Password,
|
Password: d.Password,
|
||||||
@@ -51,8 +50,8 @@ func (d *DockerConfigJsonSecret) ToYaml(encryptionKey *rsa.PublicKey) ([]byte, e
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
var k8sDockerConfigJsonMapMaybeEncryptedBytes []byte
|
var k8sDockerConfigJsonMapMaybeEncryptedBytes []byte
|
||||||
if encryptionKey != nil {
|
if encryptionKey != "" {
|
||||||
if k8sDockerConfigJsonMapMaybeEncryptedBytes, err = Encrypt(k8sDockerConfigJsonMapBytes, encryptionKey); err != nil {
|
if k8sDockerConfigJsonMapMaybeEncryptedBytes, err = EncryptData(k8sDockerConfigJsonMapBytes, encryptionKey); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -76,7 +75,7 @@ func (d *DockerConfigJsonSecret) ToYaml(encryptionKey *rsa.PublicKey) ([]byte, e
|
|||||||
return K8sSecretToYaml(k8sSecret)
|
return K8sSecretToYaml(k8sSecret)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *DockerConfigJsonSecret) FromYaml(secretBytes []byte, decryptionKey *rsa.PrivateKey) error {
|
func (d *DockerConfigJsonSecret) FromYaml(secretBytes []byte, decryptionKey string) error {
|
||||||
k8sDockerConfigJsonMap := k8sDockerConfigJsonMapType{}
|
k8sDockerConfigJsonMap := k8sDockerConfigJsonMapType{}
|
||||||
if k8sSecret, err := K8sSecretFromYaml(secretBytes); err != nil {
|
if k8sSecret, err := K8sSecretFromYaml(secretBytes); err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -86,7 +85,7 @@ func (d *DockerConfigJsonSecret) FromYaml(secretBytes []byte, decryptionKey *rsa
|
|||||||
return errors.New("not a kubernetes.io/dockerconfigjson type")
|
return errors.New("not a kubernetes.io/dockerconfigjson type")
|
||||||
} else if k8sDockerConfigJsonMapEncryptedBytes, ok := k8sSecret.Data[".dockerconfigjson"]; !ok {
|
} else if k8sDockerConfigJsonMapEncryptedBytes, ok := k8sSecret.Data[".dockerconfigjson"]; !ok {
|
||||||
return errors.New("secret data is missing a value for the .dockerconfigjson key")
|
return errors.New("secret data is missing a value for the .dockerconfigjson key")
|
||||||
} else if k8sDockerConfigJsonMapBytes, err := Decrypt(k8sDockerConfigJsonMapEncryptedBytes, decryptionKey); err != nil {
|
} else if k8sDockerConfigJsonMapBytes, err := DecryptData(k8sDockerConfigJsonMapEncryptedBytes, decryptionKey); err != nil {
|
||||||
return errors.New("secret data is missing a value for the .dockerconfigjson key")
|
return errors.New("secret data is missing a value for the .dockerconfigjson key")
|
||||||
} else if err := json.Unmarshal(k8sDockerConfigJsonMapBytes, &k8sDockerConfigJsonMap); err != nil {
|
} else if err := json.Unmarshal(k8sDockerConfigJsonMapBytes, &k8sDockerConfigJsonMap); err != nil {
|
||||||
return err
|
return err
|
||||||
|
|||||||
@@ -1,8 +1,6 @@
|
|||||||
package api
|
package api
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"crypto/rand"
|
|
||||||
"crypto/rsa"
|
|
||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
@@ -23,12 +21,12 @@ func TestDockerConfigJsonSecret(t *testing.T) {
|
|||||||
dockerConfigJsonSecretFromYaml := DockerConfigJsonSecret{}
|
dockerConfigJsonSecretFromYaml := DockerConfigJsonSecret{}
|
||||||
validYamlMap := map[string]interface{}{}
|
validYamlMap := map[string]interface{}{}
|
||||||
|
|
||||||
privateKey, err := rsa.GenerateKey(rand.Reader, RSA_KEY_LENGTH)
|
encryptionKey, err := GenerateKey()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("error generating RSA private key: %v\n", err)
|
t.Fatalf("error generating RSA private key: %v\n", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
dockerConfigJsonSecretYamlBytes, err := dockerConfigJsonSecret.ToYaml(&privateKey.PublicKey)
|
dockerConfigJsonSecretYamlBytes, err := dockerConfigJsonSecret.ToYaml(encryptionKey)
|
||||||
dockerConfigJsonMap := map[string]interface{}{}
|
dockerConfigJsonMap := map[string]interface{}{}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("error converting secret to yaml: %v", err)
|
t.Fatalf("error converting secret to yaml: %v", err)
|
||||||
@@ -43,7 +41,7 @@ func TestDockerConfigJsonSecret(t *testing.T) {
|
|||||||
t.Fatalf("no .dockerconfigjson data key in the secret yaml: %v", string(dockerConfigJsonSecretYamlBytes))
|
t.Fatalf("no .dockerconfigjson data key in the secret yaml: %v", string(dockerConfigJsonSecretYamlBytes))
|
||||||
} else if dockerConfigJsonEncryptedBytes, err := base64.StdEncoding.DecodeString(dockerConfigJsonBytesBase64.(string)); err != nil {
|
} else if dockerConfigJsonEncryptedBytes, err := base64.StdEncoding.DecodeString(dockerConfigJsonBytesBase64.(string)); err != nil {
|
||||||
t.Fatalf("error decoding dockerConfigJsonBytes from base64: %v", err)
|
t.Fatalf("error decoding dockerConfigJsonBytes from base64: %v", err)
|
||||||
} else if dockerConfigJsonBytes, err := Decrypt(dockerConfigJsonEncryptedBytes, privateKey); err != nil {
|
} else if dockerConfigJsonBytes, err := DecryptData(dockerConfigJsonEncryptedBytes, encryptionKey); err != nil {
|
||||||
t.Fatalf("error decrypting dockerConfigJsonBytes: %v", err)
|
t.Fatalf("error decrypting dockerConfigJsonBytes: %v", err)
|
||||||
} else if err := json.Unmarshal(dockerConfigJsonBytes, &dockerConfigJsonMap); err != nil {
|
} else if err := json.Unmarshal(dockerConfigJsonBytes, &dockerConfigJsonMap); err != nil {
|
||||||
t.Fatalf("error unmarshalling dockerConfigJson from json: %v", err)
|
t.Fatalf("error unmarshalling dockerConfigJson from json: %v", err)
|
||||||
@@ -63,7 +61,7 @@ func TestDockerConfigJsonSecret(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
t.Logf("dockerConfigJsonSecretYaml: \n%v\n", string(dockerConfigJsonSecretYamlBytes))
|
t.Logf("dockerConfigJsonSecretYaml: \n%v\n", string(dockerConfigJsonSecretYamlBytes))
|
||||||
if err := dockerConfigJsonSecretFromYaml.FromYaml(dockerConfigJsonSecretYamlBytes, privateKey); err != nil {
|
if err := dockerConfigJsonSecretFromYaml.FromYaml(dockerConfigJsonSecretYamlBytes, encryptionKey); err != nil {
|
||||||
t.Fatalf("error reading secret in from yaml: %v", err)
|
t.Fatalf("error reading secret in from yaml: %v", err)
|
||||||
} else if !reflect.DeepEqual(dockerConfigJsonSecret, dockerConfigJsonSecretFromYaml) {
|
} else if !reflect.DeepEqual(dockerConfigJsonSecret, dockerConfigJsonSecretFromYaml) {
|
||||||
t.Fatalf("secret: %v does not equal secret: %v", dockerConfigJsonSecret, dockerConfigJsonSecretFromYaml)
|
t.Fatalf("secret: %v does not equal secret: %v", dockerConfigJsonSecret, dockerConfigJsonSecretFromYaml)
|
||||||
|
|||||||
@@ -1,58 +1,42 @@
|
|||||||
package api
|
package api
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"crypto/aes"
|
||||||
|
"crypto/cipher"
|
||||||
"crypto/rand"
|
"crypto/rand"
|
||||||
"crypto/rsa"
|
"encoding/hex"
|
||||||
"crypto/x509"
|
"errors"
|
||||||
"encoding/pem"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"log"
|
"log"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
RSA_KEY_LENGTH = 4096
|
key_file_name = "user_secret_key"
|
||||||
|
|
||||||
QliksensePublicKey = "qliksensePub"
|
|
||||||
QliksensePrivateKey = "qliksensePriv"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// GenerateAndStoreSecretKeypair generates and stores key pairs
|
// GenerateAndStoreSecretKey generates and stores key
|
||||||
func GenerateAndStoreSecretKeypair(secretsPath string) error {
|
func GenerateAndStoreSecretKey(secretsDir string) (string, error) {
|
||||||
LogDebugMessage("%s exists", secretsPath)
|
// creating contexts/qlik-default/secrets/user_secret_key
|
||||||
// creating contexts/qlik-default/secrets/qliksensePub and contexts/qlik-default/secrets/qliksensePriv files
|
keyFile := filepath.Join(secretsDir, key_file_name)
|
||||||
publicKeyFilePath := filepath.Join(secretsPath, QliksensePublicKey)
|
key, err := GenerateKey()
|
||||||
privateKeyFilePath := filepath.Join(secretsPath, QliksensePrivateKey)
|
|
||||||
LogDebugMessage("Generating public-private key pair.....")
|
|
||||||
GenerateRSAEncryptionKeys(publicKeyFilePath, privateKeyFilePath)
|
|
||||||
LogDebugMessage("Generated public-private key pairs")
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// GenerateRSAEncryptionKeys is used to generate a new public-private key pair
|
|
||||||
func GenerateRSAEncryptionKeys(publicKeyFilePath, privateKeyFilePath string) error {
|
|
||||||
LogDebugMessage("Generating new RSA key pair")
|
|
||||||
privateKey, err := rsa.GenerateKey(rand.Reader, RSA_KEY_LENGTH)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("error generating RSA private key: %v\n", err)
|
return "", err
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
|
if err := writeContentToFile([]byte(key), keyFile); err != nil {
|
||||||
privateKeyPEM := EncodePrivateKey(privateKey)
|
return "", err
|
||||||
if err := writeContentToFile(privateKeyPEM, privateKeyFilePath); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
pubKeyPEM, err2 := EncodePublicKey(&privateKey.PublicKey)
|
return key, nil
|
||||||
if err2 != nil {
|
}
|
||||||
log.Printf("error occurred when encoding public key: %v\n", err2)
|
func LoadSecretKey(secretsDir string) (string, error) {
|
||||||
return err2
|
keyFile := filepath.Join(secretsDir, key_file_name)
|
||||||
|
by, err := ioutil.ReadFile(keyFile)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
}
|
}
|
||||||
if err := writeContentToFile(pubKeyPEM, publicKeyFilePath); err != nil {
|
return string(by), nil
|
||||||
return err
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// writeContentToFile writes keys to a file
|
// writeContentToFile writes keys to a file
|
||||||
@@ -65,104 +49,54 @@ func writeContentToFile(keyData []byte, fileName string) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Encrypt encrypts data with public key
|
func GenerateKey() (string, error) {
|
||||||
func Encrypt(pt []byte, pub *rsa.PublicKey) ([]byte, error) {
|
salt := make([]byte, 32)
|
||||||
//hash := sha512.New()
|
if _, err := rand.Read(salt); err != nil {
|
||||||
//ct, err := rsa.EncryptOAEP(hash, rand.Reader, pub, pt, nil)
|
return "", err
|
||||||
ct, err := rsa.EncryptPKCS1v15(rand.Reader, pub, pt)
|
|
||||||
if err != nil {
|
|
||||||
log.Println(err)
|
|
||||||
return nil, err
|
|
||||||
}
|
}
|
||||||
return ct, nil
|
s := fmt.Sprintf("%x", salt)
|
||||||
|
return s, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Decrypt decrypts data with private key
|
func EncryptData(plaintext []byte, userKey string) ([]byte, error) {
|
||||||
func Decrypt(ct []byte, priv *rsa.PrivateKey) ([]byte, error) {
|
key, _ := hex.DecodeString(userKey)
|
||||||
// hash := sha512.New()
|
|
||||||
// plaintext, err := rsa.DecryptOAEP(hash, rand.Reader, priv, ciphertext, nil)
|
block, err := aes.NewCipher(key)
|
||||||
pt, err := rsa.DecryptPKCS1v15(rand.Reader, priv, ct)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Println(err)
|
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return pt, nil
|
|
||||||
|
aesgcm, err := cipher.NewGCM(block)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
nonce := make([]byte, aesgcm.NonceSize())
|
||||||
|
if _, err := io.ReadFull(rand.Reader, nonce); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return aesgcm.Seal(nonce, nonce, plaintext, nil), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// EncodePrivateKey private key to bytes
|
func DecryptData(ciphertext []byte, userKey string) ([]byte, error) {
|
||||||
func EncodePrivateKey(priv *rsa.PrivateKey) []byte {
|
key, _ := hex.DecodeString(userKey)
|
||||||
privBytes := pem.EncodeToMemory(
|
block, err := aes.NewCipher(key)
|
||||||
&pem.Block{
|
if err != nil {
|
||||||
Type: "RSA PRIVATE KEY",
|
return nil, err
|
||||||
Bytes: x509.MarshalPKCS1PrivateKey(priv),
|
}
|
||||||
},
|
|
||||||
)
|
|
||||||
|
|
||||||
return privBytes
|
aesgcm, err := cipher.NewGCM(block)
|
||||||
}
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
// EncodePublicKey public key to bytes
|
}
|
||||||
func EncodePublicKey(pub *rsa.PublicKey) ([]byte, error) {
|
nonceSize := aesgcm.NonceSize()
|
||||||
pubASN1, err := x509.MarshalPKIXPublicKey(pub)
|
if len(ciphertext) < nonceSize {
|
||||||
if err != nil {
|
return nil, errors.New("ciphertext too short")
|
||||||
log.Println(err)
|
}
|
||||||
return nil, err
|
nonce, ciphertext := ciphertext[:nonceSize], ciphertext[nonceSize:]
|
||||||
}
|
plaintext, err := aesgcm.Open(nil, nonce, ciphertext, nil)
|
||||||
|
if err != nil {
|
||||||
pubBytes := pem.EncodeToMemory(&pem.Block{
|
return nil, err
|
||||||
Type: "RSA PUBLIC KEY",
|
}
|
||||||
Bytes: pubASN1,
|
return plaintext, nil
|
||||||
})
|
|
||||||
|
|
||||||
return pubBytes, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// DecodeToPrivateKey bytes to private key
|
|
||||||
func DecodeToPrivateKey(priv []byte) (*rsa.PrivateKey, error) {
|
|
||||||
block, _ := pem.Decode(priv)
|
|
||||||
enc := x509.IsEncryptedPEMBlock(block)
|
|
||||||
b := block.Bytes
|
|
||||||
var err error
|
|
||||||
if enc {
|
|
||||||
log.Println("is encrypted pem block")
|
|
||||||
b, err = x509.DecryptPEMBlock(block, nil)
|
|
||||||
if err != nil {
|
|
||||||
log.Println(err)
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
key, err := x509.ParsePKCS1PrivateKey(b)
|
|
||||||
if err != nil {
|
|
||||||
log.Println(err)
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return key, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// DecodeToPublicKey bytes to public key
|
|
||||||
func DecodeToPublicKey(pub []byte) (*rsa.PublicKey, error) {
|
|
||||||
block, _ := pem.Decode(pub)
|
|
||||||
enc := x509.IsEncryptedPEMBlock(block)
|
|
||||||
b := block.Bytes
|
|
||||||
var err error
|
|
||||||
if enc {
|
|
||||||
log.Println("is encrypted pem block")
|
|
||||||
b, err = x509.DecryptPEMBlock(block, nil)
|
|
||||||
if err != nil {
|
|
||||||
log.Println(err)
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
iface, err := x509.ParsePKIXPublicKey(b)
|
|
||||||
if err != nil {
|
|
||||||
log.Println(err)
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
key, ok := iface.(*rsa.PublicKey)
|
|
||||||
if !ok {
|
|
||||||
err := fmt.Errorf("Unable to decode public key")
|
|
||||||
log.Println(err)
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return key, nil
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,128 +1,29 @@
|
|||||||
package api
|
package api
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/base64"
|
|
||||||
"log"
|
|
||||||
"os"
|
|
||||||
"testing"
|
"testing"
|
||||||
)
|
)
|
||||||
|
|
||||||
func Test_generateRSAEncryptionKeys(t *testing.T) {
|
func Test_encrypt_decrypt(t *testing.T) {
|
||||||
tests := []struct {
|
key, err := GenerateKey()
|
||||||
name string
|
if err != nil {
|
||||||
wantErr bool
|
t.Log(err)
|
||||||
}{
|
t.FailNow()
|
||||||
{
|
|
||||||
name: "valid case",
|
|
||||||
wantErr: false,
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
for _, tt := range tests {
|
testData := "this is a secret value"
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
enc, err := EncryptData([]byte(testData), key)
|
||||||
if err := GenerateAndStoreSecretKeypair(os.TempDir()); (err != nil) != tt.wantErr {
|
if err != nil {
|
||||||
t.Errorf("generateRSAEncryptionKeys() error = %v, wantErr %v", err, tt.wantErr)
|
t.Log(err)
|
||||||
|
t.FailNow()
|
||||||
}
|
}
|
||||||
})
|
dec, err := DecryptData(enc, key)
|
||||||
}
|
if err != nil {
|
||||||
}
|
t.Log(err)
|
||||||
|
t.FailNow()
|
||||||
func Test_encryption_decryption(t *testing.T) {
|
}
|
||||||
privKeyBytes := []byte(`-----BEGIN RSA PRIVATE KEY-----
|
if testData != string(dec) {
|
||||||
MIIJJwIBAAKCAgEAwUCimKCidbF3UxEHPy8K+hvhklRB9JYhj5sJy0if4lTVibkK
|
t.Log("expected: " + testData)
|
||||||
1MrYCykOnmC40pPU9GLY1b8HxAg9tvyRn0YHUxOra6vVQaVcOVJhTM8D18d+lSr3
|
t.Log("actual: " + string(dec))
|
||||||
Lp1yiX+UGT4nzWI9+R1CCbwXrqeQVoZs6QZKynEXMkFI9/wNMOwPOvQFOSTuoEoC
|
t.Fail()
|
||||||
O+zyTyUWEkNbUq825ELUQdIsjgmlWUOONudxsAr7ESRXW9QTHVh6uWmr3VRKZHby
|
|
||||||
1JdU3I/wjdlGg5M2dDuXy5nQO9w/nYLjJXiw+zzOetZ/+t7/VOkOpNTeJQhwTM1W
|
|
||||||
F7Y2VLetbi9FHgyzHatrduh07+XEiTbgDf3GIx2bp2p6oh0G3N2zpiLcK/aZj8ro
|
|
||||||
uWWydfFfsU3MZ4FfJDP8I6b9awxjmKYqIr6hiPQCJaLBED8mwK+I5evIbnKv6E6u
|
|
||||||
K+BApWA/R7ElragoFYbqQ1VpvntVMtJt9Dy5ZrI+IQARdXD3bb34oh0IPBhClnvv
|
|
||||||
MUc1cWxDoXEX6oJ4I+LzxE87Zkwnan9qOwengolMVKFwPx1o37qrbmrXID21kKt7
|
|
||||||
FL6xN4HxHLkItr1fKzdyWDFRHgASTAWfx5BIwvPuUW0vZHkvO80VyV2L63whVhPn
|
|
||||||
PASmFkbviomrBttYfpr2aGQqF/qR1Nlxe834MFxk1pS9LMa/WnzvFr0gWakCAwEA
|
|
||||||
AQKCAgARSp9B2N2wejibDiL/3E23I1eDqFZedDB8kPrHXbAwqDaTJCN79spt9TaB
|
|
||||||
pVXkQaYEV/Pe7EDdoX8kKGU/QxzUqiXkdHOYdBtUZbKfFMbbP9ZrsnR7j0r4UpoF
|
|
||||||
yDH3hprU93E5PcNAtW2M0GpeT1nR01yn+n908PCdOAIE3GC7RDq1zOl2QzVLL55R
|
|
||||||
9ATv2Q2oTvJ/ETc7XlGVMx4+e2cIwXLFjeLjLI6pSYlxnarrGuetJZeEviWxto9n
|
|
||||||
odFVZI6yx8JFTXX8ZTCr/1IjwDDVyhMPmrHI2Lsv9cqBpSpbVe32cUkKxhsGaYjz
|
|
||||||
GvesQKamOPhco2ATNxPm0yopFlPsGKMfVl0BK0J6BqFh1BvU/SYJmXfnFuUNO3vV
|
|
||||||
4u2Saa0q1iddxV0rXDwIqUfn+S6rwzK0G7y8bH2yvpB2VwiG3TFPnULep4wsefNq
|
|
||||||
Fj92kqFBjacGpQLEEslUY0CMgeZ2+NuBQSUTscP3wBRsottMR6YXJtINdvfHBx+e
|
|
||||||
EcN71z8D00w3mYqIQ7qb4Ml6HOqknunn58g43L9sACMUMTlEBXa9pUnScNYgWBAz
|
|
||||||
W2q2mH37cIydM2JRZPpA8B4yTHt5ugJmChwyNFM7941arjKrebH+6AzLkofGedOP
|
|
||||||
zg+vZQuPEXWs+3MBBnkWoyJW3Y0fbQdjsuQTtnd+7iyoxoBroQKCAQEA4dIiFlIS
|
|
||||||
MDfRhQQWSiDvaw9aneDEJ3uo63ZRH5tm/IynLgtjYgEm/ZxlBCQgqRKLYELBxhu8
|
|
||||||
SaF0uPK8pmpFJt0mIwSlsdeVhuE2obQeKUCczaqrKeaHS3PdWLjTlwph81BGRkHy
|
|
||||||
qfqtNylyyMxrdEbnR51EtsWgFq6anTUAui1Q09JMuMNZRMOzDs1F4gExgD22rc0V
|
|
||||||
c9YQ+jHJRxBGtNKMpMEqc8cvaxBidbItrN9SMTSWog7uYPBuEuaJ6K9vpgyJMOzJ
|
|
||||||
SYcQEFGqgIqIDCg+ABE4d/4YROMKZ1DV/bJCind9brUHSx6XALsF0nC5c1Q9TnUL
|
|
||||||
qI2khOwts4KYKwKCAQEA2xRC6Az97Vkdzu7BjLJ1FKmx4S2nEEgVS12ds82U+5Xf
|
|
||||||
BHKAJnjqlqmmpzzJG+d77IYktz0+mey1QCNkqlm2fhuKs8LZMnpZRf0l8VcoBsUP
|
|
||||||
/xKz7wfiE7RRFZtLJhPp4hhe43GzX5/JFMWMnC6UykwQbj4t1E/GNM/Suqwvg12M
|
|
||||||
wktAJ6nqLgfhjQSO4xWo+nPzcbX+fNtrPCZVrBhYXihhcwRRNImWUCGJ6J4LMdPY
|
|
||||||
Y9Z59qhOvE9cReH/Xw1av46omyiSyAqlgPyZ/kzA2IJSqYCjiQR/2+RD/g13jpcJ
|
|
||||||
jatXLVZ8MJSL5OTS40G/HHTNNpNHbKKh0GOyxBA3ewKCAQBAn8UXhCcmW2L/YPsL
|
|
||||||
/b7mcX9qPP+FmRLvR23R0MQ5M/tH5wRq8I969n3GIJykJeVzB8eybQ+GNslTgEvS
|
|
||||||
iAkAJTubu+G7MkndTqg2wHf9MDtvdA8Fr646Po8yq7oJuHPtkKR7yLWsRUu6xIbP
|
|
||||||
xgheP0hCq1QVxhqZQyCGKrvpi7xc0gsYuPbcAfFFJCOCmPrUi1SzCkTAYJt9LjA+
|
|
||||||
wP6rErIjGBCRD4iXaBn1OqdtmH9KC5WsDP/VCBlIGWeQCly2NVIxiSHVg+xp7yUP
|
|
||||||
IhXq/L05gbQaSsIhPKQmivCiaJg4The8TdwneDqYf+0bmxzHT203/bD3bImPbJNr
|
|
||||||
ksz/AoIBAEwu4Y1cZzkQUmNRd5D7xecnk6ngfEYXKwCIT3zlMrfCSEl9n77BMaKu
|
|
||||||
4Dsr0iuX9eosQ7xM2eYhAG6LYEg05lc4MKWOToVVMpI6E+W3Dz47bPKgiF3I+f8s
|
|
||||||
Jz5CQIG/TwfGvciOE3hfUkec4ua09BzdEqGjkcBQ9XYMBxXPJr6h2379OBQS7FKR
|
|
||||||
fwfQ2/dv4tElXTTfut2kV8gU9Jnh5Wjo1epvR+XjKpg28YQo4W+0YX1magcyRB8L
|
|
||||||
4eSTUIC3XiVa8Jr0IwbZXPBb5xkdi7o+p4w2JahSHjxTRqmj+T1mnHXdbXVgq9Mg
|
|
||||||
9Pzl7cgFZvX4UBx4XtASRf73jITNtt0CggEADH9K+O7FrIOSQly0sMvsRCMtejp3
|
|
||||||
o+MDh1Q+vEg2kEgNXjS4ZFVljUpM2kg1OdUz7feS4dLXUJiIQ8ZWtZPedcq7wjHd
|
|
||||||
02he5+s06l0jPifN3tX1ADfXGpXg5R2fbkrIzakkPP5/RO/aDxIUo7qhklNsVTXO
|
|
||||||
VlGGfWLdk0ekA4upKm02Q1+YOlbIcAicEYYY8K7IffUwnohzKwL9yfuGi1VKTXpE
|
|
||||||
4fzdegsHI03FSqR7V+LvtBpIupQ7RO4kuBmCEyI4E9FVknchg4te4gO3qwd9y0rJ
|
|
||||||
Gu7HNIOrwOHzviI7J6Nd/l9MmeKqklHSgJvko/f5TmiXuQQ8xDZf84rcjQ==
|
|
||||||
-----END RSA PRIVATE KEY-----
|
|
||||||
`)
|
|
||||||
|
|
||||||
publicKeyBytes := []byte(`-----BEGIN RSA PUBLIC KEY-----
|
|
||||||
MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAwUCimKCidbF3UxEHPy8K
|
|
||||||
+hvhklRB9JYhj5sJy0if4lTVibkK1MrYCykOnmC40pPU9GLY1b8HxAg9tvyRn0YH
|
|
||||||
UxOra6vVQaVcOVJhTM8D18d+lSr3Lp1yiX+UGT4nzWI9+R1CCbwXrqeQVoZs6QZK
|
|
||||||
ynEXMkFI9/wNMOwPOvQFOSTuoEoCO+zyTyUWEkNbUq825ELUQdIsjgmlWUOONudx
|
|
||||||
sAr7ESRXW9QTHVh6uWmr3VRKZHby1JdU3I/wjdlGg5M2dDuXy5nQO9w/nYLjJXiw
|
|
||||||
+zzOetZ/+t7/VOkOpNTeJQhwTM1WF7Y2VLetbi9FHgyzHatrduh07+XEiTbgDf3G
|
|
||||||
Ix2bp2p6oh0G3N2zpiLcK/aZj8rouWWydfFfsU3MZ4FfJDP8I6b9awxjmKYqIr6h
|
|
||||||
iPQCJaLBED8mwK+I5evIbnKv6E6uK+BApWA/R7ElragoFYbqQ1VpvntVMtJt9Dy5
|
|
||||||
ZrI+IQARdXD3bb34oh0IPBhClnvvMUc1cWxDoXEX6oJ4I+LzxE87Zkwnan9qOwen
|
|
||||||
golMVKFwPx1o37qrbmrXID21kKt7FL6xN4HxHLkItr1fKzdyWDFRHgASTAWfx5BI
|
|
||||||
wvPuUW0vZHkvO80VyV2L63whVhPnPASmFkbviomrBttYfpr2aGQqF/qR1Nlxe834
|
|
||||||
MFxk1pS9LMa/WnzvFr0gWakCAwEAAQ==
|
|
||||||
-----END RSA PUBLIC KEY-----
|
|
||||||
`)
|
|
||||||
origStr := "Value1234"
|
|
||||||
|
|
||||||
pubKey, err := DecodeToPublicKey(publicKeyBytes)
|
|
||||||
if err != nil {
|
|
||||||
t.Error(err)
|
|
||||||
t.FailNow()
|
|
||||||
}
|
|
||||||
privKey, err := DecodeToPrivateKey(privKeyBytes)
|
|
||||||
if err != nil {
|
|
||||||
t.Error(err)
|
|
||||||
t.FailNow()
|
|
||||||
}
|
|
||||||
encData, err := Encrypt([]byte(origStr), pubKey)
|
|
||||||
if err != nil {
|
|
||||||
t.Error(err)
|
|
||||||
t.FailNow()
|
|
||||||
}
|
|
||||||
|
|
||||||
encDataStr := base64.StdEncoding.EncodeToString(encData)
|
|
||||||
log.Println("Encoded text:", encDataStr)
|
|
||||||
dec, _ := base64.StdEncoding.DecodeString(encDataStr)
|
|
||||||
data, err := Decrypt(dec, privKey)
|
|
||||||
if err != nil {
|
|
||||||
t.Error(err)
|
|
||||||
t.FailNow()
|
|
||||||
}
|
|
||||||
if string(data) != origStr {
|
|
||||||
t.Error("original string and decrypted string don't match")
|
|
||||||
t.FailNow()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,12 +15,20 @@ func KubectlApply(manifests, namespace string) error {
|
|||||||
return kubectlOperation(manifests, "apply", namespace)
|
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,
|
// KubectlDelete delete resoruces in the provided namespace,
|
||||||
// if namespace="" then use whatever the kubectl default is
|
// if namespace="" then use whatever the kubectl default is
|
||||||
func KubectlDelete(manifests, namespace string) error {
|
func KubectlDelete(manifests, namespace string) error {
|
||||||
return kubectlOperation(manifests, "delete", namespace)
|
return kubectlOperation(manifests, "delete", namespace)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func KubectlDeleteVerbose(manifests, namespace string, verbose bool) error {
|
||||||
|
return kubectlOperationVerbose(manifests, "delete", namespace, verbose)
|
||||||
|
}
|
||||||
|
|
||||||
func GetKubectlNamespace() string {
|
func GetKubectlNamespace() string {
|
||||||
namespace := ""
|
namespace := ""
|
||||||
cmd := exec.Command("kubectl", "config", "current-context")
|
cmd := exec.Command("kubectl", "config", "current-context")
|
||||||
@@ -61,6 +69,10 @@ func SetKubectlNamespace(ns string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func kubectlOperation(manifests string, oprName string, namespace string) error {
|
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("", "")
|
tempYaml, err := ioutil.TempFile("", "")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println("cannot create file ", err)
|
fmt.Println("cannot create file ", err)
|
||||||
@@ -88,12 +100,16 @@ func kubectlOperation(manifests string, oprName string, namespace string) error
|
|||||||
}
|
}
|
||||||
|
|
||||||
sterrBuffer := &bytes.Buffer{}
|
sterrBuffer := &bytes.Buffer{}
|
||||||
cmd.Stdout = os.Stdout
|
stoutBuffer := &bytes.Buffer{}
|
||||||
|
cmd.Stdout = stoutBuffer
|
||||||
cmd.Stderr = sterrBuffer
|
cmd.Stderr = sterrBuffer
|
||||||
err = cmd.Run()
|
err = cmd.Run()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("kubectl %v failed with: %v, %v, temp k8s yaml file:%v\n", oprName, err, sterrBuffer.String(), tempYaml.Name())
|
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())
|
os.Remove(tempYaml.Name())
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,10 +1,11 @@
|
|||||||
package preflight
|
package api
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"os"
|
"os"
|
||||||
|
"path"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
|
|
||||||
api "github.com/qlik-oss/sense-installer/pkg/api"
|
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -43,8 +44,10 @@ func NewPreflightConfig(qHome string) *PreflightConfig {
|
|||||||
if _, err := os.Lstat(conFile); err != nil {
|
if _, err := os.Lstat(conFile); err != nil {
|
||||||
return p
|
return p
|
||||||
}
|
}
|
||||||
p = &PreflightConfig{}
|
p = &PreflightConfig{
|
||||||
if err := api.ReadFromFile(p, conFile); err != nil {
|
QliksenseHomePath: qHome,
|
||||||
|
}
|
||||||
|
if err := ReadFromFile(p, conFile); err != nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
return p
|
return p
|
||||||
@@ -61,7 +64,7 @@ func (p *PreflightConfig) Write() error {
|
|||||||
if err := os.MkdirAll(pDir, os.ModePerm); err != nil {
|
if err := os.MkdirAll(pDir, os.ModePerm); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return api.WriteToFile(p, p.GetConfigFilePath())
|
return WriteToFile(p, p.GetConfigFilePath())
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *PreflightConfig) AddMinK8sV(version string) {
|
func (p *PreflightConfig) AddMinK8sV(version string) {
|
||||||
@@ -78,11 +81,22 @@ func (p *PreflightConfig) AddImage(imageFor, imageName string) {
|
|||||||
p.Spec.Images[imageFor] = imageName
|
p.Spec.Images[imageFor] = imageName
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *PreflightConfig) GetImageName(imageFor string) string {
|
func (p *PreflightConfig) GetImageName(imageFor string, accountForImageRegistry bool) (string, error) {
|
||||||
if p.Spec.Images == nil {
|
if p.Spec.Images == nil {
|
||||||
return ""
|
return "", nil
|
||||||
}
|
}
|
||||||
return p.Spec.Images[imageFor]
|
image := p.Spec.Images[imageFor]
|
||||||
|
if accountForImageRegistry {
|
||||||
|
qConfig := NewQConfig(p.QliksenseHomePath)
|
||||||
|
if currentCR, err := qConfig.GetCurrentCR(); err != nil {
|
||||||
|
return "", err
|
||||||
|
} else if imageRegistry := currentCR.Spec.GetImageRegistry(); imageRegistry != "" {
|
||||||
|
imageSegments := strings.Split(image, "/")
|
||||||
|
imageNameAndTag := imageSegments[len(imageSegments)-1]
|
||||||
|
return path.Join(imageRegistry, imageNameAndTag), nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return image, nil
|
||||||
}
|
}
|
||||||
func (p *PreflightConfig) GetMinK8sVersion() string {
|
func (p *PreflightConfig) GetMinK8sVersion() string {
|
||||||
return p.Spec.MinK8sVersion
|
return p.Spec.MinK8sVersion
|
||||||
@@ -105,5 +119,6 @@ func (p *PreflightConfig) Initialize() error {
|
|||||||
p.AddMinK8sV("1.15")
|
p.AddMinK8sV("1.15")
|
||||||
p.AddImage("nginx", "nginx")
|
p.AddImage("nginx", "nginx")
|
||||||
p.AddImage("netcat", "subfuzion/netcat")
|
p.AddImage("netcat", "subfuzion/netcat")
|
||||||
|
p.AddImage("mongo", "mongo")
|
||||||
return p.Write()
|
return p.Write()
|
||||||
}
|
}
|
||||||
138
pkg/api/preflight_apis_test.go
Normal file
138
pkg/api/preflight_apis_test.go
Normal file
@@ -0,0 +1,138 @@
|
|||||||
|
package api
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
|
"os"
|
||||||
|
"path"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Test_Initalize(t *testing.T) {
|
||||||
|
testCases := []struct {
|
||||||
|
name string
|
||||||
|
validate func(t *testing.T, tempDir string)
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "without account for imageRegistry",
|
||||||
|
validate: func(t *testing.T, tempDir string) {
|
||||||
|
preflightConfig := NewPreflightConfig(tempDir)
|
||||||
|
imageName, err := preflightConfig.GetImageName("test", false)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unexpected error: %v", err)
|
||||||
|
}
|
||||||
|
if imageName != "testimage" {
|
||||||
|
t.Fatalf("expected image name: testimage, got: %v", imageName)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "with account for configured imageRegistry",
|
||||||
|
validate: func(t *testing.T, tempDir string) {
|
||||||
|
registry := "registryFoo"
|
||||||
|
setupQliksenseTestDefaultContext(t, tempDir, fmt.Sprintf(`
|
||||||
|
apiVersion: qlik.com/v1
|
||||||
|
kind: Qliksense
|
||||||
|
metadata:
|
||||||
|
name: qlik-default
|
||||||
|
spec:
|
||||||
|
configs:
|
||||||
|
qliksense:
|
||||||
|
- name: imageRegistry
|
||||||
|
value: %v
|
||||||
|
`, registry))
|
||||||
|
preflightConfig := NewPreflightConfig(tempDir)
|
||||||
|
imageName, err := preflightConfig.GetImageName("test", true)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unexpected error: %v", err)
|
||||||
|
}
|
||||||
|
expectedImageName := fmt.Sprintf("%v/testimage", registry)
|
||||||
|
if imageName != expectedImageName {
|
||||||
|
t.Fatalf("expected image name: %v, got: %v", expectedImageName, imageName)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "with account for un-configured imageRegistry",
|
||||||
|
validate: func(t *testing.T, tempDir string) {
|
||||||
|
setupQliksenseTestDefaultContext(t, tempDir, `
|
||||||
|
apiVersion: qlik.com/v1
|
||||||
|
kind: Qliksense
|
||||||
|
metadata:
|
||||||
|
name: qlik-default
|
||||||
|
spec:
|
||||||
|
configs:
|
||||||
|
qliksense:
|
||||||
|
- name: something
|
||||||
|
value: other
|
||||||
|
`)
|
||||||
|
preflightConfig := NewPreflightConfig(tempDir)
|
||||||
|
imageName, err := preflightConfig.GetImageName("test", true)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unexpected error: %v", err)
|
||||||
|
}
|
||||||
|
expectedImageName := "testimage"
|
||||||
|
if imageName != expectedImageName {
|
||||||
|
t.Fatalf("expected image name: %v, got: %v", expectedImageName, imageName)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, testCase := range testCases {
|
||||||
|
t.Run(testCase.name, func(t *testing.T) {
|
||||||
|
tempDir, err := ioutil.TempDir("", "")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
defer os.RemoveAll(tempDir)
|
||||||
|
setupPreflightConfig(t, tempDir)
|
||||||
|
testCase.validate(t, tempDir)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func setupPreflightConfig(t *testing.T, tempDir string) {
|
||||||
|
pf := NewPreflightConfig(tempDir)
|
||||||
|
if err := pf.Initialize(); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
p := &PreflightConfig{
|
||||||
|
QliksenseHomePath: tempDir,
|
||||||
|
}
|
||||||
|
if err := ReadFromFile(p, pf.GetConfigFilePath()); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if p.GetMinK8sVersion() != "1.15" {
|
||||||
|
t.Fatalf("expected k8 version: 1.15, but got " + p.GetMinK8sVersion())
|
||||||
|
}
|
||||||
|
p.AddImage("test", "testimage")
|
||||||
|
if err := p.Write(); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func setupQliksenseTestDefaultContext(t *testing.T, tmpQlikSenseHome, CR string) {
|
||||||
|
if err := ioutil.WriteFile(path.Join(tmpQlikSenseHome, "config.yaml"), []byte(`
|
||||||
|
apiVersion: config.qlik.com/v1
|
||||||
|
kind: QliksenseConfig
|
||||||
|
metadata:
|
||||||
|
name: QliksenseConfigMetadata
|
||||||
|
spec:
|
||||||
|
contexts:
|
||||||
|
- name: qlik-default
|
||||||
|
crFile: contexts/qlik-default/qlik-default.yaml
|
||||||
|
currentContext: qlik-default
|
||||||
|
`), os.ModePerm); err != nil {
|
||||||
|
t.Fatalf("unexpected error: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
defaultContextDir := path.Join(tmpQlikSenseHome, "contexts", "qlik-default")
|
||||||
|
if err := os.MkdirAll(defaultContextDir, os.ModePerm); err != nil {
|
||||||
|
t.Fatalf("unexpected error: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := ioutil.WriteFile(path.Join(defaultContextDir, "qlik-default.yaml"), []byte(CR), os.ModePerm); err != nil {
|
||||||
|
t.Fatalf("unexpected error: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -4,6 +4,7 @@ import (
|
|||||||
"archive/tar"
|
"archive/tar"
|
||||||
"archive/zip"
|
"archive/zip"
|
||||||
"compress/gzip"
|
"compress/gzip"
|
||||||
|
b64 "encoding/base64"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
@@ -11,7 +12,6 @@ import (
|
|||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"regexp"
|
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@@ -46,7 +46,7 @@ func DirExists(dirname string) bool {
|
|||||||
// LogDebugMessage logs a debug message
|
// LogDebugMessage logs a debug message
|
||||||
func LogDebugMessage(strMessage string, args ...interface{}) {
|
func LogDebugMessage(strMessage string, args ...interface{}) {
|
||||||
if os.Getenv("QLIKSENSE_DEBUG") == "true" {
|
if os.Getenv("QLIKSENSE_DEBUG") == "true" {
|
||||||
log.Printf(strMessage, args...)
|
fmt.Printf(strMessage, args...)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -62,27 +62,38 @@ func ReadKeys(keyFile string) ([]byte, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ProcessConfigArgs processes args and returns an service, key, value slice
|
// ProcessConfigArgs processes args and returns an service, key, value slice
|
||||||
func ProcessConfigArgs(args []string) ([]*ServiceKeyValue, error) {
|
func ProcessConfigArgs(args []string, base64Encoded bool) ([]*ServiceKeyValue, error) {
|
||||||
// prepare received args
|
// prepare received args
|
||||||
// split args[0] into key and value
|
// split args[0] into key and value
|
||||||
if len(args) == 0 {
|
if len(args) == 0 {
|
||||||
err := fmt.Errorf("No args were provided. Please provide args to configure the current context")
|
err := fmt.Errorf("No args were provided. Please provide args to configure the current context")
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
notValidErr := fmt.Errorf("Please provide valid args for this command")
|
||||||
resultSvcKV := make([]*ServiceKeyValue, len(args))
|
resultSvcKV := make([]*ServiceKeyValue, len(args))
|
||||||
re1 := regexp.MustCompile(`([\w\-]{1,}).([\w\-]{1,})=("*[\w\-?=_/:0-9\.]+"*)`)
|
// qliksense.mongodb=somethig
|
||||||
for i, arg := range args {
|
for i, arg := range args {
|
||||||
LogDebugMessage("Arg received: %s", arg)
|
LogDebugMessage("Arg received: %s", arg)
|
||||||
result := re1.FindStringSubmatch(arg)
|
first := strings.SplitN(arg, "=", 2)
|
||||||
// check if result array's length is == 4 (index 0 - is the full match & indices 1,2,3- are the fields we need)
|
if len(first) != 2 {
|
||||||
if len(result) != 4 {
|
return nil, notValidErr
|
||||||
err := fmt.Errorf("Please provide valid args for this command")
|
}
|
||||||
|
second := strings.SplitN(first[0], ".", 2)
|
||||||
|
if len(second) != 2 {
|
||||||
|
return nil, notValidErr
|
||||||
|
}
|
||||||
|
resultValue := strings.Trim(first[1], "\"")
|
||||||
|
if base64Encoded {
|
||||||
|
if decodeByte, err := b64.StdEncoding.DecodeString(resultValue); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
} else {
|
||||||
|
resultValue = strings.Trim(string(decodeByte), "\n ")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
resultSvcKV[i] = &ServiceKeyValue{
|
resultSvcKV[i] = &ServiceKeyValue{
|
||||||
SvcName: result[1],
|
SvcName: second[0],
|
||||||
Key: result[2],
|
Key: second[1],
|
||||||
Value: strings.ReplaceAll(result[3], `"`, ""),
|
Value: resultValue,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return resultSvcKV, nil
|
return resultSvcKV, nil
|
||||||
|
|||||||
@@ -11,11 +11,12 @@ func TestProcessConfigArgs(t *testing.T) {
|
|||||||
"test-dash.dash-key=value-dash",
|
"test-dash.dash-key=value-dash",
|
||||||
"test-dot.dot-key=127.0.0.1",
|
"test-dot.dot-key=127.0.0.1",
|
||||||
"test123.key123=value123",
|
"test123.key123=value123",
|
||||||
|
"test-equal.keyequal=newvalue=@hj",
|
||||||
}
|
}
|
||||||
expectedKeys := []string{"mongodb", "test", "dash-key", "dot-key", "key123"}
|
expectedKeys := []string{"mongodb", "test", "dash-key", "dot-key", "key123", "keyequal"}
|
||||||
expectedValue := []string{"mongouri://something?ffall", "value_under", "value-dash", "127.0.0.1", "value123"}
|
expectedValue := []string{"mongouri://something?ffall", "value_under", "value-dash", "127.0.0.1", "value123", "newvalue=@hj"}
|
||||||
exppectedSvc := []string{"qliksense", "test_under", "test-dash", "test-dot", "test123"}
|
exppectedSvc := []string{"qliksense", "test_under", "test-dash", "test-dot", "test123", "test-equal"}
|
||||||
sv, err := ProcessConfigArgs(args)
|
sv, err := ProcessConfigArgs(args, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Log(err)
|
t.Log(err)
|
||||||
t.FailNow()
|
t.FailNow()
|
||||||
|
|||||||
@@ -2,96 +2,110 @@ package preflight
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
|
ansi "github.com/mattn/go-colorable"
|
||||||
|
"github.com/pkg/errors"
|
||||||
|
. "github.com/logrusorgru/aurora"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (qp *QliksensePreflight) RunAllPreflightChecks(namespace string, kubeConfigContents []byte, mongodbUrl string) {
|
func (qp *QliksensePreflight) RunAllPreflightChecks(kubeConfigContents []byte, namespace string, preflightOpts *PreflightOptions) error {
|
||||||
|
|
||||||
checkCount := 0
|
checkCount := 0
|
||||||
|
totalCount := 0
|
||||||
|
|
||||||
|
out := ansi.NewColorableStdout()
|
||||||
// Preflight minimum kuberenetes version check
|
// Preflight minimum kuberenetes version check
|
||||||
fmt.Printf("\nPreflight kubernetes minimum version check\n")
|
|
||||||
fmt.Println("------------------------------------------")
|
|
||||||
if err := qp.CheckK8sVersion(namespace, kubeConfigContents); err != nil {
|
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 {
|
} else {
|
||||||
|
fmt.Fprintf(out, "%s\n\n", Green("Preflight kubernetes minimum version check PASSED"))
|
||||||
checkCount++
|
checkCount++
|
||||||
}
|
}
|
||||||
|
totalCount++
|
||||||
|
|
||||||
// Preflight deployment check
|
// Preflight deployment check
|
||||||
fmt.Printf("\nPreflight deployment check\n")
|
|
||||||
fmt.Println("--------------------------")
|
|
||||||
if err := qp.CheckDeployment(namespace, kubeConfigContents); err != nil {
|
if err := qp.CheckDeployment(namespace, kubeConfigContents); err != nil {
|
||||||
fmt.Printf("Preflight deployment check: FAILED\n")
|
fmt.Fprintf(out, "%s\n", Red("Preflight deployment check FAILED"))
|
||||||
|
fmt.Printf("Error: %v\n\n", err)
|
||||||
} else {
|
} else {
|
||||||
|
fmt.Fprintf(out, "%s\n\n", Green("Preflight deployment check PASSED"))
|
||||||
checkCount++
|
checkCount++
|
||||||
}
|
}
|
||||||
|
totalCount++
|
||||||
|
|
||||||
// Preflight service check
|
// Preflight service check
|
||||||
fmt.Printf("\nPreflight service check\n")
|
|
||||||
fmt.Println("-----------------------")
|
|
||||||
if err := qp.CheckService(namespace, kubeConfigContents); err != nil {
|
if err := qp.CheckService(namespace, kubeConfigContents); err != nil {
|
||||||
fmt.Printf("Preflight service check: FAILED\n")
|
fmt.Fprintf(out, "%s\n", Red("Preflight service check FAILED"))
|
||||||
|
fmt.Printf("Error: %v\n\n", err)
|
||||||
} else {
|
} else {
|
||||||
|
fmt.Fprintf(out, "%s\n\n", Green("Preflight service check PASSED"))
|
||||||
checkCount++
|
checkCount++
|
||||||
}
|
}
|
||||||
|
totalCount++
|
||||||
|
|
||||||
// Preflight pod check
|
// Preflight pod check
|
||||||
fmt.Printf("\nPreflight pod check\n")
|
|
||||||
fmt.Println("-----------------------")
|
|
||||||
if err := qp.CheckPod(namespace, kubeConfigContents); err != nil {
|
if err := qp.CheckPod(namespace, kubeConfigContents); err != nil {
|
||||||
fmt.Printf("Preflight pod check: FAILED\n")
|
fmt.Fprintf(out, "%s\n", Red("Preflight pod check FAILED"))
|
||||||
|
fmt.Printf("Error: %v\n\n", err)
|
||||||
} else {
|
} else {
|
||||||
|
fmt.Fprintf(out, "%s\n\n", Green("Preflight pod check PASSED"))
|
||||||
checkCount++
|
checkCount++
|
||||||
}
|
}
|
||||||
|
totalCount++
|
||||||
|
|
||||||
// Preflight role check
|
// Preflight role check
|
||||||
fmt.Printf("\nPreflight role check\n")
|
|
||||||
fmt.Println("--------------------------")
|
|
||||||
if err := qp.CheckCreateRole(namespace); err != nil {
|
if err := qp.CheckCreateRole(namespace); err != nil {
|
||||||
fmt.Printf("Preflight role check: FAILED\n")
|
fmt.Fprintf(out, "%s\n", Red("Preflight role check FAILED"))
|
||||||
|
fmt.Printf("Error: %v\n\n", err)
|
||||||
} else {
|
} else {
|
||||||
|
fmt.Fprintf(out, "%s\n\n", Green("Preflight role check PASSED"))
|
||||||
checkCount++
|
checkCount++
|
||||||
}
|
}
|
||||||
|
totalCount++
|
||||||
|
|
||||||
// Preflight rolebinding check
|
// Preflight rolebinding check
|
||||||
fmt.Printf("\nPreflight rolebinding check\n")
|
|
||||||
fmt.Println("---------------------------------")
|
|
||||||
if err := qp.CheckCreateRoleBinding(namespace); err != nil {
|
if err := qp.CheckCreateRoleBinding(namespace); err != nil {
|
||||||
fmt.Printf("Preflight rolebinding check: FAILED\n")
|
fmt.Fprintf(out, "%s\n", Red(" Preflight rolebinding check FAILED"))
|
||||||
|
fmt.Printf("Error: %v\n\n", err)
|
||||||
} else {
|
} else {
|
||||||
|
fmt.Fprintf(out, "%s\n\n", Green("Preflight rolebinding check PASSED"))
|
||||||
checkCount++
|
checkCount++
|
||||||
}
|
}
|
||||||
|
totalCount++
|
||||||
|
|
||||||
// Preflight serviceaccount check
|
// Preflight serviceaccount check
|
||||||
fmt.Printf("\nPreflight serviceaccount check\n")
|
|
||||||
fmt.Println("------------------------------------")
|
|
||||||
if err := qp.CheckCreateServiceAccount(namespace); err != nil {
|
if err := qp.CheckCreateServiceAccount(namespace); err != nil {
|
||||||
fmt.Printf("Preflight serviceaccount check: FAILED\n")
|
fmt.Fprintf(out, "%s\n", Red(" Preflight serviceaccount check FAILED"))
|
||||||
|
fmt.Printf("Error: %v\n\n", err)
|
||||||
} else {
|
} else {
|
||||||
|
fmt.Fprintf(out, "%s\n\n", Green("Preflight serviceaccount check PASSED"))
|
||||||
checkCount++
|
checkCount++
|
||||||
}
|
}
|
||||||
|
totalCount++
|
||||||
|
|
||||||
// Preflight mongo check
|
// Preflight mongo check
|
||||||
fmt.Printf("\nPreflight mongo check\n")
|
if err := qp.CheckMongo(kubeConfigContents, namespace, preflightOpts); err != nil {
|
||||||
fmt.Println("---------------------")
|
fmt.Fprintf(out, "%s\n", Red(" Preflight mongo check FAILED"))
|
||||||
if err := qp.CheckMongo(kubeConfigContents, namespace, mongodbUrl); err != nil {
|
fmt.Printf("Error: %v\n\n", err)
|
||||||
fmt.Printf("Preflight mongo check: FAILED\n")
|
|
||||||
} else {
|
} else {
|
||||||
|
fmt.Fprintf(out, "%s\n\n", Green("Preflight mongo check PASSED"))
|
||||||
checkCount++
|
checkCount++
|
||||||
}
|
}
|
||||||
|
totalCount++
|
||||||
|
|
||||||
// Preflight DNS check
|
// Preflight DNS check
|
||||||
fmt.Printf("\nPreflight DNS check\n")
|
|
||||||
fmt.Println("-------------------")
|
|
||||||
if err := qp.CheckDns(namespace, kubeConfigContents); err != nil {
|
if err := qp.CheckDns(namespace, kubeConfigContents); err != nil {
|
||||||
fmt.Printf("Preflight DNS check: FAILED\n")
|
fmt.Fprintf(out, "%s\n", Red(" Preflight DNS check FAILED"))
|
||||||
|
fmt.Printf("Error: %v\n\n", err)
|
||||||
} else {
|
} else {
|
||||||
|
fmt.Fprintf(out, "%s\n\n", Green("Preflight DNS check PASSED"))
|
||||||
checkCount++
|
checkCount++
|
||||||
}
|
}
|
||||||
|
totalCount++
|
||||||
|
|
||||||
if checkCount == 9 {
|
if checkCount == totalCount {
|
||||||
fmt.Printf("\nAll preflight checks have PASSED\n")
|
// All preflight checks were successful
|
||||||
} else {
|
return nil
|
||||||
fmt.Printf("\n1 or more preflight checks have FAILED\n")
|
|
||||||
}
|
}
|
||||||
fmt.Println("Completed running all preflight checks")
|
return errors.New("1 or more preflight checks have FAILED")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,18 +10,18 @@ func (qp *QliksensePreflight) CheckDeployment(namespace string, kubeConfigConten
|
|||||||
clientset, _, err := getK8SClientSet(kubeConfigContents, "")
|
clientset, _, err := getK8SClientSet(kubeConfigContents, "")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
err = fmt.Errorf("Kube config error: %v\n", err)
|
err = fmt.Errorf("Kube config error: %v\n", err)
|
||||||
fmt.Print(err)
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Deployment check
|
// Deployment check
|
||||||
fmt.Printf("Preflight deployment check: \n")
|
qp.P.LogVerboseMessage("Preflight deployment check: \n")
|
||||||
|
qp.P.LogVerboseMessage("--------------------------- \n")
|
||||||
err = qp.checkPfDeployment(clientset, namespace, "deployment-preflight-check")
|
err = qp.checkPfDeployment(clientset, namespace, "deployment-preflight-check")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println("Preflight Deployment check: FAILED")
|
qp.P.LogVerboseMessage("Preflight Deployment check: FAILED\n")
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
fmt.Println("Completed preflight deployment check")
|
qp.P.LogVerboseMessage("Completed preflight deployment check\n")
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@@ -29,18 +29,18 @@ func (qp *QliksensePreflight) CheckDeployment(namespace string, kubeConfigConten
|
|||||||
func (qp *QliksensePreflight) CheckService(namespace string, kubeConfigContents []byte) error {
|
func (qp *QliksensePreflight) CheckService(namespace string, kubeConfigContents []byte) error {
|
||||||
clientset, _, err := getK8SClientSet(kubeConfigContents, "")
|
clientset, _, err := getK8SClientSet(kubeConfigContents, "")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
err = fmt.Errorf("error: unable to create a kubernetes client: %v\n", err)
|
err = fmt.Errorf("unable to create a kubernetes client: %v\n", err)
|
||||||
fmt.Println(err)
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
// Service check
|
// Service check
|
||||||
fmt.Printf("\nPreflight service check: \n")
|
qp.P.LogVerboseMessage("Preflight service check: \n")
|
||||||
err = checkPfService(clientset, namespace)
|
qp.P.LogVerboseMessage("------------------------ \n")
|
||||||
|
err = qp.checkPfService(clientset, namespace)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println("Preflight Service check: FAILED")
|
qp.P.LogVerboseMessage("Preflight Service check: FAILED\n")
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
fmt.Println("Completed preflight service check")
|
qp.P.LogVerboseMessage("Completed preflight service check\n")
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -48,71 +48,80 @@ func (qp *QliksensePreflight) CheckPod(namespace string, kubeConfigContents []by
|
|||||||
clientset, _, err := getK8SClientSet(kubeConfigContents, "")
|
clientset, _, err := getK8SClientSet(kubeConfigContents, "")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
err = fmt.Errorf("error: unable to create a kubernetes client: %v\n", err)
|
err = fmt.Errorf("error: unable to create a kubernetes client: %v\n", err)
|
||||||
fmt.Print(err)
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
// Pod check
|
// Pod check
|
||||||
fmt.Printf("\nPreflight pod check: \n")
|
qp.P.LogVerboseMessage("Preflight pod check: \n")
|
||||||
|
qp.P.LogVerboseMessage("-------------------- \n")
|
||||||
err = qp.checkPfPod(clientset, namespace)
|
err = qp.checkPfPod(clientset, namespace)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println("Preflight Pod check: FAILED")
|
qp.P.LogVerboseMessage("Preflight Pod check: FAILED\n")
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
fmt.Println("Completed preflight pod check")
|
qp.P.LogVerboseMessage("Completed preflight pod check\n")
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (qp *QliksensePreflight) checkPfPod(clientset *kubernetes.Clientset, namespace string) error {
|
func (qp *QliksensePreflight) checkPfPod(clientset *kubernetes.Clientset, namespace string) error {
|
||||||
// create a pod
|
// create a pod
|
||||||
podName := "pod-pf-check"
|
podName := "pod-pf-check"
|
||||||
pod, err := createPreflightTestPod(clientset, namespace, podName, qp.GetPreflightConfigObj().GetImageName(nginx))
|
commandToRun := []string{}
|
||||||
|
|
||||||
|
imageName, err := qp.GetPreflightConfigObj().GetImageName(nginx, true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
err = fmt.Errorf("error: unable to create pod %s - %v\n", podName, err)
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
defer deletePod(clientset, namespace, podName)
|
pod, err := qp.createPreflightTestPod(clientset, namespace, podName, imageName, nil, commandToRun)
|
||||||
|
if err != nil {
|
||||||
|
err = fmt.Errorf("unable to create pod - %v\n", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer qp.deletePod(clientset, namespace, podName)
|
||||||
|
|
||||||
if err := waitForPod(clientset, namespace, pod); err != nil {
|
if err := waitForPod(clientset, namespace, pod); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Println("Preflight pod creation check: PASSED")
|
qp.P.LogVerboseMessage("Preflight pod creation check: PASSED\n")
|
||||||
fmt.Println("Cleaning up resources...")
|
qp.P.LogVerboseMessage("Cleaning up resources...\n")
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func checkPfService(clientset *kubernetes.Clientset, namespace string) error {
|
func (qp *QliksensePreflight) checkPfService(clientset *kubernetes.Clientset, namespace string) error {
|
||||||
// creating service
|
// creating service
|
||||||
serviceName := "svc-pf-check"
|
serviceName := "svc-pf-check"
|
||||||
pfService, err := createPreflightTestService(clientset, namespace, serviceName)
|
pfService, err := qp.createPreflightTestService(clientset, namespace, serviceName)
|
||||||
if err != nil {
|
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
|
return err
|
||||||
}
|
}
|
||||||
defer deleteService(clientset, namespace, serviceName)
|
defer qp.deleteService(clientset, namespace, serviceName)
|
||||||
_, err = getService(clientset, namespace, pfService.GetName())
|
_, err = getService(clientset, namespace, pfService.GetName())
|
||||||
if err != nil {
|
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
|
return err
|
||||||
}
|
}
|
||||||
fmt.Println("Preflight service creation check: PASSED")
|
qp.P.LogVerboseMessage("Preflight service creation check: PASSED\n")
|
||||||
fmt.Println("Cleaning up resources...")
|
qp.P.LogVerboseMessage("Cleaning up resources...\n")
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (qp *QliksensePreflight) checkPfDeployment(clientset *kubernetes.Clientset, namespace, depName string) error {
|
func (qp *QliksensePreflight) checkPfDeployment(clientset *kubernetes.Clientset, namespace, depName string) error {
|
||||||
// check if we are able to create a deployment
|
// check if we are able to create a deployment
|
||||||
pfDeployment, err := createPreflightTestDeployment(clientset, namespace, depName, qp.GetPreflightConfigObj().GetImageName(nginx))
|
imageName, err := qp.GetPreflightConfigObj().GetImageName(nginx, true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
err = fmt.Errorf("error: unable to create deployment: %v\n", err)
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
defer deleteDeployment(clientset, namespace, depName)
|
pfDeployment, err := qp.createPreflightTestDeployment(clientset, namespace, depName, imageName)
|
||||||
|
if err != nil {
|
||||||
|
err = fmt.Errorf("unable to create deployment - %v\n", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer qp.deleteDeployment(clientset, namespace, depName)
|
||||||
if err := waitForDeployment(clientset, namespace, pfDeployment); err != nil {
|
if err := waitForDeployment(clientset, namespace, pfDeployment); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
fmt.Println("Preflight Deployment check: PASSED")
|
qp.P.LogVerboseMessage("Preflight Deployment check: PASSED\n")
|
||||||
fmt.Println("Cleaning up resources...")
|
qp.P.LogVerboseMessage("Cleaning up resources...\n")
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,8 +3,6 @@ package preflight
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/qlik-oss/sense-installer/pkg/api"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@@ -13,22 +11,26 @@ const (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func (qp *QliksensePreflight) CheckDns(namespace string, kubeConfigContents []byte) error {
|
func (qp *QliksensePreflight) CheckDns(namespace string, kubeConfigContents []byte) error {
|
||||||
clientset, clientConfig, err := getK8SClientSet(kubeConfigContents, "")
|
qp.P.LogVerboseMessage("Preflight DNS check: \n")
|
||||||
|
qp.P.LogVerboseMessage("------------------- \n")
|
||||||
|
clientset, _, err := getK8SClientSet(kubeConfigContents, "")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
err = fmt.Errorf("error: unable to create a kubernetes client: %v\n", err)
|
err = fmt.Errorf("unable to create a kubernetes client: %v\n", err)
|
||||||
fmt.Println(err)
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// creating deployment
|
// creating deployment
|
||||||
depName := "dep-dns-preflight-check"
|
depName := "dep-dns-preflight-check"
|
||||||
dnsDeployment, err := createPreflightTestDeployment(clientset, namespace, depName, qp.GetPreflightConfigObj().GetImageName(nginx))
|
nginxImageName, err := qp.GetPreflightConfigObj().GetImageName(nginx, true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
err = fmt.Errorf("error: unable to create deployment: %v\n", err)
|
|
||||||
fmt.Println(err)
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
defer deleteDeployment(clientset, namespace, depName)
|
dnsDeployment, err := qp.createPreflightTestDeployment(clientset, namespace, depName, nginxImageName)
|
||||||
|
if err != nil {
|
||||||
|
err = fmt.Errorf("unable to create deployment: %v\n", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer qp.deleteDeployment(clientset, namespace, depName)
|
||||||
|
|
||||||
if err := waitForDeployment(clientset, namespace, dnsDeployment); err != nil {
|
if err := waitForDeployment(clientset, namespace, dnsDeployment); err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -36,46 +38,54 @@ func (qp *QliksensePreflight) CheckDns(namespace string, kubeConfigContents []by
|
|||||||
|
|
||||||
// creating service
|
// creating service
|
||||||
serviceName := "svc-dns-pf-check"
|
serviceName := "svc-dns-pf-check"
|
||||||
dnsService, err := createPreflightTestService(clientset, namespace, serviceName)
|
dnsService, err := qp.createPreflightTestService(clientset, namespace, serviceName)
|
||||||
if err != nil {
|
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
|
return err
|
||||||
}
|
}
|
||||||
defer deleteService(clientset, namespace, serviceName)
|
defer qp.deleteService(clientset, namespace, serviceName)
|
||||||
|
|
||||||
// create a pod
|
// create a pod
|
||||||
podName := "pf-pod-1"
|
podName := "pf-pod-1"
|
||||||
dnsPod, err := createPreflightTestPod(clientset, namespace, podName, qp.GetPreflightConfigObj().GetImageName(netcat))
|
commandToRun := []string{"sh", "-c", "sleep 10; nc -z -v -w 1 " + dnsService.Name + " 80"}
|
||||||
|
netcatImageName, err := qp.GetPreflightConfigObj().GetImageName(netcat, true)
|
||||||
if err != nil {
|
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
|
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 {
|
if err := waitForPod(clientset, namespace, dnsPod); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if len(dnsPod.Spec.Containers) == 0 {
|
if len(dnsPod.Spec.Containers) == 0 {
|
||||||
err := fmt.Errorf("error: there are no containers in the pod")
|
err := fmt.Errorf("there are no containers in the pod")
|
||||||
fmt.Println(err)
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
api.LogDebugMessage("Exec-ing into the container...")
|
|
||||||
stdout, stderr, err := executeRemoteCommand(clientset, clientConfig, dnsPod.Name, dnsPod.Spec.Containers[0].Name, namespace, []string{"nc", "-z", "-v", "-w 1", dnsService.Name, "80"})
|
waitForPodToDie(clientset, namespace, dnsPod)
|
||||||
|
|
||||||
|
logStr, err := getPodLogs(clientset, dnsPod)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
err = fmt.Errorf("error: unable to execute dns check in the cluster: %v", err)
|
err = fmt.Errorf("unable to execute dns check in the cluster: %v", err)
|
||||||
fmt.Println(err)
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if strings.HasSuffix(stdout, "succeeded!") || strings.HasSuffix(stderr, "succeeded!") {
|
if strings.HasSuffix(strings.TrimSpace(logStr), "succeeded!") {
|
||||||
fmt.Println("Preflight DNS check: PASSED")
|
qp.P.LogVerboseMessage("Preflight DNS check: PASSED\n")
|
||||||
} else {
|
} else {
|
||||||
fmt.Println("Preflight DNS check: FAILED")
|
err = fmt.Errorf("Expected response not found\n")
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Println("Completed preflight DNS check")
|
qp.P.LogVerboseMessage("Completed preflight DNS check\n")
|
||||||
fmt.Println("Cleaning up resources...")
|
qp.P.LogVerboseMessage("Cleaning up resources...\n")
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,22 +2,26 @@ package preflight
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/qlik-oss/sense-installer/pkg/api"
|
"github.com/qlik-oss/sense-installer/pkg/api"
|
||||||
qapi "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 (
|
const (
|
||||||
mongoImage = "mongo"
|
mongo = "mongo"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (qp *QliksensePreflight) CheckMongo(kubeConfigContents []byte, namespace, mongodbUrl string) error {
|
func (qp *QliksensePreflight) CheckMongo(kubeConfigContents []byte, namespace string, preflightOpts *PreflightOptions) error {
|
||||||
fmt.Printf("Preflight mongodb check: \n")
|
qp.P.LogVerboseMessage("Preflight mongodb check: \n")
|
||||||
|
qp.P.LogVerboseMessage("------------------------ \n")
|
||||||
|
|
||||||
if mongodbUrl == "" {
|
if preflightOpts.MongoOptions.MongodbUrl == "" {
|
||||||
// infer mongoDbUrl from currentCR
|
// 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)
|
qConfig := qapi.NewQConfig(qp.Q.QliksenseHome)
|
||||||
var currentCR *qapi.QliksenseCR
|
var currentCR *qapi.QliksenseCR
|
||||||
|
|
||||||
@@ -25,61 +29,131 @@ func (qp *QliksensePreflight) CheckMongo(kubeConfigContents []byte, namespace, m
|
|||||||
qConfig.SetNamespace(namespace)
|
qConfig.SetNamespace(namespace)
|
||||||
currentCR, err = qConfig.GetCurrentCR()
|
currentCR, err = qConfig.GetCurrentCR()
|
||||||
if err != nil {
|
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
|
return err
|
||||||
}
|
}
|
||||||
decryptedCR, err := qConfig.GetDecryptedCr(currentCR)
|
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)
|
||||||
|
|
||||||
fmt.Printf("mongodbUrl: %s\n", mongodbUrl)
|
|
||||||
if err := mongoConnCheck(kubeConfigContents, namespace, mongodbUrl); err != nil {
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
fmt.Println("Completed preflight mongodb check")
|
preflightOpts.MongoOptions.MongodbUrl = decryptedCR.Spec.GetFromSecrets("qliksense", "mongoDbUri")
|
||||||
|
}
|
||||||
|
|
||||||
|
qp.P.LogVerboseMessage("MongodbUrl: %s\n", preflightOpts.MongoOptions.MongodbUrl)
|
||||||
|
if err := qp.mongoConnCheck(kubeConfigContents, namespace, preflightOpts); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
qp.P.LogVerboseMessage("Completed preflight mongodb check\n")
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func mongoConnCheck(kubeConfigContents []byte, namespace, mongodbUrl string) error {
|
func (qp *QliksensePreflight) mongoConnCheck(kubeConfigContents []byte, namespace string, preflightOpts *PreflightOptions) error {
|
||||||
clientset, clientConfig, err := getK8SClientSet(kubeConfigContents, "")
|
var caCertSecretName, clientCertSecretName string
|
||||||
|
clientset, _, err := getK8SClientSet(kubeConfigContents, "")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
err = fmt.Errorf("error: unable to create a kubernetes client: %v\n", err)
|
err = fmt.Errorf("unable to create a kubernetes client: %v\n", err)
|
||||||
fmt.Println(err)
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
var secrets []string
|
||||||
|
if preflightOpts.MongoOptions.CaCertFile != "" {
|
||||||
|
caCertSecretName = "preflight-mongo-test-cacert"
|
||||||
|
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)
|
||||||
|
secrets = append(secrets, caCertSecretName)
|
||||||
|
}
|
||||||
|
if preflightOpts.MongoOptions.ClientCertFile != "" {
|
||||||
|
clientCertSecretName = "preflight-mongo-test-clientcert"
|
||||||
|
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)
|
||||||
|
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
|
// create a pod
|
||||||
podName := "pf-mongo-pod"
|
podName := "pf-mongo-pod"
|
||||||
mongoPod, err := createPreflightTestPod(clientset, namespace, podName, mongoImage)
|
imageName, err := qp.GetPreflightConfigObj().GetImageName(mongo, true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
err = fmt.Errorf("error: unable to create pod : %s\n", podName)
|
err = fmt.Errorf("unable to retrieve image : %v\n", err)
|
||||||
fmt.Println("Preflight mongo check: FAILED")
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
defer deletePod(clientset, namespace, podName)
|
mongoPod, err := qp.createPreflightTestPod(clientset, namespace, podName, imageName, secrets, commandToRun)
|
||||||
|
if err != nil {
|
||||||
|
err = fmt.Errorf("unable to create pod : %v\n", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer qp.deletePod(clientset, namespace, podName)
|
||||||
|
|
||||||
if err := waitForPod(clientset, namespace, mongoPod); err != nil {
|
if err := waitForPod(clientset, namespace, mongoPod); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if len(mongoPod.Spec.Containers) == 0 {
|
if len(mongoPod.Spec.Containers) == 0 {
|
||||||
err := fmt.Errorf("error: there are no containers in the pod")
|
err := fmt.Errorf("there are no containers in the pod- %v\n", err)
|
||||||
fmt.Println(err)
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
api.LogDebugMessage("Exec-ing into the container...")
|
waitForPodToDie(clientset, namespace, mongoPod)
|
||||||
stdout, stderr, err := executeRemoteCommand(clientset, clientConfig, mongoPod.Name, mongoPod.Spec.Containers[0].Name, namespace, []string{"mongo", mongodbUrl})
|
logStr, err := getPodLogs(clientset, mongoPod)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
err = fmt.Errorf("error: unable to execute mongo check in the cluster: %v", err)
|
err = fmt.Errorf("unable to execute mongo check in the cluster: %v\n", err)
|
||||||
fmt.Println(err)
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Println("stdout:", stdout)
|
stringToCheck := "Implicit session:"
|
||||||
fmt.Println("stderr:", stderr)
|
if strings.Contains(logStr, stringToCheck) {
|
||||||
stringToCheck := "Implicit session"
|
qp.P.LogVerboseMessage("Preflight mongo check: PASSED\n")
|
||||||
if strings.Contains(stdout, stringToCheck) || strings.Contains(stderr, stringToCheck) {
|
|
||||||
fmt.Println("Preflight mongo check: PASSED")
|
|
||||||
} else {
|
} else {
|
||||||
fmt.Println("Preflight mongo check: FAILED")
|
err = fmt.Errorf("Connection failed: %s\n", logStr)
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
return nil
|
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
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,41 +0,0 @@
|
|||||||
package preflight
|
|
||||||
|
|
||||||
import (
|
|
||||||
"io/ioutil"
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
api "github.com/qlik-oss/sense-installer/pkg/api"
|
|
||||||
)
|
|
||||||
|
|
||||||
func Test_Initalize(t *testing.T) {
|
|
||||||
tempDir, err := ioutil.TempDir("", "")
|
|
||||||
if err != nil {
|
|
||||||
t.Log(err)
|
|
||||||
t.FailNow()
|
|
||||||
}
|
|
||||||
pf := NewPreflightConfig(tempDir)
|
|
||||||
if err := pf.Initialize(); err != nil {
|
|
||||||
t.Log()
|
|
||||||
t.FailNow()
|
|
||||||
}
|
|
||||||
p := &PreflightConfig{
|
|
||||||
QliksenseHomePath: tempDir,
|
|
||||||
}
|
|
||||||
if err := api.ReadFromFile(p, pf.GetConfigFilePath()); err != nil {
|
|
||||||
t.Log(err)
|
|
||||||
t.FailNow()
|
|
||||||
}
|
|
||||||
if p.GetMinK8sVersion() != "1.15" {
|
|
||||||
t.Log("expected k8 version: 1.15, but got " + p.GetMinK8sVersion())
|
|
||||||
t.Fail()
|
|
||||||
}
|
|
||||||
p.AddImage("test", "testimage")
|
|
||||||
if err := p.Write(); err != nil {
|
|
||||||
t.Log(err)
|
|
||||||
t.Fail()
|
|
||||||
}
|
|
||||||
p2 := NewPreflightConfig(tempDir)
|
|
||||||
if p2.GetImageName("test") != "testimage" {
|
|
||||||
t.Log("expected image name: testimage, got: " + p2.GetImageName("test"))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -6,43 +6,57 @@ import (
|
|||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"log"
|
"log"
|
||||||
"net/url"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/mitchellh/go-homedir"
|
"github.com/mitchellh/go-homedir"
|
||||||
|
|
||||||
"k8s.io/apimachinery/pkg/util/wait"
|
|
||||||
|
|
||||||
"k8s.io/client-go/util/retry"
|
|
||||||
|
|
||||||
"k8s.io/client-go/rest"
|
|
||||||
"k8s.io/client-go/tools/clientcmd"
|
|
||||||
"k8s.io/client-go/tools/remotecommand"
|
|
||||||
"k8s.io/kubectl/pkg/scheme"
|
|
||||||
|
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
"github.com/qlik-oss/sense-installer/pkg/api"
|
"github.com/qlik-oss/sense-installer/pkg/api"
|
||||||
"github.com/qlik-oss/sense-installer/pkg/qliksense"
|
"github.com/qlik-oss/sense-installer/pkg/qliksense"
|
||||||
appsv1 "k8s.io/api/apps/v1"
|
appsv1 "k8s.io/api/apps/v1"
|
||||||
apiv1 "k8s.io/api/core/v1"
|
apiv1 "k8s.io/api/core/v1"
|
||||||
"k8s.io/api/rbac/v1beta1"
|
"k8s.io/api/rbac/v1beta1"
|
||||||
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
|
||||||
"k8s.io/client-go/kubernetes"
|
|
||||||
restclient "k8s.io/client-go/rest"
|
|
||||||
|
|
||||||
k8serrors "k8s.io/apimachinery/pkg/api/errors"
|
k8serrors "k8s.io/apimachinery/pkg/api/errors"
|
||||||
|
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
|
"k8s.io/apimachinery/pkg/util/wait"
|
||||||
|
"k8s.io/client-go/kubernetes"
|
||||||
|
"k8s.io/client-go/rest"
|
||||||
|
"k8s.io/client-go/tools/clientcmd"
|
||||||
|
"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
|
var gracePeriod int64 = 0
|
||||||
|
|
||||||
type QliksensePreflight struct {
|
type QliksensePreflight struct {
|
||||||
Q *qliksense.Qliksense
|
Q *qliksense.Qliksense
|
||||||
|
P *PreflightOptions
|
||||||
}
|
}
|
||||||
|
|
||||||
func (qp *QliksensePreflight) GetPreflightConfigObj() *PreflightConfig {
|
func (qp *QliksensePreflight) GetPreflightConfigObj() *api.PreflightConfig {
|
||||||
return NewPreflightConfig(qp.Q.QliksenseHome)
|
return api.NewPreflightConfig(qp.Q.QliksenseHome)
|
||||||
}
|
}
|
||||||
|
|
||||||
func InitPreflight() (string, []byte, error) {
|
func InitPreflight() (string, []byte, error) {
|
||||||
@@ -102,14 +116,12 @@ func getK8SClientSet(kubeconfig []byte, contextName string) (*kubernetes.Clients
|
|||||||
clientConfig, err = rest.InClusterConfig()
|
clientConfig, err = rest.InClusterConfig()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
err = errors.Wrap(err, "Unable to load in-cluster kubeconfig")
|
err = errors.Wrap(err, "Unable to load in-cluster kubeconfig")
|
||||||
fmt.Println(err)
|
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
config, err := clientcmd.Load(kubeconfig)
|
config, err := clientcmd.Load(kubeconfig)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
err = errors.Wrap(err, "Unable to load kubeconfig")
|
err = errors.Wrap(err, "Unable to load kubeconfig")
|
||||||
fmt.Println(err)
|
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
if contextName != "" {
|
if contextName != "" {
|
||||||
@@ -118,20 +130,18 @@ func getK8SClientSet(kubeconfig []byte, contextName string) (*kubernetes.Clients
|
|||||||
clientConfig, err = clientcmd.NewDefaultClientConfig(*config, &clientcmd.ConfigOverrides{}).ClientConfig()
|
clientConfig, err = clientcmd.NewDefaultClientConfig(*config, &clientcmd.ConfigOverrides{}).ClientConfig()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
err = errors.Wrap(err, "Unable to create client config from config")
|
err = errors.Wrap(err, "Unable to create client config from config")
|
||||||
fmt.Println(err)
|
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
clientset, err := kubernetes.NewForConfig(clientConfig)
|
clientset, err := kubernetes.NewForConfig(clientConfig)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
err = errors.Wrap(err, "Unable to create clientset")
|
err = errors.Wrap(err, "Unable to create clientset")
|
||||||
fmt.Println(err)
|
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
return clientset, clientConfig, nil
|
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)
|
deploymentsClient := clientset.AppsV1().Deployments(namespace)
|
||||||
deployment := &appsv1.Deployment{
|
deployment := &appsv1.Deployment{
|
||||||
ObjectMeta: v1.ObjectMeta{
|
ObjectMeta: v1.ObjectMeta{
|
||||||
@@ -176,11 +186,10 @@ func createPreflightTestDeployment(clientset *kubernetes.Clientset, namespace st
|
|||||||
result, err = deploymentsClient.Create(deployment)
|
result, err = deploymentsClient.Create(deployment)
|
||||||
return err
|
return err
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
err = errors.Wrapf(err, "error: unable to create deployments in the %s namespace", namespace)
|
err = errors.Wrapf(err, "unable to create deployments in the %s namespace", namespace)
|
||||||
fmt.Println(err)
|
|
||||||
return nil, err
|
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
|
return deployment, nil
|
||||||
}
|
}
|
||||||
@@ -192,14 +201,14 @@ func getDeployment(clientset *kubernetes.Clientset, namespace, depName string) (
|
|||||||
deployment, err = deploymentsClient.Get(depName, v1.GetOptions{})
|
deployment, err = deploymentsClient.Get(depName, v1.GetOptions{})
|
||||||
return err
|
return err
|
||||||
}); err != nil {
|
}); 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)
|
api.LogDebugMessage("%v\n", err)
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return deployment, nil
|
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)
|
deploymentsClient := clientset.AppsV1().Deployments(namespace)
|
||||||
// Create Deployment
|
// Create Deployment
|
||||||
deletePolicy := v1.DeletePropagationForeground
|
deletePolicy := v1.DeletePropagationForeground
|
||||||
@@ -211,17 +220,16 @@ func deleteDeployment(clientset *kubernetes.Clientset, namespace, name string) e
|
|||||||
if err := retryOnError(func() (err error) {
|
if err := retryOnError(func() (err error) {
|
||||||
return deploymentsClient.Delete(name, &deleteOptions)
|
return deploymentsClient.Delete(name, &deleteOptions)
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
fmt.Println(err)
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if err := waitForDeploymentToDelete(clientset, namespace, name); err != nil {
|
if err := waitForDeploymentToDelete(clientset, namespace, name); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
fmt.Printf("Deleted deployment: %s\n", name)
|
qp.P.LogVerboseMessage("Deleted deployment: %s\n", name)
|
||||||
return nil
|
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)
|
iptr := int32Ptr(80)
|
||||||
servicesClient := clientset.CoreV1().Services(namespace)
|
servicesClient := clientset.CoreV1().Services(namespace)
|
||||||
service := &apiv1.Service{
|
service := &apiv1.Service{
|
||||||
@@ -249,10 +257,9 @@ func createPreflightTestService(clientset *kubernetes.Clientset, namespace strin
|
|||||||
result, err = servicesClient.Create(service)
|
result, err = servicesClient.Create(service)
|
||||||
return err
|
return err
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
fmt.Println(err)
|
|
||||||
return nil, 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
|
return service, nil
|
||||||
}
|
}
|
||||||
@@ -265,14 +272,13 @@ func getService(clientset *kubernetes.Clientset, namespace, svcName string) (*ap
|
|||||||
return err
|
return err
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
err = errors.Wrapf(err, "unable to get services in the %s namespace", namespace)
|
err = errors.Wrapf(err, "unable to get services in the %s namespace", namespace)
|
||||||
fmt.Println(err)
|
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return svc, nil
|
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)
|
servicesClient := clientset.CoreV1().Services(namespace)
|
||||||
// Create Deployment
|
// Create Deployment
|
||||||
deletePolicy := v1.DeletePropagationForeground
|
deletePolicy := v1.DeletePropagationForeground
|
||||||
@@ -285,11 +291,11 @@ func deleteService(clientset *kubernetes.Clientset, namespace, name string) erro
|
|||||||
fmt.Println(err)
|
fmt.Println(err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
fmt.Printf("Deleted service: %s\n", name)
|
qp.P.LogVerboseMessage("Deleted service: %s\n", name)
|
||||||
return nil
|
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)
|
podsClient := clientset.CoreV1().Pods(namespace)
|
||||||
deletePolicy := v1.DeletePropagationForeground
|
deletePolicy := v1.DeletePropagationForeground
|
||||||
@@ -300,17 +306,16 @@ func deletePod(clientset *kubernetes.Clientset, namespace, name string) error {
|
|||||||
if err := retryOnError(func() (err error) {
|
if err := retryOnError(func() (err error) {
|
||||||
return podsClient.Delete(name, &deleteOptions)
|
return podsClient.Delete(name, &deleteOptions)
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
fmt.Println(err)
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if err := waitForPodToDelete(clientset, namespace, name); err != nil {
|
if err := waitForPodToDelete(clientset, namespace, name); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
fmt.Printf("Deleted pod: %s\n", name)
|
qp.P.LogVerboseMessage("Deleted pod: %s\n", name)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func createPreflightTestPod(clientset *kubernetes.Clientset, namespace string, podName string, imageName 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
|
// build the pod definition we want to deploy
|
||||||
pod := &apiv1.Pod{
|
pod := &apiv1.Pod{
|
||||||
ObjectMeta: v1.ObjectMeta{
|
ObjectMeta: v1.ObjectMeta{
|
||||||
@@ -321,18 +326,41 @@ func createPreflightTestPod(clientset *kubernetes.Clientset, namespace string, p
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
Spec: apiv1.PodSpec{
|
Spec: apiv1.PodSpec{
|
||||||
|
RestartPolicy: apiv1.RestartPolicyNever,
|
||||||
Containers: []apiv1.Container{
|
Containers: []apiv1.Container{
|
||||||
{
|
{
|
||||||
Name: "cnt",
|
Name: "cnt",
|
||||||
Image: imageName,
|
Image: imageName,
|
||||||
ImagePullPolicy: apiv1.PullIfNotPresent,
|
ImagePullPolicy: apiv1.PullIfNotPresent,
|
||||||
Command: []string{
|
Command: commandToRun,
|
||||||
"sleep",
|
},
|
||||||
"3600",
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
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
|
// now create the pod in kubernetes cluster using the clientset
|
||||||
@@ -340,10 +368,9 @@ func createPreflightTestPod(clientset *kubernetes.Clientset, namespace string, p
|
|||||||
pod, err = clientset.CoreV1().Pods(namespace).Create(pod)
|
pod, err = clientset.CoreV1().Pods(namespace).Create(pod)
|
||||||
return err
|
return err
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
fmt.Println(err)
|
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
fmt.Printf("Created pod: %s\n", pod.Name)
|
qp.P.LogVerboseMessage("Created pod: %s\n", pod.Name)
|
||||||
return pod, nil
|
return pod, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -360,67 +387,68 @@ func getPod(clientset *kubernetes.Clientset, namespace, podName string) (*apiv1.
|
|||||||
return pod, nil
|
return pod, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func execute(method string, url *url.URL, config *restclient.Config, stdin io.Reader, stdout, stderr io.Writer, tty bool) error {
|
func getPodLogs(clientset *kubernetes.Clientset, pod *apiv1.Pod) (string, error) {
|
||||||
exec, err := remotecommand.NewSPDYExecutor(config, method, url)
|
podLogOpts := apiv1.PodLogOptions{}
|
||||||
|
|
||||||
|
api.LogDebugMessage("Retrieving logs for pod: %s namespace: %s\n", pod.GetName(), pod.Namespace)
|
||||||
|
req := clientset.CoreV1().Pods(pod.Namespace).GetLogs(pod.Name, &podLogOpts)
|
||||||
|
podLogs, err := req.Stream()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return "", err
|
||||||
}
|
}
|
||||||
return exec.Stream(remotecommand.StreamOptions{
|
defer podLogs.Close()
|
||||||
Stdin: stdin,
|
time.Sleep(15 * time.Second)
|
||||||
Stdout: stdout,
|
buf := new(bytes.Buffer)
|
||||||
Stderr: stderr,
|
_, err = io.Copy(buf, podLogs)
|
||||||
Tty: tty,
|
if err != nil {
|
||||||
})
|
return "", err
|
||||||
|
}
|
||||||
|
api.LogDebugMessage("Log from pod: %s\n", buf.String())
|
||||||
|
return buf.String(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func executeRemoteCommand(clientset *kubernetes.Clientset, config *rest.Config, podName, containerName, namespace string, command []string) (string, string, error) {
|
func waitForResource(checkFunc func() (interface{}, error), validateFunc func(interface{}) bool) error {
|
||||||
tty := false
|
|
||||||
req := clientset.CoreV1().RESTClient().Post().
|
|
||||||
Resource("pods").
|
|
||||||
Name(podName).
|
|
||||||
Namespace(namespace).
|
|
||||||
SubResource("exec").
|
|
||||||
Param("container", containerName)
|
|
||||||
req.VersionedParams(&apiv1.PodExecOptions{
|
|
||||||
Container: containerName,
|
|
||||||
Command: command,
|
|
||||||
Stdin: false,
|
|
||||||
Stdout: true,
|
|
||||||
Stderr: true,
|
|
||||||
TTY: tty,
|
|
||||||
}, scheme.ParameterCodec)
|
|
||||||
|
|
||||||
var stdout, stderr bytes.Buffer
|
|
||||||
err := execute("POST", req.URL(), config, nil, &stdout, &stderr, tty)
|
|
||||||
return strings.TrimSpace(stdout.String()), strings.TrimSpace(stderr.String()), err
|
|
||||||
}
|
|
||||||
|
|
||||||
func waitForDeployment(clientset *kubernetes.Clientset, namespace string, pfDeployment *appsv1.Deployment) error {
|
|
||||||
timeout := time.NewTicker(2 * time.Minute)
|
timeout := time.NewTicker(2 * time.Minute)
|
||||||
defer timeout.Stop()
|
defer timeout.Stop()
|
||||||
var d *appsv1.Deployment
|
OUT:
|
||||||
var err error
|
|
||||||
WAIT:
|
|
||||||
for {
|
for {
|
||||||
d, err = getDeployment(clientset, namespace, pfDeployment.GetName())
|
r, err := checkFunc()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
err = fmt.Errorf("error: unable to retrieve deployment: %s\n", pfDeployment.GetName())
|
|
||||||
fmt.Println(err)
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
select {
|
select {
|
||||||
case <-timeout.C:
|
case <-timeout.C:
|
||||||
break WAIT
|
break OUT
|
||||||
default:
|
default:
|
||||||
if int(d.Status.ReadyReplicas) > 0 {
|
if validateFunc(r) {
|
||||||
break WAIT
|
break OUT
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
time.Sleep(5 * time.Second)
|
time.Sleep(5 * time.Second)
|
||||||
}
|
}
|
||||||
if int(d.Status.ReadyReplicas) == 0 {
|
return nil
|
||||||
err = fmt.Errorf("error: deployment took longer than expected to spin up pods")
|
}
|
||||||
fmt.Println(err)
|
|
||||||
|
func waitForDeployment(clientset *kubernetes.Clientset, namespace string, pfDeployment *appsv1.Deployment) error {
|
||||||
|
var err error
|
||||||
|
depName := pfDeployment.GetName()
|
||||||
|
checkFunc := func() (interface{}, error) {
|
||||||
|
pfDeployment, err = getDeployment(clientset, namespace, depName)
|
||||||
|
if err != nil {
|
||||||
|
err = fmt.Errorf("unable to retrieve deployment: %s\n", depName)
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return pfDeployment, nil
|
||||||
|
}
|
||||||
|
validateFunc := func(data interface{}) bool {
|
||||||
|
d := data.(*appsv1.Deployment)
|
||||||
|
return int(d.Status.ReadyReplicas) > 0
|
||||||
|
}
|
||||||
|
if err := waitForResource(checkFunc, validateFunc); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if int(pfDeployment.Status.ReadyReplicas) == 0 {
|
||||||
|
err = fmt.Errorf("deployment took longer than expected to spin up pods")
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
@@ -428,87 +456,92 @@ WAIT:
|
|||||||
|
|
||||||
func waitForPod(clientset *kubernetes.Clientset, namespace string, pod *apiv1.Pod) error {
|
func waitForPod(clientset *kubernetes.Clientset, namespace string, pod *apiv1.Pod) error {
|
||||||
var err error
|
var err error
|
||||||
if len(pod.Spec.Containers) > 0 {
|
if len(pod.Spec.Containers) == 0 {
|
||||||
timeout := time.NewTicker(2 * time.Minute)
|
err = fmt.Errorf("there are no containers in the pod")
|
||||||
defer timeout.Stop()
|
|
||||||
podName := pod.Name
|
|
||||||
OUT:
|
|
||||||
for {
|
|
||||||
pod, err = getPod(clientset, namespace, podName)
|
|
||||||
if err != nil {
|
|
||||||
err = fmt.Errorf("error: unable to retrieve %s pod by name", podName)
|
|
||||||
fmt.Println(err)
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
select {
|
podName := pod.Name
|
||||||
case <-timeout.C:
|
checkFunc := func() (interface{}, error) {
|
||||||
break OUT
|
pod, err = getPod(clientset, namespace, podName)
|
||||||
default:
|
if err != nil {
|
||||||
if len(pod.Status.ContainerStatuses) > 0 && pod.Status.ContainerStatuses[0].Ready {
|
err = fmt.Errorf("unable to retrieve %s pod by name", podName)
|
||||||
break OUT
|
return nil, err
|
||||||
}
|
}
|
||||||
|
return pod, nil
|
||||||
}
|
}
|
||||||
time.Sleep(5 * time.Second)
|
validateFunc := func(data interface{}) bool {
|
||||||
|
po := data.(*apiv1.Pod)
|
||||||
|
return len(po.Status.ContainerStatuses) > 0 && po.Status.ContainerStatuses[0].Ready
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := waitForResource(checkFunc, validateFunc); err != nil {
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
if len(pod.Status.ContainerStatuses) == 0 || !pod.Status.ContainerStatuses[0].Ready {
|
if len(pod.Status.ContainerStatuses) == 0 || !pod.Status.ContainerStatuses[0].Ready {
|
||||||
err = fmt.Errorf("error: container is taking much longer than expected")
|
err = fmt.Errorf("container is taking much longer than expected")
|
||||||
fmt.Println(err)
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func waitForPodToDie(clientset *kubernetes.Clientset, namespace string, pod *apiv1.Pod) error {
|
||||||
|
podName := pod.Name
|
||||||
|
checkFunc := func() (interface{}, error) {
|
||||||
|
po, err := getPod(clientset, namespace, podName)
|
||||||
|
if err != nil {
|
||||||
|
err = fmt.Errorf("unable to retrieve %s pod by name", podName)
|
||||||
|
return nil, err
|
||||||
}
|
}
|
||||||
err = fmt.Errorf("error: there are no containers in the pod")
|
api.LogDebugMessage("pod status: %v\n", po.Status.Phase)
|
||||||
fmt.Println(err)
|
return po, nil
|
||||||
|
}
|
||||||
|
validateFunc := func(r interface{}) bool {
|
||||||
|
po := r.(*apiv1.Pod)
|
||||||
|
return po.Status.Phase == apiv1.PodFailed || po.Status.Phase == apiv1.PodSucceeded
|
||||||
|
}
|
||||||
|
if err := waitForResource(checkFunc, validateFunc); err != nil {
|
||||||
return err
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func waitForPodToDelete(clientset *kubernetes.Clientset, namespace, podName string) error {
|
func waitForPodToDelete(clientset *kubernetes.Clientset, namespace, podName string) error {
|
||||||
var err error
|
checkFunc := func() (interface{}, error) {
|
||||||
timeout := time.NewTicker(2 * time.Minute)
|
po, err := getPod(clientset, namespace, podName)
|
||||||
defer timeout.Stop()
|
|
||||||
OUT:
|
|
||||||
for {
|
|
||||||
_, err = getPod(clientset, namespace, podName)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return po, nil
|
||||||
|
}
|
||||||
|
validateFunc := func(po interface{}) bool {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if err := waitForResource(checkFunc, validateFunc); err != nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
select {
|
err := fmt.Errorf("delete pod is taking unusually long")
|
||||||
case <-timeout.C:
|
|
||||||
break OUT
|
|
||||||
default:
|
|
||||||
|
|
||||||
}
|
|
||||||
time.Sleep(5 * time.Second)
|
|
||||||
}
|
|
||||||
err = fmt.Errorf("error: delete pod is taking unusually long")
|
|
||||||
fmt.Println(err)
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func waitForDeploymentToDelete(clientset *kubernetes.Clientset, namespace, deploymentName string) error {
|
func waitForDeploymentToDelete(clientset *kubernetes.Clientset, namespace, deploymentName string) error {
|
||||||
var err error
|
checkFunc := func() (interface{}, error) {
|
||||||
timeout := time.NewTicker(2 * time.Minute)
|
dep, err := getDeployment(clientset, namespace, deploymentName)
|
||||||
defer timeout.Stop()
|
|
||||||
OUT:
|
|
||||||
for {
|
|
||||||
_, err = getDeployment(clientset, namespace, deploymentName)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return dep, nil
|
||||||
|
}
|
||||||
|
validateFunc := func(po interface{}) bool {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if err := waitForResource(checkFunc, validateFunc); err != nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
select {
|
err := fmt.Errorf("delete deployment is taking unusually long")
|
||||||
case <-timeout.C:
|
|
||||||
break OUT
|
|
||||||
default:
|
|
||||||
|
|
||||||
}
|
|
||||||
time.Sleep(5 * time.Second)
|
|
||||||
}
|
|
||||||
err = fmt.Errorf("error: delete deployment is taking unusually long")
|
|
||||||
fmt.Println(err)
|
|
||||||
return err
|
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
|
// build the role defination we want to create
|
||||||
var role *v1beta1.Role
|
var role *v1beta1.Role
|
||||||
roleSpec := &v1beta1.Role{
|
roleSpec := &v1beta1.Role{
|
||||||
@@ -527,16 +560,15 @@ func createPfRole(clientset *kubernetes.Clientset, namespace, roleName string) (
|
|||||||
role, err = clientset.RbacV1beta1().Roles(namespace).Create(roleSpec)
|
role, err = clientset.RbacV1beta1().Roles(namespace).Create(roleSpec)
|
||||||
return err
|
return err
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
fmt.Println(err)
|
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Printf("Created role: %s\n", role.Name)
|
qp.P.LogVerboseMessage("Created role: %s\n", role.Name)
|
||||||
|
|
||||||
return role, nil
|
return role, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func deleteRole(clientset *kubernetes.Clientset, namespace string, role *v1beta1.Role) {
|
func (qp *QliksensePreflight) deleteRole(clientset *kubernetes.Clientset, namespace string, role *v1beta1.Role) {
|
||||||
rolesClient := clientset.RbacV1beta1().Roles(namespace)
|
rolesClient := clientset.RbacV1beta1().Roles(namespace)
|
||||||
|
|
||||||
deletePolicy := v1.DeletePropagationForeground
|
deletePolicy := v1.DeletePropagationForeground
|
||||||
@@ -547,10 +579,10 @@ func deleteRole(clientset *kubernetes.Clientset, namespace string, role *v1beta1
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
fmt.Printf("Deleted role: %s\n\n", role.Name)
|
qp.P.LogVerboseMessage("Deleted role: %s\n\n", role.Name)
|
||||||
}
|
}
|
||||||
|
|
||||||
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
|
var roleBinding *v1beta1.RoleBinding
|
||||||
// build the rolebinding defination we want to create
|
// build the rolebinding defination we want to create
|
||||||
roleBindingSpec := &v1beta1.RoleBinding{
|
roleBindingSpec := &v1beta1.RoleBinding{
|
||||||
@@ -558,7 +590,7 @@ func createPfRoleBinding(clientset *kubernetes.Clientset, namespace, roleBinding
|
|||||||
Name: roleBindingName,
|
Name: roleBindingName,
|
||||||
Namespace: namespace,
|
Namespace: namespace,
|
||||||
Labels: map[string]string{
|
Labels: map[string]string{
|
||||||
"app": "demo",
|
"app": "preflight",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Subjects: []v1beta1.Subject{
|
Subjects: []v1beta1.Subject{
|
||||||
@@ -581,14 +613,13 @@ func createPfRoleBinding(clientset *kubernetes.Clientset, namespace, roleBinding
|
|||||||
roleBinding, err = clientset.RbacV1beta1().RoleBindings(namespace).Create(roleBindingSpec)
|
roleBinding, err = clientset.RbacV1beta1().RoleBindings(namespace).Create(roleBindingSpec)
|
||||||
return err
|
return err
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
fmt.Println(err)
|
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
fmt.Printf("Created RoleBinding: %s\n", roleBindingSpec.Name)
|
qp.P.LogVerboseMessage("Created RoleBinding: %s\n", roleBindingSpec.Name)
|
||||||
return roleBinding, nil
|
return roleBinding, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func deleteRoleBinding(clientset *kubernetes.Clientset, namespace string, roleBinding *v1beta1.RoleBinding) {
|
func (qp *QliksensePreflight) deleteRoleBinding(clientset *kubernetes.Clientset, namespace string, roleBinding *v1beta1.RoleBinding) {
|
||||||
roleBindingClient := clientset.RbacV1beta1().RoleBindings(namespace)
|
roleBindingClient := clientset.RbacV1beta1().RoleBindings(namespace)
|
||||||
|
|
||||||
deletePolicy := v1.DeletePropagationForeground
|
deletePolicy := v1.DeletePropagationForeground
|
||||||
@@ -599,10 +630,10 @@ func deleteRoleBinding(clientset *kubernetes.Clientset, namespace string, roleBi
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
fmt.Printf("Deleted RoleBinding: %s\n\n", roleBinding.Name)
|
qp.P.LogVerboseMessage("Deleted RoleBinding: %s\n\n", roleBinding.Name)
|
||||||
}
|
}
|
||||||
|
|
||||||
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
|
var serviceAccount *apiv1.ServiceAccount
|
||||||
// build the serviceAccount defination we want to create
|
// build the serviceAccount defination we want to create
|
||||||
serviceAccountSpec := &apiv1.ServiceAccount{
|
serviceAccountSpec := &apiv1.ServiceAccount{
|
||||||
@@ -610,7 +641,7 @@ func createPfServiceAccount(clientset *kubernetes.Clientset, namespace, serviceA
|
|||||||
Name: "preflight-check-test-serviceaccount",
|
Name: "preflight-check-test-serviceaccount",
|
||||||
Namespace: namespace,
|
Namespace: namespace,
|
||||||
Labels: map[string]string{
|
Labels: map[string]string{
|
||||||
"app": "demo",
|
"app": "preflight",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@@ -620,14 +651,13 @@ func createPfServiceAccount(clientset *kubernetes.Clientset, namespace, serviceA
|
|||||||
serviceAccount, err = clientset.CoreV1().ServiceAccounts(namespace).Create(serviceAccountSpec)
|
serviceAccount, err = clientset.CoreV1().ServiceAccounts(namespace).Create(serviceAccountSpec)
|
||||||
return err
|
return err
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
fmt.Println(err)
|
|
||||||
return nil, 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
|
return serviceAccount, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func deleteServiceAccount(clientset *kubernetes.Clientset, namespace string, serviceAccount *apiv1.ServiceAccount) {
|
func (qp *QliksensePreflight) deleteServiceAccount(clientset *kubernetes.Clientset, namespace string, serviceAccount *apiv1.ServiceAccount) {
|
||||||
serviceAccountClient := clientset.CoreV1().ServiceAccounts(namespace)
|
serviceAccountClient := clientset.CoreV1().ServiceAccounts(namespace)
|
||||||
|
|
||||||
deletePolicy := v1.DeletePropagationForeground
|
deletePolicy := v1.DeletePropagationForeground
|
||||||
@@ -638,5 +668,47 @@ func deleteServiceAccount(clientset *kubernetes.Clientset, namespace string, ser
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
fmt.Printf("Deleted ServiceAccount: %s\n\n", serviceAccount.Name)
|
qp.P.LogVerboseMessage("Deleted ServiceAccount: %s\n\n", serviceAccount.Name)
|
||||||
|
}
|
||||||
|
|
||||||
|
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, k8sSecret *apiv1.Secret) {
|
||||||
|
secretClient := clientset.CoreV1().Secrets(namespace)
|
||||||
|
|
||||||
|
deletePolicy := v1.DeletePropagationForeground
|
||||||
|
deleteOptions := v1.DeleteOptions{
|
||||||
|
PropagationPolicy: &deletePolicy,
|
||||||
|
}
|
||||||
|
err := secretClient.Delete(k8sSecret.GetName(), &deleteOptions)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
qp.P.LogVerboseMessage("Deleted Secret: %s\n", k8sSecret.Name)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,41 +5,47 @@ import (
|
|||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"github.com/pkg/errors"
|
||||||
"github.com/qlik-oss/sense-installer/pkg/api"
|
"github.com/qlik-oss/sense-installer/pkg/api"
|
||||||
qapi "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"
|
"github.com/qlik-oss/sense-installer/pkg/qliksense"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var resultYamlBytes = []byte("")
|
||||||
|
|
||||||
func (qp *QliksensePreflight) CheckCreateRole(namespace string) error {
|
func (qp *QliksensePreflight) CheckCreateRole(namespace string) error {
|
||||||
// create a Role
|
// create a Role
|
||||||
fmt.Printf("Preflight role check: \n")
|
qp.P.LogVerboseMessage("Preflight role check: \n")
|
||||||
|
qp.P.LogVerboseMessage("--------------------- \n")
|
||||||
err := qp.checkCreateEntity(namespace, "Role")
|
err := qp.checkCreateEntity(namespace, "Role")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
fmt.Println("Completed preflight role check")
|
qp.P.LogVerboseMessage("Completed preflight role check\n")
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (qp *QliksensePreflight) CheckCreateRoleBinding(namespace string) error {
|
func (qp *QliksensePreflight) CheckCreateRoleBinding(namespace string) error {
|
||||||
// create a RoleBinding
|
// create a RoleBinding
|
||||||
fmt.Printf("Preflight rolebinding check: \n")
|
qp.P.LogVerboseMessage("Preflight rolebinding check: \n")
|
||||||
|
qp.P.LogVerboseMessage("---------------------------- \n")
|
||||||
err := qp.checkCreateEntity(namespace, "RoleBinding")
|
err := qp.checkCreateEntity(namespace, "RoleBinding")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
fmt.Println("Completed preflight rolebinding check")
|
qp.P.LogVerboseMessage("Completed preflight rolebinding check\n")
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (qp *QliksensePreflight) CheckCreateServiceAccount(namespace string) error {
|
func (qp *QliksensePreflight) CheckCreateServiceAccount(namespace string) error {
|
||||||
// create a service account
|
// create a service account
|
||||||
fmt.Printf("Preflight serviceaccount check: \n")
|
qp.P.LogVerboseMessage("Preflight serviceaccount check: \n")
|
||||||
|
qp.P.LogVerboseMessage("------------------------------- \n")
|
||||||
err := qp.checkCreateEntity(namespace, "ServiceAccount")
|
err := qp.checkCreateEntity(namespace, "ServiceAccount")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
fmt.Println("Completed preflight serviceaccount check")
|
qp.P.LogVerboseMessage("Completed preflight serviceaccount check\n")
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
func (qp *QliksensePreflight) checkCreateEntity(namespace, entityToTest string) error {
|
func (qp *QliksensePreflight) checkCreateEntity(namespace, entityToTest string) error {
|
||||||
@@ -50,13 +56,13 @@ func (qp *QliksensePreflight) checkCreateEntity(namespace, entityToTest string)
|
|||||||
var err error
|
var err error
|
||||||
currentCR, err = qConfig.GetCurrentCR()
|
currentCR, err = qConfig.GetCurrentCR()
|
||||||
if err != nil {
|
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
|
return err
|
||||||
}
|
}
|
||||||
if currentCR.IsRepoExist() {
|
if currentCR.IsRepoExist() {
|
||||||
mfroot = currentCR.Spec.GetManifestsRoot()
|
mfroot = currentCR.Spec.GetManifestsRoot()
|
||||||
} else if tempDownloadedDir, err := qliksense.DownloadFromGitRepoToTmpDir(qliksense.QLIK_GIT_REPO, "master"); err != nil {
|
} 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
|
return err
|
||||||
} else {
|
} else {
|
||||||
mfroot = tempDownloadedDir
|
mfroot = tempDownloadedDir
|
||||||
@@ -67,65 +73,85 @@ func (qp *QliksensePreflight) checkCreateEntity(namespace, entityToTest string)
|
|||||||
} else {
|
} else {
|
||||||
kusDir = filepath.Join(mfroot, "manifests", currentCR.Spec.Profile)
|
kusDir = filepath.Join(mfroot, "manifests", currentCR.Spec.Profile)
|
||||||
}
|
}
|
||||||
resultYamlString, err := qliksense.ExecuteKustomizeBuild(kusDir)
|
if len(resultYamlBytes) == 0 {
|
||||||
|
resultYamlBytes, err = qliksense.ExecuteKustomizeBuild(kusDir)
|
||||||
if err != nil {
|
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
|
return err
|
||||||
}
|
}
|
||||||
|
}
|
||||||
sa := qliksense.GetYamlsFromMultiDoc(string(resultYamlString), entityToTest)
|
sa := qliksense.GetYamlsFromMultiDoc(string(resultYamlBytes), entityToTest)
|
||||||
if sa != "" {
|
if sa != "" {
|
||||||
sa = strings.ReplaceAll(sa, "namespace: default\n", fmt.Sprintf("namespace: %s\n", namespace))
|
sa = strings.Replace(sa, "name: qliksense", "name: preflight", -1)
|
||||||
} else {
|
} else {
|
||||||
err := fmt.Errorf("Unable to retrieve yamls to apply on cluster")
|
err := fmt.Errorf("Unable to retrieve yamls to apply on cluster from dir: %s, error: %v", kusDir, err)
|
||||||
fmt.Println(err)
|
return err
|
||||||
|
}
|
||||||
|
namespace = "" // namespace is handled when generating the manifests
|
||||||
|
|
||||||
|
defer func() {
|
||||||
|
qp.P.LogVerboseMessage("Cleaning up resources...\n")
|
||||||
|
err := api.KubectlDeleteVerbose(sa, namespace, qp.P.Verbose)
|
||||||
|
if err != nil {
|
||||||
|
qp.P.LogVerboseMessage("Preflight cleanup failed!\n")
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
err = api.KubectlApplyVerbose(sa, namespace, qp.P.Verbose)
|
||||||
|
if err != nil {
|
||||||
|
err := fmt.Errorf("Failed to create entity on the cluster: %v", err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
err = api.KubectlApply(sa, namespace)
|
qp.P.LogVerboseMessage("Preflight %s check: PASSED\n", entityToTest)
|
||||||
if err != nil {
|
|
||||||
err := fmt.Errorf("Failed to create entity on the cluster")
|
|
||||||
fmt.Println(err)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
fmt.Printf("Preflight %s check: PASSED\n", entityToTest)
|
|
||||||
fmt.Println("Cleaning up resources")
|
|
||||||
err = api.KubectlDelete(sa, namespace)
|
|
||||||
if err != nil {
|
|
||||||
fmt.Println("Preflight cleanup failed!")
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (qp *QliksensePreflight) CheckCreateRB(namespace string, kubeConfigContents []byte) error {
|
func (qp *QliksensePreflight) CheckCreateRB(namespace string, kubeConfigContents []byte) error {
|
||||||
|
|
||||||
// create a role
|
// create a role
|
||||||
fmt.Printf("Preflight createRole check: \n")
|
qp.P.LogVerboseMessage("Preflight createRole check: \n")
|
||||||
err := qp.checkCreateEntity(namespace, "Role")
|
qp.P.LogVerboseMessage("--------------------------- \n")
|
||||||
if err != nil {
|
errStr := strings.Builder{}
|
||||||
fmt.Println("Preflight role check: FAILED")
|
err1 := qp.checkCreateEntity(namespace, "Role")
|
||||||
|
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
|
// create a roleBinding
|
||||||
fmt.Printf("Preflight rolebinding check: \n")
|
qp.P.LogVerboseMessage("Preflight rolebinding check: \n")
|
||||||
err = qp.checkCreateEntity(namespace, "RoleBinding")
|
qp.P.LogVerboseMessage("---------------------------- \n")
|
||||||
if err != nil {
|
err2 := qp.checkCreateEntity(namespace, "RoleBinding")
|
||||||
fmt.Println("Preflight rolebinding check: FAILED")
|
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
|
// create a service account
|
||||||
fmt.Printf("Preflight serviceaccount check: \n")
|
qp.P.LogVerboseMessage("Preflight serviceaccount check: \n")
|
||||||
err = qp.checkCreateEntity(namespace, "ServiceAccount")
|
qp.P.LogVerboseMessage("------------------------------- \n")
|
||||||
if err != nil {
|
err3 := qp.checkCreateEntity(namespace, "ServiceAccount")
|
||||||
fmt.Println("Preflight serviceaccount check: FAILED")
|
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")
|
if err1 != nil || err2 != nil || err3 != nil {
|
||||||
fmt.Println("Completed preflight CreateRB check")
|
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
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,11 +4,13 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/Masterminds/semver/v3"
|
"github.com/Masterminds/semver/v3"
|
||||||
|
"github.com/qlik-oss/sense-installer/pkg/api"
|
||||||
"k8s.io/apimachinery/pkg/version"
|
"k8s.io/apimachinery/pkg/version"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (qp *QliksensePreflight) CheckK8sVersion(namespace string, kubeConfigContents []byte) error {
|
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
|
var currentVersion *semver.Version
|
||||||
|
|
||||||
clientset, _, err := getK8SClientSet(kubeConfigContents, "")
|
clientset, _, err := getK8SClientSet(kubeConfigContents, "")
|
||||||
@@ -22,35 +24,29 @@ func (qp *QliksensePreflight) CheckK8sVersion(namespace string, kubeConfigConten
|
|||||||
return err
|
return err
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
err = fmt.Errorf("Unable to get server version: %v\n", err)
|
err = fmt.Errorf("Unable to get server version: %v\n", err)
|
||||||
//fmt.Println(err)
|
|
||||||
return 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
|
// Compare K8s version on the cluster with minimum supported k8s version
|
||||||
currentVersion, err = semver.NewVersion(serverVersion.String())
|
currentVersion, err = semver.NewVersion(serverVersion.String())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
err = fmt.Errorf("Unable to convert server version into semver version: %v\n", err)
|
err = fmt.Errorf("Unable to convert server version into semver version: %v\n", err)
|
||||||
//fmt.Println(err)
|
|
||||||
return 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())
|
minK8sVersionSemver, err := semver.NewVersion(qp.GetPreflightConfigObj().GetMinK8sVersion())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
err = fmt.Errorf("Unable to convert minimum Kubernetes version into semver version:%v\n", err)
|
err = fmt.Errorf("Unable to convert minimum Kubernetes version into semver version:%v\n", err)
|
||||||
fmt.Println(err)
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if currentVersion.GreaterThan(minK8sVersionSemver) {
|
if currentVersion.GreaterThan(minK8sVersionSemver) {
|
||||||
//fmt.Printf("\n\nCurrent %s Component version: %s is less than minimum required version:%s\n", component, currentComponentVersion, componentVersionFromDependenciesYaml)
|
qp.P.LogVerboseMessage("Current Kubernetes API Server version %s is greater than or equal to minimum required version: %s\n", currentVersion, minK8sVersionSemver)
|
||||||
fmt.Printf("Current %s is greater than minimum required version:%s\n", currentVersion, minK8sVersionSemver)
|
|
||||||
fmt.Println("Preflight minimum kubernetes version check: PASSED")
|
|
||||||
} else {
|
} else {
|
||||||
fmt.Printf("Current %s is less than minimum required version:%s\n", currentVersion, minK8sVersionSemver)
|
err = fmt.Errorf("Current Kubernetes API Server version %s is less than minimum required version: %s", currentVersion, minK8sVersionSemver)
|
||||||
fmt.Println("Preflight minimum kubernetes version check: FAILED")
|
return err
|
||||||
}
|
}
|
||||||
fmt.Printf("Completed Preflight kubernetes minimum version check\n")
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -194,8 +194,10 @@ func getImageList(yamlContent []byte) ([]string, error) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
var sortedImageList []string
|
var sortedImageList []string
|
||||||
for image, _ := range imageMap {
|
for image, v := range imageMap {
|
||||||
sortedImageList = append(sortedImageList, image)
|
sortedImageList = append(sortedImageList, image)
|
||||||
|
// a warning "simplify range expression" if written like this 'for image _ :=range imageMap'
|
||||||
|
_ = v
|
||||||
}
|
}
|
||||||
sort.Strings(sortedImageList)
|
sort.Strings(sortedImageList)
|
||||||
return sortedImageList, nil
|
return sortedImageList, nil
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import (
|
|||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
"path"
|
"path"
|
||||||
|
"path/filepath"
|
||||||
"reflect"
|
"reflect"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
@@ -234,11 +235,12 @@ func Test_About_getConfigDirectory(t *testing.T) {
|
|||||||
verifyAsdBranch := func(configDir string) (ok bool, reason string) {
|
verifyAsdBranch := func(configDir string) (ok bool, reason string) {
|
||||||
tmpDir := os.TempDir()
|
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)
|
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 false, fmt.Sprintf(`expected to find file: "asdczxc" under directory: %v`, configDir)
|
||||||
}
|
}
|
||||||
return true, ""
|
return true, ""
|
||||||
@@ -247,15 +249,16 @@ func Test_About_getConfigDirectory(t *testing.T) {
|
|||||||
verifyMasterBranch := func(configDir string) (ok bool, reason string) {
|
verifyMasterBranch := func(configDir string) (ok bool, reason string) {
|
||||||
tmpDir := os.TempDir()
|
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)
|
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)
|
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 false, fmt.Sprintf(`expected to find file: "sad"" under directory: %v`, configDir)
|
||||||
}
|
}
|
||||||
return true, ""
|
return true, ""
|
||||||
@@ -305,7 +308,7 @@ func Test_About_getConfigDirectory(t *testing.T) {
|
|||||||
cleanup: func(_ *Qliksense, configDir string) error {
|
cleanup: func(_ *Qliksense, configDir string) error {
|
||||||
if currentDirectory, err := os.Getwd(); err != nil {
|
if currentDirectory, err := os.Getwd(); err != nil {
|
||||||
return err
|
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 err
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
@@ -320,7 +323,7 @@ func Test_About_getConfigDirectory(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
profileEntered = "foo"
|
profileEntered = "foo"
|
||||||
defaultProfilePath := path.Join(currentDirectory, "manifests", profileEntered)
|
defaultProfilePath := filepath.Join(currentDirectory, "manifests", profileEntered)
|
||||||
err = os.MkdirAll(defaultProfilePath, os.ModePerm)
|
err = os.MkdirAll(defaultProfilePath, os.ModePerm)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("error making path: %v, err: %v\n", defaultProfilePath, err)
|
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 {
|
cleanup: func(_ *Qliksense, configDir string) error {
|
||||||
if currentDirectory, err := os.Getwd(); err != nil {
|
if currentDirectory, err := os.Getwd(); err != nil {
|
||||||
return err
|
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 err
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
@@ -380,8 +383,8 @@ func Test_About_getConfigDirectory(t *testing.T) {
|
|||||||
cleanup: func(_ *Qliksense, configDir string) error {
|
cleanup: func(_ *Qliksense, configDir string) error {
|
||||||
tmpDir := os.TempDir()
|
tmpDir := os.TempDir()
|
||||||
|
|
||||||
if path.Clean(path.Dir(path.Dir(configDir))) == path.Clean(tmpDir) && path.Base(configDir) == "repo" {
|
tmpTmpDir := filepath.Dir(configDir)
|
||||||
tmpTmpDir := path.Dir(configDir)
|
if filepath.Clean(filepath.Dir(tmpTmpDir)) == filepath.Clean(tmpDir) && filepath.Base(configDir) == "repo" {
|
||||||
if err := os.RemoveAll(tmpTmpDir); err != nil {
|
if err := os.RemoveAll(tmpTmpDir); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -413,8 +416,8 @@ func Test_About_getConfigDirectory(t *testing.T) {
|
|||||||
cleanup: func(_ *Qliksense, configDir string) error {
|
cleanup: func(_ *Qliksense, configDir string) error {
|
||||||
tmpDir := os.TempDir()
|
tmpDir := os.TempDir()
|
||||||
|
|
||||||
if path.Clean(path.Dir(path.Dir(configDir))) == path.Clean(tmpDir) && path.Base(configDir) == "repo" {
|
tmpTmpDir := filepath.Dir(configDir)
|
||||||
tmpTmpDir := path.Dir(configDir)
|
if filepath.Clean(filepath.Dir(tmpTmpDir)) == filepath.Clean(tmpDir) && filepath.Base(configDir) == "repo" {
|
||||||
if err := os.RemoveAll(tmpTmpDir); err != nil {
|
if err := os.RemoveAll(tmpTmpDir); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -456,8 +459,9 @@ func Test_About_getConfigDirectory(t *testing.T) {
|
|||||||
},
|
},
|
||||||
cleanup: func(q *Qliksense, configDir string) error {
|
cleanup: func(q *Qliksense, configDir string) error {
|
||||||
tmpDir := os.TempDir()
|
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 {
|
if err := os.RemoveAll(tmpTmpDir); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -502,8 +506,9 @@ func Test_About_getConfigDirectory(t *testing.T) {
|
|||||||
},
|
},
|
||||||
cleanup: func(q *Qliksense, configDir string) error {
|
cleanup: func(q *Qliksense, configDir string) error {
|
||||||
tmpDir := os.TempDir()
|
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 {
|
if err := os.RemoveAll(tmpTmpDir); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -525,13 +530,17 @@ func Test_About_getConfigDirectory(t *testing.T) {
|
|||||||
if err := q.SetUpQliksenseDefaultContext(); err != nil {
|
if err := q.SetUpQliksenseDefaultContext(); err != nil {
|
||||||
t.Fatalf("error setting up default context in the tmp dir: %v\n", err)
|
t.Fatalf("error setting up default context in the tmp dir: %v\n", err)
|
||||||
return nil, "", "", ""
|
return nil, "", "", ""
|
||||||
} else if err := q.FetchQK8s("master"); err != nil {
|
} else if qConfig, err := qapi.NewQConfigE(q.QliksenseHome); err != nil {
|
||||||
|
t.Fatalf("cannot initiallize qConfig: %v\n", err)
|
||||||
|
return nil, "", "", ""
|
||||||
|
} else if !qConfig.IsRepoExistForCurrent("master") {
|
||||||
|
if err := q.FetchQK8s("master"); err != nil {
|
||||||
t.Fatalf("error fetching master config to the tmp dir: %v\n", err)
|
t.Fatalf("error fetching master config to the tmp dir: %v\n", err)
|
||||||
return nil, "", "", ""
|
return nil, "", "", ""
|
||||||
} else {
|
|
||||||
return q, "no-git-clone-for-you", "", ""
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return q, "no-git-clone-for-you", "", ""
|
||||||
|
}
|
||||||
},
|
},
|
||||||
verify: func(q *Qliksense, configDir string, isTemporary bool, profile string) (ok bool, reason string, err error) {
|
verify: func(q *Qliksense, configDir string, isTemporary bool, profile string) (ok bool, reason string, err error) {
|
||||||
qConfig := qapi.NewQConfig(q.QliksenseHome)
|
qConfig := qapi.NewQConfig(q.QliksenseHome)
|
||||||
|
|||||||
@@ -1,12 +1,13 @@
|
|||||||
package qliksense
|
package qliksense
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
|
|
||||||
qapi "github.com/qlik-oss/sense-installer/pkg/api"
|
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 {
|
if err := q.LoadCr(r, overwriteExistingContext); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -15,16 +16,33 @@ func (q *Qliksense) ApplyCRFromReader(r io.Reader, opts *InstallCommandOptions,
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
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()) {
|
if IsQliksenseInstalled(cr.GetName()) {
|
||||||
// it is needed in case want to upgrade from one version to another
|
// it is needed in case want to upgrade from one version to another
|
||||||
if cr.Spec.ManifestsRoot == "" && cr.Spec.Git == nil {
|
if cr.Spec.ManifestsRoot == "" && cr.Spec.Git == nil {
|
||||||
if err := q.FetchQK8s(cr.GetLabelFromCr("version")); err != nil {
|
if !qConfig.IsRepoExistForCurrent(version) {
|
||||||
|
if err := q.FetchQK8s(version); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return q.UpgradeQK8s(keepPatchFiles)
|
return q.UpgradeQK8s(keepPatchFiles)
|
||||||
}
|
}
|
||||||
return q.InstallQK8s(cr.GetLabelFromCr("version"), opts, keepPatchFiles)
|
return q.InstallQK8s(version, opts, keepPatchFiles)
|
||||||
}
|
}
|
||||||
|
|
||||||
func IsQliksenseInstalled(crName string) bool {
|
func IsQliksenseInstalled(crName string) bool {
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
Q_INIT_CRD_PATH = "manifests/base/manifests/qliksense-init"
|
Q_INIT_CRD_PATH = "manifests/base/crds"
|
||||||
agreementTempalte = `
|
agreementTempalte = `
|
||||||
Please read the agreement at https://www.qlik.com/us/legal/license-terms
|
Please read the agreement at https://www.qlik.com/us/legal/license-terms
|
||||||
Accept the end user license agreement by providing acceptEULA=yes
|
Accept the end user license agreement by providing acceptEULA=yes
|
||||||
@@ -146,10 +146,15 @@ func (q *Qliksense) getCurrentCrDependentResourceAsString() (string, error) {
|
|||||||
var crString strings.Builder
|
var crString strings.Builder
|
||||||
|
|
||||||
for svcName, v := range qcr.Spec.Secrets {
|
for svcName, v := range qcr.Spec.Secrets {
|
||||||
|
hasFile := false
|
||||||
for _, item := range v {
|
for _, item := range v {
|
||||||
if item.ValueFrom != nil && item.ValueFrom.SecretKeyRef != nil {
|
if item.ValueFrom != nil && item.ValueFrom.SecretKeyRef != nil {
|
||||||
|
hasFile = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if hasFile {
|
||||||
secretFilePath := filepath.Join(q.QliksenseHome, QliksenseContextsDir, qcr.GetName(), QliksenseSecretsDir, svcName+".yaml")
|
secretFilePath := filepath.Join(q.QliksenseHome, QliksenseContextsDir, qcr.GetName(), QliksenseSecretsDir, svcName+".yaml")
|
||||||
|
|
||||||
if api.FileExists(secretFilePath) {
|
if api.FileExists(secretFilePath) {
|
||||||
secretFile, err := ioutil.ReadFile(secretFilePath)
|
secretFile, err := ioutil.ReadFile(secretFilePath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -160,7 +165,6 @@ func (q *Qliksense) getCurrentCrDependentResourceAsString() (string, error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
crString.WriteString("\n---\n")
|
crString.WriteString("\n---\n")
|
||||||
return crString.String(), nil
|
return crString.String(), nil
|
||||||
}
|
}
|
||||||
|
|||||||
24
pkg/qliksense/confirmation.go
Normal file
24
pkg/qliksense/confirmation.go
Normal 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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,8 +1,9 @@
|
|||||||
package qliksense
|
package qliksense
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"crypto/rsa"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io"
|
||||||
|
|
||||||
"github.com/qlik-oss/k-apis/pkg/config"
|
"github.com/qlik-oss/k-apis/pkg/config"
|
||||||
"github.com/robfig/cron/v3"
|
"github.com/robfig/cron/v3"
|
||||||
@@ -19,10 +20,10 @@ import (
|
|||||||
|
|
||||||
ansi "github.com/mattn/go-colorable"
|
ansi "github.com/mattn/go-colorable"
|
||||||
"github.com/qlik-oss/sense-installer/pkg/api"
|
"github.com/qlik-oss/sense-installer/pkg/api"
|
||||||
"github.com/ttacon/chalk"
|
|
||||||
_ "gopkg.in/yaml.v2"
|
_ "gopkg.in/yaml.v2"
|
||||||
v1 "k8s.io/api/core/v1"
|
v1 "k8s.io/api/core/v1"
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
|
. "github.com/logrusorgru/aurora"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@@ -35,10 +36,25 @@ const (
|
|||||||
|
|
||||||
imageRegistryConfigKey = "imageRegistry"
|
imageRegistryConfigKey = "imageRegistry"
|
||||||
pullSecretName = "artifactory-docker-secret"
|
pullSecretName = "artifactory-docker-secret"
|
||||||
|
qliksenseOperatorImageRepo = "qlik-docker-oss.bintray.io"
|
||||||
|
qliksenseOperatorImageName = "qliksense-operator"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func (q *Qliksense) SetSecretsFromReader(arg string, reader io.Reader, createSecret, base64Encoded bool) error {
|
||||||
|
//take only name from the arguments, value should be from reader
|
||||||
|
argName := strings.SplitN(arg, "=", 1)
|
||||||
|
if len(argName) != 1 {
|
||||||
|
return errors.New("can only have one argument from pipe")
|
||||||
|
}
|
||||||
|
valueBytes, err := ioutil.ReadAll(reader)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return q.SetSecrets([]string{argName[0] + "=" + string(valueBytes)}, createSecret, base64Encoded)
|
||||||
|
}
|
||||||
|
|
||||||
// SetSecrets - set-secrets <key>=<value> commands
|
// SetSecrets - set-secrets <key>=<value> commands
|
||||||
func (q *Qliksense) SetSecrets(args []string, isSecretSet bool) error {
|
func (q *Qliksense) SetSecrets(args []string, isSecretSet bool, base64Encoded bool) error {
|
||||||
qConfig := api.NewQConfig(q.QliksenseHome)
|
qConfig := api.NewQConfig(q.QliksenseHome)
|
||||||
qliksenseCR, err := qConfig.GetCurrentCR()
|
qliksenseCR, err := qConfig.GetCurrentCR()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -47,17 +63,17 @@ func (q *Qliksense) SetSecrets(args []string, isSecretSet bool) error {
|
|||||||
|
|
||||||
// Metadata name in qliksense CR is the name of the current context
|
// Metadata name in qliksense CR is the name of the current context
|
||||||
api.LogDebugMessage("Current context: %s", qliksenseCR.GetName())
|
api.LogDebugMessage("Current context: %s", qliksenseCR.GetName())
|
||||||
rsaPublicKey, _, err := qConfig.GetCurrentContextEncryptionKeyPair()
|
encryptionKey, err := qConfig.GetEncryptionKeyForCurrent()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
resultArgs, err := api.ProcessConfigArgs(args)
|
resultArgs, err := api.ProcessConfigArgs(args, base64Encoded)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
for _, ra := range resultArgs {
|
for _, ra := range resultArgs {
|
||||||
api.LogDebugMessage("value args to be encrypted: %s", ra.Value)
|
api.LogDebugMessage("value args to be encrypted: %s", ra.Value)
|
||||||
if err := q.processSecret(ra, rsaPublicKey, qliksenseCR, isSecretSet); err != nil {
|
if err := q.processSecret(ra, encryptionKey, qliksenseCR, isSecretSet); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -65,14 +81,11 @@ func (q *Qliksense) SetSecrets(args []string, isSecretSet bool) error {
|
|||||||
return qConfig.WriteCR(qliksenseCR)
|
return qConfig.WriteCR(qliksenseCR)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (q *Qliksense) processSecret(ra *api.ServiceKeyValue, rsaPublicKey *rsa.PublicKey, qliksenseCR *api.QliksenseCR, isSecretSet bool) error {
|
func (q *Qliksense) processSecret(ra *api.ServiceKeyValue, encryptionKey string, qliksenseCR *api.QliksenseCR, isSecretSet bool) error {
|
||||||
// encrypt value with RSA key pair
|
cipherText, e2 := api.EncryptData([]byte(ra.Value), encryptionKey)
|
||||||
valueBytes := []byte(ra.Value)
|
|
||||||
cipherText, e2 := api.Encrypt(valueBytes, rsaPublicKey)
|
|
||||||
if e2 != nil {
|
if e2 != nil {
|
||||||
return e2
|
return e2
|
||||||
}
|
}
|
||||||
base64EncodedSecret := b64.StdEncoding.EncodeToString(cipherText)
|
|
||||||
secretName := ""
|
secretName := ""
|
||||||
if isSecretSet {
|
if isSecretSet {
|
||||||
secretFolder := qliksenseCR.GetK8sSecretsFolder(q.QliksenseHome)
|
secretFolder := qliksenseCR.GetK8sSecretsFolder(q.QliksenseHome)
|
||||||
@@ -104,7 +117,8 @@ func (q *Qliksense) processSecret(ra *api.ServiceKeyValue, rsaPublicKey *rsa.Pub
|
|||||||
if k8sSecret.Data == nil {
|
if k8sSecret.Data == nil {
|
||||||
k8sSecret.Data = map[string][]byte{}
|
k8sSecret.Data = map[string][]byte{}
|
||||||
}
|
}
|
||||||
k8sSecret.Data[ra.Key] = []byte(base64EncodedSecret)
|
// v1.Secret does enconding, so no need to encode again
|
||||||
|
k8sSecret.Data[ra.Key] = []byte(cipherText)
|
||||||
|
|
||||||
// Write secret to file
|
// Write secret to file
|
||||||
k8sSecretBytes, err := api.K8sSecretToYaml(k8sSecret)
|
k8sSecretBytes, err := api.K8sSecretToYaml(k8sSecret)
|
||||||
@@ -117,18 +131,28 @@ func (q *Qliksense) processSecret(ra *api.ServiceKeyValue, rsaPublicKey *rsa.Pub
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
api.LogDebugMessage("Created a Kubernetes secret")
|
api.LogDebugMessage("Created a Kubernetes secret")
|
||||||
|
|
||||||
// Prepare args to update CR in the next step
|
|
||||||
base64EncodedSecret = ""
|
|
||||||
}
|
}
|
||||||
|
base64EncodedSecret := b64.StdEncoding.EncodeToString([]byte(cipherText))
|
||||||
// write into CR the keyref of the secret
|
// write into CR the keyref of the secret
|
||||||
qliksenseCR.Spec.AddToSecrets(ra.SvcName, ra.Key, base64EncodedSecret, secretName)
|
qliksenseCR.Spec.AddToSecrets(ra.SvcName, ra.Key, base64EncodedSecret, secretName)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (q *Qliksense) SetConfigFromReader(arg string, reader io.Reader, base64Encoded bool) error {
|
||||||
|
//take only name from the arguments, value should be from reader
|
||||||
|
argName := strings.SplitN(arg, "=", 1)
|
||||||
|
if len(argName) != 1 {
|
||||||
|
return errors.New("can only have one argument from pipe")
|
||||||
|
}
|
||||||
|
valueBytes, err := ioutil.ReadAll(reader)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return q.SetConfigs([]string{argName[0] + "=" + string(valueBytes)}, base64Encoded)
|
||||||
|
}
|
||||||
|
|
||||||
// SetConfigs - set-configs <key>=<value> commands
|
// SetConfigs - set-configs <key>=<value> commands
|
||||||
func (q *Qliksense) SetConfigs(args []string) error {
|
func (q *Qliksense) SetConfigs(args []string, base64Encoded bool) error {
|
||||||
// retieve current context from config.yaml
|
// retieve current context from config.yaml
|
||||||
qConfig := api.NewQConfig(q.QliksenseHome)
|
qConfig := api.NewQConfig(q.QliksenseHome)
|
||||||
qliksenseCR, err := qConfig.GetCurrentCR()
|
qliksenseCR, err := qConfig.GetCurrentCR()
|
||||||
@@ -136,7 +160,7 @@ func (q *Qliksense) SetConfigs(args []string) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
resultArgs, err := api.ProcessConfigArgs(args)
|
resultArgs, err := api.ProcessConfigArgs(args, base64Encoded)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -216,43 +240,130 @@ func (q *Qliksense) SetOtherConfigs(args []string) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for _, arg := range args {
|
for _, arg := range args {
|
||||||
argsString := strings.Split(arg, "=")
|
if strings.HasPrefix(arg, "fetchSource.") {
|
||||||
key := strings.ToLower(argsString[0])
|
if err := q.processSetFetchSource(arg, qliksenseCR); err != nil {
|
||||||
value := argsString[1]
|
return err
|
||||||
// check if key is for git or gitops (sub objects)
|
}
|
||||||
keySplit := strings.Split(key, ".")
|
} else if strings.HasPrefix(arg, "git.") {
|
||||||
key = keySplit[0]
|
if err := q.processSetGit(arg, qliksenseCR); err != nil {
|
||||||
keySub := ""
|
return err
|
||||||
|
}
|
||||||
if len(keySplit) == 2 {
|
} else if strings.HasPrefix(arg, "gitOps.") {
|
||||||
keySub = strings.ToLower(keySplit[1])
|
if err := q.processSetGitOps(arg, qliksenseCR); err != nil {
|
||||||
}
|
|
||||||
|
|
||||||
valid := true
|
|
||||||
valid, qliksenseCR = validateCR(key, keySub, value, qliksenseCR)
|
|
||||||
field := caseInsenstiveFieldByName(reflect.Indirect(reflect.ValueOf(qliksenseCR.Spec)), key)
|
|
||||||
if !valid {
|
|
||||||
err := fmt.Errorf("Please enter one of: profile, storageClassName,rotateKeys, manifestRoot, git.repository or gitops arguments to configure the current context")
|
|
||||||
return err
|
return err
|
||||||
} else if strings.EqualFold("", keySub) {
|
|
||||||
// set spec for everything excluding git and gitops
|
|
||||||
if field.CanSet() {
|
|
||||||
field.SetString(value)
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// set spec for git or gitops
|
if err := processSetSingleArg(arg, qliksenseCR); err != nil {
|
||||||
subField := caseInsenstiveFieldByName(reflect.Indirect(field), keySub)
|
return err
|
||||||
if subField.CanSet() {
|
|
||||||
subField.SetString(value)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
fmt.Println(Green("Successfully added to Custom Resource Spec"))
|
||||||
|
}
|
||||||
|
|
||||||
fmt.Println(chalk.Green.Color("Successfully added to Custom Resource Spec"))
|
|
||||||
}
|
|
||||||
// write modified content into context.yaml
|
// write modified content into context.yaml
|
||||||
return qConfig.WriteCR(qliksenseCR)
|
return qConfig.WriteCR(qliksenseCR)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func processSetSingleArg(arg string, cr *api.QliksenseCR) error {
|
||||||
|
nv := strings.Split(arg, "=")
|
||||||
|
switch nv[0] {
|
||||||
|
case "manifestsRoot":
|
||||||
|
cr.Spec.ManifestsRoot = nv[1]
|
||||||
|
case "profile":
|
||||||
|
cr.Spec.Profile = nv[1]
|
||||||
|
case "storageClassName":
|
||||||
|
cr.Spec.StorageClassName = nv[1]
|
||||||
|
case "rotateKeys":
|
||||||
|
valid := false
|
||||||
|
for _, v := range []string{"yes", "no", "None"} {
|
||||||
|
if nv[1] == v {
|
||||||
|
valid = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !valid {
|
||||||
|
return errors.New("please povide rotateKeys=yes|no|None")
|
||||||
|
}
|
||||||
|
cr.Spec.RotateKeys = nv[1]
|
||||||
|
default:
|
||||||
|
return errors.New("Please enter one of: profile, storageClassName,rotateKeys, manifestRoot to configure the current context")
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (q *Qliksense) processSetFetchSource(arg string, cr *api.QliksenseCR) error {
|
||||||
|
args := strings.Split(arg, "=")
|
||||||
|
subs := strings.Split(args[0], ".")
|
||||||
|
if cr.Spec.FetchSource == nil {
|
||||||
|
cr.Spec.FetchSource = &config.Repo{}
|
||||||
|
}
|
||||||
|
switch subs[1] {
|
||||||
|
case "repository":
|
||||||
|
cr.Spec.FetchSource.Repository = args[1]
|
||||||
|
case "accessToken":
|
||||||
|
qConfig := api.NewQConfig(q.QliksenseHome)
|
||||||
|
key, err := qConfig.GetEncryptionKeyFor(cr.GetName())
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return cr.SetFetchAccessToken(args[1], key)
|
||||||
|
case "secretName":
|
||||||
|
cr.Spec.FetchSource.SecretName = args[1]
|
||||||
|
case "userName":
|
||||||
|
cr.Spec.FetchSource.UserName = args[1]
|
||||||
|
default:
|
||||||
|
return errors.New(arg + " does not match any cr spec")
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (q *Qliksense) processSetGit(arg string, cr *api.QliksenseCR) error {
|
||||||
|
args := strings.Split(arg, "=")
|
||||||
|
subs := strings.Split(args[0], ".")
|
||||||
|
if cr.Spec.Git == nil {
|
||||||
|
cr.Spec.Git = &config.Repo{}
|
||||||
|
}
|
||||||
|
switch subs[1] {
|
||||||
|
case "repository":
|
||||||
|
cr.Spec.Git.Repository = args[1]
|
||||||
|
case "accessToken":
|
||||||
|
cr.Spec.Git.AccessToken = args[1]
|
||||||
|
case "secretName":
|
||||||
|
cr.Spec.Git.SecretName = args[1]
|
||||||
|
case "userName":
|
||||||
|
cr.Spec.Git.UserName = args[1]
|
||||||
|
default:
|
||||||
|
return errors.New(arg + " does not match any cr spec")
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (q *Qliksense) processSetGitOps(arg string, cr *api.QliksenseCR) error {
|
||||||
|
args := strings.Split(arg, "=")
|
||||||
|
subs := strings.Split(args[0], ".")
|
||||||
|
if cr.Spec.Git == nil {
|
||||||
|
cr.Spec.GitOps = &config.GitOps{}
|
||||||
|
}
|
||||||
|
switch subs[1] {
|
||||||
|
case "enabled":
|
||||||
|
if args[1] != "yes" && args[1] != "no" {
|
||||||
|
return errors.New("Please use yes or no for key enabled")
|
||||||
|
}
|
||||||
|
cr.Spec.GitOps.Enabled = args[1]
|
||||||
|
case "schedule":
|
||||||
|
if _, err := cron.ParseStandard(args[1]); err != nil {
|
||||||
|
return errors.New("Please enter string with standard cron scheduling syntax ")
|
||||||
|
}
|
||||||
|
cr.Spec.GitOps.Schedule = args[1]
|
||||||
|
case "watchBranch":
|
||||||
|
cr.Spec.GitOps.WatchBranch = args[1]
|
||||||
|
case "image":
|
||||||
|
cr.Spec.GitOps.Image = args[1]
|
||||||
|
default:
|
||||||
|
return errors.New(arg + " does not match any cr spec")
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// SetContextConfig - set the context for qliksense kubernetes resources to live in
|
// SetContextConfig - set the context for qliksense kubernetes resources to live in
|
||||||
func (q *Qliksense) SetContextConfig(args []string) error {
|
func (q *Qliksense) SetContextConfig(args []string) error {
|
||||||
if len(args) == 1 {
|
if len(args) == 1 {
|
||||||
@@ -277,7 +388,7 @@ func (q *Qliksense) ListContextConfigs() error {
|
|||||||
}
|
}
|
||||||
out := ansi.NewColorableStdout()
|
out := ansi.NewColorableStdout()
|
||||||
w := tabwriter.NewWriter(out, 5, 8, 0, '\t', 0)
|
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()
|
w.Flush()
|
||||||
if len(qliksenseConfig.Spec.Contexts) > 0 {
|
if len(qliksenseConfig.Spec.Contexts) > 0 {
|
||||||
for _, cont := range qliksenseConfig.Spec.Contexts {
|
for _, cont := range qliksenseConfig.Spec.Contexts {
|
||||||
@@ -285,14 +396,14 @@ func (q *Qliksense) ListContextConfigs() error {
|
|||||||
}
|
}
|
||||||
w.Flush()
|
w.Flush()
|
||||||
fmt.Fprintln(out, "")
|
fmt.Fprintln(out, "")
|
||||||
fmt.Fprintln(out, chalk.Bold.TextStyle("Current Context : "), qliksenseConfig.Spec.CurrentContext)
|
fmt.Fprintln(out, Bold("Current Context : "), qliksenseConfig.Spec.CurrentContext)
|
||||||
} else {
|
} else {
|
||||||
fmt.Fprintln(out, "No Contexts Available")
|
fmt.Fprintln(out, "No Contexts Available")
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (q *Qliksense) DeleteContextConfig(args []string) error {
|
func (q *Qliksense) DeleteContextConfig(args []string, flag bool) error {
|
||||||
if len(args) == 1 {
|
if len(args) == 1 {
|
||||||
qliksenseConfigFile := filepath.Join(q.QliksenseHome, QliksenseConfigFile)
|
qliksenseConfigFile := filepath.Join(q.QliksenseHome, QliksenseConfigFile)
|
||||||
var qliksenseConfig api.QliksenseConfig
|
var qliksenseConfig api.QliksenseConfig
|
||||||
@@ -300,11 +411,11 @@ func (q *Qliksense) DeleteContextConfig(args []string) error {
|
|||||||
out := ansi.NewColorableStdout()
|
out := ansi.NewColorableStdout()
|
||||||
switch args[0] {
|
switch args[0] {
|
||||||
case qliksenseConfig.Spec.CurrentContext:
|
case qliksenseConfig.Spec.CurrentContext:
|
||||||
fmt.Fprintln(out, chalk.Yellow.Color("Please switch contexts to be able to delete this context."))
|
fmt.Fprintln(out,Yellow("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)))
|
err := fmt.Errorf(Red("Cannot delete current context - %s").String(), White(Bold(qliksenseConfig.Spec.CurrentContext)))
|
||||||
return err
|
return err
|
||||||
case DefaultQliksenseContext:
|
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
|
return err
|
||||||
default:
|
default:
|
||||||
qliksenseContextsDir1 := filepath.Join(q.QliksenseHome, QliksenseContextsDir)
|
qliksenseContextsDir1 := filepath.Join(q.QliksenseHome, QliksenseContextsDir)
|
||||||
@@ -334,11 +445,19 @@ func (q *Qliksense) DeleteContextConfig(args []string) error {
|
|||||||
}
|
}
|
||||||
newLength := len(qliksenseConfig.Spec.Contexts)
|
newLength := len(qliksenseConfig.Spec.Contexts)
|
||||||
if currentLength != newLength {
|
if currentLength != newLength {
|
||||||
|
ans := flag
|
||||||
|
if ans == false {
|
||||||
|
ans = AskForConfirmation("Are You Sure? ")
|
||||||
|
}
|
||||||
|
if ans == true {
|
||||||
api.WriteToFile(&qliksenseConfig, qliksenseConfigFile)
|
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, Yellow(Underline("Warning: Active resources may still be running in-cluster")))
|
||||||
fmt.Fprintln(out, chalk.Green.Color("Successfully deleted context: "), chalk.Bold.TextStyle(args[0]))
|
fmt.Fprintln(out, Green("Successfully deleted context: "),Bold(args[0]))
|
||||||
} else {
|
} else {
|
||||||
err := fmt.Errorf(chalk.Red.Color("Context not found"))
|
return nil
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
err := fmt.Errorf(Red("Context not found").String())
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -401,7 +520,7 @@ func (q *Qliksense) SetUpQliksenseContext(contextName string) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// set the encrypted default mongo
|
// set the encrypted default mongo
|
||||||
return q.SetSecrets([]string{`qliksense.mongoDbUri="mongodb://qlik-default-mongodb:27017/qliksense?ssl=false"`}, false)
|
return q.SetSecrets([]string{`qliksense.mongoDbUri="mongodb://qlik-default-mongodb:27017/qliksense?ssl=false"`}, false, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
func validateInput(input string) (string, error) {
|
func validateInput(input string) (string, error) {
|
||||||
@@ -422,7 +541,8 @@ func validateInput(input string) (string, error) {
|
|||||||
return input, err
|
return input, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// PrepareK8sSecret decodes and decrypts the secret value in the secret.yaml file and returns a B64encoded string
|
// PrepareK8sSecret targetFile contains base64 encoded value of encrypted value.
|
||||||
|
// this method decodes and decrypts the secret value in the secret.yaml file and returns a B64encoded string
|
||||||
func (q *Qliksense) PrepareK8sSecret(targetFile string) (string, error) {
|
func (q *Qliksense) PrepareK8sSecret(targetFile string) (string, error) {
|
||||||
// check if targetFile exists
|
// check if targetFile exists
|
||||||
if !api.FileExists(targetFile) {
|
if !api.FileExists(targetFile) {
|
||||||
@@ -431,7 +551,7 @@ func (q *Qliksense) PrepareK8sSecret(targetFile string) (string, error) {
|
|||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
qConfig := api.NewQConfig(q.QliksenseHome)
|
qConfig := api.NewQConfig(q.QliksenseHome)
|
||||||
_, rsaPrivateKey, err := qConfig.GetCurrentContextEncryptionKeyPair()
|
encryptionKey, err := qConfig.GetEncryptionKeyForCurrent()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
@@ -449,17 +569,13 @@ func (q *Qliksense) PrepareK8sSecret(targetFile string) (string, error) {
|
|||||||
dataMap := k8sSecret1.Data
|
dataMap := k8sSecret1.Data
|
||||||
var resultMap = make(map[string][]byte)
|
var resultMap = make(map[string][]byte)
|
||||||
for k, v := range dataMap {
|
for k, v := range dataMap {
|
||||||
ba, err := b64.StdEncoding.DecodeString(string(v))
|
//k8s secrets has already base64 decoed value
|
||||||
if err != nil {
|
decryptedString, err := api.DecryptData(v, encryptionKey)
|
||||||
err := fmt.Errorf("Not able to decode message: %v", err)
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
decryptedString, err := api.Decrypt(ba, rsaPrivateKey)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
err := fmt.Errorf("Not able to decrypt message: %v", err)
|
err := fmt.Errorf("Not able to decrypt message: %v", err)
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
resultMap[k] = decryptedString
|
resultMap[k] = []byte(decryptedString)
|
||||||
}
|
}
|
||||||
|
|
||||||
// putting the above map back into the k8sSecret struct
|
// putting the above map back into the k8sSecret struct
|
||||||
|
|||||||
@@ -35,119 +35,35 @@ metadata:
|
|||||||
name: testctx-qliksense-senseinstaller
|
name: testctx-qliksense-senseinstaller
|
||||||
type: Opaque
|
type: Opaque
|
||||||
`
|
`
|
||||||
var encText = "SFpVZ2t5SGsrN2lLQjlTYm9rbFUxSDFRcmVYdUxhTW9MUHlQOGtGditxMEcwZTlIZDl1dVRrV0tEYm5qUURSWFp3dStuNklueGk3anI2c1djSVdsbWlKTHdWQUJwdUg0a1NXd3llMUlMa2oxK3FRSFlMM2dQUExvN1pBYkVDeDROMUVvam12M0t0NmQwbkdhSXlWWEpmWWJUVVFDM1Y4L0ZTVXBVN0JUb0l4OVZWdmlPam5HTHk4RlF2a3RUaHJxWTUvZEh2N3pVUmhiOTc2Q2YwbEovZ3I2L2NwRk9RMUFXVXdodVhrTG9lYjVzNFdtTEZzNldqT3k0bWlKM1J6VllLaWVUSFJ2SE85eDB6dUthanRwSGEzWEZkaE5QNnpySVJJNTRFalUyblVYYUNlYXVnWnZEOUxjdWluOFhFcjExbkFINURCUDAycXhoZk5BejVoMlV2eFNWVmR0aW1QTDBhMVBJTUxGQTgyWUkrQkFOQkhkSUNnZGU5SkxIRFBoTzR6c0llaE1LRmhVQkNoOUhQa3kyRnhTeDJ3YWp3M1UycEsvcFJVZUxDazRUbkhmL25LN3h5ekdpV3dSUFFFZHdsWE5JbUhjVlVPV3gvNWh4WlJCUTZtb3pGYk1HbXR1Mkh5Z3RVV2gzNFYzd1BhS01TNFRsa0hyODFjRjVCWVpxenBFK1pKWnVyLy8zbzJsU0tFMjMxTG1pcGk1K0FqbXZvUVcyWHBocjFNVWJQY1pXUkJFRkkyQXBCM0FhQXFPa0k1MkRqNG43Mko5bCtaMzdydTk1aHk5K1lzY0FxMjZVbExYRlc0S3RUUkRLSjlMNnVmdlIrUUNudER3em5UTFRHUnEwZU5COWt6S0Q4MFlUdXozeHNXK3cxdjlHbDJaMnBZMTZWTCtEV1k9"
|
|
||||||
var decText = "mongodb://qlik-default-mongodb:27017/qliksense?ssl=false"
|
var decText = "mongodb://qlik-default-mongodb:27017/qliksense?ssl=false"
|
||||||
|
|
||||||
func setupTargetFileAndPrivateKey() ([]byte, []byte, string, error) {
|
func setupTargetFileAndPrivateKey() (string, string, error) {
|
||||||
targetFileString := fmt.Sprintf(targetFileStringTemplate, encText)
|
|
||||||
privKeyBytes := []byte(`-----BEGIN RSA PRIVATE KEY-----
|
|
||||||
MIIJJwIBAAKCAgEApFf3qCQhAr2QLRRZdhLyB8exLjrQiXLr8hwDe0xHSLJX3w7v
|
|
||||||
5z4ujJWrHUulQ2/hvS8uffxMVrp2YqeA4sjy/ku1KqZVQv/WNTdL2v9Z1ewbRnBj
|
|
||||||
DQvmkWDKZ+cP8VPdHGzQ4iM2z6BZ4RQTkdQMKqsVwUsLO9amI2TOny/M696eFRW0
|
|
||||||
pk4+W3QZZRawT0HqJPvKKXKqoO2+62W54rOV8glJi29Do06e4S6CZUl1hBUy0VlL
|
|
||||||
trLlRSOHTois0dF2a9f7+GGgU11MHO6w1k1NesSlfZ0vnrrkW8WFLqewk+Jj+w1x
|
|
||||||
eQnYHOeHjx6zi9f9DC96eSylSB3iJ71NmXcMc0IEZ2LiQIqTL83BLOgMBCsK3FSl
|
|
||||||
GMakQUR2GJ+M0I/selYkRMhid6eOmhlsTNMPbpcTHxZ+ReIzS+5B1X0FZ7RIL+jS
|
|
||||||
L9mFcxmD3dxurrrt/DkLpXcuWdi1s1bpVn3jIQhU0+bgA6hT0k8Kj2f3Q9QnvkHS
|
|
||||||
Eff+XyLvLwQeSsSAcnM+1I7fNSPEo2cq0au6ZtjHcirXmMminAQ6cKW1XrEvJBef
|
|
||||||
HHibtjJjIM4bHH7MKRA5H3km/J4CCwI1VogSTcE05Z6ypAFU2TCrnec9c9VXkRDP
|
|
||||||
94h0GuoG8sdhmQudqvghr/8T7CV+sGRQbdeqrXwanfnGPrjcMVIO/dSOxOUCAwEA
|
|
||||||
AQKCAgA5b2TmJnpC8u0IVCxPz582iNurRHLNFpTPMGsnFCl1hp6fHiFJt7mc+FGt
|
|
||||||
E1rWjqtd6rdc4Gfth40IPXIV0BTcOqk+FpOFrtO2FXU1PDixQqrlmzGCxb324NTc
|
|
||||||
KyyvMpf77yuxXI0zUt8WgmW0eV8nKlOYEhoC96lohTqQ96uuY0bsJ4HS/VVdsN2P
|
|
||||||
Lra/fFHQSw8EHUb0pyIqMoscZ5bn18cUK/Z/hGKSYCbCL0Iavy3bbFHBsBPgbeJD
|
|
||||||
2BBN4953Iiy1Sak2eUy4b9LtkmaZmVAc7mpOFxLn38gD3icgB+bZPoGBw6b7sw71
|
|
||||||
Pc2R+hI9x/oNj0TUR11adhZApBJ9RhBbnSCUt8OUt9U5prNj+9qs8cHJGywtz1da
|
|
||||||
ZT1M6mn2MFSsaOyOlJPzGUzSf4AhI7HiouDpLHtHDqLmc8Vv4rZUqrcFw6kZTCY5
|
|
||||||
564yE8hh/UimOgQr7467/hADHZ0kBsupFEDWRqQ3qTIikHmGhTYZehDrSGL/3BMG
|
|
||||||
rvsFdv0krUHyW4FfHqPN09jfP3LTqd5vVbzRhxcGsoGmP/1kXIDtO8Cp1s/K6Mse
|
|
||||||
tInRCRla8ttZ3CZZ+Vf8HLi/n8XSRfbnMGYi7lVVxnp6kNsTEBgosbdU/r1zbMRJ
|
|
||||||
8mMMHygyugaRLHmOD/8fkWLfyR88cxPH8u9NufTfvJgiFpZboQKCAQEA0uSU6IGZ
|
|
||||||
pXIVZdmDWt4mxpS5T2UYarw3V9z/Isd3kkUU5YrC2XrvPRwmx5Jh9GXl9WENYJAR
|
|
||||||
wH7PaJT0HpBwpxJa1RqHHDSka7DnDcy44oRXyM7e2AmcW8QvcDty/0HPo4oZq4IT
|
|
||||||
m/+ot1R+bIpmJOweGRhVauzxJEUlQyt+kiH/ad8GiOS6LwqFPq42alnUxPQ106wF
|
|
||||||
EZZ2WQdzkyV6tF9aMG18AT1fJsGwNjCLRxJ52t/aEUP5mYwlL2UTT5Acn8KbtrTO
|
|
||||||
fFLAxGuB9LDdT1tGgIpzsXmxAaaeuPvSK4TDFdQyLAUdQJdz0GD9j9ciMPQH3UPe
|
|
||||||
Vjt6qtpfY6QK2wKCAQEAx36Vys5BlQI0TG6qORI0fiOYpLG1GqmdbCNRgBUsMj5T
|
|
||||||
LFe7uSd4qnDvGmns4MdkSSOlpF17bQiWhWKbjKRQpT0U/46zcIT4pWyajXJe+i9H
|
|
||||||
M/DpSRkMq2kGkx6KX2u9L66QBzcxJjtS17amdSpDAfsrvJgOWkxxInzw9n1u6aTe
|
|
||||||
ZjRDXdVX0KjPebEPOaoJToxne21Od3t+47TnDsQPsO1dvvrXX76IfH8cAlD5+0C/
|
|
||||||
b2YvDqWDmh9ICjKShwuDWgi4KjCV5PMHCIxH0FQ2L6mSbwIb9YgGin3wjN3KbWqz
|
|
||||||
dgEu7MeDxEwxZSSg4OstYVLQVgM39G/2ZA4YVJEbPwKCAQAo9FjymhBzb6c2Izp+
|
|
||||||
D/wpvkIKaBCI0cpRlso5P9E5p466UOsr/tKs5GWnhgbdxlgVAebuJKw93KJ8pciO
|
|
||||||
kvA9kbPwBHnOgW6Ytz73kBUrcBX4GixueddSftPTkMfxSB+Bm9UGWHlkZw6lo5P1
|
|
||||||
kh7p9qyVpQMZg7AEoiTtWWn4CQAn2DbVqM17Syi7Fmvc1VsbcG1vkM1fMAAFpAvO
|
|
||||||
vI2Kr6W9F9XoC7oJtb15mI3DnJPrbGNVzQSQzAWAoblRTyQv5kQFBDHBNPTYcCRJ
|
|
||||||
l3sy6P/VAI4dHgvAzVGvjL+w0dRszct8fvXCUGceRWeYYmfyZ8GLN53a0ywsN8Ik
|
|
||||||
gHvXAoIBACee5HEa9bt6bJihgf1DuFk1CKPtB2L8PN+1RAKEMfrolexAoG/tfvGa
|
|
||||||
7GH6l6ks8KX2BnfWeST2h66GHw6Xs8ydjQYUeV7nidqQ70EYbfSSXznZpvt1liaU
|
|
||||||
/VFKx4CcDT7jFIfaVlCZh6KADB9I/XXvRIh4SqF0fSO0XMcXsmeE7watapPAQ2iV
|
|
||||||
nl804yk4tBB9oi/JTcQ9Kr5et2UfW15wRiYf+5ZwaPsQ46cyHfPgsCSXztDB3plF
|
|
||||||
jTE5ShC4IKZJBQqcC6kk+0ifU8P0da6RpxuU96iUE3h9+sB/bCy+/FV7dq5gEbNy
|
|
||||||
znygAbOqAaFKqUXr7bkGY5ELm5lwGFECggEACcyaF9mMqLGghR55ew+cMmdeYdK3
|
|
||||||
meMLi5nrgtbQpVLlz+IV7Vdmrv7lZjeTr4nvU/5miU+p+If14CCFBiSucGq3Kmyp
|
|
||||||
OSM5cNCjDhw8uIDfY2qWCrZ2NSMR3qaAoBAQyQ2ER1IL98TDF/Qui0ZatbPiM4Ns
|
|
||||||
GErhkBZh3MCDSt24yiVKcUB79BxatWB4K7h7y8wqpX4Rj7rpfJMF7wz/I1cgyuCE
|
|
||||||
7XFpRwj7F1B2MmXnvV3KAgAD0EqrJDLeM0vIlDhpOUEaFUkuqmQyeB8qQkWfyXbD
|
|
||||||
jzloS3cNq0MBijB8oixwD2b4dVhBM7z8vQMX6OntN+97luWgO8OIukoYAg==
|
|
||||||
-----END RSA PRIVATE KEY-----
|
|
||||||
`)
|
|
||||||
|
|
||||||
publicKeyBytes := []byte(`-----BEGIN RSA PUBLIC KEY-----
|
secretKeyLocation := filepath.Join(testDir, secrets, contexts, qlikDefaultContext, secrets)
|
||||||
MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEApFf3qCQhAr2QLRRZdhLy
|
if err := os.MkdirAll(secretKeyLocation, 0777); err != nil {
|
||||||
B8exLjrQiXLr8hwDe0xHSLJX3w7v5z4ujJWrHUulQ2/hvS8uffxMVrp2YqeA4sjy
|
|
||||||
/ku1KqZVQv/WNTdL2v9Z1ewbRnBjDQvmkWDKZ+cP8VPdHGzQ4iM2z6BZ4RQTkdQM
|
|
||||||
KqsVwUsLO9amI2TOny/M696eFRW0pk4+W3QZZRawT0HqJPvKKXKqoO2+62W54rOV
|
|
||||||
8glJi29Do06e4S6CZUl1hBUy0VlLtrLlRSOHTois0dF2a9f7+GGgU11MHO6w1k1N
|
|
||||||
esSlfZ0vnrrkW8WFLqewk+Jj+w1xeQnYHOeHjx6zi9f9DC96eSylSB3iJ71NmXcM
|
|
||||||
c0IEZ2LiQIqTL83BLOgMBCsK3FSlGMakQUR2GJ+M0I/selYkRMhid6eOmhlsTNMP
|
|
||||||
bpcTHxZ+ReIzS+5B1X0FZ7RIL+jSL9mFcxmD3dxurrrt/DkLpXcuWdi1s1bpVn3j
|
|
||||||
IQhU0+bgA6hT0k8Kj2f3Q9QnvkHSEff+XyLvLwQeSsSAcnM+1I7fNSPEo2cq0au6
|
|
||||||
ZtjHcirXmMminAQ6cKW1XrEvJBefHHibtjJjIM4bHH7MKRA5H3km/J4CCwI1VogS
|
|
||||||
TcE05Z6ypAFU2TCrnec9c9VXkRDP94h0GuoG8sdhmQudqvghr/8T7CV+sGRQbdeq
|
|
||||||
rXwanfnGPrjcMVIO/dSOxOUCAwEAAQ==
|
|
||||||
-----END RSA PUBLIC KEY-----
|
|
||||||
`)
|
|
||||||
|
|
||||||
targetFile := filepath.Join(testDir, "targetfile.yaml")
|
|
||||||
// tests/config.yaml exists
|
|
||||||
err := ioutil.WriteFile(targetFile, []byte(targetFileString), 0777)
|
|
||||||
if err != nil {
|
|
||||||
log.Printf("Error while creating file: %v", err)
|
|
||||||
return nil, nil, "", err
|
|
||||||
}
|
|
||||||
|
|
||||||
secretKeyPairDir := filepath.Join(testDir, secrets, contexts, qlikDefaultContext, secrets)
|
|
||||||
if err := os.MkdirAll(secretKeyPairDir, 0777); err != nil {
|
|
||||||
err = fmt.Errorf("Not able to create directories")
|
err = fmt.Errorf("Not able to create directories")
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
os.Setenv("QLIKSENSE_KEY_LOCATION", secretKeyPairDir)
|
os.Setenv("QLIKSENSE_KEY_LOCATION", secretKeyLocation)
|
||||||
|
|
||||||
privKeyFile := filepath.Join(secretKeyPairDir, "qliksensePriv")
|
//privKeyFile := filepath.Join(secretKeyLocation, "user_secret_key")
|
||||||
// construct and write priv key file into secretsDir location
|
key, err := api.LoadSecretKey(secretKeyLocation)
|
||||||
err = ioutil.WriteFile(privKeyFile, privKeyBytes, 0777)
|
if key == "" {
|
||||||
|
key, err = api.GenerateAndStoreSecretKey(secretKeyLocation)
|
||||||
|
}
|
||||||
|
encData, _ := api.EncryptData([]byte(decText), key)
|
||||||
|
encText := b64.StdEncoding.EncodeToString(encData)
|
||||||
|
|
||||||
|
targetFileString := fmt.Sprintf(targetFileStringTemplate, encText)
|
||||||
|
targetFile := filepath.Join(testDir, "targetfile.yaml")
|
||||||
|
// tests/config.yaml exists
|
||||||
|
err = ioutil.WriteFile(targetFile, []byte(targetFileString), 0777)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("Error while creating file: %v", err)
|
log.Printf("Error while creating file: %v", err)
|
||||||
return nil, nil, "", err
|
return "", "", err
|
||||||
}
|
}
|
||||||
pubKeyFile := filepath.Join(secretKeyPairDir, "qliksensePub")
|
|
||||||
api.LogDebugMessage("Test setup - \npub key path: %s\n, priv key path: %s\n", pubKeyFile, privKeyFile)
|
|
||||||
// construct and write pub key file into secretsDir location
|
|
||||||
err = ioutil.WriteFile(pubKeyFile, publicKeyBytes, 0777)
|
|
||||||
if err != nil {
|
|
||||||
log.Printf("Error while creating file: %v", err)
|
|
||||||
return nil, nil, "", err
|
|
||||||
}
|
|
||||||
return publicKeyBytes, privKeyBytes, targetFile, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func removePrivateKey() {
|
return targetFile, key, err
|
||||||
err := os.Remove(filepath.Join(testDir, secrets, contexts, qlikDefaultContext, secrets, "qliksensePriv"))
|
|
||||||
if err != nil {
|
|
||||||
log.Fatalf("Could not delete private key %v", err)
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func setup() func() {
|
func setup() func() {
|
||||||
@@ -328,7 +244,7 @@ func TestSetOtherConfigs(t *testing.T) {
|
|||||||
q: &Qliksense{
|
q: &Qliksense{
|
||||||
QliksenseHome: testDir,
|
QliksenseHome: testDir,
|
||||||
},
|
},
|
||||||
args: []string{"profile=minikube", "rotateKeys=yes", "storageClassName=efs", "gitops.enabled=yes", "gitops.schedule=30 * * * *", "git.repository=master", "git.username=foo", "git.accesstoken=1234"},
|
args: []string{"profile=minikube", "rotateKeys=yes", "storageClassName=efs", "gitOps.enabled=yes", "gitOps.schedule=30 * * * *", "git.repository=master", "git.userName=foo", "git.accessToken=1234"},
|
||||||
},
|
},
|
||||||
wantErr: false,
|
wantErr: false,
|
||||||
},
|
},
|
||||||
@@ -338,7 +254,7 @@ func TestSetOtherConfigs(t *testing.T) {
|
|||||||
q: &Qliksense{
|
q: &Qliksense{
|
||||||
QliksenseHome: testDir,
|
QliksenseHome: testDir,
|
||||||
},
|
},
|
||||||
args: []string{"someconfig=somevalue, gitops.schedule=bar", "gitops.enabled=bar", "git.foo=bar", "rotatekeys=bar"},
|
args: []string{"someconfig=somevalue, gitOps.schedule=bar", "gitOps.enabled=bar", "git.foo=bar", "rotateKeys=bar"},
|
||||||
},
|
},
|
||||||
wantErr: true,
|
wantErr: true,
|
||||||
},
|
},
|
||||||
@@ -389,7 +305,7 @@ func TestSetConfigs(t *testing.T) {
|
|||||||
defer tearDown()
|
defer tearDown()
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
if err := tt.args.q.SetConfigs(tt.args.args); (err != nil) != tt.wantErr {
|
if err := tt.args.q.SetConfigs(tt.args.args, false); (err != nil) != tt.wantErr {
|
||||||
t.Errorf("SetConfigs() error = %v, wantErr %v", err, tt.wantErr)
|
t.Errorf("SetConfigs() error = %v, wantErr %v", err, tt.wantErr)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@@ -508,9 +424,14 @@ spec:
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
func removePrivateKey() {
|
||||||
|
err := os.Remove(filepath.Join(testDir, secrets, contexts, qlikDefaultContext, secrets, "user_secret_key"))
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("Could not delete private key %v", err)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
func Test_PrepareK8sSecret(t *testing.T) {
|
func Test_PrepareK8sSecret(t *testing.T) {
|
||||||
|
|
||||||
type fields struct {
|
type fields struct {
|
||||||
QliksenseHome string
|
QliksenseHome string
|
||||||
}
|
}
|
||||||
@@ -530,7 +451,7 @@ func Test_PrepareK8sSecret(t *testing.T) {
|
|||||||
wantErr: false,
|
wantErr: false,
|
||||||
setup: func() (string, func()) {
|
setup: func() (string, func()) {
|
||||||
tearDown := setup()
|
tearDown := setup()
|
||||||
_, _, targetFile, _ := setupTargetFileAndPrivateKey()
|
targetFile, _, _ := setupTargetFileAndPrivateKey()
|
||||||
return targetFile, tearDown
|
return targetFile, tearDown
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -543,7 +464,7 @@ func Test_PrepareK8sSecret(t *testing.T) {
|
|||||||
wantErr: true,
|
wantErr: true,
|
||||||
setup: func() (string, func()) {
|
setup: func() (string, func()) {
|
||||||
tearDown := setup()
|
tearDown := setup()
|
||||||
_, _, targetFile, _ := setupTargetFileAndPrivateKey()
|
targetFile, _, _ := setupTargetFileAndPrivateKey()
|
||||||
removePrivateKey()
|
removePrivateKey()
|
||||||
return targetFile, tearDown
|
return targetFile, tearDown
|
||||||
},
|
},
|
||||||
@@ -557,8 +478,7 @@ func Test_PrepareK8sSecret(t *testing.T) {
|
|||||||
wantErr: true,
|
wantErr: true,
|
||||||
setup: func() (string, func()) {
|
setup: func() (string, func()) {
|
||||||
tearDown := setup()
|
tearDown := setup()
|
||||||
_, _, _, _ = setupTargetFileAndPrivateKey()
|
setupTargetFileAndPrivateKey()
|
||||||
removePrivateKey()
|
|
||||||
return "", tearDown
|
return "", tearDown
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -638,6 +558,7 @@ func Test_SetSecrets(t *testing.T) {
|
|||||||
type args struct {
|
type args struct {
|
||||||
args []string
|
args []string
|
||||||
isSecretSet bool
|
isSecretSet bool
|
||||||
|
base64 bool
|
||||||
}
|
}
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
name string
|
name string
|
||||||
@@ -656,6 +577,18 @@ func Test_SetSecrets(t *testing.T) {
|
|||||||
},
|
},
|
||||||
wantErr: false,
|
wantErr: false,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "valid secret secrets=false base64 encoded",
|
||||||
|
fields: fields{
|
||||||
|
QliksenseHome: testDir,
|
||||||
|
},
|
||||||
|
args: args{
|
||||||
|
args: []string{"qliksense.mongoDbUri=bW9uZ29kYjovL3FsaWstZGVmYXVsdC1tb25nb2RiOjI3MDE3L3FsaWtzZW5zZT9zc2w9ZmFsc2U="},
|
||||||
|
isSecretSet: false,
|
||||||
|
base64: true,
|
||||||
|
},
|
||||||
|
wantErr: false,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: "test1 valid secret secrets=true",
|
name: "test1 valid secret secrets=true",
|
||||||
fields: fields{
|
fields: fields{
|
||||||
@@ -691,22 +624,17 @@ func Test_SetSecrets(t *testing.T) {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
tearDown := setup()
|
tearDown := setup()
|
||||||
_, privateKeyBytes, _, err := setupTargetFileAndPrivateKey()
|
_, encryptionKey, err := setupTargetFileAndPrivateKey()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.FailNow()
|
t.FailNow()
|
||||||
}
|
}
|
||||||
defer tearDown()
|
defer tearDown()
|
||||||
|
|
||||||
privKey, err := api.DecodeToPrivateKey(privateKeyBytes)
|
|
||||||
if err != nil {
|
|
||||||
t.FailNow()
|
|
||||||
}
|
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
q := &Qliksense{
|
q := &Qliksense{
|
||||||
QliksenseHome: tt.fields.QliksenseHome,
|
QliksenseHome: tt.fields.QliksenseHome,
|
||||||
}
|
}
|
||||||
if err := q.SetSecrets(tt.args.args, tt.args.isSecretSet); (err != nil) != tt.wantErr {
|
if err := q.SetSecrets(tt.args.args, tt.args.isSecretSet, tt.args.base64); (err != nil) != tt.wantErr {
|
||||||
t.Errorf("SetSecrets() error = %v, wantErr %v", err, tt.wantErr)
|
t.Errorf("SetSecrets() error = %v, wantErr %v", err, tt.wantErr)
|
||||||
t.FailNow()
|
t.FailNow()
|
||||||
}
|
}
|
||||||
@@ -717,7 +645,10 @@ func Test_SetSecrets(t *testing.T) {
|
|||||||
// extract the value for testing
|
// extract the value for testing
|
||||||
testValueArr := strings.SplitN(tt.args.args[0], "=", 2)
|
testValueArr := strings.SplitN(tt.args.args[0], "=", 2)
|
||||||
testValue := strings.ReplaceAll(testValueArr[1], "\"", "")
|
testValue := strings.ReplaceAll(testValueArr[1], "\"", "")
|
||||||
|
if tt.args.base64 {
|
||||||
|
d, _ := b64.StdEncoding.DecodeString(testValue)
|
||||||
|
testValue = strings.Trim(string(d), "\n ")
|
||||||
|
}
|
||||||
qliksenseCR, err := readCRFile()
|
qliksenseCR, err := readCRFile()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
err = fmt.Errorf("Not able to read from context file: %v", err)
|
err = fmt.Errorf("Not able to read from context file: %v", err)
|
||||||
@@ -734,13 +665,7 @@ func Test_SetSecrets(t *testing.T) {
|
|||||||
log.Printf("decode error: %v", err)
|
log.Printf("decode error: %v", err)
|
||||||
t.FailNow()
|
t.FailNow()
|
||||||
}
|
}
|
||||||
decodedValue, err := b64.StdEncoding.DecodeString(valToBeEncrypted)
|
decryptedVal, err := api.DecryptData([]byte(valToBeEncrypted), encryptionKey)
|
||||||
if err != nil {
|
|
||||||
err := fmt.Errorf("Error occurred while decoding: %v", err)
|
|
||||||
log.Printf("decode error: %v", err)
|
|
||||||
t.FailNow()
|
|
||||||
}
|
|
||||||
decryptedVal, err := api.Decrypt(decodedValue, privKey)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
err := fmt.Errorf("Error occurred while testing decryption: %v", err)
|
err := fmt.Errorf("Error occurred while testing decryption: %v", err)
|
||||||
log.Printf("No Data in Secret: %v", err)
|
log.Printf("No Data in Secret: %v", err)
|
||||||
@@ -781,7 +706,8 @@ func getValueToBeDecodedForSetSecrets(item config.NameValue, qliksenseCR *api.Ql
|
|||||||
}
|
}
|
||||||
// secret=false
|
// secret=false
|
||||||
if item.Value != "" {
|
if item.Value != "" {
|
||||||
return item.Value, nil
|
b, err := b64.RawStdEncoding.DecodeString(item.Value)
|
||||||
|
return string(b), err
|
||||||
}
|
}
|
||||||
err := fmt.Errorf("Both Value and ValueFrom are empty")
|
err := fmt.Errorf("Both Value and ValueFrom are empty")
|
||||||
return "", err
|
return "", err
|
||||||
@@ -929,9 +855,10 @@ func TestDeleteContexts(t *testing.T) {
|
|||||||
q := New(tt.args.qlikSenseHome)
|
q := New(tt.args.qlikSenseHome)
|
||||||
var arg []string
|
var arg []string
|
||||||
arg = append(arg, tt.args.contextName)
|
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)
|
t.Errorf("DeleteContext() error = %v, wantErr %v", err, tt.wantErr)
|
||||||
}
|
}
|
||||||
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package qliksense
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
|
||||||
qapi "github.com/qlik-oss/sense-installer/pkg/api"
|
qapi "github.com/qlik-oss/sense-installer/pkg/api"
|
||||||
@@ -85,6 +86,10 @@ func getQliksenseInitCrd(qcr *qapi.QliksenseCR) (string, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
qInitMsPath := filepath.Join(repoPath, Q_INIT_CRD_PATH)
|
qInitMsPath := filepath.Join(repoPath, Q_INIT_CRD_PATH)
|
||||||
|
if _, err := os.Lstat(qInitMsPath); err != nil {
|
||||||
|
// older version of qliksense-init used
|
||||||
|
qInitMsPath = filepath.Join(repoPath, "manifests/base/manifests/qliksense-init")
|
||||||
|
}
|
||||||
qInitByte, err := ExecuteKustomizeBuild(qInitMsPath)
|
qInitByte, err := ExecuteKustomizeBuild(qInitMsPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println("cannot generate crds for qliksense-init", err)
|
fmt.Println("cannot generate crds for qliksense-init", err)
|
||||||
|
|||||||
@@ -31,10 +31,12 @@ const (
|
|||||||
func (q *Qliksense) PullImages(version, profile string) error {
|
func (q *Qliksense) PullImages(version, profile string) error {
|
||||||
qConfig := qapi.NewQConfig(q.QliksenseHome)
|
qConfig := qapi.NewQConfig(q.QliksenseHome)
|
||||||
if version != "" {
|
if version != "" {
|
||||||
|
if !qConfig.IsRepoExistForCurrent(version) {
|
||||||
if err := q.FetchQK8s(version); err != nil {
|
if err := q.FetchQK8s(version); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
qcr, err := qConfig.GetCurrentCR()
|
qcr, err := qConfig.GetCurrentCR()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -44,8 +46,8 @@ func (q *Qliksense) PullImages(version, profile string) error {
|
|||||||
}
|
}
|
||||||
if profile != "" {
|
if profile != "" {
|
||||||
qcr.Spec.Profile = profile
|
qcr.Spec.Profile = profile
|
||||||
if e := qConfig.WriteCR(qcr); e != nil {
|
if err := qConfig.WriteCR(qcr); err != nil {
|
||||||
return e
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return q.PullImagesForCurrentCR()
|
return q.PullImagesForCurrentCR()
|
||||||
@@ -73,7 +75,7 @@ func (q *Qliksense) PullImagesForCurrentCR() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
images := versionOut.Images
|
images := versionOut.Images
|
||||||
if err := q.appendOperatorImages(&images); err != nil {
|
if err := q.appendAdditionalImages(&images, qcr); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -93,6 +95,19 @@ func (q *Qliksense) PullImagesForCurrentCR() error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (q *Qliksense) appendGitOpsImage(images *[]string, qcr *qapi.QliksenseCR) {
|
||||||
|
if qcr.Spec.GitOps != nil && qcr.Spec.GitOps.Image != "" {
|
||||||
|
*images = append(*images, qcr.Spec.GitOps.Image)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (q *Qliksense) appendPreflightImages(images *[]string) {
|
||||||
|
pf := qapi.NewPreflightConfig(q.QliksenseHome)
|
||||||
|
for _, preflightImage := range pf.GetImageMap() {
|
||||||
|
*images = append(*images, preflightImage)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (q *Qliksense) appendOperatorImages(images *[]string) error {
|
func (q *Qliksense) appendOperatorImages(images *[]string) error {
|
||||||
if operatorImages, err := getImageList([]byte(q.GetOperatorControllerString())); err != nil {
|
if operatorImages, err := getImageList([]byte(q.GetOperatorControllerString())); err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -140,7 +155,6 @@ func pullImage(image, imagesDir string) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// TagAndPushImages ...
|
|
||||||
func (q *Qliksense) PushImagesForCurrentCR() error {
|
func (q *Qliksense) PushImagesForCurrentCR() error {
|
||||||
qConfig := qapi.NewQConfig(q.QliksenseHome)
|
qConfig := qapi.NewQConfig(q.QliksenseHome)
|
||||||
qcr, err := qConfig.GetCurrentCR()
|
qcr, err := qConfig.GetCurrentCR()
|
||||||
@@ -155,7 +169,7 @@ func (q *Qliksense) PushImagesForCurrentCR() error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
if os.IsNotExist(err) {
|
if os.IsNotExist(err) {
|
||||||
dockerConfigJsonSecret = &qapi.DockerConfigJsonSecret{
|
dockerConfigJsonSecret = &qapi.DockerConfigJsonSecret{
|
||||||
Uri: qcr.GetImageRegistry(),
|
Uri: qcr.Spec.GetImageRegistry(),
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return err
|
return err
|
||||||
@@ -173,7 +187,7 @@ func (q *Qliksense) PushImagesForCurrentCR() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
images := versionOut.Images
|
images := versionOut.Images
|
||||||
if err := q.appendOperatorImages(&images); err != nil {
|
if err := q.appendAdditionalImages(&images, qcr); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -194,6 +208,15 @@ func (q *Qliksense) PushImagesForCurrentCR() error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (q *Qliksense) appendAdditionalImages(images *[]string, qcr *qapi.QliksenseCR) error {
|
||||||
|
if err := q.appendOperatorImages(images); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
q.appendGitOpsImage(images, qcr)
|
||||||
|
q.appendPreflightImages(images)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func pushImage(image, imagesDir string, dockerConfigJsonSecret *qapi.DockerConfigJsonSecret) error {
|
func pushImage(image, imagesDir string, dockerConfigJsonSecret *qapi.DockerConfigJsonSecret) error {
|
||||||
imageNameParts := getImageNameParts(image)
|
imageNameParts := getImageNameParts(image)
|
||||||
srcDir := filepath.Join(imagesDir, imageIndexDirName, imageNameParts.name, imageNameParts.tag)
|
srcDir := filepath.Join(imagesDir, imageIndexDirName, imageNameParts.name, imageNameParts.tag)
|
||||||
|
|||||||
@@ -68,6 +68,9 @@ const (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func Test_Pull_Push_ImagesForCurrentCR(t *testing.T) {
|
func Test_Pull_Push_ImagesForCurrentCR(t *testing.T) {
|
||||||
|
if testing.Short() {
|
||||||
|
t.Skip("Skipping pull/push tests in short mode")
|
||||||
|
}
|
||||||
var testCases = []struct {
|
var testCases = []struct {
|
||||||
name string
|
name string
|
||||||
registryAuth bool
|
registryAuth bool
|
||||||
@@ -131,7 +134,7 @@ func Test_Pull_Push_ImagesForCurrentCR(t *testing.T) {
|
|||||||
}
|
}
|
||||||
q := &Qliksense{
|
q := &Qliksense{
|
||||||
QliksenseHome: tmpQlikSenseHome,
|
QliksenseHome: tmpQlikSenseHome,
|
||||||
CrdBox: packr.New("crds", "./crds"),
|
CrdBox: &packr.Box{},
|
||||||
}
|
}
|
||||||
var versionOut VersionOutput
|
var versionOut VersionOutput
|
||||||
|
|
||||||
@@ -170,29 +173,88 @@ func Test_Pull_Push_ImagesForCurrentCR(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func setupQlikSenseHome(t *testing.T, tmpQlikSenseHome string, registry *testRegistryV2, clientAuth clientAuthType) error {
|
func Test_appendAdditionalImages(t *testing.T) {
|
||||||
if err := ioutil.WriteFile(path.Join(tmpQlikSenseHome, "config.yaml"), []byte(`
|
tmpQlikSenseHome, err := ioutil.TempDir("", "tmp-qlik-sense-home-")
|
||||||
apiVersion: config.qlik.com/v1
|
if err != nil {
|
||||||
kind: QliksenseConfig
|
t.Fatalf("unexpected error creating tmp dir: %v", err)
|
||||||
|
}
|
||||||
|
defer os.RemoveAll(tmpQlikSenseHome)
|
||||||
|
|
||||||
|
setupQliksenseTestDefaultContext(t, tmpQlikSenseHome, `
|
||||||
|
apiVersion: qlik.com/v1
|
||||||
|
kind: Qliksense
|
||||||
metadata:
|
metadata:
|
||||||
name: QliksenseConfigMetadata
|
name: qlik-default
|
||||||
spec:
|
spec:
|
||||||
contexts:
|
gitOps:
|
||||||
- name: qlik-default
|
image: some-gitops-image
|
||||||
crFile: contexts/qlik-default/qlik-default.yaml
|
`)
|
||||||
currentContext: qlik-default
|
|
||||||
`), os.ModePerm); err != nil {
|
q := &Qliksense{
|
||||||
return err
|
QliksenseHome: tmpQlikSenseHome,
|
||||||
|
CrdBox: packr.New("crds", "./crds"),
|
||||||
}
|
}
|
||||||
|
|
||||||
defaultContextDir := path.Join(tmpQlikSenseHome, "contexts", "qlik-default")
|
pf := api.NewPreflightConfig(q.QliksenseHome)
|
||||||
if err := os.MkdirAll(defaultContextDir, os.ModePerm); err != nil {
|
if err := pf.Initialize(); err != nil {
|
||||||
return err
|
t.Fatalf("unexpected error initializing preflight: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
qConfig := api.NewQConfig(q.QliksenseHome)
|
||||||
|
qcr, err := qConfig.GetCurrentCR()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unexpected error getting current CR: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
images := make([]string, 0)
|
||||||
|
if err := q.appendAdditionalImages(&images, qcr); err != nil {
|
||||||
|
t.Fatalf("unexpected error appending additional images: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
expectedNumberAdditionalImages := 5
|
||||||
|
if len(images) != expectedNumberAdditionalImages {
|
||||||
|
t.Fatalf("unexpected number of additional images: %v, expected: %v", len(images), expectedNumberAdditionalImages)
|
||||||
|
}
|
||||||
|
|
||||||
|
haveMatchingImage := func(test func(string) bool) bool {
|
||||||
|
for _, image := range images {
|
||||||
|
if test(image) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if !haveMatchingImage(func(image string) bool {
|
||||||
|
return strings.Contains(image, "qlik-docker-oss.bintray.io/qliksense-operator:v")
|
||||||
|
}) {
|
||||||
|
t.Fatal("expected to find the operator image in the list, but it wasn't there")
|
||||||
|
}
|
||||||
|
if !haveMatchingImage(func(image string) bool {
|
||||||
|
return image == "some-gitops-image"
|
||||||
|
}) {
|
||||||
|
t.Fatal("expected to find the GitOps image in the list, but it wasn't there")
|
||||||
|
}
|
||||||
|
if !haveMatchingImage(func(image string) bool {
|
||||||
|
return image == "nginx"
|
||||||
|
}) {
|
||||||
|
t.Fatal("expected to find the nginx Preflight image in the list, but it wasn't there")
|
||||||
|
}
|
||||||
|
if !haveMatchingImage(func(image string) bool {
|
||||||
|
return image == "subfuzion/netcat"
|
||||||
|
}) {
|
||||||
|
t.Fatal("expected to find the netcat Preflight image in the list, but it wasn't there")
|
||||||
|
}
|
||||||
|
if !haveMatchingImage(func(image string) bool {
|
||||||
|
return image == "mongo"
|
||||||
|
}) {
|
||||||
|
t.Fatal("expected to find the mongo Preflight image in the list, but it wasn't there")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func setupQlikSenseHome(t *testing.T, tmpQlikSenseHome string, registry *testRegistryV2, clientAuth clientAuthType) error {
|
||||||
version := "foo"
|
version := "foo"
|
||||||
manifestsRootDir := fmt.Sprintf("%s/repo/%s", defaultContextDir, version)
|
manifestsRootDir := filepath.ToSlash(path.Join(tmpQlikSenseHome, "contexts", "qlik-default", "repo", version))
|
||||||
if err := ioutil.WriteFile(path.Join(defaultContextDir, "qlik-default.yaml"), []byte(fmt.Sprintf(`
|
cr := fmt.Sprintf(`
|
||||||
apiVersion: qlik.com/v1
|
apiVersion: qlik.com/v1
|
||||||
kind: Qliksense
|
kind: Qliksense
|
||||||
metadata:
|
metadata:
|
||||||
@@ -208,9 +270,8 @@ spec:
|
|||||||
manifestsRoot: %s
|
manifestsRoot: %s
|
||||||
rotateKeys: "yes"
|
rotateKeys: "yes"
|
||||||
releaseName: qlik-default
|
releaseName: qlik-default
|
||||||
`, version, registry.url, manifestsRootDir)), os.ModePerm); err != nil {
|
`, version, registry.url, manifestsRootDir)
|
||||||
return err
|
setupQliksenseTestDefaultContext(t, tmpQlikSenseHome, cr)
|
||||||
}
|
|
||||||
|
|
||||||
if clientAuth == clientAuthProvided || clientAuth == clientAuthProvidedButIncorrect {
|
if clientAuth == clientAuthProvided || clientAuth == clientAuthProvidedButIncorrect {
|
||||||
if registry.username == "" || clientAuth == clientAuthProvidedButIncorrect {
|
if registry.username == "" || clientAuth == clientAuthProvidedButIncorrect {
|
||||||
|
|||||||
71
pkg/qliksense/export.go
Normal file
71
pkg/qliksense/export.go
Normal file
@@ -0,0 +1,71 @@
|
|||||||
|
package qliksense
|
||||||
|
|
||||||
|
import (
|
||||||
|
"archive/zip"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (q *Qliksense) ExportContext(context string, output string) error {
|
||||||
|
qliksenseContextsDir := filepath.Join(q.QliksenseHome, QliksenseContextsDir)
|
||||||
|
qliksenseContextFile := filepath.Join(qliksenseContextsDir, context)
|
||||||
|
qliksenseSecretsDir := filepath.Join(q.QliksenseHome, QliksenseSecretsDir, QliksenseContextsDir)
|
||||||
|
qliksenseSecretsFile := filepath.Join(qliksenseSecretsDir, context)
|
||||||
|
// files := []string{qliksenseContextFile, qliksenseSecretsFile}
|
||||||
|
|
||||||
|
fmt.Println(q.QliksenseHome)
|
||||||
|
fmt.Println(qliksenseSecretsFile)
|
||||||
|
fmt.Println(qliksenseContextFile)
|
||||||
|
|
||||||
|
filename := "result.zip"
|
||||||
|
destinationFile, err := os.Create(output + "/" + filename)
|
||||||
|
var folders []string
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
folders = append(folders, qliksenseContextFile, qliksenseSecretsFile)
|
||||||
|
if err := RecursiveZip(folders, destinationFile); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func RecursiveZip(pathToZip []string, destinationFile *os.File) error {
|
||||||
|
s myZip := zip.NewWriter(destinationFile)
|
||||||
|
for _, element := range pathToZip {
|
||||||
|
err := filepath.Walk(element, func(filePath string, info os.FileInfo, err error) error {
|
||||||
|
if info.IsDir() {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
relPath := strings.TrimPrefix(filePath, element)
|
||||||
|
zipFile, err := myZip.Create(relPath)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
fsFile, err := os.Open(filePath)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
_, err = io.Copy(zipFile, fsFile)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
})xs
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
err := myZip.Close()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
@@ -1,13 +1,28 @@
|
|||||||
package qliksense
|
package qliksense
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bufio"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
|
"os"
|
||||||
|
"path"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/google/uuid"
|
"github.com/go-git/go-git/v5/plumbing/transport"
|
||||||
|
"github.com/go-git/go-git/v5/plumbing/transport/http"
|
||||||
kapis_git "github.com/qlik-oss/k-apis/pkg/git"
|
kapis_git "github.com/qlik-oss/k-apis/pkg/git"
|
||||||
qapi "github.com/qlik-oss/sense-installer/pkg/api"
|
qapi "github.com/qlik-oss/sense-installer/pkg/api"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type FetchCommandOptions struct {
|
||||||
|
GitUrl string
|
||||||
|
AccessToken string
|
||||||
|
Version string
|
||||||
|
SecretName string
|
||||||
|
Overwrite bool
|
||||||
|
}
|
||||||
|
|
||||||
const (
|
const (
|
||||||
QLIK_GIT_REPO = "https://github.com/qlik-oss/qliksense-k8s"
|
QLIK_GIT_REPO = "https://github.com/qlik-oss/qliksense-k8s"
|
||||||
)
|
)
|
||||||
@@ -17,24 +32,130 @@ func (q *Qliksense) FetchQK8s(version string) error {
|
|||||||
return fetchAndUpdateCR(qConfig, version)
|
return fetchAndUpdateCR(qConfig, version)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (q *Qliksense) FetchK8sWithOpts(opts *FetchCommandOptions) error {
|
||||||
|
qConfig := qapi.NewQConfig(q.QliksenseHome)
|
||||||
|
cr, err := qConfig.GetCurrentCR()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if opts.AccessToken != "" {
|
||||||
|
encKey, err := qConfig.GetEncryptionKeyFor(cr.GetName())
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := cr.SetFetchAccessToken(opts.AccessToken, encKey); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if opts.SecretName != "" {
|
||||||
|
cr.SetFetchAccessSecretName(opts.SecretName)
|
||||||
|
}
|
||||||
|
if opts.GitUrl != "" {
|
||||||
|
cr.SetFetchUrl(opts.GitUrl)
|
||||||
|
}
|
||||||
|
v := getVersion(opts, cr)
|
||||||
|
if v == "" {
|
||||||
|
return errors.New("Cannot find gitref/tag/branch/version to fetch")
|
||||||
|
}
|
||||||
|
if qConfig.IsRepoExistForCurrent(v) {
|
||||||
|
if opts.Overwrite || getVerionsOverwriteConfirmation(v) == "y" {
|
||||||
|
if err := qConfig.DeleteRepoForCurrent(v); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// nothing to do
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
qConfig.WriteCR(cr)
|
||||||
|
return fetchAndUpdateCR(qConfig, v)
|
||||||
|
}
|
||||||
|
|
||||||
|
// fetchAndUpdateCR fetch
|
||||||
func fetchAndUpdateCR(qConfig *qapi.QliksenseConfig, version string) error {
|
func fetchAndUpdateCR(qConfig *qapi.QliksenseConfig, version string) error {
|
||||||
qcr, err := qConfig.GetCurrentCR()
|
qcr, err := qConfig.GetCurrentCR()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println("cannot get the current-context cr", err)
|
fmt.Println("cannot get the current-context cr", err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if qConfig.IsRepoExistForCurrent(version) {
|
if version == "" {
|
||||||
return nil
|
if qcr.GetLabelFromCr("version") == "" {
|
||||||
|
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")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
encKey, err := qConfig.GetEncryptionKeyFor(qcr.GetName())
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
// downlaod to temp first
|
||||||
|
tempDest, err := fetchToTempDir(qcr.GetFetchUrl(), version, qcr.GetFetchAccessToken(encKey))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
destDir := qConfig.BuildRepoPath(version)
|
|
||||||
fmt.Printf("fetching version [%s] from %s\n", version, QLIK_GIT_REPO)
|
|
||||||
|
|
||||||
if repo, err := kapis_git.CloneRepository(destDir, QLIK_GIT_REPO, nil); err != nil {
|
destDir := qConfig.BuildRepoPath(version)
|
||||||
return err
|
fmt.Printf("fetching version [%s] from %s\n", version, qcr.GetFetchUrl())
|
||||||
} else if err = kapis_git.Checkout(repo, version, fmt.Sprintf("%v-by-operator-%v", version, uuid.New().String()), nil); err != nil {
|
if err := qapi.CopyDirectory(tempDest, destDir); err != nil {
|
||||||
return err
|
return nil
|
||||||
}
|
}
|
||||||
qcr.Spec.ManifestsRoot = qConfig.BuildCurrentManifestsRoot(version)
|
qcr.Spec.ManifestsRoot = qConfig.BuildCurrentManifestsRoot(version)
|
||||||
qcr.AddLabelToCr("version", version)
|
qcr.AddLabelToCr("version", version)
|
||||||
return qConfig.WriteCurrentContextCR(qcr)
|
return qConfig.WriteCurrentContextCR(qcr)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func fetchToTempDir(gitUrl, gitRef, accessToken string) (string, error) {
|
||||||
|
tmpDir, err := ioutil.TempDir("", "")
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
downloadPath := path.Join(tmpDir, "repo")
|
||||||
|
var auth transport.AuthMethod
|
||||||
|
if accessToken != "" {
|
||||||
|
auth = &http.BasicAuth{
|
||||||
|
Username: "something",
|
||||||
|
Password: accessToken,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if repo, err := kapis_git.CloneRepository(downloadPath, gitUrl, auth); err != nil {
|
||||||
|
return "", err
|
||||||
|
} else if err := kapis_git.Checkout(repo, gitRef, "", auth); err != nil {
|
||||||
|
return "", err
|
||||||
|
} else {
|
||||||
|
return downloadPath, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func getVersion(opts *FetchCommandOptions, qcr *qapi.QliksenseCR) string {
|
||||||
|
if opts.Version == "" {
|
||||||
|
if qcr.GetLabelFromCr("version") != "" {
|
||||||
|
return qcr.GetLabelFromCr("version")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return opts.Version
|
||||||
|
}
|
||||||
|
|
||||||
|
func getVerionsOverwriteConfirmation(version string) string {
|
||||||
|
reader := bufio.NewReader(os.Stdin)
|
||||||
|
fmt.Println("The version [" + version + "] already exist")
|
||||||
|
cfm := "n"
|
||||||
|
for {
|
||||||
|
fmt.Print("Do you want to delete and fetch again [y/N]: ")
|
||||||
|
cfm, _ = reader.ReadString('\n')
|
||||||
|
cfm = strings.Replace(cfm, "\n", "", -1)
|
||||||
|
cfm = strings.TrimSpace(cfm)
|
||||||
|
if cfm == "" {
|
||||||
|
cfm = "n"
|
||||||
|
}
|
||||||
|
cfm = strings.ToLower(cfm)
|
||||||
|
if cfm == "y" || cfm == "n" {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return cfm
|
||||||
|
}
|
||||||
|
|||||||
@@ -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.Log("actual path: " + cr.Spec.ManifestsRoot + ", expected path: contexts/test1/qlik-k8s/v0.0.2")
|
||||||
t.FailNow()
|
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()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/Masterminds/semver/v3"
|
||||||
"github.com/qlik-oss/k-apis/pkg/git"
|
"github.com/qlik-oss/k-apis/pkg/git"
|
||||||
qapi "github.com/qlik-oss/sense-installer/pkg/api"
|
qapi "github.com/qlik-oss/sense-installer/pkg/api"
|
||||||
)
|
)
|
||||||
@@ -86,3 +87,69 @@ func (q *Qliksense) GetInstallableVersions(opts *LsRemoteCmdOptions) error {
|
|||||||
|
|
||||||
return nil
|
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
|
||||||
|
}
|
||||||
|
|||||||
25
pkg/qliksense/get_installable_versions_test.go
Normal file
25
pkg/qliksense/get_installable_versions_test.go
Normal 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()
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -3,6 +3,9 @@ package qliksense
|
|||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
|
"os"
|
||||||
|
"path"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
|
||||||
"github.com/qlik-oss/k-apis/pkg/config"
|
"github.com/qlik-oss/k-apis/pkg/config"
|
||||||
@@ -27,11 +30,9 @@ func (q *Qliksense) InstallQK8s(version string, opts *InstallCommandOptions, kee
|
|||||||
// fetch the version
|
// fetch the version
|
||||||
qConfig := qapi.NewQConfig(q.QliksenseHome)
|
qConfig := qapi.NewQConfig(q.QliksenseHome)
|
||||||
if !keepPatchFiles {
|
if !keepPatchFiles {
|
||||||
defer func() {
|
|
||||||
if err := q.DiscardAllUnstagedChangesFromGitRepo(qConfig); err != nil {
|
if err := q.DiscardAllUnstagedChangesFromGitRepo(qConfig); err != nil {
|
||||||
fmt.Printf("error removing temporary changes to the config: %v\n", err)
|
fmt.Printf("error removing temporary changes to the config: %v\n", err)
|
||||||
}
|
}
|
||||||
}()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
qcr, err := qConfig.GetCurrentCR()
|
qcr, err := qConfig.GetCurrentCR()
|
||||||
@@ -66,16 +67,11 @@ func (q *Qliksense) InstallQK8s(version string, opts *InstallCommandOptions, kee
|
|||||||
//CRD will be installed outside of operator
|
//CRD will be installed outside of operator
|
||||||
//install operator controller into the namespace
|
//install operator controller into the namespace
|
||||||
fmt.Println("Installing operator controller")
|
fmt.Println("Installing operator controller")
|
||||||
operatorControllerString := q.GetOperatorControllerString()
|
if operatorControllerString, err := q.getProcessedOperatorControllerString(qcr); err != nil {
|
||||||
if imageRegistry := qcr.GetImageRegistry(); imageRegistry != "" {
|
fmt.Println("error extracting/transforming operator controller", err)
|
||||||
operatorControllerString, err = kustomizeForImageRegistry(operatorControllerString, pullSecretName,
|
|
||||||
"qlik/qliksense-operator", fmt.Sprintf("%v/qliksense-operator", imageRegistry))
|
|
||||||
if err != nil {
|
|
||||||
return err
|
return err
|
||||||
}
|
} else if err := qapi.KubectlApply(operatorControllerString, ""); err != nil {
|
||||||
}
|
fmt.Println("cannot do kubectl apply on operator controller", err)
|
||||||
if err := qapi.KubectlApply(operatorControllerString, ""); err != nil {
|
|
||||||
fmt.Println("cannot do kubectl apply on opeartor controller", err)
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -94,12 +90,11 @@ func (q *Qliksense) InstallQK8s(version string, opts *InstallCommandOptions, kee
|
|||||||
return q.applyCR(dcr)
|
return q.applyCR(dcr)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if version == "" {
|
if !qcr.IsRepoExist() {
|
||||||
version = qcr.GetLabelFromCr("version")
|
|
||||||
}
|
|
||||||
if err := fetchAndUpdateCR(qConfig, version); err != nil {
|
if err := fetchAndUpdateCR(qConfig, version); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
qcr, err = qConfig.GetCurrentCR()
|
qcr, err = qConfig.GetCurrentCR()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -114,17 +109,32 @@ func (q *Qliksense) InstallQK8s(version string, opts *InstallCommandOptions, kee
|
|||||||
|
|
||||||
if dcr, err := qConfig.GetDecryptedCr(qcr); err != nil {
|
if dcr, err := qConfig.GetDecryptedCr(qcr); err != nil {
|
||||||
return err
|
return err
|
||||||
} else if err := q.applyConfigToK8s(dcr); err != nil {
|
} else {
|
||||||
|
if IsQliksenseInstalled(dcr.GetName()) {
|
||||||
|
return q.UpgradeQK8s(keepPatchFiles)
|
||||||
|
}
|
||||||
|
if err := q.applyConfigToK8s(dcr); err != nil {
|
||||||
fmt.Println("cannot do kubectl apply on manifests")
|
fmt.Println("cannot do kubectl apply on manifests")
|
||||||
return err
|
return err
|
||||||
} else {
|
} else {
|
||||||
return q.applyCR(dcr)
|
return q.applyCR(dcr)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (q *Qliksense) getProcessedOperatorControllerString(qcr *qapi.QliksenseCR) (string, error) {
|
||||||
|
operatorControllerString := q.GetOperatorControllerString()
|
||||||
|
if imageRegistry := qcr.Spec.GetImageRegistry(); imageRegistry != "" {
|
||||||
|
return kustomizeForImageRegistry(operatorControllerString, pullSecretName,
|
||||||
|
path.Join(qliksenseOperatorImageRepo, qliksenseOperatorImageName),
|
||||||
|
path.Join(imageRegistry, qliksenseOperatorImageName))
|
||||||
|
}
|
||||||
|
return operatorControllerString, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func installOrRemoveImagePullSecret(qConfig *qapi.QliksenseConfig) error {
|
func installOrRemoveImagePullSecret(qConfig *qapi.QliksenseConfig) error {
|
||||||
if pullDockerConfigJsonSecret, err := qConfig.GetPullDockerConfigJsonSecret(); err == nil {
|
if pullDockerConfigJsonSecret, err := qConfig.GetPullDockerConfigJsonSecret(); err == nil {
|
||||||
if dockerConfigJsonSecretYaml, err := pullDockerConfigJsonSecret.ToYaml(nil); err != nil {
|
if dockerConfigJsonSecretYaml, err := pullDockerConfigJsonSecret.ToYaml(""); err != nil {
|
||||||
return err
|
return err
|
||||||
} else if err := qapi.KubectlApply(string(dockerConfigJsonSecretYaml), ""); err != nil {
|
} else if err := qapi.KubectlApply(string(dockerConfigJsonSecretYaml), ""); err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -133,7 +143,7 @@ func installOrRemoveImagePullSecret(qConfig *qapi.QliksenseConfig) error {
|
|||||||
deleteDockerConfigJsonSecret := qapi.DockerConfigJsonSecret{
|
deleteDockerConfigJsonSecret := qapi.DockerConfigJsonSecret{
|
||||||
Name: pullSecretName,
|
Name: pullSecretName,
|
||||||
}
|
}
|
||||||
if deleteDockerConfigJsonSecretYaml, err := deleteDockerConfigJsonSecret.ToYaml(nil); err != nil {
|
if deleteDockerConfigJsonSecretYaml, err := deleteDockerConfigJsonSecret.ToYaml(""); err != nil {
|
||||||
return err
|
return err
|
||||||
} else if err := qapi.KubectlDelete(string(deleteDockerConfigJsonSecretYaml), ""); err != nil {
|
} else if err := qapi.KubectlDelete(string(deleteDockerConfigJsonSecretYaml), ""); err != nil {
|
||||||
qapi.LogDebugMessage("failed deleting %v, error: %v\n", pullSecretName, err)
|
qapi.LogDebugMessage("failed deleting %v, error: %v\n", pullSecretName, err)
|
||||||
@@ -143,10 +153,15 @@ func installOrRemoveImagePullSecret(qConfig *qapi.QliksenseConfig) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func kustomizeForImageRegistry(resources, dockerConfigJsonSecretName, name, newName string) (string, error) {
|
func kustomizeForImageRegistry(resources, dockerConfigJsonSecretName, name, newName string) (string, error) {
|
||||||
fSys := filesys.MakeFsInMemory()
|
dir, err := ioutil.TempDir("", "")
|
||||||
if err := fSys.WriteFile("/resources.yaml", []byte(resources)); err != nil {
|
if err != nil {
|
||||||
return "", err
|
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
|
apiVersion: builtin
|
||||||
kind: PatchTransformer
|
kind: PatchTransformer
|
||||||
metadata:
|
metadata:
|
||||||
@@ -155,9 +170,9 @@ patch: '[{"op": "add", "path": "/spec/template/spec/imagePullSecrets", "value":
|
|||||||
target:
|
target:
|
||||||
name: .*-operator
|
name: .*-operator
|
||||||
kind: Deployment
|
kind: Deployment
|
||||||
`, dockerConfigJsonSecretName))); err != nil {
|
`, dockerConfigJsonSecretName)), os.ModePerm); err != nil {
|
||||||
return "", err
|
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:
|
||||||
- resources.yaml
|
- resources.yaml
|
||||||
transformers:
|
transformers:
|
||||||
@@ -165,9 +180,9 @@ transformers:
|
|||||||
images:
|
images:
|
||||||
- name: %s
|
- name: %s
|
||||||
newName: %s
|
newName: %s
|
||||||
`, name, newName))); err != nil {
|
`, name, newName)), os.ModePerm); err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
} else if out, err := executeKustomizeBuildForFileSystem("/", fSys); err != nil {
|
} else if out, err := executeKustomizeBuildForFileSystem(dir, filesys.MakeFsOnDisk()); err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
} else {
|
} else {
|
||||||
return string(out), nil
|
return string(out), nil
|
||||||
|
|||||||
@@ -1,11 +1,20 @@
|
|||||||
package qliksense
|
package qliksense
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
|
"path"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"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"
|
||||||
|
|
||||||
|
"github.com/gobuffalo/packr/v2"
|
||||||
qapi "github.com/qlik-oss/sense-installer/pkg/api"
|
qapi "github.com/qlik-oss/sense-installer/pkg/api"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -63,3 +72,105 @@ spec:
|
|||||||
}
|
}
|
||||||
td()
|
td()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func setupQliksenseTestDefaultContext(t *testing.T, tmpQlikSenseHome, CR string) {
|
||||||
|
if err := ioutil.WriteFile(path.Join(tmpQlikSenseHome, "config.yaml"), []byte(`
|
||||||
|
apiVersion: config.qlik.com/v1
|
||||||
|
kind: QliksenseConfig
|
||||||
|
metadata:
|
||||||
|
name: QliksenseConfigMetadata
|
||||||
|
spec:
|
||||||
|
contexts:
|
||||||
|
- name: qlik-default
|
||||||
|
crFile: contexts/qlik-default/qlik-default.yaml
|
||||||
|
currentContext: qlik-default
|
||||||
|
`), os.ModePerm); err != nil {
|
||||||
|
t.Fatalf("unexpected error: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
defaultContextDir := path.Join(tmpQlikSenseHome, "contexts", "qlik-default")
|
||||||
|
if err := os.MkdirAll(defaultContextDir, os.ModePerm); err != nil {
|
||||||
|
t.Fatalf("unexpected error: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := ioutil.WriteFile(path.Join(defaultContextDir, "qlik-default.yaml"), []byte(CR), os.ModePerm); err != nil {
|
||||||
|
t.Fatalf("unexpected error: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_getProcessedOperatorControllerString(t *testing.T) {
|
||||||
|
tmpQlikSenseHome, err := ioutil.TempDir("", "tmp-qlik-sense-home-")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unexpected error creating tmp dir: %v", err)
|
||||||
|
}
|
||||||
|
defer os.RemoveAll(tmpQlikSenseHome)
|
||||||
|
|
||||||
|
registry := "registryFoo"
|
||||||
|
setupQliksenseTestDefaultContext(t, tmpQlikSenseHome, fmt.Sprintf(`
|
||||||
|
apiVersion: qlik.com/v1
|
||||||
|
kind: Qliksense
|
||||||
|
metadata:
|
||||||
|
name: qlik-default
|
||||||
|
spec:
|
||||||
|
configs:
|
||||||
|
qliksense:
|
||||||
|
- name: imageRegistry
|
||||||
|
value: %v
|
||||||
|
`, registry))
|
||||||
|
|
||||||
|
q := &Qliksense{
|
||||||
|
QliksenseHome: tmpQlikSenseHome,
|
||||||
|
CrdBox: packr.New("crds", "./crds"),
|
||||||
|
}
|
||||||
|
|
||||||
|
qConfig := qapi.NewQConfig(q.QliksenseHome)
|
||||||
|
qcr, err := qConfig.GetCurrentCR()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unexpected error getting current CR: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
originalOperatorString := q.GetOperatorControllerString()
|
||||||
|
processedOperatorString, err := q.getProcessedOperatorControllerString(qcr)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unexpected error: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
controllerImageChecks := map[string]func(t *testing.T, controllerImage string){
|
||||||
|
originalOperatorString: func(t *testing.T, controllerImage string) {
|
||||||
|
expectedControllerImagePrefix := fmt.Sprintf("%v/%v:", qliksenseOperatorImageRepo, qliksenseOperatorImageName)
|
||||||
|
if !strings.HasPrefix(controllerImage, expectedControllerImagePrefix) {
|
||||||
|
t.Fatalf("expected controller image: %v to have prefix: %v", controllerImage, expectedControllerImagePrefix)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
processedOperatorString: func(t *testing.T, controllerImage string) {
|
||||||
|
expectedControllerImagePrefix := fmt.Sprintf("%v/%v:", registry, qliksenseOperatorImageName)
|
||||||
|
if !strings.HasPrefix(controllerImage, expectedControllerImagePrefix) {
|
||||||
|
t.Fatalf("expected controller image: %v to have prefix: %v", controllerImage, expectedControllerImagePrefix)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
resourceFactory := resmap.NewFactory(resource.NewFactory(kunstruct.NewKunstructuredFactoryImpl()), nil)
|
||||||
|
for operatorString, controllerImageCheck := range controllerImageChecks {
|
||||||
|
resMap, err := resourceFactory.NewResMapFromBytes([]byte(operatorString))
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unexpected error: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
res, err := resMap.GetById(resid.NewResId(resid.Gvk{
|
||||||
|
Group: "apps",
|
||||||
|
Version: "v1",
|
||||||
|
Kind: "Deployment",
|
||||||
|
}, "qliksense-operator"))
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unexpected error: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
controllerImage, err := res.GetString("spec.template.spec.containers[0].image")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unexpected error: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
controllerImageCheck(t, controllerImage)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -57,7 +57,7 @@ func GetYamlsFromMultiDoc(multiYaml string, kind string) string {
|
|||||||
for _, doc := range yamlDocs {
|
for _, doc := range yamlDocs {
|
||||||
scanner := bufio.NewScanner(strings.NewReader(doc))
|
scanner := bufio.NewScanner(strings.NewReader(doc))
|
||||||
for scanner.Scan() {
|
for scanner.Scan() {
|
||||||
if strings.TrimSpace(scanner.Text()) == "kind: "+kind {
|
if scanner.Text() == "kind: "+kind {
|
||||||
resultDocs = resultDocs + "\n---\n" + doc
|
resultDocs = resultDocs + "\n---\n" + doc
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,13 +3,24 @@ package qliksense
|
|||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"log"
|
"log"
|
||||||
"os"
|
"os"
|
||||||
"path"
|
"path/filepath"
|
||||||
|
"regexp"
|
||||||
"strings"
|
"strings"
|
||||||
|
"sync"
|
||||||
|
"sync/atomic"
|
||||||
"testing"
|
"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"
|
"gopkg.in/yaml.v3"
|
||||||
|
|
||||||
@@ -27,7 +38,7 @@ func Test_ExecuteKustomizeBuild(t *testing.T) {
|
|||||||
}
|
}
|
||||||
defer os.RemoveAll(tmpDir)
|
defer os.RemoveAll(tmpDir)
|
||||||
|
|
||||||
kustomizationYamlFilePath := path.Join(tmpDir, "kustomization.yaml")
|
kustomizationYamlFilePath := filepath.Join(tmpDir, "kustomization.yaml")
|
||||||
kustomizationYaml := `
|
kustomizationYaml := `
|
||||||
generatorOptions:
|
generatorOptions:
|
||||||
disableNameSuffixHash: true
|
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) {
|
func Test_executeKustomizeBuild_onQlikConfig_regenerateKeys(t *testing.T) {
|
||||||
tmpDir, err := ioutil.TempDir("", "")
|
tmpDir, err := ioutil.TempDir("", "")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -65,10 +273,10 @@ func Test_executeKustomizeBuild_onQlikConfig_regenerateKeys(t *testing.T) {
|
|||||||
}
|
}
|
||||||
defer os.RemoveAll(tmpDir)
|
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 {
|
if repo, err := kapis_git.CloneRepository(configPath, defaultConfigRepoGitUrl, nil); err != nil {
|
||||||
t.Fatalf("unexpected error: %v\n", err)
|
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)
|
t.Fatalf("unexpected error: %v\n", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -86,7 +294,7 @@ func Test_executeKustomizeBuild_onQlikConfig_regenerateKeys(t *testing.T) {
|
|||||||
|
|
||||||
generateKeys(cr, "won't-use")
|
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 {
|
if err != nil {
|
||||||
t.Fatalf("unexpected kustomize error: %v\n", err)
|
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)
|
log.Printf("error generating application keys: %v\n", err)
|
||||||
} else if err := os.MkdirAll(keyDir, os.ModePerm); err != nil {
|
} 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)
|
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)
|
log.Printf("error storing ejson private key: %v\n", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -147,8 +355,8 @@ func Test_GetYamlDocKindFromMultiDoc(t *testing.T) {
|
|||||||
}
|
}
|
||||||
defer os.RemoveAll(tmpDir)
|
defer os.RemoveAll(tmpDir)
|
||||||
|
|
||||||
kustomizationYamlFilePath := path.Join(tmpDir, "kustomization.yaml")
|
kustomizationYamlFilePath := filepath.Join(tmpDir, "kustomization.yaml")
|
||||||
testResFileYamlFilePath := path.Join(tmpDir, "test-file.yaml")
|
testResFileYamlFilePath := filepath.Join(tmpDir, "test-file.yaml")
|
||||||
kustomizationYaml := `
|
kustomizationYaml := `
|
||||||
apiVersion: kustomize.config.k8s.io/v1beta1
|
apiVersion: kustomize.config.k8s.io/v1beta1
|
||||||
kind: Kustomization
|
kind: Kustomization
|
||||||
|
|||||||
@@ -51,7 +51,7 @@ func (q *Qliksense) loadCrStringIntoFileSystem(crstr string, overwriteExistingCo
|
|||||||
}
|
}
|
||||||
|
|
||||||
// encrypt the secrets and do base64 then update the CR
|
// encrypt the secrets and do base64 then update the CR
|
||||||
rsaPublicKey, _, err := qConfig.GetContextEncryptionKeyPair(cr.GetName())
|
encryptionKey, err := qConfig.GetEncryptionKeyFor(cr.GetName())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
@@ -63,13 +63,17 @@ func (q *Qliksense) loadCrStringIntoFileSystem(crstr string, overwriteExistingCo
|
|||||||
Value: nv.Value,
|
Value: nv.Value,
|
||||||
SvcName: svc,
|
SvcName: svc,
|
||||||
}
|
}
|
||||||
if err := q.processSecret(skv, rsaPublicKey, cr, false); err != nil {
|
if err := q.processSecret(skv, encryptionKey, cr, false); err != nil {
|
||||||
return cr.GetName(), err
|
return cr.GetName(), err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if cr.Spec.FetchSource != nil && cr.Spec.FetchSource.AccessToken != "" {
|
||||||
|
if err := cr.SetFetchAccessToken(cr.Spec.FetchSource.AccessToken, encryptionKey); err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
}
|
||||||
// update manifestsRoot in case already exist
|
// update manifestsRoot in case already exist
|
||||||
if existingCr, err := qConfig.GetCR(cr.GetName()); err == nil {
|
if existingCr, err := qConfig.GetCR(cr.GetName()); err == nil {
|
||||||
// cr exists, so update the manifestsRoot if version exist
|
// cr exists, so update the manifestsRoot if version exist
|
||||||
|
|||||||
@@ -6,7 +6,13 @@ import (
|
|||||||
qapi "github.com/qlik-oss/sense-installer/pkg/api"
|
qapi "github.com/qlik-oss/sense-installer/pkg/api"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (q *Qliksense) UninstallQK8s(contextName string) error {
|
func (q *Qliksense) UninstallQK8s(contextName string, skipConfirmation bool) error {
|
||||||
|
ans := skipConfirmation
|
||||||
|
|
||||||
|
if ans == false {
|
||||||
|
ans = AskForConfirmation("Are You Sure? ")
|
||||||
|
}
|
||||||
|
if ans == true {
|
||||||
qConfig := qapi.NewQConfig(q.QliksenseHome)
|
qConfig := qapi.NewQConfig(q.QliksenseHome)
|
||||||
if contextName == "" {
|
if contextName == "" {
|
||||||
contextName = qConfig.Spec.CurrentContext
|
contextName = qConfig.Spec.CurrentContext
|
||||||
@@ -18,4 +24,6 @@ func (q *Qliksense) UninstallQK8s(contextName string) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return qapi.KubectlDelete(str, "")
|
return qapi.KubectlDelete(str, "")
|
||||||
|
}
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user