Compare commits

..

7 Commits

Author SHA1 Message Date
Ashwathi Shiva
26955d749e fixed typo 2020-05-08 16:33:30 -04:00
Ashwathi Shiva
3e678d9056 fixed typo 2020-05-08 16:32:38 -04:00
Ashwathi Shiva
ec9423330d updated docs and typo in help text 2020-05-08 16:18:26 -04:00
Ashwathi Shiva
c5b6443179 updated doc 2020-05-08 16:14:00 -04:00
Ashwathi Shiva
a228757e0b need for both priv key and pub key in the client cert 2020-05-08 15:35:11 -04:00
Ashwathi Shiva
8f2e464d0e Issue-85- replaced github-errors with golang equivalent 2020-05-08 00:34:30 -04:00
Ashwathi Shiva
9d547bfe0c mongo check working when ca cert and client cert put in same file 2020-05-08 00:09:25 -04:00
11 changed files with 132 additions and 42 deletions

View File

@@ -152,7 +152,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 +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,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.

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.2
github.com/qlik-oss/k-apis v0.1.1
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,8 +885,6 @@ 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,8 +157,6 @@ 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,6 +1,7 @@
package preflight
import (
"encoding/pem"
"fmt"
"io/ioutil"
"os"
@@ -74,8 +75,35 @@ func (qp *QliksensePreflight) CheckMongo(kubeConfigContents []byte, namespace st
return errors.New("MongoDbUrl is empty")
}
}
if err := qp.mongoConnCheck(kubeConfigContents, namespace, preflightOpts, cleanup); err != nil {
return err
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 !cleanup {
qp.P.LogVerboseMessage("Completed preflight mongodb check\n")
@@ -247,3 +275,41 @@ 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,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"
@@ -115,13 +114,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 +128,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 +185,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 +200,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 +270,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
}

View File

@@ -213,8 +213,8 @@ func validateCR(key string, keySub string, value string, crSpec *api.QliksenseCR
}
} else {
switch key {
case "opsrunner":
crSpec.Spec.OpsRunner = &config.OpsRunner{}
case "gitops":
crSpec.Spec.GitOps = &config.GitOps{}
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, "opsRunner.") {
if err := q.processSetOpsRunner(arg, qliksenseCR); err != nil {
} else if strings.HasPrefix(arg, "gitOps.") {
if err := q.processSetGitOps(arg, qliksenseCR); err != nil {
return err
}
} else {
@@ -337,29 +337,27 @@ func (q *Qliksense) processSetGit(arg string, cr *api.QliksenseCR) error {
return nil
}
func (q *Qliksense) processSetOpsRunner(arg string, cr *api.QliksenseCR) error {
func (q *Qliksense) processSetGitOps(arg string, cr *api.QliksenseCR) error {
args := strings.Split(arg, "=")
subs := strings.Split(args[0], ".")
if cr.Spec.OpsRunner == nil {
cr.Spec.OpsRunner = &config.OpsRunner{}
if cr.Spec.Git == nil {
cr.Spec.GitOps = &config.GitOps{}
}
switch subs[1] {
case "enabled":
if args[1] != "yes" && args[1] != "no" {
return errors.New("Please use yes or no for key enabled")
}
cr.Spec.OpsRunner.Enabled = args[1]
cr.Spec.GitOps.Enabled = args[1]
case "schedule":
if _, err := cron.ParseStandard(args[1]); err != nil {
return errors.New("Please enter string with standard cron scheduling syntax ")
}
cr.Spec.OpsRunner.Schedule = args[1]
cr.Spec.GitOps.Schedule = args[1]
case "watchBranch":
cr.Spec.OpsRunner.WatchBranch = args[1]
cr.Spec.GitOps.WatchBranch = args[1]
case "image":
cr.Spec.OpsRunner.Image = args[1]
case "crPvc":
cr.Spec.OpsRunner.CrPvc = args[1]
cr.Spec.GitOps.Image = 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", "opsRunner.enabled=yes", "opsRunner.schedule=30 * * * *", "git.repository=master", "git.userName=foo", "git.accessToken=1234"},
args: []string{"profile=minikube", "rotateKeys=yes", "storageClassName=efs", "gitOps.enabled=yes", "gitOps.schedule=30 * * * *", "git.repository=master", "git.userName=foo", "git.accessToken=1234"},
},
wantErr: false,
},
@@ -254,7 +254,7 @@ func TestSetOtherConfigs(t *testing.T) {
q: &Qliksense{
QliksenseHome: testDir,
},
args: []string{"someconfig=somevalue, opsRunner.schedule=bar", "opsRunner.enabled=bar", "git.foo=bar", "rotateKeys=bar"},
args: []string{"someconfig=somevalue, gitOps.schedule=bar", "gitOps.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) appendOpsRunnerImage(images *[]string, qcr *qapi.QliksenseCR) {
if qcr.Spec.OpsRunner != nil && qcr.Spec.OpsRunner.Image != "" {
*images = append(*images, qcr.Spec.OpsRunner.Image)
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)
}
}
@@ -212,7 +212,7 @@ func (q *Qliksense) appendAdditionalImages(images *[]string, qcr *qapi.Qliksense
if err := q.appendOperatorImages(images); err != nil {
return err
}
q.appendOpsRunnerImage(images, qcr)
q.appendGitOpsImage(images, qcr)
q.appendPreflightImages(images)
return nil
}

View File

@@ -186,7 +186,7 @@ kind: Qliksense
metadata:
name: qlik-default
spec:
opsRunner:
gitOps:
image: some-gitops-image
`)