Compare commits
8 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f1871279d0 | ||
|
|
775f438762 | ||
|
|
aa180b4af1 | ||
|
|
af679c89bf | ||
|
|
dcd3c0a99b | ||
|
|
2bc65f0bad | ||
|
|
b2a980de3a | ||
|
|
bfba8198cf |
4
.github/workflows/mkdocs.yml
vendored
4
.github/workflows/mkdocs.yml
vendored
@@ -4,8 +4,8 @@ on:
|
||||
branches:
|
||||
- master
|
||||
paths:
|
||||
- docs/
|
||||
- mkdocs.yml
|
||||
- 'docs/**'
|
||||
- 'mkdocs.yml'
|
||||
|
||||
jobs:
|
||||
build:
|
||||
|
||||
28
Makefile
28
Makefile
@@ -46,11 +46,11 @@ build: clean generate
|
||||
.PHONY: test
|
||||
test: clean generate
|
||||
ifeq ($(shell ${WHICH} docker-registry 2>${DEVNUL}),)
|
||||
$(eval TMP := $(shell mktemp -d))
|
||||
git clone https://github.com/docker/distribution.git $(TMP)/docker-distribution
|
||||
cd $(TMP)/docker-distribution; git checkout -b v2.7.1; make
|
||||
cp $(TMP)/docker-distribution/bin/registry pkg/qliksense/docker-registry
|
||||
-rm -rf $(TMP)/docker-distribution
|
||||
$(eval TMP-docker-distribution := $(shell mktemp -d))
|
||||
git clone https://github.com/docker/distribution.git $(TMP-docker-distribution)/docker-distribution
|
||||
cd $(TMP-docker-distribution)/docker-distribution; git checkout -b v2.7.1; make
|
||||
cp $(TMP-docker-distribution)/docker-distribution/bin/registry pkg/qliksense/docker-registry
|
||||
-rm -rf $(TMP-docker-distribution)
|
||||
endif
|
||||
go test -short -count=1 -tags "$(BUILDTAGS)" -v ./...
|
||||
$(MAKE) clean
|
||||
@@ -70,7 +70,7 @@ $(BINDIR)/$(VERSION)/$(MIXIN)-$(CLIENT_PLATFORM)-$(CLIENT_ARCH)$(FILE_EXT):
|
||||
GOOS=$(CLIENT_PLATFORM) GOARCH=$(CLIENT_ARCH) $(XBUILD) -o $@ ./cmd/$(MIXIN)
|
||||
|
||||
ifeq ($(CLIENT_PLATFORM),windows)
|
||||
zip $(BINDIR)/$(VERSION)/$(MIXIN)-$(CLIENT_PLATFORM)-$(CLIENT_ARCH).zip $(BINDIR)/$(VERSION)/ $(MIXIN)-$(CLIENT_PLATFORM)-$(CLIENT_ARCH)$(FILE_EXT)
|
||||
zip $(BINDIR)/$(VERSION)/$(MIXIN)-$(CLIENT_PLATFORM)-$(CLIENT_ARCH).zip $(BINDIR)/$(VERSION)/$(MIXIN)-$(CLIENT_PLATFORM)-$(CLIENT_ARCH)$(FILE_EXT)
|
||||
else
|
||||
tar -czvf $(BINDIR)/$(VERSION)/$(MIXIN)-$(CLIENT_PLATFORM)-$(CLIENT_ARCH).tar.gz -C $(BINDIR)/$(VERSION)/ $(MIXIN)-$(CLIENT_PLATFORM)-$(CLIENT_ARCH)$(FILE_EXT)
|
||||
endif
|
||||
@@ -91,12 +91,16 @@ clean-packr: packr2
|
||||
cd pkg/qliksense && packr2 clean
|
||||
|
||||
get-crds:
|
||||
$(eval TMP := $(shell mktemp -d))
|
||||
git clone https://github.com/qlik-oss/qliksense-operator.git -b master $(TMP)/operator
|
||||
ifeq ($(QLIKSENSE_OPERATOR_DIR),)
|
||||
$(eval TMP-operator := $(shell mktemp -d))
|
||||
git clone https://github.com/qlik-oss/qliksense-operator.git -b master $(TMP-operator)/operator
|
||||
$(MAKE) QLIKSENSE_OPERATOR_DIR=$(TMP-operator)/operator get-crds
|
||||
-rm -rf $(TMP-operator)
|
||||
else
|
||||
mkdir -p pkg/qliksense/crds/cr
|
||||
mkdir -p pkg/qliksense/crds/crd
|
||||
mkdir -p pkg/qliksense/crds/crd-deploy
|
||||
cp $(TMP)/operator/deploy/*.yaml pkg/qliksense/crds/crd-deploy
|
||||
cp $(TMP)/operator/deploy/crds/*_crd.yaml pkg/qliksense/crds/crd
|
||||
cp $(TMP)/operator/deploy/crds/*_cr.yaml pkg/qliksense/crds/cr
|
||||
-rm -rf $(TMP)/operator
|
||||
cp $(QLIKSENSE_OPERATOR_DIR)/deploy/*.yaml pkg/qliksense/crds/crd-deploy
|
||||
cp $(QLIKSENSE_OPERATOR_DIR)/deploy/crds/*_crd.yaml pkg/qliksense/crds/crd
|
||||
cp $(QLIKSENSE_OPERATOR_DIR)/deploy/crds/*_cr.yaml pkg/qliksense/crds/cr
|
||||
endif
|
||||
|
||||
39
cmd/qliksense/apply.go
Normal file
39
cmd/qliksense/apply.go
Normal file
@@ -0,0 +1,39 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"os"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/qlik-oss/sense-installer/pkg/qliksense"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
func applyCmd(q *qliksense.Qliksense) *cobra.Command {
|
||||
|
||||
filePath := ""
|
||||
c := &cobra.Command{
|
||||
Use: "apply",
|
||||
Short: "install qliksense based on provided cr file",
|
||||
Long: `install qliksense based on provided cr file`,
|
||||
Example: `qliksense apply -f file_name or cat cr_file | qliksense apply -f -`,
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
if filePath == "-" {
|
||||
if !isInputFromPipe() {
|
||||
return errors.New("No input pipe present")
|
||||
}
|
||||
return q.ApplyCRFromReader(os.Stdin)
|
||||
}
|
||||
file, e := os.Open(filePath)
|
||||
if e != nil {
|
||||
return errors.Wrapf(e,
|
||||
"unable to read the file %s", filePath)
|
||||
}
|
||||
return q.ApplyCRFromReader(file)
|
||||
},
|
||||
}
|
||||
|
||||
f := c.Flags()
|
||||
f.StringVarP(&filePath, "file", "f", "", "Install from a CR file")
|
||||
c.MarkFlagRequired("file")
|
||||
return c
|
||||
}
|
||||
47
cmd/qliksense/eula.go
Normal file
47
cmd/qliksense/eula.go
Normal file
@@ -0,0 +1,47 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
qapi "github.com/qlik-oss/sense-installer/pkg/api"
|
||||
"github.com/qlik-oss/sense-installer/pkg/qliksense"
|
||||
)
|
||||
|
||||
var eulaEnforced = false
|
||||
var eulaText = "EULA text goes here..."
|
||||
var eulaPrompt = "Do you accept our EULA? (y/n): "
|
||||
var eulaErrorInstruction = "You must enter y/yes to continue"
|
||||
|
||||
func isEulaEnforced() bool {
|
||||
return eulaEnforced
|
||||
}
|
||||
|
||||
func enforceEula(q *qliksense.Qliksense) {
|
||||
if isEulaEnforced() {
|
||||
if qConfig, err := qapi.NewQConfigE(q.QliksenseHome); err != nil {
|
||||
doEnforceEula()
|
||||
} else if qcr, err := qConfig.GetCurrentCR(); err != nil || !qcr.IsEULA() {
|
||||
doEnforceEula()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func doEnforceEula() {
|
||||
fmt.Println(eulaText)
|
||||
fmt.Print(eulaPrompt)
|
||||
scanner := bufio.NewScanner(os.Stdin)
|
||||
scanSuccess := scanner.Scan()
|
||||
if !scanSuccess {
|
||||
fmt.Println(eulaErrorInstruction)
|
||||
os.Exit(1)
|
||||
}
|
||||
line := scanner.Text()
|
||||
answer := strings.ToLower(strings.TrimSpace(line))
|
||||
if answer != "y" && answer != "yes" {
|
||||
fmt.Println(eulaErrorInstruction)
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
41
cmd/qliksense/load.go
Normal file
41
cmd/qliksense/load.go
Normal file
@@ -0,0 +1,41 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"os"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/qlik-oss/sense-installer/pkg/qliksense"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
func loadCrFile(q *qliksense.Qliksense) *cobra.Command {
|
||||
filePath := ""
|
||||
c := &cobra.Command{
|
||||
Use: "load",
|
||||
Short: "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`,
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
if filePath == "-" {
|
||||
if !isInputFromPipe() {
|
||||
return errors.New("No input pipe present")
|
||||
}
|
||||
return q.LoadCr(os.Stdin)
|
||||
}
|
||||
file, e := os.Open(filePath)
|
||||
if e != nil {
|
||||
return errors.Wrapf(e,
|
||||
"unable to read the file %s", filePath)
|
||||
}
|
||||
return q.LoadCr(file)
|
||||
},
|
||||
}
|
||||
f := c.Flags()
|
||||
f.StringVarP(&filePath, "file", "f", "", "File to laod CR from")
|
||||
c.MarkFlagRequired("file")
|
||||
return c
|
||||
}
|
||||
|
||||
func isInputFromPipe() bool {
|
||||
fileInfo, _ := os.Stdin.Stat()
|
||||
return fileInfo.Mode()&os.ModeCharDevice == 0
|
||||
}
|
||||
@@ -42,7 +42,6 @@ func initAndExecute() error {
|
||||
api.LogDebugMessage("QliksenseHomeDir: %s", qlikSenseHome)
|
||||
|
||||
qliksenseClient := qliksense.New(qlikSenseHome)
|
||||
qliksenseClient.SetUpQliksenseDefaultContext()
|
||||
cmd := rootCmd(qliksenseClient)
|
||||
if err := cmd.Execute(); err != nil {
|
||||
//levenstein checks (auto-suggestions)
|
||||
@@ -50,7 +49,7 @@ func initAndExecute() error {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
return nil
|
||||
}
|
||||
|
||||
func setUpPaths() (string, error) {
|
||||
@@ -85,16 +84,37 @@ var versionCmd = &cobra.Command{
|
||||
},
|
||||
}
|
||||
|
||||
func rootCmd(p *qliksense.Qliksense) *cobra.Command {
|
||||
var (
|
||||
cmd *cobra.Command
|
||||
)
|
||||
func commandUsesContext(command string) bool {
|
||||
return command != "" && command != "help" && command != "version"
|
||||
}
|
||||
|
||||
cmd = &cobra.Command{
|
||||
func globalPreRun(cmd *cobra.Command, p *qliksense.Qliksense) {
|
||||
if command := cmd.CalledAs(); commandUsesContext(command) {
|
||||
if isEulaEnforced() {
|
||||
enforceEula(p)
|
||||
}
|
||||
|
||||
if err := p.SetUpQliksenseDefaultContext(); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
if isEulaEnforced() {
|
||||
if err := p.SetEulaAccepted(); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func rootCmd(p *qliksense.Qliksense) *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "qliksense",
|
||||
Short: "Qliksense cli tool",
|
||||
Long: `qliksense cli tool provides functionality to perform operations on qliksense-k8s, qliksense operator, and kubernetes cluster`,
|
||||
Args: cobra.ArbitraryArgs,
|
||||
PersistentPreRun: func(cmd *cobra.Command, args []string) {
|
||||
globalPreRun(cmd, p)
|
||||
},
|
||||
}
|
||||
|
||||
cmd.Flags().SetInterspersed(false)
|
||||
@@ -172,7 +192,8 @@ func rootCmd(p *qliksense.Qliksense) *cobra.Command {
|
||||
//preflightCmd.AddCommand(preflightCheckAllCmd(p))
|
||||
|
||||
cmd.AddCommand(preflightCmd)
|
||||
|
||||
cmd.AddCommand(loadCrFile(p))
|
||||
cmd.AddCommand((applyCmd(p)))
|
||||
return cmd
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
qapi "github.com/qlik-oss/sense-installer/pkg/api"
|
||||
"github.com/qlik-oss/sense-installer/pkg/qliksense"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
@@ -9,7 +8,7 @@ import (
|
||||
func uninstallCmd(q *qliksense.Qliksense) *cobra.Command {
|
||||
c := &cobra.Command{
|
||||
Use: "uninstall",
|
||||
Short: "Uninstall the deployed qliksense with release name [ " + qapi.NewQConfig(q.QliksenseHome).Spec.CurrentContext + " ]",
|
||||
Short: "Uninstall the deployed qliksense.",
|
||||
Long: `Uninstall the deployed qliksense. By default uninstall the current context`,
|
||||
Example: `qliksense uninstall <context-name>`,
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
|
||||
41
docs/command_reference.md
Normal file
41
docs/command_reference.md
Normal file
@@ -0,0 +1,41 @@
|
||||
# qliksense command reference
|
||||
|
||||
## qliksense apply
|
||||
|
||||
`qliksense apply` command takes input a cr file or input from pipe
|
||||
|
||||
- `qliksense apply -f cr-file.yaml`
|
||||
- `cat cr-file.yaml | qliksense apply -f -`
|
||||
|
||||
the content of `cr-file.yaml` should be something similar
|
||||
|
||||
```yaml
|
||||
apiVersion: qlik.com/v1
|
||||
kind: Qliksense
|
||||
metadata:
|
||||
name: qlik-test
|
||||
labels:
|
||||
version: v0.0.2
|
||||
spec:
|
||||
configs:
|
||||
qliksense:
|
||||
- name: acceptEULA
|
||||
value: "yes"
|
||||
secrets:
|
||||
qliksense:
|
||||
- name: mongoDbUri
|
||||
value: mongodb://qlik-test-mongodb:27017/qliksense?ssl=false
|
||||
profile: docker-desktop
|
||||
rotateKeys: "yes"
|
||||
```
|
||||
|
||||
after doing one of the above commands, cli will set the current context to the cr name and install the qliksense into the cluster. so make sure you dont have a context (cr name = context name) with the same name already. It will though error if it same context name already exist. It will encrypt the secrets from CR while writing CR into the disk.
|
||||
|
||||
## qliksense load
|
||||
|
||||
`qliksense load` command takes input a cr file or input from pipe.
|
||||
|
||||
- `qliksense load -f cr-file.yaml`
|
||||
- `cat cr-file.yaml | qliksense load -f -`
|
||||
|
||||
It will load the cr into `~/.qliksense` folder and create context strcture with for the CR and set the current context with the cr name. In case of multiple documents in a single stream/file it will set the current context to the last one. It will encrypt the secrets from CR while writing the CR into the disk.
|
||||
@@ -76,21 +76,55 @@ When you perform `qliksense install` or `qliksene config apply`, qliksense opera
|
||||
- Push generated patches into a new branch in the provided git repo. _Gives you ability to merge patches into your master branch_
|
||||
- Create a CronJob to monitor master branch. Any changes pushed to master branch will be applied into the cluster. _This is a light weight `git-ops` model_
|
||||
|
||||
## Enable GitOps
|
||||
## GitOps
|
||||
|
||||
to enable gitops the following section should be in the CR
|
||||
To enable gitops, the following section should be in the CR
|
||||
|
||||
```yaml
|
||||
....
|
||||
spec:
|
||||
git:
|
||||
repository: https://github.com/ffoysal/qliksense-k8s
|
||||
accessToken: git-token
|
||||
userName: git-username
|
||||
repository: https://github.com/<OWNER>/<REPO>
|
||||
accessToken: "<git-token>"
|
||||
userName: "<git-username>"
|
||||
gitOps:
|
||||
enabled: "yes"
|
||||
schedule: "*/5 * * * *"
|
||||
watchBranch: pr-branch-24868a33
|
||||
watchBranch: <myBranch>
|
||||
image: qlik-docker-oss.bintray.io/qliksense-repo-watcher
|
||||
....
|
||||
```
|
||||
|
||||
##Preflight checks
|
||||
Preflight checks provide pre-installation cluster conformance testing and validation before we install qliksense on the cluster. We gather a suite of conformance tests that can be easily written and run on the target cluster to verify that cluster-specific requirements are met.
|
||||
The suite consists of a set of `collectors` which run the specifications of every test and `analyzers` which analyze the results of every test run by the collector.
|
||||
We support the following tests at the moment as part of preflight checks, and the range of the suite will be expanded in future.
|
||||
|
||||
### DNS check
|
||||
Run the following command to view help about the commands supported by preflight at any moment:
|
||||
```console
|
||||
qliksense preflight
|
||||
perform preflight checks on the cluster
|
||||
|
||||
Usage:
|
||||
qliksense preflight [command]
|
||||
|
||||
Examples:
|
||||
qliksense preflight <preflight_check_to_run>
|
||||
|
||||
Usage:
|
||||
qliksense preflight dns
|
||||
|
||||
Available Commands:
|
||||
dns perform preflight dns check
|
||||
```
|
||||
|
||||
Run the following command to perform preflight DNS check. The expected output is also shown below.
|
||||
```console
|
||||
qliksense preflight dns
|
||||
Running Preflight checks ⠧
|
||||
--- PASS DNS check
|
||||
--- DNS check passed
|
||||
--- PASS cluster-preflight-checks
|
||||
PASS
|
||||
```
|
||||
|
||||
@@ -17,6 +17,7 @@ markdown_extensions:
|
||||
nav:
|
||||
- Overview: index.md
|
||||
- getting_started.md
|
||||
- command_reference.md
|
||||
- concepts.md
|
||||
- air_gap.md
|
||||
- Releases ⧉: https://github.com/qlik-oss/sense-installer/releases
|
||||
|
||||
101
pkg/api/apis.go
101
pkg/api/apis.go
@@ -27,16 +27,24 @@ const (
|
||||
|
||||
// NewQConfig create QliksenseConfig object from file ~/.qliksense/config.yaml
|
||||
func NewQConfig(qsHome string) *QliksenseConfig {
|
||||
qc, err := NewQConfigE(qsHome)
|
||||
if err != nil {
|
||||
fmt.Println("yaml unmarshalling error ", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
return qc
|
||||
}
|
||||
|
||||
func NewQConfigE(qsHome string) (*QliksenseConfig, error) {
|
||||
configFile := filepath.Join(qsHome, "config.yaml")
|
||||
qc := &QliksenseConfig{}
|
||||
|
||||
err := ReadFromFile(qc, configFile)
|
||||
if err != nil {
|
||||
fmt.Println("yaml unmarshalling error ", err)
|
||||
os.Exit(1)
|
||||
return nil, err
|
||||
}
|
||||
qc.QliksenseHomePath = qsHome
|
||||
return qc
|
||||
return qc, nil
|
||||
}
|
||||
|
||||
// GetCR create a QliksenseCR object for a particular context
|
||||
@@ -46,11 +54,7 @@ func (qc *QliksenseConfig) GetCR(contextName string) (*QliksenseCR, error) {
|
||||
if crFilePath == "" {
|
||||
return nil, errors.New("context name " + contextName + " not found")
|
||||
}
|
||||
return getCRObject(crFilePath)
|
||||
}
|
||||
|
||||
func getUnencryptedCR() {
|
||||
|
||||
return GetCRObject(crFilePath)
|
||||
}
|
||||
|
||||
// GetCurrentCR create a QliksenseCR object for current context
|
||||
@@ -77,7 +81,8 @@ func (qc *QliksenseConfig) SetCrLocation(contextName, filepath string) (*Qliksen
|
||||
return nil, errors.New("cannot find the context")
|
||||
}
|
||||
|
||||
func getCRObject(crfile string) (*QliksenseCR, error) {
|
||||
// GetCRObject create a qliksense CR object from file
|
||||
func GetCRObject(crfile string) (*QliksenseCR, error) {
|
||||
cr := &QliksenseCR{}
|
||||
err := ReadFromFile(cr, crfile)
|
||||
if err != nil {
|
||||
@@ -88,6 +93,20 @@ func getCRObject(crfile string) (*QliksenseCR, error) {
|
||||
return cr, nil
|
||||
}
|
||||
|
||||
//CreateCRObjectFromString create a QliksenseCR from string content
|
||||
func CreateCRObjectFromString(crContent string) (*QliksenseCR, error) {
|
||||
if crContent == "" {
|
||||
return nil, errors.New("empty string cannot qliksensecr")
|
||||
}
|
||||
cr := &QliksenseCR{}
|
||||
err := ReadFromStream(cr, strings.NewReader(crContent))
|
||||
if err != nil {
|
||||
fmt.Println("cannot unmarshal cr ", err)
|
||||
return nil, err
|
||||
}
|
||||
return cr, nil
|
||||
}
|
||||
|
||||
func (qc *QliksenseConfig) getCRFilePath(contextName string) string {
|
||||
crFilePath := ""
|
||||
for _, ctx := range qc.Spec.Contexts {
|
||||
@@ -222,6 +241,15 @@ func (qc *QliksenseConfig) getDockerConfigJsonSecret(name string) (*DockerConfig
|
||||
}
|
||||
|
||||
func (qc *QliksenseConfig) getCurrentContextEncryptionKeyPairLocation() (string, error) {
|
||||
|
||||
if qcr, err := qc.GetCurrentCR(); err != nil {
|
||||
return "", err
|
||||
} else {
|
||||
return qc.getContextEncryptionKeyPairLocation(qcr.GetName())
|
||||
}
|
||||
}
|
||||
|
||||
func (qc *QliksenseConfig) getContextEncryptionKeyPairLocation(contextName string) (string, error) {
|
||||
// Check env var: QLIKSENSE_KEY_LOCATION to determine location to store keypair
|
||||
var secretKeyPairLocation string
|
||||
if os.Getenv("QLIKSENSE_KEY_LOCATION") != "" {
|
||||
@@ -230,13 +258,9 @@ func (qc *QliksenseConfig) getCurrentContextEncryptionKeyPairLocation() (string,
|
||||
} else {
|
||||
// QLIKSENSE_KEY_LOCATION has not been set, hence storing key pair in default location:
|
||||
// /.qliksense/secrets/contexts/<current-context>/secrets/
|
||||
if qcr, err := qc.GetCurrentCR(); err != nil {
|
||||
return "", err
|
||||
} else {
|
||||
secretKeyPairLocation = filepath.Join(qc.QliksenseHomePath, qliksenseSecretsDirName, qliksenseContextsDirName, qcr.GetObjectMeta().GetName(), qliksenseSecretsDirName)
|
||||
}
|
||||
secretKeyPairLocation = filepath.Join(qc.QliksenseHomePath, qliksenseSecretsDirName, qliksenseContextsDirName, contextName, qliksenseSecretsDirName)
|
||||
|
||||
}
|
||||
LogDebugMessage("SecretKeyLocation to store key pair: %s", secretKeyPairLocation)
|
||||
return secretKeyPairLocation, nil
|
||||
}
|
||||
|
||||
@@ -253,7 +277,15 @@ func (qc *QliksenseConfig) GetCurrentContextEjsonKeyDir() (string, error) {
|
||||
}
|
||||
|
||||
func (qc *QliksenseConfig) GetCurrentContextEncryptionKeyPair() (*rsa.PublicKey, *rsa.PrivateKey, error) {
|
||||
secretKeyPairLocation, err := qc.getCurrentContextEncryptionKeyPairLocation()
|
||||
if qcr, err := qc.GetCurrentCR(); err != nil {
|
||||
return nil, nil, err
|
||||
} else {
|
||||
return qc.GetContextEncryptionKeyPair(qcr.GetName())
|
||||
}
|
||||
}
|
||||
|
||||
func (qc *QliksenseConfig) GetContextEncryptionKeyPair(contextName string) (*rsa.PublicKey, *rsa.PrivateKey, error) {
|
||||
secretKeyPairLocation, err := qc.getContextEncryptionKeyPairLocation(contextName)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
@@ -342,6 +374,10 @@ func (cr *QliksenseCR) IsEULA() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (cr *QliksenseCR) SetEULA(value string) {
|
||||
cr.Spec.AddToConfigs("qliksense", "acceptEULA", value)
|
||||
}
|
||||
|
||||
// GetDecryptedCr it decrypts all the encrypted value and return a new CR
|
||||
func (qc *QliksenseConfig) GetDecryptedCr(cr *QliksenseCR) (*QliksenseCR, error) {
|
||||
newCr := &QliksenseCR{}
|
||||
@@ -374,3 +410,36 @@ func (qc *QliksenseConfig) GetDecryptedCr(cr *QliksenseCR) (*QliksenseCR, error)
|
||||
newCr.Spec.Secrets = finalSecrets
|
||||
return newCr, nil
|
||||
}
|
||||
|
||||
//Validate validate CR
|
||||
func (cr *QliksenseCR) Validate() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
//CreateContextDirs create context dir structure ~/.qliksense/contexts/contextName
|
||||
func (qc *QliksenseConfig) CreateContextDirs(contextName string) {
|
||||
contexPath := filepath.Join(qc.QliksenseHomePath, qliksenseContextsDirName, contextName)
|
||||
os.MkdirAll(contexPath, os.ModePerm)
|
||||
}
|
||||
|
||||
func (qc *QliksenseConfig) BuildCrFilePath(contextName string) string {
|
||||
return filepath.Join(qc.QliksenseHomePath, qliksenseContextsDirName, contextName, contextName+".yaml")
|
||||
}
|
||||
|
||||
//AddToContexts add the context into qc.Spec.Contexts
|
||||
func (qc *QliksenseConfig) AddToContexts(crName, crFile string) {
|
||||
qc.Spec.Contexts = append(qc.Spec.Contexts, []Context{
|
||||
{CrFile: crFile,
|
||||
Name: crName},
|
||||
}...)
|
||||
}
|
||||
|
||||
//SetCurrentContextName set the qc.Spec.CurrentContext
|
||||
func (qc *QliksenseConfig) SetCurrentContextName(name string) {
|
||||
qc.Spec.CurrentContext = name
|
||||
}
|
||||
|
||||
//Write write QliksenseConfig into config.yaml
|
||||
func (qc *QliksenseConfig) Write() error {
|
||||
return WriteToFile(qc, filepath.Join(qc.QliksenseHomePath, "config.yaml"))
|
||||
}
|
||||
|
||||
@@ -3,8 +3,10 @@ package api
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"os"
|
||||
|
||||
"github.com/qlik-oss/k-apis/pkg/config"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
@@ -103,14 +105,22 @@ func ReadFromFile(content interface{}, sourceFile string) error {
|
||||
if content == nil || sourceFile == "" {
|
||||
return nil
|
||||
}
|
||||
contents, err := ioutil.ReadFile(sourceFile)
|
||||
file, e := os.Open(sourceFile)
|
||||
if e != nil {
|
||||
return e
|
||||
}
|
||||
return ReadFromStream(content, file)
|
||||
}
|
||||
|
||||
// ReadFromStream reads from input stream and creat yaml struct of type content
|
||||
func ReadFromStream(content interface{}, reader io.Reader) error {
|
||||
contents, err := ioutil.ReadAll(reader)
|
||||
if err != nil {
|
||||
err = fmt.Errorf("There was an error reading from file: %s, %v", sourceFile, err)
|
||||
err = fmt.Errorf("There was an error reading from reader: %v", err)
|
||||
return err
|
||||
}
|
||||
// reading k8s style object
|
||||
// https://stackoverflow.com/questions/44306554/how-to-deserialize-kubernetes-yaml-file
|
||||
dec := machine_yaml.NewYAMLOrJSONDecoder(bytes.NewReader(contents), 10000)
|
||||
dec.Decode(content)
|
||||
return nil
|
||||
return dec.Decode(content)
|
||||
}
|
||||
|
||||
@@ -109,6 +109,7 @@ func KubectlDirectOps(opr []string, namespace string) error {
|
||||
LogDebugMessage("Kubectl command: %s %v\n", "kubectl", arguments)
|
||||
sterrBuffer := &bytes.Buffer{}
|
||||
cmd.Stderr = sterrBuffer
|
||||
cmd.Stdout = os.Stdout
|
||||
if err := cmd.Run(); err != nil {
|
||||
return fmt.Errorf("kubectl %v failed with: %v, %v\n", opr, err, sterrBuffer.String())
|
||||
}
|
||||
|
||||
23
pkg/qliksense/apply.go
Normal file
23
pkg/qliksense/apply.go
Normal file
@@ -0,0 +1,23 @@
|
||||
package qliksense
|
||||
|
||||
import (
|
||||
"io"
|
||||
|
||||
qapi "github.com/qlik-oss/sense-installer/pkg/api"
|
||||
)
|
||||
|
||||
func (q *Qliksense) ApplyCRFromReader(r io.Reader) error {
|
||||
if err := q.LoadCr(r); err != nil {
|
||||
return err
|
||||
}
|
||||
qConfig := qapi.NewQConfig(q.QliksenseHome)
|
||||
cr, err := qConfig.GetCurrentCR()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
opts := &InstallCommandOptions{}
|
||||
if err := q.InstallQK8s(cr.GetLabelFromCr("version"), opts, true); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -3,7 +3,6 @@ package qliksense
|
||||
import (
|
||||
"crypto/rsa"
|
||||
"fmt"
|
||||
"github.com/robfig/cron/v3"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"os"
|
||||
@@ -11,6 +10,8 @@ import (
|
||||
"strings"
|
||||
"text/tabwriter"
|
||||
|
||||
"github.com/robfig/cron/v3"
|
||||
|
||||
"github.com/qlik-oss/k-apis/pkg/config"
|
||||
|
||||
b64 "encoding/base64"
|
||||
@@ -578,3 +579,13 @@ func (q *Qliksense) SetImageRegistry(registry, pushUsername, pushPassword, pullU
|
||||
qliksenseCR.Spec.AddToConfigs("qliksense", imageRegistryConfigKey, registry)
|
||||
return api.WriteToFile(&qliksenseCR, qliksenseContextsFile)
|
||||
}
|
||||
|
||||
func (q *Qliksense) SetEulaAccepted() error {
|
||||
qConfig := api.NewQConfig(q.QliksenseHome)
|
||||
qcr, err := qConfig.GetCurrentCR()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
qcr.SetEULA("yes")
|
||||
return qConfig.WriteCurrentContextCR(qcr)
|
||||
}
|
||||
|
||||
@@ -152,6 +152,7 @@ func removePrivateKey() {
|
||||
|
||||
func setup() func() {
|
||||
// create tests dir
|
||||
os.RemoveAll(testDir)
|
||||
if err := os.Mkdir(testDir, 0777); err != nil {
|
||||
log.Printf("\nError occurred: %v", err)
|
||||
}
|
||||
@@ -164,7 +165,7 @@ metadata:
|
||||
spec:
|
||||
contexts:
|
||||
- name: qlik-default
|
||||
crFile: /root/.qliksense/contexts/qlik-default.yaml
|
||||
crFile: ./tests/contexts/qlik-default/qlik-default.yaml
|
||||
currentContext: qlik-default
|
||||
`
|
||||
configFile := filepath.Join(testDir, "config.yaml")
|
||||
|
||||
@@ -42,7 +42,7 @@ func (q *Qliksense) InstallQK8s(version string, opts *InstallCommandOptions, kee
|
||||
}
|
||||
|
||||
if opts.AcceptEULA != "" {
|
||||
qcr.Spec.AddToConfigs("qliksense", "acceptEULA", opts.AcceptEULA)
|
||||
qcr.SetEULA(opts.AcceptEULA)
|
||||
}
|
||||
if opts.MongoDbUri != "" {
|
||||
qcr.Spec.AddToSecrets("qliksense", "mongoDbUri", opts.MongoDbUri, "")
|
||||
|
||||
65
pkg/qliksense/install_test.go
Normal file
65
pkg/qliksense/install_test.go
Normal file
@@ -0,0 +1,65 @@
|
||||
package qliksense
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
qapi "github.com/qlik-oss/sense-installer/pkg/api"
|
||||
)
|
||||
|
||||
func TestCreateK8sResoruceBeforePatch(t *testing.T) {
|
||||
td := setup()
|
||||
sampleCr := `
|
||||
apiVersion: qlik.com/v1
|
||||
kind: Qliksense
|
||||
metadata:
|
||||
name: qlik-test3
|
||||
labels:
|
||||
version: v0.0.2
|
||||
spec:
|
||||
git:
|
||||
repository: https://github.com/ffoysal/qliksense-k8s
|
||||
accessToken: abababababababaab
|
||||
userName: "blblbl"
|
||||
gitOps:
|
||||
enabled: "no"
|
||||
schedule: "*/1 * * * *"
|
||||
watchBranch: pr-branch-db1d26d6
|
||||
image: qlik-docker-oss.bintray.io/qliksense-repo-watcher
|
||||
configs:
|
||||
qliksense:
|
||||
- name: acceptEULA
|
||||
value: "yes"
|
||||
secrets:
|
||||
qliksense:
|
||||
- name: mongoDbUri
|
||||
value: mongodb://qlik-default-mongodb:27017/qliksense?ssl=false
|
||||
profile: docker-desktop
|
||||
rotateKeys: "yes"`
|
||||
|
||||
crFile := filepath.Join(testDir, "install_test.yaml")
|
||||
ioutil.WriteFile(crFile, []byte(sampleCr), 0644)
|
||||
q := New(testDir)
|
||||
file, e := os.Open(crFile)
|
||||
if e != nil {
|
||||
t.Log(e)
|
||||
t.FailNow()
|
||||
}
|
||||
if err := q.LoadCr(file); err != nil {
|
||||
t.Log(err)
|
||||
t.FailNow()
|
||||
}
|
||||
qConfig := qapi.NewQConfig(testDir)
|
||||
cr, err := qConfig.GetCR("qlik-test3")
|
||||
if err != nil {
|
||||
t.Log(err)
|
||||
t.FailNow()
|
||||
}
|
||||
if err = q.createK8sResoruceBeforePatch(cr); err != nil {
|
||||
t.Log(err)
|
||||
t.FailNow()
|
||||
}
|
||||
td()
|
||||
}
|
||||
83
pkg/qliksense/load_cr.go
Normal file
83
pkg/qliksense/load_cr.go
Normal file
@@ -0,0 +1,83 @@
|
||||
package qliksense
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
|
||||
qapi "github.com/qlik-oss/sense-installer/pkg/api"
|
||||
)
|
||||
|
||||
//
|
||||
func (q *Qliksense) LoadCr(reader io.Reader) error {
|
||||
for _, doc := range readMultipleYamlFromReader(reader) {
|
||||
if crName, err := q.loadCrStringIntoFileSystem(doc); err != nil {
|
||||
return err
|
||||
} else {
|
||||
fmt.Println("cr name: [ " + crName + " ] has been loaded")
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (q *Qliksense) loadCrStringIntoFileSystem(crstr string) (string, error) {
|
||||
cr, err := qapi.CreateCRObjectFromString(crstr)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
qConfig := qapi.NewQConfig(q.QliksenseHome)
|
||||
if qConfig.IsContextExist(cr.GetName()) {
|
||||
return "", errors.New("Context Name: " + cr.GetName() + " already exist. please delete the existing context first using delete-context command")
|
||||
}
|
||||
qConfig.CreateContextDirs(cr.GetName())
|
||||
|
||||
// encrypt the secrets and do base64 then update the CR
|
||||
rsaPublicKey, _, err := qConfig.GetContextEncryptionKeyPair(cr.GetName())
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
for svc, nvs := range cr.Spec.Secrets {
|
||||
for _, nv := range nvs {
|
||||
if nv.ValueFrom == nil {
|
||||
skv := &qapi.ServiceKeyValue{
|
||||
Key: nv.Name,
|
||||
Value: nv.Value,
|
||||
SvcName: svc,
|
||||
}
|
||||
if err := q.processSecret(skv, rsaPublicKey, cr, false); err != nil {
|
||||
return cr.GetName(), err
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// write to disk
|
||||
if err = qapi.WriteToFile(cr, qConfig.BuildCrFilePath(cr.GetName())); err != nil {
|
||||
return "", err
|
||||
}
|
||||
qConfig.AddToContexts(cr.GetName(), qConfig.BuildCrFilePath(cr.GetName()))
|
||||
qConfig.SetCurrentContextName(cr.GetName())
|
||||
qConfig.Write()
|
||||
|
||||
return cr.GetName(), nil
|
||||
}
|
||||
|
||||
func readMultipleYamlFromReader(reader io.Reader) []string {
|
||||
docs := make([]string, 0)
|
||||
scanner := bufio.NewScanner(bufio.NewReader(reader))
|
||||
adoc := ""
|
||||
for scanner.Scan() {
|
||||
s := scanner.Text()
|
||||
if s == "---" {
|
||||
docs = append(docs, adoc)
|
||||
adoc = ""
|
||||
s = ""
|
||||
}
|
||||
adoc = adoc + "\n" + s
|
||||
}
|
||||
if adoc != "" {
|
||||
docs = append(docs, adoc)
|
||||
}
|
||||
return docs
|
||||
}
|
||||
129
pkg/qliksense/load_cr_test.go
Normal file
129
pkg/qliksense/load_cr_test.go
Normal file
@@ -0,0 +1,129 @@
|
||||
package qliksense
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
qapi "github.com/qlik-oss/sense-installer/pkg/api"
|
||||
)
|
||||
|
||||
func TestLoadCrFile(t *testing.T) {
|
||||
td := setup()
|
||||
setup()
|
||||
sampleCr := `
|
||||
apiVersion: qlik.com/v1
|
||||
kind: Qliksense
|
||||
metadata:
|
||||
name: qlik-test
|
||||
labels:
|
||||
version: v0.0.2
|
||||
spec:
|
||||
git:
|
||||
repository: https://github.com/ffoysal/qliksense-k8s
|
||||
accessToken: abababababababaab
|
||||
userName: "blblbl"
|
||||
gitOps:
|
||||
enabled: "no"
|
||||
schedule: "*/1 * * * *"
|
||||
watchBranch: pr-branch-db1d26d6
|
||||
image: qlik-docker-oss.bintray.io/qliksense-repo-watcher
|
||||
configs:
|
||||
qliksense:
|
||||
- name: acceptEULA
|
||||
value: "yes"
|
||||
secrets:
|
||||
qliksense:
|
||||
- name: mongoDbUri
|
||||
value: mongodb://qlik-default-mongodb:27017/qliksense?ssl=false
|
||||
profile: docker-desktop
|
||||
rotateKeys: "yes"
|
||||
---
|
||||
apiVersion: qlik.com/v1
|
||||
kind: Qliksense
|
||||
metadata:
|
||||
name: qlik-test3
|
||||
labels:
|
||||
version: v0.0.2
|
||||
spec:
|
||||
git:
|
||||
repository: https://github.com/ffoysal/qliksense-k8s
|
||||
accessToken: abababababababaab
|
||||
userName: "blblbl"
|
||||
gitOps:
|
||||
enabled: "no"
|
||||
schedule: "*/1 * * * *"
|
||||
watchBranch: pr-branch-db1d26d6
|
||||
image: qlik-docker-oss.bintray.io/qliksense-repo-watcher
|
||||
configs:
|
||||
qliksense:
|
||||
- name: acceptEULA
|
||||
value: "yes"
|
||||
secrets:
|
||||
qliksense:
|
||||
- name: mongoDbUri
|
||||
value: mongodb://qlik-default-mongodb:27017/qliksense?ssl=false
|
||||
profile: docker-desktop
|
||||
rotateKeys: "yes"`
|
||||
|
||||
duplicateCr := `
|
||||
apiVersion: qlik.com/v1
|
||||
kind: Qliksense
|
||||
metadata:
|
||||
name: qlik-default
|
||||
labels:
|
||||
version: v0.0.2
|
||||
spec:
|
||||
git:
|
||||
repository: https://github.com/ffoysal/qliksense-k8s
|
||||
accessToken: abababababababaab
|
||||
userName: "blblbl"`
|
||||
crFile := filepath.Join(testDir, "testcr.yaml")
|
||||
ioutil.WriteFile(crFile, []byte(sampleCr), 0644)
|
||||
|
||||
dupCrFile := filepath.Join(testDir, "dupcr.yaml")
|
||||
ioutil.WriteFile(dupCrFile, []byte(duplicateCr), 0644)
|
||||
|
||||
q := New(testDir)
|
||||
file, e := os.Open(crFile)
|
||||
if e != nil {
|
||||
t.Log(e)
|
||||
t.FailNow()
|
||||
}
|
||||
if err := q.LoadCr(file); err != nil {
|
||||
t.Log(err)
|
||||
t.FailNow()
|
||||
}
|
||||
qConfig := qapi.NewQConfig(testDir)
|
||||
cr, err := qConfig.GetCR("qlik-test")
|
||||
if err != nil {
|
||||
t.Log(err)
|
||||
t.FailNow()
|
||||
}
|
||||
if cr.GetName() != "qlik-test" {
|
||||
t.FailNow()
|
||||
}
|
||||
|
||||
cr, err = qConfig.GetCR("qlik-test3")
|
||||
if err != nil {
|
||||
t.Log(err)
|
||||
t.FailNow()
|
||||
}
|
||||
if cr.GetName() != "qlik-test3" {
|
||||
t.FailNow()
|
||||
}
|
||||
|
||||
if qConfig.Spec.CurrentContext != "qlik-test3" {
|
||||
t.FailNow()
|
||||
}
|
||||
file, e = os.Open(dupCrFile)
|
||||
if e != nil {
|
||||
t.Log(e)
|
||||
t.FailNow()
|
||||
}
|
||||
if err := q.LoadCr(file); err == nil {
|
||||
t.FailNow()
|
||||
}
|
||||
td()
|
||||
}
|
||||
@@ -163,7 +163,8 @@ func determinePlatformSpecificUrls(platform string) (string, string, error) {
|
||||
func (q *Qliksense) CheckDns() error {
|
||||
// retrieve namespace
|
||||
namespace := api.GetKubectlNamespace()
|
||||
api.LogDebugMessage("Namespace here: %s", namespace)
|
||||
|
||||
api.LogDebugMessage("Namespace: %s\n", namespace)
|
||||
|
||||
tmpl, err := template.New("test").Parse(dnsCheckYAML)
|
||||
if err != nil {
|
||||
@@ -191,6 +192,8 @@ func (q *Qliksense) CheckDns() error {
|
||||
const PreflightChecksDirName = "preflight_checks"
|
||||
const preflightFileName = "preflight"
|
||||
|
||||
fmt.Println("Creating resources to run preflight checks")
|
||||
|
||||
// kubectl create deployment
|
||||
opr := fmt.Sprintf("create deployment %s --image=nginx", appName)
|
||||
err = initiateK8sOps(opr, namespace)
|
||||
@@ -198,7 +201,6 @@ func (q *Qliksense) CheckDns() error {
|
||||
fmt.Println(err)
|
||||
return err
|
||||
}
|
||||
api.LogDebugMessage("create deployment executed")
|
||||
|
||||
defer func() {
|
||||
// Deleting deployment..
|
||||
@@ -215,7 +217,6 @@ func (q *Qliksense) CheckDns() error {
|
||||
fmt.Println(err)
|
||||
return err
|
||||
}
|
||||
api.LogDebugMessage("create service executed")
|
||||
|
||||
defer func() {
|
||||
// delete service
|
||||
@@ -236,18 +237,13 @@ func (q *Qliksense) CheckDns() error {
|
||||
|
||||
// call preflight
|
||||
preflightCommand := filepath.Join(q.QliksenseHome, PreflightChecksDirName, preflightFileName)
|
||||
trackSuccess, err := invokePreflight(preflightCommand, tempYaml)
|
||||
|
||||
err = invokePreflight(preflightCommand, tempYaml)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return err
|
||||
}
|
||||
|
||||
if trackSuccess {
|
||||
fmt.Println("PREFLIGHT DNS CHECK PASSED")
|
||||
} else {
|
||||
fmt.Println("PREFLIGHT DNS CHECK FAILED")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -261,7 +257,7 @@ func initiateK8sOps(opr, namespace string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func invokePreflight(preflightCommand string, yamlFile *os.File) (bool, error) {
|
||||
func invokePreflight(preflightCommand string, yamlFile *os.File) error {
|
||||
arguments := []string{}
|
||||
arguments = append(arguments, yamlFile.Name(), "--interactive=false")
|
||||
cmd := exec.Command(preflightCommand, arguments...)
|
||||
@@ -270,7 +266,7 @@ func invokePreflight(preflightCommand string, yamlFile *os.File) (bool, error) {
|
||||
cmd.Stdout = sterrBuffer
|
||||
cmd.Stderr = sterrBuffer
|
||||
if err := cmd.Run(); err != nil {
|
||||
return false, fmt.Errorf("Error when running preflight command: %v\n", err)
|
||||
return fmt.Errorf("Error when running preflight command: %v\n", err)
|
||||
}
|
||||
ind := strings.Index(sterrBuffer.String(), "---")
|
||||
output := sterrBuffer.String()
|
||||
@@ -278,25 +274,28 @@ func invokePreflight(preflightCommand string, yamlFile *os.File) (bool, error) {
|
||||
output = fmt.Sprintf("%s\n%s", output[:ind], output[ind:])
|
||||
}
|
||||
fmt.Printf("%v\n", output)
|
||||
outputArr := strings.Fields(strings.TrimSpace(output))
|
||||
trackSuccess := false
|
||||
trackPrg := false
|
||||
|
||||
// We are only checking the overall "PASS" or "FAIL"
|
||||
// Maybe good to retain this part in case we need to process the output in future.
|
||||
// We are going to look for the first occurance of PASS or FAIL from the end
|
||||
// there are also some space-like deceiving characters
|
||||
for i := len(outputArr) - 1; i >= 0; i-- {
|
||||
if strings.TrimSpace(outputArr[i]) != "" {
|
||||
if outputArr[i] == "PASS" {
|
||||
trackSuccess = true
|
||||
trackPrg = true
|
||||
} else if outputArr[i] == "FAIL" {
|
||||
trackPrg = true
|
||||
}
|
||||
}
|
||||
if trackPrg {
|
||||
break
|
||||
}
|
||||
}
|
||||
return trackSuccess, nil
|
||||
// there are also some space-like deceiving characters which are being hard to get by
|
||||
|
||||
//outputArr := strings.Fields(strings.TrimSpace(output))
|
||||
//trackSuccess := false
|
||||
//trackPrg := false
|
||||
|
||||
//for i := len(outputArr) - 1; i >= 0; i-- {
|
||||
// if strings.TrimSpace(outputArr[i]) != "" {
|
||||
// if outputArr[i] == "PASS" {
|
||||
// trackSuccess = true
|
||||
// trackPrg = true
|
||||
// } else if outputArr[i] == "FAIL" {
|
||||
// trackPrg = true
|
||||
// }
|
||||
// }
|
||||
// if trackPrg {
|
||||
// break
|
||||
// }
|
||||
//}
|
||||
fmt.Println("Preflight checks completed, cleaning up resources now")
|
||||
return nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user