diff --git a/cli/cmd/dev/dev.go b/cli/cmd/dev/dev.go index 58092ac5..32d60dfb 100644 --- a/cli/cmd/dev/dev.go +++ b/cli/cmd/dev/dev.go @@ -38,6 +38,8 @@ var devRunTestsAllowedArgs = []string{"olm", "standalone", "upgrade"} var microshiftUser = "cloud-user" var defaultDiskSpace = "20G" +var errMissingArg = errors.New("missing argument") + func createMicroshift(kmd *cobra.Command, cliCtx cliutils.SoftwareFactoryConfigContext) { skipLocalSetup, _ := kmd.Flags().GetBool("skip-local-setup") skipDeploy, _ := kmd.Flags().GetBool("skip-deploy") @@ -45,11 +47,9 @@ func createMicroshift(kmd *cobra.Command, cliCtx cliutils.SoftwareFactoryConfigC dryRun, _ := kmd.Flags().GetBool("dry-run") rootDir := ms.CreateTempRootDir() - // Arg validation - missingArgError := errors.New("missing argument") msHost := cliCtx.Dev.Microshift.Host if msHost == "" { - ctrl.Log.Error(missingArgError, "Host must be set in `microshift` section of the configuration") + ctrl.Log.Error(errMissingArg, "Host must be set in `microshift` section of the configuration") os.Exit(1) } msUser := cliCtx.Dev.Microshift.User @@ -60,7 +60,7 @@ func createMicroshift(kmd *cobra.Command, cliCtx cliutils.SoftwareFactoryConfigC } msOpenshiftPullSecret := cliCtx.Dev.Microshift.OpenshiftPullSecret if msOpenshiftPullSecret == "" { - ctrl.Log.Error(missingArgError, "A valid OpenShift pull secret must be set in `microshift` section of the configuration") + ctrl.Log.Error(errMissingArg, "A valid OpenShift pull secret must be set in `microshift` section of the configuration") os.Exit(1) } msDiskFileSize := cliCtx.Dev.Microshift.DiskFileSize @@ -75,7 +75,7 @@ func createMicroshift(kmd *cobra.Command, cliCtx cliutils.SoftwareFactoryConfigC } msSFOperatorRepositoryPath := cliCtx.Dev.SFOperatorRepositoryPath if msSFOperatorRepositoryPath == "" { - ctrl.Log.Error(missingArgError, "The path to the sf-operator repository must be set in `dev` section of the configuration") + ctrl.Log.Error(errMissingArg, "The path to the sf-operator repository must be set in `dev` section of the configuration") os.Exit(1) } @@ -115,6 +115,37 @@ func createMicroshift(kmd *cobra.Command, cliCtx cliutils.SoftwareFactoryConfigC } } +func devRunTests(kmd *cobra.Command, args []string) { + cliCtx := cliutils.GetCLIctxOrDie(kmd, args, runTestsAllowedArgs) + target := args[0] + sfOperatorRepositoryPath := cliCtx.Dev.SFOperatorRepositoryPath + extraVars := cliCtx.Dev.Tests.ExtraVars + if len(extraVars) == 0 { + vars, _ := kmd.Flags().GetStringSlice("extra-var") + extraVars = cliutils.VarListToMap(vars) + } + if sfOperatorRepositoryPath == "" { + ctrl.Log.Error(errMissingArg, "The path to the sf-operator repository must be set in `dev` section of the configuration") + os.Exit(1) + } + var verbosity string + verbose, _ := kmd.Flags().GetBool("v") + debug, _ := kmd.Flags().GetBool("vvv") + if verbose { + verbosity = "verbose" + } + if debug { + verbosity = "debug" + } + if target == "olm" { + runTestOLM(extraVars, sfOperatorRepositoryPath, verbosity) + } else if target == "standalone" { + runTestStandalone(extraVars, sfOperatorRepositoryPath, verbosity) + } else if target == "upgrade" { + runTestUpgrade(extraVars, sfOperatorRepositoryPath, verbosity) + } +} + func devCreate(kmd *cobra.Command, args []string) { cliCtx := cliutils.GetCLIctxOrDie(kmd, args, devCreateAllowedArgs) target := args[0] @@ -186,8 +217,6 @@ func devCloneAsAdmin(kmd *cobra.Command, args []string) { gerrit.CloneAsAdmin(&env, fqdn, repoName, dest, verify) } -func devRunTests(kmd *cobra.Command, args []string) {} - func MkDevCmd() *cobra.Command { var ( @@ -198,6 +227,9 @@ func MkDevCmd() *cobra.Command { msSkipPostInstall bool msDryRun bool sfResource string + extraVars []string + testVerbose bool + testDebug bool devCmd = &cobra.Command{ Use: "dev", Short: "development subcommands", @@ -221,8 +253,8 @@ func MkDevCmd() *cobra.Command { Run: devCloneAsAdmin, } runTestsCmd = &cobra.Command{ - Use: "runTests TESTNAME", - Long: "Wipe a development resource. The resource can be a gerrit instance.", + Use: "run-tests TESTNAME", + Long: "Runs a test suite locally. TESTNAME can be `olm`, `standalone` or `upgrade`", ValidArgs: devRunTestsAllowedArgs, Run: devRunTests, } @@ -239,6 +271,10 @@ func MkDevCmd() *cobra.Command { createCmd.Flags().StringVar(&sfResource, "cr", "", "The path to the CR defining the Software Factory deployment.") + runTestsCmd.Flags().StringSliceVar(&extraVars, "extra-var", []string{}, "Set an extra variable in the form `key=value` to pass to the test playbook. Repeatable") + runTestsCmd.Flags().BoolVar(&testVerbose, "v", false, "run ansible in verbose mode") + runTestsCmd.Flags().BoolVar(&testDebug, "vvv", false, "run ansible in debug mode") + devCmd.AddCommand(createCmd) devCmd.AddCommand(wipeCmd) devCmd.AddCommand(cloneAsAdminCmd) diff --git a/cli/cmd/dev/runTests.go b/cli/cmd/dev/runTests.go new file mode 100644 index 00000000..2d85cd30 --- /dev/null +++ b/cli/cmd/dev/runTests.go @@ -0,0 +1,83 @@ +/* +Copyright © 2024 Redhat +*/ + +package dev + +import ( + "context" + _ "embed" + "os" + "path/filepath" + + "github.com/apenella/go-ansible/pkg/execute" + "github.com/apenella/go-ansible/pkg/options" + "github.com/apenella/go-ansible/pkg/playbook" + + ctrl "sigs.k8s.io/controller-runtime" +) + +var runTestsAllowedArgs = []string{"standalone", "olm", "upgrade"} + +func mkTestPlaybook(vars map[string]string, sfOperatorRepoPath string, playbookName string, verbosity string) *playbook.AnsiblePlaybookCmd { + + ansiblePlaybookOptions := &playbook.AnsiblePlaybookOptions{} + ansiblePlaybookConnectionOptions := &options.AnsibleConnectionOptions{} + + ansiblePlaybookOptions.AddExtraVar("hostname", "localhost") + if verbosity == "verbose" { + ansiblePlaybookOptions.VerboseV = true + } + if verbosity == "debug" { + ansiblePlaybookOptions.VerboseVVVV = true + } + for keyV, valueV := range vars { + ansiblePlaybookOptions.AddExtraVar(keyV, valueV) + } + + pbFullPath := filepath.Join(sfOperatorRepoPath, playbookName) + pb := &playbook.AnsiblePlaybookCmd{ + Exec: execute.NewDefaultExecute( + execute.WithEnvVar("ANSIBLE_ROLES_PATH", sfOperatorRepoPath)), + Playbooks: []string{pbFullPath}, + Options: ansiblePlaybookOptions, + ConnectionOptions: ansiblePlaybookConnectionOptions, + } + return pb +} + +func runPlaybook(pb *playbook.AnsiblePlaybookCmd) error { + options.AnsibleForceColor() + ctrl.Log.Info(pb.String()) + return pb.Run(context.TODO()) +} + +func runTestStandalone(extraVars map[string]string, sfOperatorRepoPath string, verbosity string) { + pbName := "playbooks/main.yaml" + pb := mkTestPlaybook(extraVars, sfOperatorRepoPath, pbName, verbosity) + pb.Options.Tags = "standalone" + pb.Options.AddExtraVar("mode", "standalone") + if err := runPlaybook(pb); err != nil { + ctrl.Log.Error(err, "Could not run standalone tests") + os.Exit(1) + } +} + +func runTestOLM(extraVars map[string]string, sfOperatorRepoPath string, verbosity string) { + pbName := "playbooks/main.yaml" + pb := mkTestPlaybook(extraVars, sfOperatorRepoPath, pbName, verbosity) + pb.Options.AddExtraVar("mode", "olm") + if err := runPlaybook(pb); err != nil { + ctrl.Log.Error(err, "Could not run OLM tests") + os.Exit(1) + } +} + +func runTestUpgrade(extraVars map[string]string, sfOperatorRepoPath string, verbosity string) { + pbName := "playbooks/upgrade.yaml" + pb := mkTestPlaybook(extraVars, sfOperatorRepoPath, pbName, verbosity) + if err := runPlaybook(pb); err != nil { + ctrl.Log.Error(err, "Could not run upgrade tests") + os.Exit(1) + } +} diff --git a/cli/cmd/utils/utils.go b/cli/cmd/utils/utils.go index 65fe0c3c..574ceac0 100644 --- a/cli/cmd/utils/utils.go +++ b/cli/cmd/utils/utils.go @@ -330,3 +330,19 @@ func EnsureServiceAccountOrDie(env *ENV, name string) { CreateROrDie(env, &sa) } } + +func VarListToMap(varsList []string) map[string]string { + + var vars = make(map[string]string) + + for _, v := range varsList { + tokens := strings.Split(v, "=") + + if len(tokens) != 2 { + ctrl.Log.Error(errors.New("parse error"), "parsed value `"+v+"` needs to be defined as 'foo=bar'") + os.Exit(1) + } + vars[tokens[0]] = tokens[1] + } + return vars +} diff --git a/doc/reference/cli/main.md b/doc/reference/cli/main.md index 6cf0a7f0..b1473ea9 100644 --- a/doc/reference/cli/main.md +++ b/doc/reference/cli/main.md @@ -14,6 +14,7 @@ deployments, beyond what can be defined in a custom resource manifest. 1. [create gerrit](#create-gerrit) 1. [create microshift](#create-microshift) 1. [create standalone-sf](#create-standalone-sf) + 1. [run-tests](#run-tests) 1. [wipe gerrit](#wipe-gerrit) 1. [Init](#init) 1. [Nodepool](#nodepool) @@ -204,6 +205,22 @@ Flags: |----------|------|-------|----|----| |--cr |string | The path to the custom resource to apply | No | If a config file is used and the flag not provided, will default to the context's `manifest-file` if set | +#### run-tests + +Run the playbook for a given test suite. Extra variables can be specified. + +```sh +go run ./main.go [GLOBAL FLAGS] dev run-tests {olm,standalone,upgrade} [FLAGS] +``` + +Flags: + +| Argument | Type | Description | Optional | Default | +|----------|------|-------|----|----| +|--extra-var | string | Set an extra variable in the form `key=value` to pass to the test playbook. Repeatable | Yes | - | +|--v | boolean | Run playbook in verbose mode | Yes | false | +|--vvv | boolean | Run playbook in debug mode | Yes | false | + #### wipe gerrit Delete a Gerrit instance deployed with `dev create gerrit`.