Compare commits

..

3 Commits

Author SHA1 Message Date
Andriy Bulynko
86295bb155 - patching tests 2020-05-12 08:47:26 -04:00
Foysal Iqbal
ab73b290b0 fix ciper and update to use opsRunner
Signed-off-by: Foysal Iqbal <mqb@qlik.com>
2020-05-11 23:47:16 -04:00
Foysal Iqbal
4a781aa7d6 fix ciper and update to use opsRunner
Signed-off-by: Foysal Iqbal <mqb@qlik.com>
2020-05-11 23:43:06 -04:00
11 changed files with 42 additions and 132 deletions

View File

@@ -152,7 +152,7 @@ func pfDeploymentCheckCmd(q *qliksense.Qliksense) *cobra.Command {
}
var pfDeploymentCheckCmd = &cobra.Command{
Use: "deployment",
Short: "perform preflight deployment check",
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 {
@@ -337,7 +337,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 {

View File

@@ -16,18 +16,9 @@ Examples:
qliksense preflight <preflight_check_to_run>
Available Commands:
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
all perform all checks
dns perform preflight dns check
k8s-version check k8s version
Flags:
-h, --help help for preflight
@@ -209,8 +200,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:
@@ -226,29 +217,7 @@ 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.

2
go.mod
View File

@@ -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

2
go.sum
View File

@@ -885,6 +885,8 @@ github.com/prometheus/procfs v0.0.5/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDa
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/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.20200424070349-b0312eb71568 h1:wHOUCGfnmgYqW3aCjuP3fXmB2T/uZXMvltO+F3us83E=
github.com/qlik-oss/kustomize/api v0.3.3-0.20200424070349-b0312eb71568/go.mod h1:Yg8bqX8Mq/eSgXfcenxCxhZuSXg+NCsKq6NBdch/oUc=
github.com/quasilyte/go-consistent v0.0.0-20190521200055-c6f3937de18c/go.mod h1:5STLWrekHfjyYwxBRVRXNOSewLJ3PWfDJd1VyTS21fI=

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

@@ -1,7 +1,6 @@
package preflight
import (
"encoding/pem"
"fmt"
"io/ioutil"
"os"
@@ -75,35 +74,8 @@ func (qp *QliksensePreflight) CheckMongo(kubeConfigContents []byte, namespace st
return errors.New("MongoDbUrl is empty")
}
}
var privKeys []string
var err error
if preflightOpts.MongoOptions.CaCertFile != "" && preflightOpts.MongoOptions.ClientCertFile == "" {
privKeys, err = qp.extractPrivateKeysFromCA(preflightOpts.MongoOptions.CaCertFile)
if err != nil {
return fmt.Errorf("unable to parse CA cert: %v", err)
}
}
privKeyCount := len(privKeys)
if privKeyCount == 0 {
api.LogDebugMessage("no private keys extrated from CA, hence proceeding with usual flow\n")
if err := qp.mongoConnCheck(kubeConfigContents, namespace, preflightOpts, cleanup); err != nil {
return err
}
} else {
api.LogDebugMessage("found %d private keys\n", privKeyCount)
successCount := 0
for _, privKey := range privKeys {
preflightOpts.MongoOptions.ClientCertFile = privKey
if err1 := qp.mongoConnCheck(kubeConfigContents, namespace, preflightOpts, cleanup); err1 != nil {
err = err1
continue
}
successCount++
break
}
if successCount == 0 {
return err
}
if err := qp.mongoConnCheck(kubeConfigContents, namespace, preflightOpts, cleanup); err != nil {
return err
}
if !cleanup {
qp.P.LogVerboseMessage("Completed preflight mongodb check\n")
@@ -275,41 +247,3 @@ func (qp *QliksensePreflight) runMongoCleanup(clientset *kubernetes.Clientset, n
qp.deleteK8sSecret(clientset, namespace, caCertSecretName)
qp.deleteK8sSecret(clientset, namespace, clientCertSecretName)
}
func (qp *QliksensePreflight) extractPrivateKeysFromCA(cafile string) ([]string, error) {
api.LogDebugMessage("extracting private keys from CA file: %s\n", cafile)
raw, err := ioutil.ReadFile(cafile)
if err != nil {
return nil, err
}
dirPath := os.TempDir()
count := 0
var files []string
for {
block, rest := pem.Decode(raw)
if block == nil {
break
}
if block.Type != "CERTIFICATE" {
api.LogDebugMessage("found a private key\n")
privFile := filepath.Join(dirPath, fmt.Sprintf("mongo_priv_%d.key", count+1))
api.LogDebugMessage("creating a private key file: %s\n", privFile)
keyData := pem.EncodeToMemory(block)
block, rest = pem.Decode(rest)
if block != nil && block.Type == "CERTIFICATE" {
api.LogDebugMessage("block type: %s\n", block.Type)
keyData = append(keyData, pem.EncodeToMemory(block)...)
}
api.LogDebugMessage("key data: %s\n", keyData)
if err := ioutil.WriteFile(privFile, keyData, 0600); err != nil {
return nil, fmt.Errorf("error writing private key to file: \"%s\"", privFile)
}
api.LogDebugMessage("successfully wrote contents to the private key file\n")
files = append(files, privFile)
count++
}
raw = rest
}
api.LogDebugMessage("extracted private key files: %v\n", files)
return files, nil
}

View File

@@ -12,6 +12,7 @@ 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"
@@ -114,13 +115,13 @@ func getK8SClientSet(kubeconfig []byte, contextName string) (*kubernetes.Clients
if len(kubeconfig) == 0 {
clientConfig, err = rest.InClusterConfig()
if err != nil {
err = fmt.Errorf("Unable to load in-cluster kubeconfig: %w", err)
err = errors.Wrap(err, "Unable to load in-cluster kubeconfig")
return nil, nil, err
}
} else {
config, err := clientcmd.Load(kubeconfig)
if err != nil {
err = fmt.Errorf("Unable to load kubeconfig: %w", err)
err = errors.Wrap(err, "Unable to load kubeconfig")
return nil, nil, err
}
if contextName != "" {
@@ -128,13 +129,13 @@ func getK8SClientSet(kubeconfig []byte, contextName string) (*kubernetes.Clients
}
clientConfig, err = clientcmd.NewDefaultClientConfig(*config, &clientcmd.ConfigOverrides{}).ClientConfig()
if err != nil {
err = fmt.Errorf("Unable to create client config from config: %w", err)
err = errors.Wrap(err, "Unable to create client config from config")
return nil, nil, err
}
}
clientset, err := kubernetes.NewForConfig(clientConfig)
if err != nil {
err = fmt.Errorf("Unable to create clientset: %w", err)
err = errors.Wrap(err, "Unable to create clientset")
return nil, nil, err
}
return clientset, clientConfig, nil
@@ -185,7 +186,7 @@ func (qp *QliksensePreflight) createPreflightTestDeployment(clientset *kubernete
result, err = deploymentsClient.Create(deployment)
return err
}); err != nil {
err = fmt.Errorf("unable to create deployments in the %s namespace: %w", namespace, err)
err = errors.Wrapf(err, "unable to create deployments in the %s namespace", namespace)
return nil, err
}
qp.P.LogVerboseMessage("Created deployment %q\n", result.GetObjectMeta().GetName())
@@ -200,7 +201,7 @@ func getDeployment(clientset *kubernetes.Clientset, namespace, depName string) (
deployment, err = deploymentsClient.Get(depName, v1.GetOptions{})
return err
}); err != nil {
err = fmt.Errorf("unable to get deployments in the %s namespace: %w", namespace, err)
err = errors.Wrapf(err, "unable to get deployments in the %s namespace", namespace)
api.LogDebugMessage("%v\n", err)
return nil, err
}
@@ -270,7 +271,7 @@ func getService(clientset *kubernetes.Clientset, namespace, svcName string) (*ap
svc, err = servicesClient.Get(svcName, v1.GetOptions{})
return err
}); err != nil {
err = fmt.Errorf("unable to get services in the %s namespace: %w", namespace, err)
err = errors.Wrapf(err, "unable to get services in the %s namespace", namespace)
return nil, err
}

View File

@@ -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")
}

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
`)