1
0
mirror of synced 2025-12-19 18:05:53 -05:00

Rotate keys overhaul (#432)

This commit is contained in:
Andriy Bulynko
2020-06-23 09:38:45 -04:00
committed by GitHub
parent c2d3f39542
commit 616e759089
23 changed files with 123 additions and 152 deletions

View File

@@ -19,7 +19,7 @@ func about(q *qliksense.Qliksense) *cobra.Command {
c := &cobra.Command{ c := &cobra.Command{
Use: "about ref", Use: "about ref",
Short: "Displays information pertaining to Qliksense on Kubernetes", Short: "Displays information pertaining to qliksense on Kubernetes",
Long: "Gives the version of QLik Sense on Kubernetes and versions of images.", Long: "Gives the version of QLik Sense on Kubernetes and versions of images.",
Example: ` Example: `
qliksense about 1.0.0 qliksense about 1.0.0

View File

@@ -24,7 +24,6 @@ func applyCmd(q *qliksense.Qliksense) *cobra.Command {
f.StringVarP(&filePath, "file", "f", "", "Install from a CR file") f.StringVarP(&filePath, "file", "f", "", "Install from a CR file")
f.StringVarP(&opts.StorageClass, "storageClass", "s", "", "Storage class for qliksense") 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.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(&opts.CleanPatchFiles, cleanPatchFilesFlagName, opts.CleanPatchFiles, cleanPatchFilesFlagUsage) f.BoolVar(&opts.CleanPatchFiles, cleanPatchFilesFlagName, opts.CleanPatchFiles, cleanPatchFilesFlagUsage)
f.BoolVarP(&opts.Pull, pullFlagName, pullFlagShorthand, opts.Pull, pullFlagUsage) f.BoolVarP(&opts.Pull, pullFlagName, pullFlagShorthand, opts.Pull, pullFlagUsage)
f.BoolVarP(&opts.Push, pushFlagName, pushFlagShorthand, opts.Push, pushFlagUsage) f.BoolVarP(&opts.Push, pushFlagName, pushFlagShorthand, opts.Push, pushFlagUsage)

View File

@@ -34,8 +34,8 @@ func crdsInstallCmd(q *qliksense.Qliksense) *cobra.Command {
} }
c := &cobra.Command{ c := &cobra.Command{
Use: "install", Use: "install",
Short: "Install CRDs for Qliksense application. Use install --all=false to exclude the operator CRD", Short: "Install CRDs for qliksense application. Use install --all=false to exclude the operator CRD",
Long: "Install CRDs for Qliksense application. Use install --all=false to exclude the operator CRD", Long: "Install CRDs for qliksense application. Use install --all=false to exclude the operator CRD",
RunE: func(cmd *cobra.Command, args []string) error { RunE: func(cmd *cobra.Command, args []string) error {
return q.InstallCrds(opts) return q.InstallCrds(opts)
}, },

View File

@@ -28,11 +28,13 @@ func installCmd(q *qliksense.Qliksense) *cobra.Command {
return err return err
} }
} else { } else {
if err1 := q.InstallQK8s(version, opts); err1 != nil { if err := q.InstallQK8s(version, opts); err != nil {
return err1 return err
} }
} }
return AllPostflightChecks(q).Execute() postflightChecksCmd := AllPostflightChecks(q)
postflightChecksCmd.DisableFlagParsing = true
return postflightChecksCmd.Execute()
}, },
} }
@@ -40,7 +42,6 @@ func installCmd(q *qliksense.Qliksense) *cobra.Command {
f.StringVarP(&filePath, "file", "f", "", "Install from a CR file") f.StringVarP(&filePath, "file", "f", "", "Install from a CR file")
f.StringVarP(&opts.StorageClass, "storageClass", "s", "", "Storage class for qliksense") 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.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(&opts.CleanPatchFiles, cleanPatchFilesFlagName, opts.CleanPatchFiles, cleanPatchFilesFlagUsage) f.BoolVar(&opts.CleanPatchFiles, cleanPatchFilesFlagName, opts.CleanPatchFiles, cleanPatchFilesFlagUsage)
f.BoolVarP(&opts.Pull, pullFlagName, pullFlagShorthand, opts.Pull, pullFlagUsage) f.BoolVarP(&opts.Pull, pullFlagName, pullFlagShorthand, opts.Pull, pullFlagUsage)
f.BoolVarP(&opts.Push, pushFlagName, pushFlagShorthand, opts.Push, pushFlagUsage) f.BoolVarP(&opts.Push, pushFlagName, pushFlagShorthand, opts.Push, pushFlagUsage)

31
cmd/qliksense/keys.go Normal file
View File

@@ -0,0 +1,31 @@
package main
import (
"github.com/qlik-oss/sense-installer/pkg/qliksense"
"github.com/spf13/cobra"
)
var keysCmd = &cobra.Command{
Use: "keys",
Short: "keys for qliksense",
}
func keysRotateCmd(q *qliksense.Qliksense) *cobra.Command {
c := &cobra.Command{
Use: "rotate",
Short: "Rotate qliksense application keys",
RunE: func(cmd *cobra.Command, args []string) error {
if err := q.InstallQK8s("", &qliksense.InstallCommandOptions{
CleanPatchFiles: true,
RotateKeys: true,
}); err != nil {
return err
} else {
postFlightChecksCmd := AllPostflightChecks(q)
postFlightChecksCmd.DisableFlagParsing = true
return postFlightChecksCmd.Execute()
}
},
}
return c
}

View File

@@ -28,10 +28,10 @@ const (
cleanPatchFilesFlagUsage = "Set --clean=false to keep any prior config repo file changes on install (for debugging)" cleanPatchFilesFlagUsage = "Set --clean=false to keep any prior config repo file changes on install (for debugging)"
pullFlagName = "pull" pullFlagName = "pull"
pullFlagShorthand = "d" pullFlagShorthand = "d"
pullFlagUsage = "If using private docker registry, pull (download) all required Qliksense images before install" pullFlagUsage = "If using private docker registry, pull (download) all required qliksense images before install"
pushFlagName = "push" pushFlagName = "push"
pushFlagShorthand = "u" pushFlagShorthand = "u"
pushFlagUsage = "If using private docker registry, push (upload) all downloaded Qliksense images to that registry before install" pushFlagUsage = "If using private docker registry, push (upload) all downloaded qliksense images to that registry before install"
rootCommandName = "qliksense" rootCommandName = "qliksense"
) )
@@ -100,7 +100,7 @@ func commandUsesContext(commandName string) bool {
func getRootCmd(p *qliksense.Qliksense) *cobra.Command { func getRootCmd(p *qliksense.Qliksense) *cobra.Command {
cmd := &cobra.Command{ cmd := &cobra.Command{
Use: rootCommandName, Use: rootCommandName,
Short: "Qliksense cli tool", Short: "qliksense cli tool",
Long: `qliksense cli tool provides functionality to perform operations on qliksense-k8s, qliksense operator, and kubernetes cluster`, Long: `qliksense cli tool provides functionality to perform operations on qliksense-k8s, qliksense operator, and kubernetes cluster`,
Args: cobra.ArbitraryArgs, Args: cobra.ArbitraryArgs,
PersistentPreRun: func(cmd *cobra.Command, args []string) { PersistentPreRun: func(cmd *cobra.Command, args []string) {
@@ -221,6 +221,10 @@ func rootCmd(p *qliksense.Qliksense) *cobra.Command {
postflightCmd.AddCommand(AllPostflightChecks(p)) postflightCmd.AddCommand(AllPostflightChecks(p))
cmd.AddCommand(postflightCmd) cmd.AddCommand(postflightCmd)
// add keys command
cmd.AddCommand(keysCmd)
keysCmd.AddCommand(keysRotateCmd(p))
return cmd return cmd
} }

View File

@@ -74,7 +74,6 @@ spec:
- name: mongodbUri - name: mongodbUri
value: mongodb://qlik-test-mongodb:27017/qliksense?ssl=false value: mongodb://qlik-test-mongodb:27017/qliksense?ssl=false
profile: docker-desktop profile: docker-desktop
rotateKeys: "yes"
``` ```
`qliksense apply` does everything `qliksense load` does but will install Qlik Sense into the cluster as well `qliksense apply` does everything `qliksense load` does but will install Qlik Sense into the cluster as well

View File

@@ -25,7 +25,6 @@ spec:
qliksense: qliksense:
- name: mongodbUri - name: mongodbUri
value: mongodb://qlik-default-mongodb:27017/qliksense?ssl=false value: mongodb://qlik-default-mongodb:27017/qliksense?ssl=false
rotateKeys: "yes"
releaseName: qlik-default releaseName: qlik-default
``` ```

2
go.mod
View File

@@ -40,7 +40,7 @@ require (
github.com/mitchellh/go-homedir v1.1.0 github.com/mitchellh/go-homedir v1.1.0
github.com/otiai10/copy v1.1.1 github.com/otiai10/copy v1.1.1
github.com/pkg/errors v0.9.1 github.com/pkg/errors v0.9.1
github.com/qlik-oss/k-apis v0.1.10 github.com/qlik-oss/k-apis v0.1.16
github.com/robfig/cron/v3 v3.0.1 github.com/robfig/cron/v3 v3.0.1
github.com/rogpeppe/go-internal v1.5.2 // indirect github.com/rogpeppe/go-internal v1.5.2 // indirect
github.com/spf13/cobra v0.0.6 github.com/spf13/cobra v0.0.6

4
go.sum
View File

@@ -885,8 +885,8 @@ 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 h1:3+auTFlqw+ZaQYJARz6ArODtkaIwtvBTx3N2NehQlL8=
github.com/prometheus/procfs v0.0.5/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ= 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/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU=
github.com/qlik-oss/k-apis v0.1.10 h1:adBXokJpE7oOr9wkPOHgpVbvuhLLKtqFdnX7V9MEyOs= github.com/qlik-oss/k-apis v0.1.16 h1:R3gCZs4A3EHPNx4B7p1idWD+OhyaU/bAlGYBWc0ZNz4=
github.com/qlik-oss/k-apis v0.1.10/go.mod h1:qJVbbSYtZ+fFCojEyG9UoiCAmymm0JEtnhulr5M7HyU= github.com/qlik-oss/k-apis v0.1.16/go.mod h1:AkNa/kaZHpGVs9l+pHe6nvz99Sp9WO1f9ylBES95o+I=
github.com/qlik-oss/kustomize/api v0.3.3-0.20200612023448-4c1f2f38ea9b h1:RDh3OZJOriy/ap1NUHVKsPG07N4DALaCzaqXFFK57T0= github.com/qlik-oss/kustomize/api v0.3.3-0.20200612023448-4c1f2f38ea9b h1:RDh3OZJOriy/ap1NUHVKsPG07N4DALaCzaqXFFK57T0=
github.com/qlik-oss/kustomize/api v0.3.3-0.20200612023448-4c1f2f38ea9b/go.mod h1:zh3yFgE5zFk1kreqzVyyj1eXyIxQJT53l4zSg8Wt4SA= github.com/qlik-oss/kustomize/api v0.3.3-0.20200612023448-4c1f2f38ea9b/go.mod h1:zh3yFgE5zFk1kreqzVyyj1eXyIxQJT53l4zSg8Wt4SA=
github.com/quasilyte/go-consistent v0.0.0-20190521200055-c6f3937de18c/go.mod h1:5STLWrekHfjyYwxBRVRXNOSewLJ3PWfDJd1VyTS21fI= github.com/quasilyte/go-consistent v0.0.0-20190521200055-c6f3937de18c/go.mod h1:5STLWrekHfjyYwxBRVRXNOSewLJ3PWfDJd1VyTS21fI=

View File

@@ -23,7 +23,6 @@ const (
QliksenseKind = "Qliksense" QliksenseKind = "Qliksense"
QliksenseGroup = "qlik.com" QliksenseGroup = "qlik.com"
QliksenseDefaultProfile = "docker-desktop" QliksenseDefaultProfile = "docker-desktop"
DefaultRotateKeys = "yes"
QliksenseMetadataName = "QliksenseConfigMetadata" QliksenseMetadataName = "QliksenseConfigMetadata"
DefaultMongodbUri = "mongodb://qlik-default-mongodb:27017/qliksense?ssl=false" DefaultMongodbUri = "mongodb://qlik-default-mongodb:27017/qliksense?ssl=false"
DefaultMongodbUriKey = "mongodbUri" DefaultMongodbUriKey = "mongodbUri"
@@ -38,8 +37,7 @@ func (qliksenseCR *QliksenseCR) AddCommonConfig(contextName string) {
}) })
qliksenseCR.SetName(contextName) qliksenseCR.SetName(contextName)
qliksenseCR.Spec = &config.CRSpec{ qliksenseCR.Spec = &config.CRSpec{
Profile: QliksenseDefaultProfile, Profile: QliksenseDefaultProfile,
RotateKeys: DefaultRotateKeys,
} }
qliksenseCR.Spec.AddToSecrets("qliksense", DefaultMongodbUriKey, strings.Replace(DefaultMongodbUri, "qlik-default", contextName, 1), "") qliksenseCR.Spec.AddToSecrets("qliksense", DefaultMongodbUriKey, strings.Replace(DefaultMongodbUri, "qlik-default", contextName, 1), "")
} }

View File

@@ -23,8 +23,7 @@ func TestAddCommonConfig(t *testing.T) {
q.SetName("myqliksense") q.SetName("myqliksense")
q.SetGroupVersionKind(gvk) q.SetGroupVersionKind(gvk)
q.Spec = &config.CRSpec{ q.Spec = &config.CRSpec{
Profile: QliksenseDefaultProfile, Profile: QliksenseDefaultProfile,
RotateKeys: DefaultRotateKeys,
Secrets: map[string]config.NameValues{ Secrets: map[string]config.NameValues{
"qliksense": []config.NameValue{{ "qliksense": []config.NameValue{{
Name: DefaultMongodbUriKey, Name: DefaultMongodbUriKey,

View File

@@ -9,6 +9,8 @@ import (
"path/filepath" "path/filepath"
"strings" "strings"
"github.com/qlik-oss/k-apis/pkg/config"
"github.com/mitchellh/go-homedir" "github.com/mitchellh/go-homedir"
"gopkg.in/yaml.v2" "gopkg.in/yaml.v2"
@@ -74,23 +76,21 @@ func (q *Qliksense) configEjson() error {
} }
func (q *Qliksense) applyConfigToK8s(qcr *qapi.QliksenseCR) error { func (q *Qliksense) applyConfigToK8s(qcr *qapi.QliksenseCR) error {
if qcr.Spec.RotateKeys != "None" { if err := q.configEjson(); err != nil {
if err := q.configEjson(); err != nil { return err
return err
}
} }
userHomeDir, err := homedir.Dir() userHomeDir, err := homedir.Dir()
if err != nil { if err != nil {
fmt.Printf(`error fetching user's home directory: %v\n`, err) fmt.Printf(`error fetching user's home directory: %v\n`, err)
return err return err
} }
fmt.Println("Manifests root: " + qcr.Spec.GetManifestsRoot())
qcr.SetNamespace(qapi.GetKubectlNamespace()) qcr.SetNamespace(qapi.GetKubectlNamespace())
b, _ := yaml.Marshal(qcr.KApiCr) b, _ := yaml.Marshal(qcr.KApiCr)
fmt.Printf("%v", string(b)) fmt.Printf("%v", string(b))
// os.Exit(0) // os.Exit(0)
// generate patches // generate patches
cr.GeneratePatches(&qcr.KApiCr, path.Join(userHomeDir, ".kube", "config")) cr.GeneratePatches(&qcr.KApiCr, config.KeysActionRestoreOrRotate, path.Join(userHomeDir, ".kube", "config"))
// apply generated manifests // apply generated manifests
profilePath := filepath.Join(qcr.Spec.GetManifestsRoot(), qcr.Spec.GetProfileDir()) profilePath := filepath.Join(qcr.Spec.GetManifestsRoot(), qcr.Spec.GetProfileDir())
fmt.Printf("Generating manifests for profile: %v\n", profilePath) fmt.Printf("Generating manifests for profile: %v\n", profilePath)

View File

@@ -176,53 +176,6 @@ func caseInsenstiveFieldByName(v reflect.Value, name string) reflect.Value {
return v.FieldByNameFunc(func(n string) bool { return strings.ToLower(n) == name }) return v.FieldByNameFunc(func(n string) bool { return strings.ToLower(n) == name })
} }
func validateCR(key string, keySub string, value string, crSpec *api.QliksenseCR) (bool, *api.QliksenseCR) {
cr := reflect.ValueOf(crSpec.Spec)
keyValid := caseInsenstiveFieldByName(reflect.Indirect(cr), key)
if !keyValid.IsValid() {
//not in main spec
fmt.Println(key, "is an invalid key")
return false, crSpec
} else if keySub == "" {
if key == "rotatekeys" {
if _, err := validateInput(value); err != nil {
return false, crSpec
}
}
}
// checks if it is git or gitops
if keySub != "" {
if !keyValid.IsNil() {
if !caseInsenstiveFieldByName(reflect.Indirect(keyValid), keySub).IsValid() {
fmt.Println(keySub, "is an invalid key")
return false, crSpec
} else {
// verify gitops enabled and gitops schedule
switch keySub {
case "schedule":
if _, err := cron.ParseStandard(value); err != nil {
fmt.Println("Please enter string with standard cron scheduling syntax ")
return false, crSpec
}
case "enabled":
if !strings.EqualFold(value, "yes") && !strings.EqualFold(value, "no") {
fmt.Println("Please use yes or no for key enabled")
return false, crSpec
}
}
}
} else {
switch key {
case "opsrunner":
crSpec.Spec.OpsRunner = &config.OpsRunner{}
case "git":
crSpec.Spec.Git = &config.Repo{}
}
}
}
return true, crSpec
}
// SetOtherConfigs - set profile/storageclassname/git.repository/manifestRoot commands // SetOtherConfigs - set profile/storageclassname/git.repository/manifestRoot commands
func (q *Qliksense) SetOtherConfigs(args []string) error { func (q *Qliksense) SetOtherConfigs(args []string) error {
// retieve current context from config.yaml // retieve current context from config.yaml
@@ -269,19 +222,8 @@ func processSetSingleArg(arg string, cr *api.QliksenseCR) error {
cr.Spec.Profile = nv[1] cr.Spec.Profile = nv[1]
case "storageClassName": case "storageClassName":
cr.Spec.StorageClassName = nv[1] cr.Spec.StorageClassName = nv[1]
case "rotateKeys":
valid := false
for _, v := range []string{"yes", "no", "None"} {
if nv[1] == v {
valid = true
}
}
if !valid {
return errors.New("please povide rotateKeys=yes|no|None")
}
cr.Spec.RotateKeys = nv[1]
default: default:
return errors.New("Please enter one of: profile, storageClassName,rotateKeys, manifestRoot, git to configure the current context") return errors.New("Please enter one of: profile, storageClassName, manifestRoot, git to configure the current context")
} }
return nil return nil
} }

View File

@@ -96,7 +96,6 @@ metadata:
name: qlik-default name: qlik-default
spec: spec:
profile: docker-desktop profile: docker-desktop
rotateKeys: "yes"
releaseName: qlik-default releaseName: qlik-default
` `
qlikDefaultContext := "qlik-default" qlikDefaultContext := "qlik-default"
@@ -244,7 +243,7 @@ func TestSetOtherConfigs(t *testing.T) {
q: &Qliksense{ q: &Qliksense{
QliksenseHome: testDir, 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", "storageClassName=efs", "opsRunner.enabled=yes", "opsRunner.schedule=30 * * * *", "git.repository=master", "git.userName=foo", "git.accessToken=1234"},
}, },
wantErr: false, wantErr: false,
}, },
@@ -254,7 +253,7 @@ func TestSetOtherConfigs(t *testing.T) {
q: &Qliksense{ q: &Qliksense{
QliksenseHome: testDir, QliksenseHome: testDir,
}, },
args: []string{"someconfig=somevalue, opsRunner.schedule=bar", "opsRunner.enabled=bar", "git.foo=bar", "rotateKeys=bar"}, args: []string{"someconfig=somevalue, opsRunner.schedule=bar", "opsRunner.enabled=bar", "git.foo=bar"},
}, },
wantErr: true, wantErr: true,
}, },
@@ -744,7 +743,6 @@ metadata:
name: qlik-default name: qlik-default
spec: spec:
profile: docker-desktop profile: docker-desktop
rotateKeys: "yes"
releaseName: qlik-default releaseName: qlik-default
` `
qlikDefaultContext := "qlik-default" qlikDefaultContext := "qlik-default"
@@ -763,7 +761,6 @@ metadata:
name: qlik1 name: qlik1
spec: spec:
profile: docker-desktop profile: docker-desktop
rotateKeys: "yes"
releaseName: qlik1` releaseName: qlik1`
contextYaml2 := contextYaml2 :=
@@ -774,7 +771,6 @@ metadata:
name: qlik2 name: qlik2
spec: spec:
profile: docker-desktop profile: docker-desktop
rotateKeys: "yes"
releaseName: qlik2` releaseName: qlik2`
contextsDir := filepath.Join(testDir, contexts, "qlik1") contextsDir := filepath.Join(testDir, contexts, "qlik1")

View File

@@ -16,7 +16,7 @@ func TestUnsetAll(t *testing.T) {
testPepareDir(qHome) testPepareDir(qHome)
defer os.RemoveAll(qHome) defer os.RemoveAll(qHome)
//fmt.Print(qHome) //fmt.Print(qHome)
args := []string{"rotateKeys", "qliksense", "qliksense2.acceptEula3", "serviceA.acceptEula", "opsRunner.watchBranch"} args := []string{"qliksense", "qliksense2.acceptEula3", "serviceA.acceptEula", "opsRunner.watchBranch"}
//args := []string{"opsRunner"} //args := []string{"opsRunner"}
//args := []string{"opsRunner.watchBranch"} //args := []string{"opsRunner.watchBranch"}
if err := unsetAll(qHome, args); err != nil { if err := unsetAll(qHome, args); err != nil {
@@ -29,10 +29,6 @@ func TestUnsetAll(t *testing.T) {
t.Log("error while getting current cr", err) t.Log("error while getting current cr", err)
t.FailNow() t.FailNow()
} }
if qcr.Spec.RotateKeys != "" {
t.Log("Expected empty rotateKeys but got: " + qcr.Spec.RotateKeys)
t.Fail()
}
if qcr.Spec.Configs["qliksense"] != nil { if qcr.Spec.Configs["qliksense"] != nil {
t.Log("qliksense in configs not deleted") t.Log("qliksense in configs not deleted")
@@ -82,7 +78,6 @@ metadata:
name: qlik-default name: qlik-default
spec: spec:
profile: docker-desktop profile: docker-desktop
rotateKeys: "yes"
opsRunner: opsRunner:
enabled: "yes" enabled: "yes"
watchBranch: something watchBranch: something

View File

@@ -268,7 +268,6 @@ spec:
- name: imageRegistry - name: imageRegistry
value: %s value: %s
manifestsRoot: %s manifestsRoot: %s
rotateKeys: "yes"
releaseName: qlik-default releaseName: qlik-default
`, version, registry.url, manifestsRootDir) `, version, registry.url, manifestsRootDir)
setupQliksenseTestDefaultContext(t, tmpQlikSenseHome, cr) setupQliksenseTestDefaultContext(t, tmpQlikSenseHome, cr)

View File

@@ -7,7 +7,9 @@ import (
"os" "os"
"path" "path"
"path/filepath" "path/filepath"
"strconv"
"strings" "strings"
"time"
"github.com/mattn/go-tty" "github.com/mattn/go-tty"
@@ -22,12 +24,12 @@ import (
type InstallCommandOptions struct { type InstallCommandOptions struct {
StorageClass string StorageClass string
MongodbUri string MongodbUri string
RotateKeys string
AcceptEULA string AcceptEULA string
DryRun bool DryRun bool
Pull bool Pull bool
Push bool Push bool
CleanPatchFiles bool CleanPatchFiles bool
RotateKeys bool
} }
const ( const (
@@ -45,6 +47,14 @@ func (q *Qliksense) InstallQK8s(version string, opts *InstallCommandOptions) err
return err return err
} }
if !qcr.IsRepoExist() {
if err := fetchAndUpdateCR(qConfig, version); err != nil {
return err
} else if qcr, err = qConfig.GetCurrentCR(); err != nil {
return err
}
}
if opts.AcceptEULA != "" && opts.AcceptEULA != "yes" { if opts.AcceptEULA != "" && opts.AcceptEULA != "yes" {
enforceEula() enforceEula()
} else if opts.AcceptEULA == "" && !qcr.IsEULA() { } else if opts.AcceptEULA == "" && !qcr.IsEULA() {
@@ -58,8 +68,9 @@ func (q *Qliksense) InstallQK8s(version string, opts *InstallCommandOptions) err
if opts.StorageClass != "" { if opts.StorageClass != "" {
qcr.Spec.StorageClassName = opts.StorageClass qcr.Spec.StorageClassName = opts.StorageClass
} }
if opts.RotateKeys != "" {
qcr.Spec.RotateKeys = opts.RotateKeys if err := qConfig.WriteCurrentContextCR(qcr); err != nil {
return err
} }
if opts.CleanPatchFiles { if opts.CleanPatchFiles {
@@ -71,13 +82,11 @@ func (q *Qliksense) InstallQK8s(version string, opts *InstallCommandOptions) err
// for debugging purpose // for debugging purpose
if opts.DryRun { if opts.DryRun {
// generate patches // generate patches
qcr.Spec.RotateKeys = "None"
userHomeDir, _ := homedir.Dir() userHomeDir, _ := homedir.Dir()
fmt.Println("Generating patches only") fmt.Println("Generating patches only")
cr.GeneratePatches(&qcr.KApiCr, path.Join(userHomeDir, ".kube", "config")) cr.GeneratePatches(&qcr.KApiCr, config.KeysActionDoNothing, path.Join(userHomeDir, ".kube", "config"))
return nil return nil
} }
qConfig.WriteCurrentContextCR(qcr)
if installed, err := q.CheckAllCrdsInstalled(); err != nil { if installed, err := q.CheckAllCrdsInstalled(); err != nil {
fmt.Println("error verifying whether CRDs are installed", err) fmt.Println("error verifying whether CRDs are installed", err)
@@ -123,6 +132,18 @@ func (q *Qliksense) InstallQK8s(version string, opts *InstallCommandOptions) err
return err return err
} }
if opts.RotateKeys {
fmt.Println("Deleting stored application keys")
if err := q.DeleteKeysClusterBackup(); err != nil {
return err
} else {
qcr.AddLabelToCr("keys-rotated", strconv.FormatInt(time.Now().Unix(), 10))
if err := qConfig.WriteCurrentContextCR(qcr); err != nil {
return err
}
}
}
if qcr.Spec.OpsRunner != nil { if qcr.Spec.OpsRunner != nil {
// fetching and applying manifest will be in the operator controller // fetching and applying manifest will be in the operator controller
// get decrypted cr // get decrypted cr
@@ -132,49 +153,19 @@ func (q *Qliksense) InstallQK8s(version string, opts *InstallCommandOptions) err
return q.applyCR(dcr) return q.applyCR(dcr)
} }
} }
if !qcr.IsRepoExist() {
if err := fetchAndUpdateCR(qConfig, version); err != nil {
return err
}
}
if qcr.Spec.GetManifestsRoot() == "" {
return errors.New("cannot get the manifest root. Use qliksense fetch <version> or qliksense set manifestsRoot")
}
// install generated manifests into cluster // install generated manifests into cluster
fmt.Println("Installing generated manifests into the cluster") fmt.Println("Installing generated manifests into the cluster")
if dcr, err := qConfig.GetDecryptedCr(qcr); err != nil { if dcr, err := qConfig.GetDecryptedCr(qcr); err != nil {
return err return err
} else if err := q.applyConfigToK8s(dcr); err != nil {
fmt.Println("cannot do kubectl apply on manifests")
return err
} else { } else {
if IsQliksenseInstalled(dcr.GetName()) { return q.applyCR(dcr)
return q.UpgradeQK8s(opts.CleanPatchFiles)
}
if err := q.applyConfigToK8s(dcr); err != nil {
fmt.Println("cannot do kubectl apply on manifests")
return err
} else {
return q.applyCR(dcr)
}
} }
} }
func IsQliksenseInstalled(crName string) bool {
args := []string{
"get",
"qliksense",
crName,
"-ogo-template",
`--template='{{ .metadata.name}}'`,
}
_, err := qapi.KubectlDirectOps(args, "")
if err != nil {
return false
}
return true
}
func (q *Qliksense) getProcessedOperatorControllerString(qcr *qapi.QliksenseCR) (string, error) { func (q *Qliksense) getProcessedOperatorControllerString(qcr *qapi.QliksenseCR) (string, error) {
operatorControllerString := q.GetOperatorControllerString() operatorControllerString := q.GetOperatorControllerString()
if imageRegistry := qcr.Spec.GetImageRegistry(); imageRegistry != "" { if imageRegistry := qcr.Spec.GetImageRegistry(); imageRegistry != "" {

View File

@@ -8,13 +8,12 @@ import (
"strings" "strings"
"testing" "testing"
"github.com/gobuffalo/packr/v2"
qapi "github.com/qlik-oss/sense-installer/pkg/api"
"sigs.k8s.io/kustomize/api/k8sdeps/kunstruct" "sigs.k8s.io/kustomize/api/k8sdeps/kunstruct"
"sigs.k8s.io/kustomize/api/resid" "sigs.k8s.io/kustomize/api/resid"
"sigs.k8s.io/kustomize/api/resmap" "sigs.k8s.io/kustomize/api/resmap"
"sigs.k8s.io/kustomize/api/resource" "sigs.k8s.io/kustomize/api/resource"
"github.com/gobuffalo/packr/v2"
qapi "github.com/qlik-oss/sense-installer/pkg/api"
) )
func TestCreateK8sResourceBeforePatch(t *testing.T) { func TestCreateK8sResourceBeforePatch(t *testing.T) {
@@ -44,8 +43,7 @@ spec:
qliksense: qliksense:
- name: mongodbUri - name: mongodbUri
value: mongodb://qlik-default-mongodb:27017/qliksense?ssl=false value: mongodb://qlik-default-mongodb:27017/qliksense?ssl=false
profile: docker-desktop profile: docker-desktop`
rotateKeys: "yes"`
q := New(testDir) q := New(testDir)
if err := q.LoadCr([]byte(sampleCr), false); err != nil { if err := q.LoadCr([]byte(sampleCr), false); err != nil {

21
pkg/qliksense/keys.go Normal file
View File

@@ -0,0 +1,21 @@
package qliksense
import (
"path"
"github.com/mitchellh/go-homedir"
"github.com/qlik-oss/k-apis/pkg/cr"
qapi "github.com/qlik-oss/sense-installer/pkg/api"
)
func (q *Qliksense) DeleteKeysClusterBackup() error {
qConfig := qapi.NewQConfig(q.QliksenseHome)
if qcr, err := qConfig.GetCurrentCR(); err != nil {
return err
} else if userHomeDir, err := homedir.Dir(); err != nil {
return err
} else if err := cr.DeleteKeysClusterBackup(&qcr.KApiCr, path.Join(userHomeDir, ".kube", "config")); err != nil {
return err
}
return nil
}

View File

@@ -276,9 +276,11 @@ func Test_executeKustomizeBuild_onQlikConfig_regenerateKeys(t *testing.T) {
configPath := filepath.Join(tmpDir, "config") configPath := filepath.Join(tmpDir, "config")
if repo, err := kapis_git.CloneRepository(configPath, defaultConfigRepoGitUrl, nil); err != nil { if repo, err := kapis_git.CloneRepository(configPath, defaultConfigRepoGitUrl, nil); err != nil {
t.Fatalf("unexpected error: %v\n", err) t.Fatalf("unexpected error: %v\n", err)
} else if err := kapis_git.Checkout(repo, "e38df644e759abf0b5941c1511d1a2cd5e3c42fa", "", nil); err != nil { } else if err := kapis_git.Checkout(repo, "e38df644e759abf0b5941c1511d1a2cd5e3c42fa", "commit-e38df644e759abf0b5941c1511d1a2cd5e3c42fa", nil); err != nil {
t.Fatalf("unexpected error: %v\n", err) t.Fatalf("unexpected error: %v\n", err)
} }
//tmpDir := "/var/folders/mf/5hs1qkq508q_scjbhxhmf9qwjrp346/T/679268230"
//configPath := "/var/folders/mf/5hs1qkq508q_scjbhxhmf9qwjrp346/T/679268230/config"
cr := &config.CRSpec{ cr := &config.CRSpec{
ManifestsRoot: configPath, ManifestsRoot: configPath,
@@ -310,8 +312,8 @@ func Test_executeKustomizeBuild_onQlikConfig_regenerateKeys(t *testing.T) {
} }
break break
} }
if resource["kind"].(string) == "Secret" && strings.Contains(resource["metadata"].(map[interface {}]interface {})["name"].(string), "users-secrets-") { if resource["kind"].(string) == "Secret" && strings.Contains(resource["metadata"].(map[interface{}]interface{})["name"].(string), "users-secrets-") {
keyIdBase64 = resource["data"].(map[interface {}]interface {})["tokenAuthPrivateKeyId"].(string) keyIdBase64 = resource["data"].(map[interface{}]interface{})["tokenAuthPrivateKeyId"].(string)
break break
} }
} }

View File

@@ -34,8 +34,7 @@ spec:
qliksense: qliksense:
- name: mongodbUri - name: mongodbUri
value: mongodb://qlik-default-mongodb:27017/qliksense?ssl=false value: mongodb://qlik-default-mongodb:27017/qliksense?ssl=false
profile: docker-desktop profile: docker-desktop`
rotateKeys: "yes"`
sampleCr2 := ` sampleCr2 := `
apiVersion: qlik.com/v1 apiVersion: qlik.com/v1
kind: Qliksense kind: Qliksense
@@ -61,8 +60,7 @@ spec:
qliksense: qliksense:
- name: mongodbUri - name: mongodbUri
value: mongodb://qlik-default-mongodb:27017/qliksense?ssl=false value: mongodb://qlik-default-mongodb:27017/qliksense?ssl=false
profile: docker-desktop profile: docker-desktop`
rotateKeys: "yes"`
duplicateCr := ` duplicateCr := `
apiVersion: qlik.com/v1 apiVersion: qlik.com/v1

View File

@@ -25,7 +25,6 @@ func (q *Qliksense) UpgradeQK8s(cleanPatchFiles bool) error {
fmt.Println("cannot get the current-context cr", err) fmt.Println("cannot get the current-context cr", err)
return err return err
} }
qcr.Spec.RotateKeys = "no"
dcr, err := qConfig.GetDecryptedCr(qcr) dcr, err := qConfig.GetDecryptedCr(qcr)
if err != nil { if err != nil {