Compare commits

...

5 Commits

Author SHA1 Message Date
Ashwathi Shiva
ed7e97332b Preflight fix output to remove symbols (#340)
* removed symbols and have all preflight checks working
2020-04-22 09:01:07 -04:00
Ashwathi Shiva
eb7517f88d Preflight beautify output (#332)
* kubernetes version check fixed with new output style
2020-04-20 09:02:55 -04:00
Foysal Iqbal
ea048f1b5f Unify install apply (#328) 2020-04-16 17:04:21 -04:00
Ilir Bekteshi
0992286e23 [action] test on supported platforms (#319) (#321)
* [action] test on supported platforms (#319)

* [action] install make on windows

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

* [action] Remove MacOS from matrix
2020-04-16 17:16:40 +02:00
Foysal Iqbal
6d87fadae0 Install latest (#326) 2020-04-16 10:29:56 -04:00
22 changed files with 647 additions and 412 deletions

View File

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

View File

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

View File

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

View File

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

View File

@@ -172,9 +172,6 @@ func rootCmd(p *qliksense.Qliksense) *cobra.Command {
viper.SetEnvKeyReplacer(strings.NewReplacer("-", "_"))
//add upgrade command
cmd.AddCommand(upgradeCmd(p))
// add the set-context config command as a sub-command to the app config command
configCmd.AddCommand(setContextConfigCmd(p))

View File

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

1
go.mod
View File

@@ -37,6 +37,7 @@ require (
github.com/hashicorp/golang-lru v0.5.4 // indirect
github.com/jinzhu/copier v0.0.0-20190924061706-b57f9002281a
github.com/kardianos/osext v0.0.0-20190222173326-2bc1f35cddc0 // indirect
github.com/kyokomi/emoji v2.2.2+incompatible
github.com/mattn/go-colorable v0.1.4
github.com/mattn/go-tty v0.0.3
github.com/mitchellh/go-homedir v1.1.0

3
go.sum
View File

@@ -675,6 +675,9 @@ github.com/kr/pty v1.1.8/go.mod h1:O1sed60cT9XZ5uDucP5qwvh+TE3NnUj51EiZO/lmSfw=
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/kyokomi/emoji v1.5.1 h1:qp9dub1mW7C4MlvoRENH6EAENb9skEFOvIEbp1Waj38=
github.com/kyokomi/emoji v2.2.2+incompatible h1:gaQFbK2+uSxOR4iGZprJAbpmtqTrHhSdgOyIMD6Oidc=
github.com/kyokomi/emoji v2.2.2+incompatible/go.mod h1:mZ6aGCD7yk8j6QY6KICwnZ2pxoszVseX1DNoGtU2tBA=
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/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=

View File

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

View File

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

View File

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

View File

@@ -10,18 +10,18 @@ func (qp *QliksensePreflight) CheckDeployment(namespace string, kubeConfigConten
clientset, _, err := getK8SClientSet(kubeConfigContents, "")
if err != nil {
err = fmt.Errorf("Kube config error: %v\n", err)
fmt.Print(err)
return err
}
// Deployment check
fmt.Printf("Preflight deployment check: \n")
qp.P.LogVerboseMessage("Preflight deployment check: \n")
qp.P.LogVerboseMessage("--------------------------- \n")
err = qp.checkPfDeployment(clientset, namespace, "deployment-preflight-check")
if err != nil {
fmt.Println("Preflight Deployment check: FAILED")
qp.P.LogVerboseMessage("Preflight Deployment check: FAILED\n")
return err
}
fmt.Println("Completed preflight deployment check")
qp.P.LogVerboseMessage("Completed preflight deployment check\n")
return nil
}
@@ -29,18 +29,18 @@ func (qp *QliksensePreflight) CheckDeployment(namespace string, kubeConfigConten
func (qp *QliksensePreflight) CheckService(namespace string, kubeConfigContents []byte) error {
clientset, _, err := getK8SClientSet(kubeConfigContents, "")
if err != nil {
err = fmt.Errorf("error: unable to create a kubernetes client: %v\n", err)
fmt.Println(err)
err = fmt.Errorf("unable to create a kubernetes client: %v\n", err)
return err
}
// Service check
fmt.Printf("\nPreflight service check: \n")
err = checkPfService(clientset, namespace)
qp.P.LogVerboseMessage("Preflight service check: \n")
qp.P.LogVerboseMessage("------------------------ \n")
err = qp.checkPfService(clientset, namespace)
if err != nil {
fmt.Println("Preflight Service check: FAILED")
qp.P.LogVerboseMessage("Preflight Service check: FAILED\n")
return err
}
fmt.Println("Completed preflight service check")
qp.P.LogVerboseMessage("Completed preflight service check\n")
return nil
}
@@ -48,18 +48,17 @@ func (qp *QliksensePreflight) CheckPod(namespace string, kubeConfigContents []by
clientset, _, err := getK8SClientSet(kubeConfigContents, "")
if err != nil {
err = fmt.Errorf("error: unable to create a kubernetes client: %v\n", err)
fmt.Print(err)
return err
}
// Pod check
fmt.Printf("\nPreflight pod check: \n")
qp.P.LogVerboseMessage("Preflight pod check: \n")
qp.P.LogVerboseMessage("-------------------- \n")
err = qp.checkPfPod(clientset, namespace)
if err != nil {
fmt.Println("Preflight Pod check: FAILED")
qp.P.LogVerboseMessage("Preflight Pod check: FAILED\n")
return err
}
fmt.Println("Completed preflight pod check")
qp.P.LogVerboseMessage("Completed preflight pod check\n")
return nil
}
@@ -72,38 +71,38 @@ func (qp *QliksensePreflight) checkPfPod(clientset *kubernetes.Clientset, namesp
if err != nil {
return err
}
pod, err := createPreflightTestPod(clientset, namespace, podName, imageName, nil, commandToRun)
pod, err := qp.createPreflightTestPod(clientset, namespace, podName, imageName, nil, commandToRun)
if err != nil {
err = fmt.Errorf("error: unable to create pod %s - %v\n", podName, err)
err = fmt.Errorf("unable to create pod - %v\n", err)
return err
}
defer deletePod(clientset, namespace, podName)
defer qp.deletePod(clientset, namespace, podName)
if err := waitForPod(clientset, namespace, pod); err != nil {
return err
}
fmt.Println("Preflight pod creation check: PASSED")
fmt.Println("Cleaning up resources...")
qp.P.LogVerboseMessage("Preflight pod creation check: PASSED\n")
qp.P.LogVerboseMessage("Cleaning up resources...\n")
return nil
}
func checkPfService(clientset *kubernetes.Clientset, namespace string) error {
func (qp *QliksensePreflight) checkPfService(clientset *kubernetes.Clientset, namespace string) error {
// creating service
serviceName := "svc-pf-check"
pfService, err := createPreflightTestService(clientset, namespace, serviceName)
pfService, err := qp.createPreflightTestService(clientset, namespace, serviceName)
if err != nil {
err = fmt.Errorf("error: unable to create service : %s\n", serviceName)
err = fmt.Errorf("unable to create service - %v\n", err)
return err
}
defer deleteService(clientset, namespace, serviceName)
defer qp.deleteService(clientset, namespace, serviceName)
_, err = getService(clientset, namespace, pfService.GetName())
if err != nil {
err = fmt.Errorf("error: unable to retrieve service: %s\n", serviceName)
err = fmt.Errorf("unable to retrieve service - %v\n", err)
return err
}
fmt.Println("Preflight service creation check: PASSED")
fmt.Println("Cleaning up resources...")
qp.P.LogVerboseMessage("Preflight service creation check: PASSED\n")
qp.P.LogVerboseMessage("Cleaning up resources...\n")
return nil
}
@@ -113,16 +112,16 @@ func (qp *QliksensePreflight) checkPfDeployment(clientset *kubernetes.Clientset,
if err != nil {
return err
}
pfDeployment, err := createPreflightTestDeployment(clientset, namespace, depName, imageName)
pfDeployment, err := qp.createPreflightTestDeployment(clientset, namespace, depName, imageName)
if err != nil {
err = fmt.Errorf("error: unable to create deployment: %v\n", err)
err = fmt.Errorf("unable to create deployment - %v\n", err)
return err
}
defer deleteDeployment(clientset, namespace, depName)
defer qp.deleteDeployment(clientset, namespace, depName)
if err := waitForDeployment(clientset, namespace, pfDeployment); err != nil {
return err
}
fmt.Println("Preflight Deployment check: PASSED")
fmt.Println("Cleaning up resources...")
qp.P.LogVerboseMessage("Preflight Deployment check: PASSED\n")
qp.P.LogVerboseMessage("Cleaning up resources...\n")
return nil
}

View File

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

View File

@@ -15,12 +15,13 @@ const (
mongo = "mongo"
)
func (qp *QliksensePreflight) CheckMongo(kubeConfigContents []byte, namespace string, preflightOpts *PreflightMongoOptions) error {
fmt.Printf("Preflight mongodb check: \n")
func (qp *QliksensePreflight) CheckMongo(kubeConfigContents []byte, namespace string, preflightOpts *PreflightOptions) error {
qp.P.LogVerboseMessage("Preflight mongodb check: \n")
qp.P.LogVerboseMessage("------------------------ \n")
if preflightOpts.MongodbUrl == "" {
if preflightOpts.MongoOptions.MongodbUrl == "" {
// infer mongoDbUrl from currentCR
fmt.Println("MongoDbUri is empty, infer from CR")
qp.P.LogVerboseMessage("MongoDbUri is empty, infer from CR\n")
qConfig := qapi.NewQConfig(qp.Q.QliksenseHome)
var currentCR *qapi.QliksenseCR
@@ -28,135 +29,130 @@ func (qp *QliksensePreflight) CheckMongo(kubeConfigContents []byte, namespace st
qConfig.SetNamespace(namespace)
currentCR, err = qConfig.GetCurrentCR()
if err != nil {
fmt.Printf("Unable to retrieve current CR: %v\n", err)
qp.P.LogVerboseMessage("Unable to retrieve current CR: %v\n", err)
return err
}
decryptedCR, err := qConfig.GetDecryptedCr(currentCR)
if err != nil {
fmt.Printf("An error occurred while retrieving mongodbUrl from current CR: %v\n", err)
qp.P.LogVerboseMessage("An error occurred while retrieving mongodbUrl from current CR: %v\n", err)
return err
}
preflightOpts.MongodbUrl = decryptedCR.Spec.GetFromSecrets("qliksense", "mongoDbUri")
preflightOpts.MongoOptions.MongodbUrl = decryptedCR.Spec.GetFromSecrets("qliksense", "mongoDbUri")
}
fmt.Printf("mongodbUrl: %s\n", preflightOpts.MongodbUrl)
qp.P.LogVerboseMessage("MongodbUrl: %s\n", preflightOpts.MongoOptions.MongodbUrl)
if err := qp.mongoConnCheck(kubeConfigContents, namespace, preflightOpts); err != nil {
return err
}
fmt.Println("Completed preflight mongodb check")
qp.P.LogVerboseMessage("Completed preflight mongodb check\n")
return nil
}
func (qp *QliksensePreflight) mongoConnCheck(kubeConfigContents []byte, namespace string, preflightOpts *PreflightMongoOptions) error {
func (qp *QliksensePreflight) mongoConnCheck(kubeConfigContents []byte, namespace string, preflightOpts *PreflightOptions) error {
var caCertSecretName, clientCertSecretName string
clientset, _, err := getK8SClientSet(kubeConfigContents, "")
if err != nil {
err = fmt.Errorf("error: unable to create a kubernetes client: %v\n", err)
fmt.Println(err)
err = fmt.Errorf("unable to create a kubernetes client: %v\n", err)
return err
}
var secrets []string
if preflightOpts.CaCertFile != "" {
if preflightOpts.MongoOptions.CaCertFile != "" {
caCertSecretName = "preflight-mongo-test-cacert"
caCertSecret, err := createSecret(clientset, namespace, preflightOpts.CaCertFile, caCertSecretName)
caCertSecret, err := qp.createSecret(clientset, namespace, preflightOpts.MongoOptions.CaCertFile, caCertSecretName)
if err != nil {
err = fmt.Errorf("error: unable to create a create ca cert kubernetes secret: %v\n", err)
fmt.Println(err)
err = fmt.Errorf("unable to create a ca cert kubernetes secret: %v\n", err)
return err
}
defer deleteK8sSecret(clientset, namespace, caCertSecret)
defer qp.deleteK8sSecret(clientset, namespace, caCertSecret)
secrets = append(secrets, caCertSecretName)
}
if preflightOpts.ClientCertFile != "" {
if preflightOpts.MongoOptions.ClientCertFile != "" {
clientCertSecretName = "preflight-mongo-test-clientcert"
clientCertSecret, err := createSecret(clientset, namespace, preflightOpts.ClientCertFile, clientCertSecretName)
clientCertSecret, err := qp.createSecret(clientset, namespace, preflightOpts.MongoOptions.ClientCertFile, clientCertSecretName)
if err != nil {
err = fmt.Errorf("error: unable to create a create client cert kubernetes secret: %v\n", err)
fmt.Println(err)
err = fmt.Errorf("unable to create a client cert kubernetes secret: %v\n", err)
return err
}
defer deleteK8sSecret(clientset, namespace, clientCertSecret)
defer qp.deleteK8sSecret(clientset, namespace, clientCertSecret)
secrets = append(secrets, clientCertSecretName)
}
mongoCommand := strings.Builder{}
mongoCommand.WriteString(fmt.Sprintf("sleep 10;mongo %s", preflightOpts.MongodbUrl))
if preflightOpts.Username != "" {
mongoCommand.WriteString(fmt.Sprintf(" --username %s", preflightOpts.Username))
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.Password != "" {
mongoCommand.WriteString(fmt.Sprintf(" --password %s", preflightOpts.Password))
if preflightOpts.MongoOptions.Password != "" {
mongoCommand.WriteString(fmt.Sprintf(" --password %s", preflightOpts.MongoOptions.Password))
api.LogDebugMessage("Adding username and password\n")
}
if preflightOpts.Tls || preflightOpts.CaCertFile != "" || preflightOpts.ClientCertFile != "" {
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))
if preflightOpts.CaCertFile != "" {
api.LogDebugMessage("Adding caCertFile: Mongo command: %s\n", mongoCommand.String())
}
if preflightOpts.ClientCertFile != "" {
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 commandToRun: %s\n", strings.Join(commandToRun, " "))
api.LogDebugMessage("Mongo command: %s\n", strings.Join(commandToRun, " "))
// create a pod
podName := "pf-mongo-pod"
imageName, err := qp.GetPreflightConfigObj().GetImageName(mongo, true)
if err != nil {
err = fmt.Errorf("unable to retrieve image : %v\n", err)
return err
}
mongoPod, err := createPreflightTestPod(clientset, namespace, podName, imageName, secrets, commandToRun)
mongoPod, err := qp.createPreflightTestPod(clientset, namespace, podName, imageName, secrets, commandToRun)
if err != nil {
err = fmt.Errorf("error: unable to create pod : %v\n", err)
err = fmt.Errorf("unable to create pod : %v\n", err)
return err
}
defer deletePod(clientset, namespace, podName)
defer qp.deletePod(clientset, namespace, podName)
if err := waitForPod(clientset, namespace, mongoPod); err != nil {
return err
}
if len(mongoPod.Spec.Containers) == 0 {
err := fmt.Errorf("error: there are no containers in the pod- %v\n", err)
fmt.Println(err)
err := fmt.Errorf("there are no containers in the pod- %v\n", err)
return err
}
waitForPodToDie(clientset, namespace, mongoPod)
logStr, err := getPodLogs(clientset, mongoPod)
if err != nil {
err = fmt.Errorf("error: unable to execute mongo check in the cluster: %v\n", err)
fmt.Println(err)
err = fmt.Errorf("unable to execute mongo check in the cluster: %v\n", err)
return err
}
stringToCheck := "Implicit session:"
if strings.Contains(logStr, stringToCheck) {
fmt.Println("Preflight mongo check: PASSED")
qp.P.LogVerboseMessage("Preflight mongo check: PASSED\n")
} else {
err = fmt.Errorf("Expected response not found\n")
err = fmt.Errorf("Connection failed: %s\n", logStr)
return err
}
return nil
}
func createSecret(clientset *kubernetes.Clientset, namespace, certFile, certSecretName string) (*apiv1.Secret, error) {
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 := createPreflightTestSecret(clientset, namespace, certSecretName, certBytes)
certSecret, err := qp.createPreflightTestSecret(clientset, namespace, certSecretName, certBytes)
if err != nil {
err = fmt.Errorf("error: unable to create secret with ca cert : %v\n", err)
err = fmt.Errorf("unable to create secret with ca cert : %v\n", err)
return nil, err
}
return certSecret, nil

View File

@@ -6,6 +6,7 @@ import (
"io"
"io/ioutil"
"log"
"os"
"path/filepath"
"strings"
"time"
@@ -26,7 +27,19 @@ import (
"k8s.io/client-go/util/retry"
)
type PreflightMongoOptions struct {
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
@@ -39,6 +52,7 @@ var gracePeriod int64 = 0
type QliksensePreflight struct {
Q *qliksense.Qliksense
P *PreflightOptions
}
func (qp *QliksensePreflight) GetPreflightConfigObj() *api.PreflightConfig {
@@ -102,14 +116,12 @@ func getK8SClientSet(kubeconfig []byte, contextName string) (*kubernetes.Clients
clientConfig, err = rest.InClusterConfig()
if err != nil {
err = errors.Wrap(err, "Unable to load in-cluster kubeconfig")
fmt.Println(err)
return nil, nil, err
}
} else {
config, err := clientcmd.Load(kubeconfig)
if err != nil {
err = errors.Wrap(err, "Unable to load kubeconfig")
fmt.Println(err)
return nil, nil, err
}
if contextName != "" {
@@ -118,20 +130,18 @@ func getK8SClientSet(kubeconfig []byte, contextName string) (*kubernetes.Clients
clientConfig, err = clientcmd.NewDefaultClientConfig(*config, &clientcmd.ConfigOverrides{}).ClientConfig()
if err != nil {
err = errors.Wrap(err, "Unable to create client config from config")
fmt.Println(err)
return nil, nil, err
}
}
clientset, err := kubernetes.NewForConfig(clientConfig)
if err != nil {
err = errors.Wrap(err, "Unable to create clientset")
fmt.Println(err)
return nil, nil, err
}
return clientset, clientConfig, nil
}
func createPreflightTestDeployment(clientset *kubernetes.Clientset, namespace string, depName string, imageName string) (*appsv1.Deployment, error) {
func (qp *QliksensePreflight) createPreflightTestDeployment(clientset *kubernetes.Clientset, namespace string, depName string, imageName string) (*appsv1.Deployment, error) {
deploymentsClient := clientset.AppsV1().Deployments(namespace)
deployment := &appsv1.Deployment{
ObjectMeta: v1.ObjectMeta{
@@ -176,11 +186,10 @@ func createPreflightTestDeployment(clientset *kubernetes.Clientset, namespace st
result, err = deploymentsClient.Create(deployment)
return err
}); err != nil {
err = errors.Wrapf(err, "error: unable to create deployments in the %s namespace", namespace)
fmt.Println(err)
err = errors.Wrapf(err, "unable to create deployments in the %s namespace", namespace)
return nil, err
}
fmt.Printf("Created deployment %q\n", result.GetObjectMeta().GetName())
qp.P.LogVerboseMessage("Created deployment %q\n", result.GetObjectMeta().GetName())
return deployment, nil
}
@@ -192,14 +201,14 @@ func getDeployment(clientset *kubernetes.Clientset, namespace, depName string) (
deployment, err = deploymentsClient.Get(depName, v1.GetOptions{})
return err
}); err != nil {
err = errors.Wrapf(err, "error: unable to get deployments in the %s namespace", namespace)
err = errors.Wrapf(err, "unable to get deployments in the %s namespace", namespace)
api.LogDebugMessage("%v\n", err)
return nil, err
}
return deployment, nil
}
func deleteDeployment(clientset *kubernetes.Clientset, namespace, name string) error {
func (qp *QliksensePreflight) deleteDeployment(clientset *kubernetes.Clientset, namespace, name string) error {
deploymentsClient := clientset.AppsV1().Deployments(namespace)
// Create Deployment
deletePolicy := v1.DeletePropagationForeground
@@ -211,17 +220,16 @@ func deleteDeployment(clientset *kubernetes.Clientset, namespace, name string) e
if err := retryOnError(func() (err error) {
return deploymentsClient.Delete(name, &deleteOptions)
}); err != nil {
fmt.Println(err)
return err
}
if err := waitForDeploymentToDelete(clientset, namespace, name); err != nil {
return err
}
fmt.Printf("Deleted deployment: %s\n", name)
qp.P.LogVerboseMessage("Deleted deployment: %s\n", name)
return nil
}
func createPreflightTestService(clientset *kubernetes.Clientset, namespace string, svcName string) (*apiv1.Service, error) {
func (qp *QliksensePreflight) createPreflightTestService(clientset *kubernetes.Clientset, namespace string, svcName string) (*apiv1.Service, error) {
iptr := int32Ptr(80)
servicesClient := clientset.CoreV1().Services(namespace)
service := &apiv1.Service{
@@ -249,10 +257,9 @@ func createPreflightTestService(clientset *kubernetes.Clientset, namespace strin
result, err = servicesClient.Create(service)
return err
}); err != nil {
fmt.Println(err)
return nil, err
}
fmt.Printf("Created service %q\n", result.GetObjectMeta().GetName())
qp.P.LogVerboseMessage("Created service %q\n", result.GetObjectMeta().GetName())
return service, nil
}
@@ -265,14 +272,13 @@ func getService(clientset *kubernetes.Clientset, namespace, svcName string) (*ap
return err
}); err != nil {
err = errors.Wrapf(err, "unable to get services in the %s namespace", namespace)
fmt.Println(err)
return nil, err
}
return svc, nil
}
func deleteService(clientset *kubernetes.Clientset, namespace, name string) error {
func (qp *QliksensePreflight) deleteService(clientset *kubernetes.Clientset, namespace, name string) error {
servicesClient := clientset.CoreV1().Services(namespace)
// Create Deployment
deletePolicy := v1.DeletePropagationForeground
@@ -285,11 +291,11 @@ func deleteService(clientset *kubernetes.Clientset, namespace, name string) erro
fmt.Println(err)
return err
}
fmt.Printf("Deleted service: %s\n", name)
qp.P.LogVerboseMessage("Deleted service: %s\n", name)
return nil
}
func deletePod(clientset *kubernetes.Clientset, namespace, name string) error {
func (qp *QliksensePreflight) deletePod(clientset *kubernetes.Clientset, namespace, name string) error {
podsClient := clientset.CoreV1().Pods(namespace)
deletePolicy := v1.DeletePropagationForeground
@@ -300,17 +306,16 @@ func deletePod(clientset *kubernetes.Clientset, namespace, name string) error {
if err := retryOnError(func() (err error) {
return podsClient.Delete(name, &deleteOptions)
}); err != nil {
fmt.Println(err)
return err
}
if err := waitForPodToDelete(clientset, namespace, name); err != nil {
return err
}
fmt.Printf("Deleted pod: %s\n", name)
qp.P.LogVerboseMessage("Deleted pod: %s\n", name)
return nil
}
func createPreflightTestPod(clientset *kubernetes.Clientset, namespace, podName, imageName string, secretNames []string, commandToRun []string) (*apiv1.Pod, error) {
func (qp *QliksensePreflight) createPreflightTestPod(clientset *kubernetes.Clientset, namespace, podName, imageName string, secretNames []string, commandToRun []string) (*apiv1.Pod, error) {
// build the pod definition we want to deploy
pod := &apiv1.Pod{
ObjectMeta: v1.ObjectMeta{
@@ -363,10 +368,9 @@ func createPreflightTestPod(clientset *kubernetes.Clientset, namespace, podName,
pod, err = clientset.CoreV1().Pods(namespace).Create(pod)
return err
}); err != nil {
fmt.Println(err)
return nil, err
}
fmt.Printf("Created pod: %s\n", pod.Name)
qp.P.LogVerboseMessage("Created pod: %s\n", pod.Name)
return pod, nil
}
@@ -431,8 +435,7 @@ func waitForDeployment(clientset *kubernetes.Clientset, namespace string, pfDepl
checkFunc := func() (interface{}, error) {
pfDeployment, err = getDeployment(clientset, namespace, depName)
if err != nil {
err = fmt.Errorf("error: unable to retrieve deployment: %s\n", depName)
fmt.Println(err)
err = fmt.Errorf("unable to retrieve deployment: %s\n", depName)
return nil, err
}
return pfDeployment, nil
@@ -445,8 +448,7 @@ func waitForDeployment(clientset *kubernetes.Clientset, namespace string, pfDepl
return err
}
if int(pfDeployment.Status.ReadyReplicas) == 0 {
err = fmt.Errorf("error: deployment took longer than expected to spin up pods")
fmt.Println(err)
err = fmt.Errorf("deployment took longer than expected to spin up pods")
return err
}
return nil
@@ -455,16 +457,14 @@ func waitForDeployment(clientset *kubernetes.Clientset, namespace string, pfDepl
func waitForPod(clientset *kubernetes.Clientset, namespace string, pod *apiv1.Pod) error {
var err error
if len(pod.Spec.Containers) == 0 {
err = fmt.Errorf("error: there are no containers in the pod")
fmt.Println(err)
err = fmt.Errorf("there are no containers in the pod")
return err
}
podName := pod.Name
checkFunc := func() (interface{}, error) {
pod, err = getPod(clientset, namespace, podName)
if err != nil {
err = fmt.Errorf("error: unable to retrieve %s pod by name", podName)
fmt.Println(err)
err = fmt.Errorf("unable to retrieve %s pod by name", podName)
return nil, err
}
return pod, nil
@@ -478,8 +478,7 @@ func waitForPod(clientset *kubernetes.Clientset, namespace string, pod *apiv1.Po
return err
}
if len(pod.Status.ContainerStatuses) == 0 || !pod.Status.ContainerStatuses[0].Ready {
err = fmt.Errorf("error: container is taking much longer than expected")
fmt.Println(err)
err = fmt.Errorf("container is taking much longer than expected")
return err
}
return nil
@@ -490,8 +489,7 @@ func waitForPodToDie(clientset *kubernetes.Clientset, namespace string, pod *api
checkFunc := func() (interface{}, error) {
po, err := getPod(clientset, namespace, podName)
if err != nil {
err = fmt.Errorf("error: unable to retrieve %s pod by name", podName)
fmt.Println(err)
err = fmt.Errorf("unable to retrieve %s pod by name", podName)
return nil, err
}
api.LogDebugMessage("pod status: %v\n", po.Status.Phase)
@@ -521,8 +519,7 @@ func waitForPodToDelete(clientset *kubernetes.Clientset, namespace, podName stri
if err := waitForResource(checkFunc, validateFunc); err != nil {
return nil
}
err := fmt.Errorf("error: delete pod is taking unusually long")
fmt.Println(err)
err := fmt.Errorf("delete pod is taking unusually long")
return err
}
@@ -540,12 +537,11 @@ func waitForDeploymentToDelete(clientset *kubernetes.Clientset, namespace, deplo
if err := waitForResource(checkFunc, validateFunc); err != nil {
return nil
}
err := fmt.Errorf("error: delete deployment is taking unusually long")
fmt.Println(err)
err := fmt.Errorf("delete deployment is taking unusually long")
return err
}
func createPfRole(clientset *kubernetes.Clientset, namespace, roleName string) (*v1beta1.Role, error) {
func (qp *QliksensePreflight) createPfRole(clientset *kubernetes.Clientset, namespace, roleName string) (*v1beta1.Role, error) {
// build the role defination we want to create
var role *v1beta1.Role
roleSpec := &v1beta1.Role{
@@ -564,16 +560,15 @@ func createPfRole(clientset *kubernetes.Clientset, namespace, roleName string) (
role, err = clientset.RbacV1beta1().Roles(namespace).Create(roleSpec)
return err
}); err != nil {
fmt.Println(err)
return nil, err
}
fmt.Printf("Created role: %s\n", role.Name)
qp.P.LogVerboseMessage("Created role: %s\n", role.Name)
return role, nil
}
func deleteRole(clientset *kubernetes.Clientset, namespace string, role *v1beta1.Role) {
func (qp *QliksensePreflight) deleteRole(clientset *kubernetes.Clientset, namespace string, role *v1beta1.Role) {
rolesClient := clientset.RbacV1beta1().Roles(namespace)
deletePolicy := v1.DeletePropagationForeground
@@ -584,10 +579,10 @@ func deleteRole(clientset *kubernetes.Clientset, namespace string, role *v1beta1
if err != nil {
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
// build the rolebinding defination we want to create
roleBindingSpec := &v1beta1.RoleBinding{
@@ -618,14 +613,13 @@ func createPfRoleBinding(clientset *kubernetes.Clientset, namespace, roleBinding
roleBinding, err = clientset.RbacV1beta1().RoleBindings(namespace).Create(roleBindingSpec)
return err
}); err != nil {
fmt.Println(err)
return nil, err
}
fmt.Printf("Created RoleBinding: %s\n", roleBindingSpec.Name)
qp.P.LogVerboseMessage("Created RoleBinding: %s\n", roleBindingSpec.Name)
return roleBinding, nil
}
func deleteRoleBinding(clientset *kubernetes.Clientset, namespace string, roleBinding *v1beta1.RoleBinding) {
func (qp *QliksensePreflight) deleteRoleBinding(clientset *kubernetes.Clientset, namespace string, roleBinding *v1beta1.RoleBinding) {
roleBindingClient := clientset.RbacV1beta1().RoleBindings(namespace)
deletePolicy := v1.DeletePropagationForeground
@@ -636,10 +630,10 @@ func deleteRoleBinding(clientset *kubernetes.Clientset, namespace string, roleBi
if err != nil {
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
// build the serviceAccount defination we want to create
serviceAccountSpec := &apiv1.ServiceAccount{
@@ -647,7 +641,7 @@ func createPfServiceAccount(clientset *kubernetes.Clientset, namespace, serviceA
Name: "preflight-check-test-serviceaccount",
Namespace: namespace,
Labels: map[string]string{
"app": "demo",
"app": "preflight",
},
},
}
@@ -657,14 +651,13 @@ func createPfServiceAccount(clientset *kubernetes.Clientset, namespace, serviceA
serviceAccount, err = clientset.CoreV1().ServiceAccounts(namespace).Create(serviceAccountSpec)
return err
}); err != nil {
fmt.Println(err)
return nil, err
}
fmt.Printf("Created Service Account: %s\n", serviceAccountSpec.Name)
qp.P.LogVerboseMessage("Created Service Account: %s\n", serviceAccountSpec.Name)
return serviceAccount, nil
}
func deleteServiceAccount(clientset *kubernetes.Clientset, namespace string, serviceAccount *apiv1.ServiceAccount) {
func (qp *QliksensePreflight) deleteServiceAccount(clientset *kubernetes.Clientset, namespace string, serviceAccount *apiv1.ServiceAccount) {
serviceAccountClient := clientset.CoreV1().ServiceAccounts(namespace)
deletePolicy := v1.DeletePropagationForeground
@@ -675,10 +668,10 @@ func deleteServiceAccount(clientset *kubernetes.Clientset, namespace string, ser
if err != nil {
log.Fatal(err)
}
fmt.Printf("Deleted ServiceAccount: %s\n\n", serviceAccount.Name)
qp.P.LogVerboseMessage("Deleted ServiceAccount: %s\n\n", serviceAccount.Name)
}
func createPreflightTestSecret(clientset *kubernetes.Clientset, namespace, secretName string, secretData []byte) (*apiv1.Secret, error) {
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
@@ -700,14 +693,13 @@ func createPreflightTestSecret(clientset *kubernetes.Clientset, namespace, secre
secret, err = clientset.CoreV1().Secrets(namespace).Create(secretSpec)
return err
}); err != nil {
fmt.Println(err)
return nil, err
}
fmt.Printf("Created Secret: %s\n", secret.Name)
qp.P.LogVerboseMessage("Created Secret: %s\n", secret.Name)
return secret, nil
}
func deleteK8sSecret(clientset *kubernetes.Clientset, namespace string, k8sSecret *apiv1.Secret) {
func (qp *QliksensePreflight) deleteK8sSecret(clientset *kubernetes.Clientset, namespace string, k8sSecret *apiv1.Secret) {
secretClient := clientset.CoreV1().Secrets(namespace)
deletePolicy := v1.DeletePropagationForeground
@@ -718,5 +710,5 @@ func deleteK8sSecret(clientset *kubernetes.Clientset, namespace string, k8sSecre
if err != nil {
log.Fatal(err)
}
fmt.Printf("Deleted Secret: %s\n\n", k8sSecret.Name)
qp.P.LogVerboseMessage("Deleted Secret: %s\n", k8sSecret.Name)
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -109,11 +109,16 @@ func (q *Qliksense) InstallQK8s(version string, opts *InstallCommandOptions, kee
if dcr, err := qConfig.GetDecryptedCr(qcr); err != nil {
return err
} else if err := q.applyConfigToK8s(dcr); err != nil {
fmt.Println("cannot do kubectl apply on manifests")
return err
} else {
return q.applyCR(dcr)
if IsQliksenseInstalled(dcr.GetName()) {
return q.UpgradeQK8s(keepPatchFiles)
}
if err := q.applyConfigToK8s(dcr); err != nil {
fmt.Println("cannot do kubectl apply on manifests")
return err
} else {
return q.applyCR(dcr)
}
}
}