Compare commits

..

5 Commits

Author SHA1 Message Date
Andriy Bulynko
dd8a48b2b8 Fixing a test expecting a "v" at the start of the operator docker image version (#379) 2020-05-27 16:26:36 -04:00
Andriy Bulynko
9fb6800993 Upgrading kustomize to qlik/v0.0.25 (#378) 2020-05-27 15:19:20 -04:00
Ashwathi Shiva
bbb811a879 Preflight mongo mutual tls (#365)
* mongo check working when ca cert and client cert put in same file
* updated code to use image from bintray
2020-05-13 20:36:07 -04:00
Foysal Iqbal
8156b884ce Fix cipher (#363) 2020-05-12 09:54:04 -04:00
Ashwathi Shiva
7525c2e698 Preflight mongo mutual tls (#357)
* preflight mongo mutual tls working when cert is specified in CR
2020-05-04 09:42:43 -04:00
16 changed files with 145 additions and 189 deletions

View File

@@ -136,12 +136,7 @@ func pfAllChecksCmd(q *qliksense.Qliksense) *cobra.Command {
f := preflightAllChecksCmd.Flags()
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
}
@@ -152,7 +147,7 @@ func pfDeploymentCheckCmd(q *qliksense.Qliksense) *cobra.Command {
}
var pfDeploymentCheckCmd = &cobra.Command{
Use: "deployment",
Short: "perform preflight deploymwnt check",
Short: "perform preflight deployment 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 {
@@ -337,7 +332,7 @@ func pfCreateServiceAccountCheckCmd(q *qliksense.Qliksense) *cobra.Command {
var preflightServiceAccountCmd = &cobra.Command{
Use: "serviceaccount",
Short: "preflight create ServiceAccount check",
Short: "preflight create serviceaccount check",
Long: `perform preflight serviceaccount check to ensure we are able to create a service account in the cluster`,
Example: `qliksense preflight serviceaccount`,
RunE: func(cmd *cobra.Command, args []string) error {
@@ -434,11 +429,7 @@ func pfMongoCheckCmd(q *qliksense.Qliksense) *cobra.Command {
f := preflightMongoCmd.Flags()
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
}
@@ -480,42 +471,3 @@ func pfCleanupCmd(q *qliksense.Qliksense) *cobra.Command {
f.BoolVarP(&preflightOpts.Verbose, "verbose", "v", false, "verbose mode")
return pfCleanCmd
}
func pfStorageClassCheckCmd(q *qliksense.Qliksense) *cobra.Command {
out := ansi.NewColorableStdout()
preflightOpts := &preflight.PreflightOptions{
MongoOptions: &preflight.MongoOptions{},
}
var pfStorageClassCmd = &cobra.Command{
Use: "storageclass",
Short: "perform preflight storage class check",
Long: `perform preflight storage class check to ensure that we are able to create a storage class in the cluster`,
Example: `qliksense preflight storageclass`,
RunE: func(cmd *cobra.Command, args []string) error {
qp := &preflight.QliksensePreflight{Q: q, P: preflightOpts}
// Preflight storage class check
namespace, kubeConfigContents, err := preflight.InitPreflight()
if err != nil {
fmt.Fprintf(out, "%s\n", Red("Preflight storageclass check FAILED"))
fmt.Printf("Error: %v\n", err)
return nil
}
if namespace == "" {
namespace = "default"
}
if err = qp.CheckStorageClass(namespace, kubeConfigContents, false); err != nil {
fmt.Fprintf(out, "%s\n", Red("Preflight storageclass check FAILED"))
fmt.Printf("Error: %v\n", err)
return nil
}
fmt.Fprintf(out, "%s\n", Green("Preflight storageclass check PASSED"))
return nil
},
}
f := pfStorageClassCmd.Flags()
f.BoolVarP(&preflightOpts.Verbose, "verbose", "v", false, "verbose mode")
return pfStorageClassCmd
}

View File

@@ -46,7 +46,7 @@ func initAndExecute() error {
log.Fatal(err)
}
// create dirs and appropriate files for setting up contexts
api.LogDebugMessage("QliksenseHomeDir: %s", qlikSenseHome)
api.LogDebugMessage("QliksenseHomeDir: %s\n", qlikSenseHome)
qliksenseClient := qliksense.New(qlikSenseHome)
cmd := rootCmd(qliksenseClient)
@@ -219,7 +219,6 @@ func rootCmd(p *qliksense.Qliksense) *cobra.Command {
preflightCmd.AddCommand(pfCreateRoleBindingCheckCmd(p))
preflightCmd.AddCommand(pfCreateServiceAccountCheckCmd(p))
preflightCmd.AddCommand(pfCreateAuthCheckCmd(p))
preflightCmd.AddCommand(pfStorageClassCheckCmd(p))
preflightCmd.AddCommand(pfCleanupCmd(p))
cmd.AddCommand(preflightCmd)

View File

@@ -16,9 +16,18 @@ Examples:
qliksense preflight <preflight_check_to_run>
Available Commands:
all perform all checks
dns perform preflight dns check
k8s-version check k8s version
all perform all checks
authcheck preflight authcheck
clean perform preflight clean
deployment perform preflight deployment check
dns perform preflight dns check
kube-version check kubernetes version
mongo preflight mongo OR preflight mongo --url=<url>
pod perform preflight pod check
role preflight create role check
rolebinding preflight create rolebinding check
service perform preflight service check
serviceaccount preflight create ServiceAccount check
Flags:
-h, --help help for preflight
@@ -200,8 +209,8 @@ We can check if we are able to connect to an instance of mongodb on the cluster
qliksense preflight mongo --url=<url> -v OR
qliksense preflight mongo -v
qliksense preflight mongo --url=<mongo-server url> --ca-cert=<path to ca-cert file> -v
```
```shell
Preflight mongo check
---------------------
Preflight mongodb check:
@@ -217,7 +226,29 @@ Deleted pod: pf-mongo-pod
Completed preflight mongodb check
```
#### Mongodb check with mutual tls
In order to perform mutual tls with mongo we need to:
- append client certificate to the beginning/end of CA certificate. Make sure to include the beginning and end tags on each certificate.
The CA certificate file should look like this in the end:
```shell
<existing contents of CA cert>
...
-----BEGIN RSA PRIVATE KEY-----
<private key>
-----END RSA PRIVATE KEY-----
-----BEGIN CERTIFICATE-----
<public key>
-----END CERTIFICATE-----
```
- Run the command below to set the ca certificate into the CR
```shell
cat <path_to_ca.crt> | base64 | qliksense config set-secrets qliksense.caCertificates --base64
```
Next, run:
```shell
qliksense preflight mongo -v
```
### Running all checks
Run the command shown below to execute all preflight checks.

4
go.mod
View File

@@ -10,7 +10,7 @@ replace (
k8s.io/client-go => k8s.io/client-go v0.17.0
k8s.io/kubectl => k8s.io/kubectl v0.0.0-20191219154910-1528d4eea6dd
sigs.k8s.io/kustomize/api => github.com/qlik-oss/kustomize/api v0.3.3-0.20200424070349-b0312eb71568
sigs.k8s.io/kustomize/api => github.com/qlik-oss/kustomize/api v0.3.3-0.20200514233516-4ac83864b7bd
)
require (
@@ -40,7 +40,7 @@ require (
github.com/mitchellh/go-homedir v1.1.0
github.com/otiai10/copy v1.1.1
github.com/pkg/errors v0.9.1
github.com/qlik-oss/k-apis v0.1.1
github.com/qlik-oss/k-apis v0.1.2
github.com/robfig/cron/v3 v3.0.1
github.com/rogpeppe/go-internal v1.5.2 // indirect
github.com/spf13/cobra v0.0.6

8
go.sum
View File

@@ -883,10 +883,10 @@ github.com/prometheus/procfs v0.0.3/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDa
github.com/prometheus/procfs v0.0.5 h1:3+auTFlqw+ZaQYJARz6ArODtkaIwtvBTx3N2NehQlL8=
github.com/prometheus/procfs v0.0.5/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ=
github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU=
github.com/qlik-oss/k-apis v0.1.1 h1:aZ4eTMB3mSn03Kuj7+RI0eFLkjK9+0qxADBioRb3qVA=
github.com/qlik-oss/k-apis v0.1.1/go.mod h1:yoYGgPJ/H0t9H3NSq64dWfyQY6QWi2L9c+hCJoVO03U=
github.com/qlik-oss/kustomize/api v0.3.3-0.20200424070349-b0312eb71568 h1:wHOUCGfnmgYqW3aCjuP3fXmB2T/uZXMvltO+F3us83E=
github.com/qlik-oss/kustomize/api v0.3.3-0.20200424070349-b0312eb71568/go.mod h1:Yg8bqX8Mq/eSgXfcenxCxhZuSXg+NCsKq6NBdch/oUc=
github.com/qlik-oss/k-apis v0.1.2 h1:BBcrXl+NxdsvuRsZuJbvIFxMv5QIXqWBzhXOcr5KUX8=
github.com/qlik-oss/k-apis v0.1.2/go.mod h1:yoYGgPJ/H0t9H3NSq64dWfyQY6QWi2L9c+hCJoVO03U=
github.com/qlik-oss/kustomize/api v0.3.3-0.20200514233516-4ac83864b7bd h1:dYd6duTr54L7OqykGkd3Z+336frAvzsibWNYruYkYVc=
github.com/qlik-oss/kustomize/api v0.3.3-0.20200514233516-4ac83864b7bd/go.mod h1:zh3yFgE5zFk1kreqzVyyj1eXyIxQJT53l4zSg8Wt4SA=
github.com/quasilyte/go-consistent v0.0.0-20190521200055-c6f3937de18c/go.mod h1:5STLWrekHfjyYwxBRVRXNOSewLJ3PWfDJd1VyTS21fI=
github.com/rainycape/unidecode v0.0.0-20150907023854-cb7f23ec59be h1:ta7tUOvsPHVHGom5hKW5VXNc2xZIkfCKP8iaqOyYtUQ=
github.com/rainycape/unidecode v0.0.0-20150907023854-cb7f23ec59be/go.mod h1:MIDFMn7db1kT65GmV94GzpX9Qdi7N/pQlwb+AN8wh+Q=

View File

@@ -157,6 +157,8 @@ func (cr *QliksenseCR) GetFetchAccessToken(encryptionKey string) string {
if tok, err := cr.Spec.FetchSource.GetAccessToken(); err != nil {
fmt.Println(err)
return ""
} else if tok == "" {
return tok
} else {
by, _ := b64.StdEncoding.DecodeString(tok)
res, err := DecryptData(by, encryptionKey)

View File

@@ -96,7 +96,7 @@ func WriteToFile(content interface{}, targetFile string) error {
log.Println(err)
return err
}
LogDebugMessage("Wrote content into %s", targetFile)
LogDebugMessage("Wrote content into %s\n", targetFile)
return nil
}

View File

@@ -133,6 +133,6 @@ func (p *PreflightConfig) Initialize() error {
p.AddMinMongoV("3.6")
p.AddImage("nginx", "nginx")
p.AddImage("netcat", "subfuzion/netcat")
p.AddImage("mongo", "mongo")
p.AddImage("preflight-mongo", "qlik-docker-oss.bintray.io/preflight-mongo")
return p.Write()
}

View File

@@ -23,7 +23,7 @@ func checkExists(filename string) os.FileInfo {
if os.IsNotExist(err) {
return nil
}
LogDebugMessage("File exists")
LogDebugMessage("File exists\n")
return info
}
@@ -73,7 +73,7 @@ func ProcessConfigArgs(args []string, base64Encoded bool) ([]*ServiceKeyValue, e
resultSvcKV := make([]*ServiceKeyValue, len(args))
// qliksense.mongodb=somethig
for i, arg := range args {
LogDebugMessage("Arg received: %s", arg)
LogDebugMessage("Arg received: %s\n", arg)
first := strings.SplitN(arg, "=", 2)
if len(first) != 2 {
return nil, notValidErr

View File

@@ -3,6 +3,8 @@ package preflight
import (
"fmt"
"io/ioutil"
"os"
"path/filepath"
"strings"
"github.com/Masterminds/semver/v3"
@@ -14,7 +16,8 @@ import (
)
const (
mongo = "mongo"
preflight_mongo = "preflight-mongo"
caCertMountPath = "/etc/ssl/certs/ca-certificates.crt"
)
func (qp *QliksensePreflight) CheckMongo(kubeConfigContents []byte, namespace string, preflightOpts *PreflightOptions, cleanup bool) error {
@@ -22,32 +25,51 @@ func (qp *QliksensePreflight) CheckMongo(kubeConfigContents []byte, namespace st
qp.P.LogVerboseMessage("Preflight mongodb check: \n")
qp.P.LogVerboseMessage("------------------------ \n")
}
if preflightOpts != nil && preflightOpts.MongoOptions.MongodbUrl == "" && !cleanup {
var currentCR *qapi.QliksenseCR
var err error
qConfig := qapi.NewQConfig(qp.Q.QliksenseHome)
qConfig.SetNamespace(namespace)
currentCR, err = qConfig.GetCurrentCR()
if err != nil {
qp.P.LogVerboseMessage("Unable to retrieve current CR: %v\n", err)
return err
}
decryptedCR, err := qConfig.GetDecryptedCr(currentCR)
if err != nil {
qp.P.LogVerboseMessage("An error occurred while retrieving mongodbUrl from current CR: %v\n", err)
return err
}
if preflightOpts.MongoOptions.MongodbUrl == "" && !cleanup {
// infer mongoDbUrl from currentCR
qp.P.LogVerboseMessage("MongoDbUri is empty, infer from CR\n")
qConfig := qapi.NewQConfig(qp.Q.QliksenseHome)
var currentCR *qapi.QliksenseCR
var err error
qConfig.SetNamespace(namespace)
currentCR, err = qConfig.GetCurrentCR()
if err != nil {
qp.P.LogVerboseMessage("Unable to retrieve current CR: %v\n", err)
return err
}
decryptedCR, err := qConfig.GetDecryptedCr(currentCR)
if err != nil {
qp.P.LogVerboseMessage("An error occurred while retrieving mongodbUrl from current CR: %v\n", err)
return err
}
preflightOpts.MongoOptions.MongodbUrl = decryptedCR.Spec.GetFromSecrets("qliksense", "mongoDbUri")
preflightOpts.MongoOptions.MongodbUrl = strings.TrimSpace(decryptedCR.Spec.GetFromSecrets("qliksense", "mongoDbUri"))
}
if preflightOpts.MongoOptions.CaCertFile == "" && !cleanup {
caCertStr := decryptedCR.Spec.GetFromSecrets("qliksense", "caCertificates")
tmpDir := os.TempDir()
caCrtFile := filepath.Join(tmpDir, "rootCA.crt")
api.LogDebugMessage("received ca crt: %s\n", caCertStr)
if err := ioutil.WriteFile(caCrtFile, []byte(caCertStr), 0644); err != nil {
return fmt.Errorf("unable to write CA crt to file: %v", err)
}
preflightOpts.MongoOptions.CaCertFile = caCrtFile
}
if !cleanup {
qp.P.LogVerboseMessage("MongodbUrl: %s\n", preflightOpts.MongoOptions.MongodbUrl)
// if mongoDbUrl is empty, abort check
if preflightOpts.MongoOptions.MongodbUrl == "" {
qp.P.LogVerboseMessage("Mongodb Url is empty, hence aborting preflight check\n")
return errors.New("MongoDbUrl is empty")
}
}
if err := qp.mongoConnCheck(kubeConfigContents, namespace, preflightOpts, cleanup); err != nil {
return err
}
if !cleanup {
qp.P.LogVerboseMessage("Completed preflight mongodb check\n")
}
@@ -55,8 +77,7 @@ func (qp *QliksensePreflight) CheckMongo(kubeConfigContents []byte, namespace st
}
func (qp *QliksensePreflight) mongoConnCheck(kubeConfigContents []byte, namespace string, preflightOpts *PreflightOptions, cleanup bool) error {
caCertSecretName := "preflight-mongo-test-cacert"
clientCertSecretName := "preflight-mongo-test-clientcert"
caCertSecretName := "ca-certificates-crt"
mongoPodName := "pf-mongo-pod"
clientset, _, err := getK8SClientSet(kubeConfigContents, "")
if err != nil {
@@ -65,11 +86,11 @@ func (qp *QliksensePreflight) mongoConnCheck(kubeConfigContents []byte, namespac
}
// cleanup before starting check
qp.runMongoCleanup(clientset, namespace, mongoPodName, caCertSecretName, clientCertSecretName)
qp.runMongoCleanup(clientset, namespace, mongoPodName, caCertSecretName)
if cleanup {
return nil
}
var secrets []string
secrets := map[string]string{}
if preflightOpts.MongoOptions.CaCertFile != "" {
caCertSecret, err := qp.createSecret(clientset, namespace, preflightOpts.MongoOptions.CaCertFile, caCertSecretName)
if err != nil {
@@ -78,52 +99,19 @@ func (qp *QliksensePreflight) mongoConnCheck(kubeConfigContents []byte, namespac
}
defer qp.deleteK8sSecret(clientset, namespace, caCertSecret.Name)
secrets = append(secrets, caCertSecretName)
}
if preflightOpts.MongoOptions.ClientCertFile != "" {
clientCertSecret, err := qp.createSecret(clientset, namespace, preflightOpts.MongoOptions.ClientCertFile, clientCertSecretName)
if err != nil {
err = fmt.Errorf("unable to create a client cert kubernetes secret: %v\n", err)
return err
}
defer qp.deleteK8sSecret(clientset, namespace, clientCertSecret.Name)
secrets = append(secrets, clientCertSecretName)
secrets[caCertSecretName] = caCertMountPath
}
mongoCommand := strings.Builder{}
mongoCommand.WriteString(fmt.Sprintf("sleep 10;mongo %s", preflightOpts.MongoOptions.MongodbUrl))
if preflightOpts.MongoOptions.Username != "" {
mongoCommand.WriteString(fmt.Sprintf(" --username %s", preflightOpts.MongoOptions.Username))
api.LogDebugMessage("Adding username: Mongo command: %s\n", mongoCommand.String())
}
if preflightOpts.MongoOptions.Password != "" {
mongoCommand.WriteString(fmt.Sprintf(" --password %s", preflightOpts.MongoOptions.Password))
api.LogDebugMessage("Adding username and password\n")
}
if preflightOpts.MongoOptions.Tls || preflightOpts.MongoOptions.CaCertFile != "" || preflightOpts.MongoOptions.ClientCertFile != "" {
mongoCommand.WriteString(" --tls")
api.LogDebugMessage("Adding --tls: Mongo command: %s\n", mongoCommand.String())
}
if preflightOpts.MongoOptions.CaCertFile != "" {
mongoCommand.WriteString(fmt.Sprintf(" --tlsCAFile=/etc/ssl/%s/%[1]s", caCertSecretName))
api.LogDebugMessage("Adding caCertFile: Mongo command: %s\n", mongoCommand.String())
}
if preflightOpts.MongoOptions.ClientCertFile != "" {
mongoCommand.WriteString(fmt.Sprintf(" --tlsCertificateKeyFile=/etc/ssl/%s/%[1]s", clientCertSecretName))
api.LogDebugMessage("Adding clientCertFile: Mongo command: %s\n", mongoCommand.String())
}
mongoCommand.WriteString(` --eval "print(\"connected to mongo\")"`)
commandToRun := []string{"sh", "-c", mongoCommand.String()}
commandToRun := []string{"./preflight-mongo", fmt.Sprintf(`-url="%s"`, preflightOpts.MongoOptions.MongodbUrl)}
api.LogDebugMessage("Mongo command: %s\n", strings.Join(commandToRun, " "))
// create a pod
imageName, err := qp.GetPreflightConfigObj().GetImageName(mongo, true)
imageName, err := qp.GetPreflightConfigObj().GetImageName(preflight_mongo, true)
if err != nil {
err = fmt.Errorf("unable to retrieve image : %v\n", err)
return err
}
api.LogDebugMessage("image name to be used: %s\n", imageName)
mongoPod, err := qp.createPreflightTestPod(clientset, namespace, mongoPodName, imageName, secrets, commandToRun)
if err != nil {
err = fmt.Errorf("unable to create pod : %v\n", err)
@@ -152,7 +140,7 @@ func (qp *QliksensePreflight) mongoConnCheck(kubeConfigContents []byte, namespac
}
// check if connection succeeded
stringToCheck := "Implicit session:"
stringToCheck := "qlik - connection succeeded!!"
if strings.Contains(logStr, stringToCheck) {
qp.P.LogVerboseMessage("Preflight mongo check: PASSED\n")
} else {
@@ -165,17 +153,16 @@ func (qp *QliksensePreflight) mongoConnCheck(kubeConfigContents []byte, namespac
func (qp *QliksensePreflight) checkMongoVersion(logStr string) (bool, error) {
// check mongo server version
api.LogDebugMessage("Minimum required mongo version: %s\n", qp.GetPreflightConfigObj().GetMinMongoVersion())
mongoVersionStrToCheck := "MongoDB server version:"
mongoVersionStrToCheck := "qlik mongo server version:"
if strings.Contains(logStr, mongoVersionStrToCheck) {
logLines := strings.Split(logStr, "\n")
for _, eachline := range logLines {
if strings.Contains(eachline, mongoVersionStrToCheck) {
mongoVersionLog := strings.Split(eachline, ":")
if len(mongoVersionLog) < 2 {
continue
}
mongoVersionStr := strings.TrimSpace(mongoVersionLog[1])
mongoVersionStr := strings.ReplaceAll(strings.TrimSpace(mongoVersionLog[1]), `"`, "")
api.LogDebugMessage("Extracted mongo version from pod log: %s\n", mongoVersionStr)
currentMongoVersionSemver, err := semver.NewVersion(mongoVersionStr)
if err != nil {
@@ -208,14 +195,13 @@ func (qp *QliksensePreflight) createSecret(clientset *kubernetes.Clientset, name
certSecret, err := qp.createPreflightTestSecret(clientset, namespace, certSecretName, certBytes)
if err != nil {
err = fmt.Errorf("unable to create secret with ca cert : %v\n", err)
err = fmt.Errorf("unable to create secret with cert : %v\n", err)
return nil, err
}
return certSecret, nil
}
func (qp *QliksensePreflight) runMongoCleanup(clientset *kubernetes.Clientset, namespace, mongoPodName, caCertSecretName, clientCertSecretName string) {
func (qp *QliksensePreflight) runMongoCleanup(clientset *kubernetes.Clientset, namespace, mongoPodName, caCertSecretName string) {
qp.deletePod(clientset, namespace, mongoPodName)
qp.deleteK8sSecret(clientset, namespace, caCertSecretName)
qp.deleteK8sSecret(clientset, namespace, clientCertSecretName)
}

View File

@@ -12,7 +12,6 @@ import (
"time"
"github.com/mitchellh/go-homedir"
"github.com/pkg/errors"
"github.com/qlik-oss/sense-installer/pkg/api"
"github.com/qlik-oss/sense-installer/pkg/qliksense"
appsv1 "k8s.io/api/apps/v1"
@@ -40,12 +39,8 @@ func (p *PreflightOptions) LogVerboseMessage(strMessage string, args ...interfac
}
type MongoOptions struct {
MongodbUrl string
Username string
Password string
CaCertFile string
ClientCertFile string
Tls bool
MongodbUrl string
CaCertFile string
}
var gracePeriod int64 = 0
@@ -115,13 +110,13 @@ func getK8SClientSet(kubeconfig []byte, contextName string) (*kubernetes.Clients
if len(kubeconfig) == 0 {
clientConfig, err = rest.InClusterConfig()
if err != nil {
err = errors.Wrap(err, "Unable to load in-cluster kubeconfig")
err = fmt.Errorf("Unable to load in-cluster kubeconfig: %w", err)
return nil, nil, err
}
} else {
config, err := clientcmd.Load(kubeconfig)
if err != nil {
err = errors.Wrap(err, "Unable to load kubeconfig")
err = fmt.Errorf("Unable to load kubeconfig: %w", err)
return nil, nil, err
}
if contextName != "" {
@@ -129,13 +124,13 @@ 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")
err = fmt.Errorf("Unable to create client config from config: %w", err)
return nil, nil, err
}
}
clientset, err := kubernetes.NewForConfig(clientConfig)
if err != nil {
err = errors.Wrap(err, "Unable to create clientset")
err = fmt.Errorf("Unable to create clientset: %w", err)
return nil, nil, err
}
return clientset, clientConfig, nil
@@ -186,7 +181,7 @@ func (qp *QliksensePreflight) createPreflightTestDeployment(clientset *kubernete
result, err = deploymentsClient.Create(deployment)
return err
}); err != nil {
err = errors.Wrapf(err, "unable to create deployments in the %s namespace", namespace)
err = fmt.Errorf("unable to create deployments in the %s namespace: %w", namespace, err)
return nil, err
}
qp.P.LogVerboseMessage("Created deployment %q\n", result.GetObjectMeta().GetName())
@@ -201,7 +196,7 @@ func getDeployment(clientset *kubernetes.Clientset, namespace, depName string) (
deployment, err = deploymentsClient.Get(depName, v1.GetOptions{})
return err
}); err != nil {
err = errors.Wrapf(err, "unable to get deployments in the %s namespace", namespace)
err = fmt.Errorf("unable to get deployments in the %s namespace: %w", namespace, err)
api.LogDebugMessage("%v\n", err)
return nil, err
}
@@ -271,7 +266,7 @@ func getService(clientset *kubernetes.Clientset, namespace, svcName string) (*ap
svc, err = servicesClient.Get(svcName, v1.GetOptions{})
return err
}); err != nil {
err = errors.Wrapf(err, "unable to get services in the %s namespace", namespace)
err = fmt.Errorf("unable to get services in the %s namespace: %w", namespace, err)
return nil, err
}
@@ -314,7 +309,7 @@ func (qp *QliksensePreflight) deletePod(clientset *kubernetes.Clientset, namespa
return nil
}
func (qp *QliksensePreflight) 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 map[string]string, commandToRun []string) (*apiv1.Pod, error) {
// build the pod definition we want to deploy
pod := &apiv1.Pod{
ObjectMeta: v1.ObjectMeta{
@@ -337,7 +332,7 @@ func (qp *QliksensePreflight) createPreflightTestPod(clientset *kubernetes.Clien
},
}
if len(secretNames) > 0 {
for _, secretName := range secretNames {
for secretName, mountPath := range secretNames {
pod.Spec.Volumes = append(pod.Spec.Volumes, apiv1.Volume{
Name: secretName,
VolumeSource: apiv1.VolumeSource{
@@ -346,7 +341,7 @@ func (qp *QliksensePreflight) createPreflightTestPod(clientset *kubernetes.Clien
Items: []apiv1.KeyToPath{
{
Key: secretName,
Path: secretName,
Path: filepath.Base(mountPath),
},
},
},
@@ -355,7 +350,7 @@ func (qp *QliksensePreflight) createPreflightTestPod(clientset *kubernetes.Clien
if len(pod.Spec.Containers) > 0 {
pod.Spec.Containers[0].VolumeMounts = append(pod.Spec.Containers[0].VolumeMounts, apiv1.VolumeMount{
Name: secretName,
MountPath: "/etc/ssl/" + secretName,
MountPath: filepath.Dir(mountPath),
ReadOnly: true,
})
}
@@ -470,13 +465,13 @@ func waitForPod(clientset *kubernetes.Clientset, namespace string, pod *apiv1.Po
}
validateFunc := func(data interface{}) bool {
po := data.(*apiv1.Pod)
return len(po.Status.ContainerStatuses) > 0 && po.Status.ContainerStatuses[0].Ready
return po.Status.Phase == apiv1.PodRunning || po.Status.Phase == apiv1.PodSucceeded || po.Status.Phase == apiv1.PodFailed
}
if err := waitForResource(checkFunc, validateFunc); err != nil {
return err
}
if len(pod.Status.ContainerStatuses) == 0 || !pod.Status.ContainerStatuses[0].Ready {
if pod.Status.Phase != apiv1.PodRunning && pod.Status.Phase != apiv1.PodSucceeded && pod.Status.Phase != apiv1.PodFailed {
err = fmt.Errorf("container is taking much longer than expected")
return err
}
@@ -491,7 +486,6 @@ func waitForPodToDie(clientset *kubernetes.Clientset, namespace string, pod *api
err = fmt.Errorf("unable to retrieve %s pod by name", podName)
return nil, err
}
api.LogDebugMessage("pod status: %v\n", po.Status.Phase)
return po, nil
}
validateFunc := func(r interface{}) bool {

View File

@@ -1,10 +0,0 @@
package preflight
import (
"fmt"
)
func (qp *QliksensePreflight) CheckStorageClass(namespace string, kubeConfigContents []byte, cleanup bool) error {
fmt.Println("Hello From Preflight storageclass check")
return nil
}

View File

@@ -18,12 +18,12 @@ import (
b64 "encoding/base64"
. "github.com/logrusorgru/aurora"
ansi "github.com/mattn/go-colorable"
"github.com/qlik-oss/sense-installer/pkg/api"
_ "gopkg.in/yaml.v2"
v1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
. "github.com/logrusorgru/aurora"
)
const (
@@ -62,7 +62,7 @@ func (q *Qliksense) SetSecrets(args []string, isSecretSet bool, base64Encoded bo
}
// Metadata name in qliksense CR is the name of the current context
api.LogDebugMessage("Current context: %s", qliksenseCR.GetName())
api.LogDebugMessage("Current context: %s\n", qliksenseCR.GetName())
encryptionKey, err := qConfig.GetEncryptionKeyForCurrent()
if err != nil {
return err
@@ -72,7 +72,7 @@ func (q *Qliksense) SetSecrets(args []string, isSecretSet bool, base64Encoded bo
return err
}
for _, ra := range resultArgs {
api.LogDebugMessage("value args to be encrypted: %s", ra.Value)
api.LogDebugMessage("value args to be encrypted: %s\n", ra.Value)
if err := q.processSecret(ra, encryptionKey, qliksenseCR, isSecretSet); err != nil {
return err
}
@@ -213,8 +213,8 @@ func validateCR(key string, keySub string, value string, crSpec *api.QliksenseCR
}
} else {
switch key {
case "gitops":
crSpec.Spec.GitOps = &config.GitOps{}
case "opsrunner":
crSpec.Spec.OpsRunner = &config.OpsRunner{}
case "git":
crSpec.Spec.Git = &config.Repo{}
}
@@ -248,8 +248,8 @@ func (q *Qliksense) SetOtherConfigs(args []string) error {
if err := q.processSetGit(arg, qliksenseCR); err != nil {
return err
}
} else if strings.HasPrefix(arg, "gitOps.") {
if err := q.processSetGitOps(arg, qliksenseCR); err != nil {
} else if strings.HasPrefix(arg, "opsRunner.") {
if err := q.processSetOpsRunner(arg, qliksenseCR); err != nil {
return err
}
} else {
@@ -337,27 +337,29 @@ func (q *Qliksense) processSetGit(arg string, cr *api.QliksenseCR) error {
return nil
}
func (q *Qliksense) processSetGitOps(arg string, cr *api.QliksenseCR) error {
func (q *Qliksense) processSetOpsRunner(arg string, cr *api.QliksenseCR) error {
args := strings.Split(arg, "=")
subs := strings.Split(args[0], ".")
if cr.Spec.Git == nil {
cr.Spec.GitOps = &config.GitOps{}
if cr.Spec.OpsRunner == nil {
cr.Spec.OpsRunner = &config.OpsRunner{}
}
switch subs[1] {
case "enabled":
if args[1] != "yes" && args[1] != "no" {
return errors.New("Please use yes or no for key enabled")
}
cr.Spec.GitOps.Enabled = args[1]
cr.Spec.OpsRunner.Enabled = args[1]
case "schedule":
if _, err := cron.ParseStandard(args[1]); err != nil {
return errors.New("Please enter string with standard cron scheduling syntax ")
}
cr.Spec.GitOps.Schedule = args[1]
cr.Spec.OpsRunner.Schedule = args[1]
case "watchBranch":
cr.Spec.GitOps.WatchBranch = args[1]
cr.Spec.OpsRunner.WatchBranch = args[1]
case "image":
cr.Spec.GitOps.Image = args[1]
cr.Spec.OpsRunner.Image = args[1]
case "crPvc":
cr.Spec.OpsRunner.CrPvc = args[1]
default:
return errors.New(arg + " does not match any cr spec")
}
@@ -411,7 +413,7 @@ func (q *Qliksense) DeleteContextConfig(args []string, flag bool) error {
out := ansi.NewColorableStdout()
switch args[0] {
case qliksenseConfig.Spec.CurrentContext:
fmt.Fprintln(out,Yellow("Please switch contexts to be able to delete this context."))
fmt.Fprintln(out, Yellow("Please switch contexts to be able to delete this context."))
err := fmt.Errorf(Red("Cannot delete current context - %s").String(), White(Bold(qliksenseConfig.Spec.CurrentContext)))
return err
case DefaultQliksenseContext:
@@ -452,7 +454,7 @@ func (q *Qliksense) DeleteContextConfig(args []string, flag bool) error {
if ans == true {
api.WriteToFile(&qliksenseConfig, qliksenseConfigFile)
fmt.Fprintln(out, Yellow(Underline("Warning: Active resources may still be running in-cluster")))
fmt.Fprintln(out, Green("Successfully deleted context: "),Bold(args[0]))
fmt.Fprintln(out, Green("Successfully deleted context: "), Bold(args[0]))
} else {
return nil
}

View File

@@ -244,7 +244,7 @@ func TestSetOtherConfigs(t *testing.T) {
q: &Qliksense{
QliksenseHome: testDir,
},
args: []string{"profile=minikube", "rotateKeys=yes", "storageClassName=efs", "gitOps.enabled=yes", "gitOps.schedule=30 * * * *", "git.repository=master", "git.userName=foo", "git.accessToken=1234"},
args: []string{"profile=minikube", "rotateKeys=yes", "storageClassName=efs", "opsRunner.enabled=yes", "opsRunner.schedule=30 * * * *", "git.repository=master", "git.userName=foo", "git.accessToken=1234"},
},
wantErr: false,
},
@@ -254,7 +254,7 @@ func TestSetOtherConfigs(t *testing.T) {
q: &Qliksense{
QliksenseHome: testDir,
},
args: []string{"someconfig=somevalue, gitOps.schedule=bar", "gitOps.enabled=bar", "git.foo=bar", "rotateKeys=bar"},
args: []string{"someconfig=somevalue, opsRunner.schedule=bar", "opsRunner.enabled=bar", "git.foo=bar", "rotateKeys=bar"},
},
wantErr: true,
},

View File

@@ -95,9 +95,9 @@ func (q *Qliksense) PullImagesForCurrentCR() error {
return nil
}
func (q *Qliksense) appendGitOpsImage(images *[]string, qcr *qapi.QliksenseCR) {
if qcr.Spec.GitOps != nil && qcr.Spec.GitOps.Image != "" {
*images = append(*images, qcr.Spec.GitOps.Image)
func (q *Qliksense) appendOpsRunnerImage(images *[]string, qcr *qapi.QliksenseCR) {
if qcr.Spec.OpsRunner != nil && qcr.Spec.OpsRunner.Image != "" {
*images = append(*images, qcr.Spec.OpsRunner.Image)
}
}
@@ -212,7 +212,7 @@ func (q *Qliksense) appendAdditionalImages(images *[]string, qcr *qapi.Qliksense
if err := q.appendOperatorImages(images); err != nil {
return err
}
q.appendGitOpsImage(images, qcr)
q.appendOpsRunnerImage(images, qcr)
q.appendPreflightImages(images)
return nil
}

View File

@@ -186,7 +186,7 @@ kind: Qliksense
metadata:
name: qlik-default
spec:
gitOps:
opsRunner:
image: some-gitops-image
`)
@@ -225,7 +225,7 @@ spec:
return false
}
if !haveMatchingImage(func(image string) bool {
return strings.Contains(image, "qlik-docker-oss.bintray.io/qliksense-operator:v")
return strings.Contains(image, "qlik-docker-oss.bintray.io/qliksense-operator:")
}) {
t.Fatal("expected to find the operator image in the list, but it wasn't there")
}
@@ -245,7 +245,7 @@ spec:
t.Fatal("expected to find the netcat Preflight image in the list, but it wasn't there")
}
if !haveMatchingImage(func(image string) bool {
return image == "mongo"
return image == "qlik-docker-oss.bintray.io/preflight-mongo"
}) {
t.Fatal("expected to find the mongo Preflight image in the list, but it wasn't there")
}