Compare commits

...

7 Commits

Author SHA1 Message Date
Andriy Bulynko
775f438762 Enforcing eula acceptance for all context/CR based commands (#239) 2020-03-24 13:37:44 -04:00
Ashwathi Shiva
aa180b4af1 Port preflight (#237)
Demo comments incorporated
2020-03-23 09:22:33 -04:00
Ilir Bekteshi
af679c89bf Merge pull request #235 from qlik-oss/ibiqlik-patch-1
Remove space in zip path
2020-03-23 10:00:20 +01:00
Ilir Bekteshi
dcd3c0a99b Merge pull request #228 from qlik-oss/ibiqlik/mkdocswf
Fix trigger paths for mkdocs
2020-03-23 09:59:01 +01:00
Ilir Bekteshi
2bc65f0bad Remove space in zip path 2020-03-20 11:39:27 +01:00
Ilir Bekteshi
b2a980de3a Generalizing gitops sample CR section 2020-03-19 15:41:26 +01:00
Ilir Bekteshi
bfba8198cf Update mkdocs.yml 2020-03-19 15:36:29 +01:00
11 changed files with 192 additions and 65 deletions

View File

@@ -4,8 +4,8 @@ on:
branches:
- master
paths:
- docs/
- mkdocs.yml
- 'docs/**'
- 'mkdocs.yml'
jobs:
build:

View File

@@ -46,11 +46,11 @@ build: clean generate
.PHONY: test
test: clean generate
ifeq ($(shell ${WHICH} docker-registry 2>${DEVNUL}),)
$(eval TMP := $(shell mktemp -d))
git clone https://github.com/docker/distribution.git $(TMP)/docker-distribution
cd $(TMP)/docker-distribution; git checkout -b v2.7.1; make
cp $(TMP)/docker-distribution/bin/registry pkg/qliksense/docker-registry
-rm -rf $(TMP)/docker-distribution
$(eval TMP-docker-distribution := $(shell mktemp -d))
git clone https://github.com/docker/distribution.git $(TMP-docker-distribution)/docker-distribution
cd $(TMP-docker-distribution)/docker-distribution; git checkout -b v2.7.1; make
cp $(TMP-docker-distribution)/docker-distribution/bin/registry pkg/qliksense/docker-registry
-rm -rf $(TMP-docker-distribution)
endif
go test -short -count=1 -tags "$(BUILDTAGS)" -v ./...
$(MAKE) clean
@@ -70,7 +70,7 @@ $(BINDIR)/$(VERSION)/$(MIXIN)-$(CLIENT_PLATFORM)-$(CLIENT_ARCH)$(FILE_EXT):
GOOS=$(CLIENT_PLATFORM) GOARCH=$(CLIENT_ARCH) $(XBUILD) -o $@ ./cmd/$(MIXIN)
ifeq ($(CLIENT_PLATFORM),windows)
zip $(BINDIR)/$(VERSION)/$(MIXIN)-$(CLIENT_PLATFORM)-$(CLIENT_ARCH).zip $(BINDIR)/$(VERSION)/ $(MIXIN)-$(CLIENT_PLATFORM)-$(CLIENT_ARCH)$(FILE_EXT)
zip $(BINDIR)/$(VERSION)/$(MIXIN)-$(CLIENT_PLATFORM)-$(CLIENT_ARCH).zip $(BINDIR)/$(VERSION)/$(MIXIN)-$(CLIENT_PLATFORM)-$(CLIENT_ARCH)$(FILE_EXT)
else
tar -czvf $(BINDIR)/$(VERSION)/$(MIXIN)-$(CLIENT_PLATFORM)-$(CLIENT_ARCH).tar.gz -C $(BINDIR)/$(VERSION)/ $(MIXIN)-$(CLIENT_PLATFORM)-$(CLIENT_ARCH)$(FILE_EXT)
endif
@@ -91,12 +91,16 @@ clean-packr: packr2
cd pkg/qliksense && packr2 clean
get-crds:
$(eval TMP := $(shell mktemp -d))
git clone https://github.com/qlik-oss/qliksense-operator.git -b master $(TMP)/operator
ifeq ($(QLIKSENSE_OPERATOR_DIR),)
$(eval TMP-operator := $(shell mktemp -d))
git clone https://github.com/qlik-oss/qliksense-operator.git -b master $(TMP-operator)/operator
$(MAKE) QLIKSENSE_OPERATOR_DIR=$(TMP-operator)/operator get-crds
-rm -rf $(TMP-operator)
else
mkdir -p pkg/qliksense/crds/cr
mkdir -p pkg/qliksense/crds/crd
mkdir -p pkg/qliksense/crds/crd-deploy
cp $(TMP)/operator/deploy/*.yaml pkg/qliksense/crds/crd-deploy
cp $(TMP)/operator/deploy/crds/*_crd.yaml pkg/qliksense/crds/crd
cp $(TMP)/operator/deploy/crds/*_cr.yaml pkg/qliksense/crds/cr
-rm -rf $(TMP)/operator
cp $(QLIKSENSE_OPERATOR_DIR)/deploy/*.yaml pkg/qliksense/crds/crd-deploy
cp $(QLIKSENSE_OPERATOR_DIR)/deploy/crds/*_crd.yaml pkg/qliksense/crds/crd
cp $(QLIKSENSE_OPERATOR_DIR)/deploy/crds/*_cr.yaml pkg/qliksense/crds/cr
endif

47
cmd/qliksense/eula.go Normal file
View File

@@ -0,0 +1,47 @@
package main
import (
"bufio"
"fmt"
"os"
"strings"
qapi "github.com/qlik-oss/sense-installer/pkg/api"
"github.com/qlik-oss/sense-installer/pkg/qliksense"
)
var eulaEnforced = false
var eulaText = "EULA text goes here..."
var eulaPrompt = "Do you accept our EULA? (y/n): "
var eulaErrorInstruction = "You must enter y/yes to continue"
func isEulaEnforced() bool {
return eulaEnforced
}
func enforceEula(q *qliksense.Qliksense) {
if isEulaEnforced() {
if qConfig, err := qapi.NewQConfigE(q.QliksenseHome); err != nil {
doEnforceEula()
} else if qcr, err := qConfig.GetCurrentCR(); err != nil || !qcr.IsEULA() {
doEnforceEula()
}
}
}
func doEnforceEula() {
fmt.Println(eulaText)
fmt.Print(eulaPrompt)
scanner := bufio.NewScanner(os.Stdin)
scanSuccess := scanner.Scan()
if !scanSuccess {
fmt.Println(eulaErrorInstruction)
os.Exit(1)
}
line := scanner.Text()
answer := strings.ToLower(strings.TrimSpace(line))
if answer != "y" && answer != "yes" {
fmt.Println(eulaErrorInstruction)
os.Exit(1)
}
}

View File

@@ -42,7 +42,6 @@ func initAndExecute() error {
api.LogDebugMessage("QliksenseHomeDir: %s", qlikSenseHome)
qliksenseClient := qliksense.New(qlikSenseHome)
qliksenseClient.SetUpQliksenseDefaultContext()
cmd := rootCmd(qliksenseClient)
if err := cmd.Execute(); err != nil {
//levenstein checks (auto-suggestions)
@@ -50,7 +49,7 @@ func initAndExecute() error {
return err
}
return nil
return nil
}
func setUpPaths() (string, error) {
@@ -85,16 +84,37 @@ var versionCmd = &cobra.Command{
},
}
func rootCmd(p *qliksense.Qliksense) *cobra.Command {
var (
cmd *cobra.Command
)
func commandUsesContext(command string) bool {
return command != "" && command != "help" && command != "version"
}
cmd = &cobra.Command{
func globalPreRun(cmd *cobra.Command, p *qliksense.Qliksense) {
if command := cmd.CalledAs(); commandUsesContext(command) {
if isEulaEnforced() {
enforceEula(p)
}
if err := p.SetUpQliksenseDefaultContext(); err != nil {
panic(err)
}
if isEulaEnforced() {
if err := p.SetEulaAccepted(); err != nil {
panic(err)
}
}
}
}
func rootCmd(p *qliksense.Qliksense) *cobra.Command {
cmd := &cobra.Command{
Use: "qliksense",
Short: "Qliksense cli tool",
Long: `qliksense cli tool provides functionality to perform operations on qliksense-k8s, qliksense operator, and kubernetes cluster`,
Args: cobra.ArbitraryArgs,
PersistentPreRun: func(cmd *cobra.Command, args []string) {
globalPreRun(cmd, p)
},
}
cmd.Flags().SetInterspersed(false)

View File

@@ -1,7 +1,6 @@
package main
import (
qapi "github.com/qlik-oss/sense-installer/pkg/api"
"github.com/qlik-oss/sense-installer/pkg/qliksense"
"github.com/spf13/cobra"
)
@@ -9,7 +8,7 @@ import (
func uninstallCmd(q *qliksense.Qliksense) *cobra.Command {
c := &cobra.Command{
Use: "uninstall",
Short: "Uninstall the deployed qliksense with release name [ " + qapi.NewQConfig(q.QliksenseHome).Spec.CurrentContext + " ]",
Short: "Uninstall the deployed qliksense.",
Long: `Uninstall the deployed qliksense. By default uninstall the current context`,
Example: `qliksense uninstall <context-name>`,
RunE: func(cmd *cobra.Command, args []string) error {

View File

@@ -76,21 +76,55 @@ When you perform `qliksense install` or `qliksene config apply`, qliksense opera
- Push generated patches into a new branch in the provided git repo. _Gives you ability to merge patches into your master branch_
- Create a CronJob to monitor master branch. Any changes pushed to master branch will be applied into the cluster. _This is a light weight `git-ops` model_
## Enable GitOps
## GitOps
to enable gitops the following section should be in the CR
To enable gitops, the following section should be in the CR
```yaml
....
spec:
git:
repository: https://github.com/ffoysal/qliksense-k8s
accessToken: git-token
userName: git-username
repository: https://github.com/<OWNER>/<REPO>
accessToken: "<git-token>"
userName: "<git-username>"
gitOps:
enabled: "yes"
schedule: "*/5 * * * *"
watchBranch: pr-branch-24868a33
watchBranch: <myBranch>
image: qlik-docker-oss.bintray.io/qliksense-repo-watcher
....
```
##Preflight checks
Preflight checks provide pre-installation cluster conformance testing and validation before we install qliksense on the cluster. We gather a suite of conformance tests that can be easily written and run on the target cluster to verify that cluster-specific requirements are met.
The suite consists of a set of `collectors` which run the specifications of every test and `analyzers` which analyze the results of every test run by the collector.
We support the following tests at the moment as part of preflight checks, and the range of the suite will be expanded in future.
### DNS check
Run the following command to view help about the commands supported by preflight at any moment:
```console
qliksense preflight
perform preflight checks on the cluster
Usage:
qliksense preflight [command]
Examples:
qliksense preflight <preflight_check_to_run>
Usage:
qliksense preflight dns
Available Commands:
dns perform preflight dns check
```
Run the following command to perform preflight DNS check. The expected output is also shown below.
```console
qliksense preflight dns
Running Preflight checks ⠧
--- PASS DNS check
--- DNS check passed
--- PASS cluster-preflight-checks
PASS
```

View File

@@ -27,16 +27,24 @@ const (
// NewQConfig create QliksenseConfig object from file ~/.qliksense/config.yaml
func NewQConfig(qsHome string) *QliksenseConfig {
qc, err := NewQConfigE(qsHome)
if err != nil {
fmt.Println("yaml unmarshalling error ", err)
os.Exit(1)
}
return qc
}
func NewQConfigE(qsHome string) (*QliksenseConfig, error) {
configFile := filepath.Join(qsHome, "config.yaml")
qc := &QliksenseConfig{}
err := ReadFromFile(qc, configFile)
if err != nil {
fmt.Println("yaml unmarshalling error ", err)
os.Exit(1)
return nil, err
}
qc.QliksenseHomePath = qsHome
return qc
return qc, nil
}
// GetCR create a QliksenseCR object for a particular context
@@ -342,6 +350,10 @@ func (cr *QliksenseCR) IsEULA() bool {
return false
}
func (cr *QliksenseCR) SetEULA(value string) {
cr.Spec.AddToConfigs("qliksense", "acceptEULA", value)
}
// GetDecryptedCr it decrypts all the encrypted value and return a new CR
func (qc *QliksenseConfig) GetDecryptedCr(cr *QliksenseCR) (*QliksenseCR, error) {
newCr := &QliksenseCR{}

View File

@@ -109,6 +109,7 @@ func KubectlDirectOps(opr []string, namespace string) error {
LogDebugMessage("Kubectl command: %s %v\n", "kubectl", arguments)
sterrBuffer := &bytes.Buffer{}
cmd.Stderr = sterrBuffer
cmd.Stdout = os.Stdout
if err := cmd.Run(); err != nil {
return fmt.Errorf("kubectl %v failed with: %v, %v\n", opr, err, sterrBuffer.String())
}

View File

@@ -3,7 +3,6 @@ package qliksense
import (
"crypto/rsa"
"fmt"
"github.com/robfig/cron/v3"
"io/ioutil"
"log"
"os"
@@ -11,6 +10,8 @@ import (
"strings"
"text/tabwriter"
"github.com/robfig/cron/v3"
"github.com/qlik-oss/k-apis/pkg/config"
b64 "encoding/base64"
@@ -578,3 +579,13 @@ func (q *Qliksense) SetImageRegistry(registry, pushUsername, pushPassword, pullU
qliksenseCR.Spec.AddToConfigs("qliksense", imageRegistryConfigKey, registry)
return api.WriteToFile(&qliksenseCR, qliksenseContextsFile)
}
func (q *Qliksense) SetEulaAccepted() error {
qConfig := api.NewQConfig(q.QliksenseHome)
qcr, err := qConfig.GetCurrentCR()
if err != nil {
return err
}
qcr.SetEULA("yes")
return qConfig.WriteCurrentContextCR(qcr)
}

View File

@@ -42,7 +42,7 @@ func (q *Qliksense) InstallQK8s(version string, opts *InstallCommandOptions, kee
}
if opts.AcceptEULA != "" {
qcr.Spec.AddToConfigs("qliksense", "acceptEULA", opts.AcceptEULA)
qcr.SetEULA(opts.AcceptEULA)
}
if opts.MongoDbUri != "" {
qcr.Spec.AddToSecrets("qliksense", "mongoDbUri", opts.MongoDbUri, "")

View File

@@ -163,7 +163,8 @@ func determinePlatformSpecificUrls(platform string) (string, string, error) {
func (q *Qliksense) CheckDns() error {
// retrieve namespace
namespace := api.GetKubectlNamespace()
api.LogDebugMessage("Namespace here: %s", namespace)
api.LogDebugMessage("Namespace: %s\n", namespace)
tmpl, err := template.New("test").Parse(dnsCheckYAML)
if err != nil {
@@ -191,6 +192,8 @@ func (q *Qliksense) CheckDns() error {
const PreflightChecksDirName = "preflight_checks"
const preflightFileName = "preflight"
fmt.Println("Creating resources to run preflight checks")
// kubectl create deployment
opr := fmt.Sprintf("create deployment %s --image=nginx", appName)
err = initiateK8sOps(opr, namespace)
@@ -198,7 +201,6 @@ func (q *Qliksense) CheckDns() error {
fmt.Println(err)
return err
}
api.LogDebugMessage("create deployment executed")
defer func() {
// Deleting deployment..
@@ -215,7 +217,6 @@ func (q *Qliksense) CheckDns() error {
fmt.Println(err)
return err
}
api.LogDebugMessage("create service executed")
defer func() {
// delete service
@@ -236,18 +237,13 @@ func (q *Qliksense) CheckDns() error {
// call preflight
preflightCommand := filepath.Join(q.QliksenseHome, PreflightChecksDirName, preflightFileName)
trackSuccess, err := invokePreflight(preflightCommand, tempYaml)
err = invokePreflight(preflightCommand, tempYaml)
if err != nil {
fmt.Println(err)
return err
}
if trackSuccess {
fmt.Println("PREFLIGHT DNS CHECK PASSED")
} else {
fmt.Println("PREFLIGHT DNS CHECK FAILED")
}
return nil
}
@@ -261,7 +257,7 @@ func initiateK8sOps(opr, namespace string) error {
return nil
}
func invokePreflight(preflightCommand string, yamlFile *os.File) (bool, error) {
func invokePreflight(preflightCommand string, yamlFile *os.File) error {
arguments := []string{}
arguments = append(arguments, yamlFile.Name(), "--interactive=false")
cmd := exec.Command(preflightCommand, arguments...)
@@ -270,7 +266,7 @@ func invokePreflight(preflightCommand string, yamlFile *os.File) (bool, error) {
cmd.Stdout = sterrBuffer
cmd.Stderr = sterrBuffer
if err := cmd.Run(); err != nil {
return false, fmt.Errorf("Error when running preflight command: %v\n", err)
return fmt.Errorf("Error when running preflight command: %v\n", err)
}
ind := strings.Index(sterrBuffer.String(), "---")
output := sterrBuffer.String()
@@ -278,25 +274,28 @@ func invokePreflight(preflightCommand string, yamlFile *os.File) (bool, error) {
output = fmt.Sprintf("%s\n%s", output[:ind], output[ind:])
}
fmt.Printf("%v\n", output)
outputArr := strings.Fields(strings.TrimSpace(output))
trackSuccess := false
trackPrg := false
// We are only checking the overall "PASS" or "FAIL"
// Maybe good to retain this part in case we need to process the output in future.
// We are going to look for the first occurance of PASS or FAIL from the end
// there are also some space-like deceiving characters
for i := len(outputArr) - 1; i >= 0; i-- {
if strings.TrimSpace(outputArr[i]) != "" {
if outputArr[i] == "PASS" {
trackSuccess = true
trackPrg = true
} else if outputArr[i] == "FAIL" {
trackPrg = true
}
}
if trackPrg {
break
}
}
return trackSuccess, nil
// there are also some space-like deceiving characters which are being hard to get by
//outputArr := strings.Fields(strings.TrimSpace(output))
//trackSuccess := false
//trackPrg := false
//for i := len(outputArr) - 1; i >= 0; i-- {
// if strings.TrimSpace(outputArr[i]) != "" {
// if outputArr[i] == "PASS" {
// trackSuccess = true
// trackPrg = true
// } else if outputArr[i] == "FAIL" {
// trackPrg = true
// }
// }
// if trackPrg {
// break
// }
//}
fmt.Println("Preflight checks completed, cleaning up resources now")
return nil
}