Compare commits
7 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
775f438762 | ||
|
|
aa180b4af1 | ||
|
|
af679c89bf | ||
|
|
dcd3c0a99b | ||
|
|
2bc65f0bad | ||
|
|
b2a980de3a | ||
|
|
bfba8198cf |
4
.github/workflows/mkdocs.yml
vendored
4
.github/workflows/mkdocs.yml
vendored
@@ -4,8 +4,8 @@ on:
|
||||
branches:
|
||||
- master
|
||||
paths:
|
||||
- docs/
|
||||
- mkdocs.yml
|
||||
- 'docs/**'
|
||||
- 'mkdocs.yml'
|
||||
|
||||
jobs:
|
||||
build:
|
||||
|
||||
28
Makefile
28
Makefile
@@ -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
47
cmd/qliksense/eula.go
Normal 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)
|
||||
}
|
||||
}
|
||||
@@ -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)
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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
|
||||
```
|
||||
|
||||
@@ -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{}
|
||||
|
||||
@@ -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())
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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, "")
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user