Skip to content

Commit

Permalink
feat: add server migration for tests and scripts (#972)
Browse files Browse the repository at this point in the history
* ref: rename test - test-suite in opanapi spec nad model part1

* rename _test to _test_suite

* fix: generated testsuite from openapispec

* chore: rename TestKube to Testkube

* rename _script to _test

* rename _script to _test part2

* testName to testSuiteName and scriptName to testName

* api client refactor

* chore: rename testsuite to test and scripts to tests - commands

* script to test refactor

* mappers renaming

* scripts

* more rename

* more scripts renaming

* feat: bump operator version

* fix: using new operator clients and apis

* docs update

* fixed tests

* renamed proxy client in tests

* docs - generated from cobra commandfs

* fix: integration tests

* fix: more scripts to tests renaming

* fix: more scripts to tests renaming

* fix: docs with testsuites

* fix: renaming

* fix: renaming

* fix: renaming in postman tests

* feat: new testkube logos

* feat: new squishies image

* feat: add server migration for 0.9.2

* fix: tune migration for tests and scripts

* fix: remove commented code

* fix: rename isValid method

* fix: update message text

* fix: nil pointer panic

* fix: kubectl plugin test suite fix

* fix: remove merging conflict

Co-authored-by: Jacek Wysocki <[email protected]>
Co-authored-by: Vladislav Sukhin <[email protected]>
  • Loading branch information
3 people authored Feb 18, 2022
1 parent b1d0776 commit dae7248
Show file tree
Hide file tree
Showing 6 changed files with 310 additions and 14 deletions.
32 changes: 30 additions & 2 deletions cmd/api-server/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,24 @@ package main

import (
"flag"
"fmt"
"net"
"os"

"github.com/kelseyhightower/envconfig"
kubeclient "github.com/kubeshop/testkube-operator/client"
executorsclientv1 "github.com/kubeshop/testkube-operator/client/executors"
scriptsclient "github.com/kubeshop/testkube-operator/client/scripts/v2"
testsclientv1 "github.com/kubeshop/testkube-operator/client/tests"
testsclientv2 "github.com/kubeshop/testkube-operator/client/tests/v2"
testsuitesclientv1 "github.com/kubeshop/testkube-operator/client/testsuites/v1"
apiv1 "github.com/kubeshop/testkube/internal/app/api/v1"
"github.com/kubeshop/testkube/internal/migrations"
"github.com/kubeshop/testkube/internal/pkg/api"
"github.com/kubeshop/testkube/internal/pkg/api/repository/result"
"github.com/kubeshop/testkube/internal/pkg/api/repository/storage"
"github.com/kubeshop/testkube/internal/pkg/api/repository/testresult"
"github.com/kubeshop/testkube/pkg/migrator"
"github.com/kubeshop/testkube/pkg/secret"
"github.com/kubeshop/testkube/pkg/telemetry"
"github.com/kubeshop/testkube/pkg/ui"
Expand All @@ -34,6 +40,21 @@ func init() {
envconfig.Process("mongo", &Config)
}

func runMigrations() (err error) {
ui.Info("Available migrations for", api.Version)
results := migrations.Migrator.GetValidMigrations(api.Version, migrator.MigrationTypeServer)
if len(results) == 0 {
ui.Warn("No migrations available for", api.Version)
return nil
}

for _, migration := range results {
fmt.Printf("- %+v - %s\n", migration.Version(), migration.Info())
}

return migrations.Migrator.Run(api.Version, migrator.MigrationTypeServer)
}

func main() {

telemetry.CollectAnonymousInfo()
Expand All @@ -55,17 +76,24 @@ func main() {
secretClient, err := secret.NewClient()
ui.ExitOnError("Getting secret client", err)

testsClient := testsclientv2.NewClient(kubeClient)
scriptsClient := scriptsclient.NewClient(kubeClient)
testsClientV1 := testsclientv1.NewClient(kubeClient)
testsClientV2 := testsclientv2.NewClient(kubeClient)
executorsClient := executorsclientv1.NewClient(kubeClient)
testsuitesClient := testsuitesclientv1.NewClient(kubeClient)

resultsRepository := result.NewMongoRespository(db)
testResultsRepository := testresult.NewMongoRespository(db)

migrations.Migrator.Add(migrations.NewVersion_0_9_2(scriptsClient, testsClientV1, testsClientV2, testsuitesClient))
if err := runMigrations(); err != nil {
ui.ExitOnError("Running server migrations", err)
}

err = apiv1.NewServer(
resultsRepository,
testResultsRepository,
testsClient,
testsClientV2,
executorsClient,
testsuitesClient,
secretClient,
Expand Down
10 changes: 5 additions & 5 deletions cmd/kubectl-testkube/commands/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (

"github.com/kubeshop/testkube/cmd/kubectl-testkube/commands/common"
"github.com/kubeshop/testkube/internal/migrations"
"github.com/kubeshop/testkube/pkg/migrator"
"github.com/kubeshop/testkube/pkg/process"
"github.com/kubeshop/testkube/pkg/ui"
"github.com/spf13/cobra"
Expand All @@ -21,19 +22,18 @@ func RunMigrations(cmd *cobra.Command) (hasMigrations bool, err error) {
ui.Failf("Can't detect cluster version")
}

migrator := migrations.Migrator
ui.Info("Available migrations for", info.Version)
migrations := migrator.GetValidMigrations(info.Version)
if len(migrations) == 0 {
results := migrations.Migrator.GetValidMigrations(info.Version, migrator.MigrationTypeClient)
if len(results) == 0 {
ui.Warn("No migrations available for", info.Version)
return false, nil
}

for _, migration := range migrations {
for _, migration := range results {
fmt.Printf("- %+v - %s\n", migration.Version(), migration.Info())
}

return true, migrator.Run(info.Version)
return true, migrations.Migrator.Run(info.Version, migrator.MigrationTypeClient)
}

func HelmUpgradeOrInstalTestkube(name, namespace, chart string, noDashboard, noMinio, noJetstack bool) error {
Expand Down
6 changes: 6 additions & 0 deletions internal/migrations/version_0.8.8.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package migrations

import "github.com/kubeshop/testkube/pkg/migrator"

// add migration to global migrator
func init() {
Migrator.Add(NewVersion_0_8_8())
Expand Down Expand Up @@ -31,3 +33,7 @@ func (m *Version_0_8_8) Migrate() error {
func (m *Version_0_8_8) Info() string {
return "Adding labels and annotations to Testkube CRDs"
}

func (m *Version_0_8_8) Type() migrator.MigrationType {
return migrator.MigrationTypeClient
}
185 changes: 185 additions & 0 deletions internal/migrations/version_0.9.2.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,185 @@
package migrations

import (
"os"
"strings"

"k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"

testsv1 "github.com/kubeshop/testkube-operator/apis/tests/v1"
testsv2 "github.com/kubeshop/testkube-operator/apis/tests/v2"
testsuite "github.com/kubeshop/testkube-operator/apis/testsuite/v1"
scriptsclientv2 "github.com/kubeshop/testkube-operator/client/scripts/v2"
testsclientv1 "github.com/kubeshop/testkube-operator/client/tests"
testsclientv2 "github.com/kubeshop/testkube-operator/client/tests/v2"
testsuitesclientv1 "github.com/kubeshop/testkube-operator/client/testsuites/v1"
"github.com/kubeshop/testkube/pkg/migrator"
)

func NewVersion_0_9_2(
scriptsClient *scriptsclientv2.ScriptsClient,
testsClientV1 *testsclientv1.TestsClient,
testsClientV2 *testsclientv2.TestsClient,
testsuitesClient *testsuitesclientv1.TestSuitesClient,
) *Version_0_9_2 {
return &Version_0_9_2{
scriptsClient: scriptsClient,
testsClientV1: testsClientV1,
testsClientV2: testsClientV2,
testsuitesClient: testsuitesClient,
}
}

type Version_0_9_2 struct {
scriptsClient *scriptsclientv2.ScriptsClient
testsClientV1 *testsclientv1.TestsClient
testsClientV2 *testsclientv2.TestsClient
testsuitesClient *testsuitesclientv1.TestSuitesClient
namespace string
}

func (m *Version_0_9_2) Version() string {
return "0.9.2"
}
func (m *Version_0_9_2) Migrate() error {
namespace := os.Getenv("TESTKUBE_NAMESPACE")

scripts, err := m.scriptsClient.List(namespace, nil)
if err != nil {
return err
}

for _, script := range scripts.Items {
if _, err = m.testsClientV2.Get(namespace, script.Name); err != nil && !errors.IsNotFound(err) {
return err
}

if err == nil {
continue
}

test := &testsv2.Test{
ObjectMeta: metav1.ObjectMeta{
Name: script.Name,
Namespace: script.Namespace,
},
Spec: testsv2.TestSpec{
Type_: script.Spec.Type_,
Name: script.Spec.Name,
Params: script.Spec.Params,
Tags: script.Spec.Tags,
},
}

if script.Spec.Content != nil {
test.Spec.Content = &testsv2.TestContent{
Type_: script.Spec.Content.Type_,
Data: script.Spec.Content.Data,
Uri: script.Spec.Content.Uri,
}

if script.Spec.Content.Repository != nil {
test.Spec.Content.Repository = &testsv2.Repository{
Type_: script.Spec.Content.Repository.Type_,
Uri: script.Spec.Content.Repository.Uri,
Branch: script.Spec.Content.Repository.Branch,
Path: script.Spec.Content.Repository.Path,
}
}
}

if _, err = m.testsClientV2.Create(test); err != nil {
return err
}

if err = m.scriptsClient.Delete(namespace, script.Name); err != nil {
return err
}
}

tests, err := m.testsClientV1.List(namespace, nil)
if err != nil {
return err
}

OUTER:
for _, test := range tests.Items {
if _, err = m.testsuitesClient.Get(namespace, test.Name); err != nil && !errors.IsNotFound(err) {
return err
}

if err == nil {
continue
}

for _, managedField := range test.GetManagedFields() {
if !strings.HasSuffix(managedField.APIVersion, "/v1") {
continue OUTER
}
}

testsuite := &testsuite.TestSuite{
ObjectMeta: metav1.ObjectMeta{
Name: test.Name,
Namespace: test.Namespace,
},
Spec: testsuite.TestSuiteSpec{
Repeats: test.Spec.Repeats,
Description: test.Spec.Description,
Tags: test.Spec.Tags,
},
}

for _, step := range test.Spec.Before {
testsuite.Spec.Before = append(testsuite.Spec.Before, copyTestStepTest2Testsuite(step))
}

for _, step := range test.Spec.Steps {
testsuite.Spec.Steps = append(testsuite.Spec.Steps, copyTestStepTest2Testsuite(step))
}

for _, step := range test.Spec.After {
testsuite.Spec.After = append(testsuite.Spec.After, copyTestStepTest2Testsuite(step))
}

if _, err = m.testsuitesClient.Create(testsuite); err != nil {
return err
}

if err = m.testsClientV1.Delete(namespace, test.Name); err != nil {
return err
}
}

return nil
}
func (m *Version_0_9_2) Info() string {
return "Moving scripts v2 resources to tests v2 ones and tests v1 resources to testsuites v1 ones"
}

func (m *Version_0_9_2) Type() migrator.MigrationType {
return migrator.MigrationTypeServer
}

func copyTestStepTest2Testsuite(step testsv1.TestStepSpec) testsuite.TestSuiteStepSpec {
result := testsuite.TestSuiteStepSpec{
Type: step.Type,
}

if step.Execute != nil {
result.Execute = &testsuite.TestSuiteStepExecute{
Namespace: step.Execute.Namespace,
Name: step.Execute.Name,
StopOnFailure: step.Execute.StopOnFailure,
}
}

if step.Delay != nil {
result.Delay = &testsuite.TestSuiteStepDelay{
Duration: step.Delay.Duration,
}
}

return result
}
26 changes: 22 additions & 4 deletions pkg/migrator/migrator.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,19 @@ type Migration interface {
Migrate() error
Version() string
Info() string
Type() MigrationType
}

// MigrationType is migration type
type MigrationType int

const (
// MigrationTypeClient is client migration type
MigrationTypeClient MigrationType = iota + 1
// MigrationTypeServer is server migration type
MigrationTypeServer
)

func NewMigrator() *Migrator {
return &Migrator{
Log: log.DefaultLogger,
Expand All @@ -31,18 +42,25 @@ func (m *Migrator) Add(migration Migration) {
m.Migrations = append(m.Migrations, migration)
}

func (m *Migrator) GetValidMigrations(currentVersion string) (migrations []Migration) {
func (m *Migrator) GetValidMigrations(currentVersion string, migrationTypes ...MigrationType) (migrations []Migration) {
types := make(map[MigrationType]struct{}, len(migrationTypes))
for _, migrationType := range migrationTypes {
types[migrationType] = struct{}{}
}

for _, migration := range m.Migrations {
if ok, err := m.IsValid(migration.Version(), currentVersion); ok && err == nil {
migrations = append(migrations, migration)
if _, ok = types[migration.Type()]; ok {
migrations = append(migrations, migration)
}
}
}

return
}

func (m *Migrator) Run(currentVersion string) error {
for _, migration := range m.GetValidMigrations(currentVersion) {
func (m *Migrator) Run(currentVersion string, migrationTypes ...MigrationType) error {
for _, migration := range m.GetValidMigrations(currentVersion, migrationTypes...) {
err := migration.Migrate()
if err != nil {
return err
Expand Down
Loading

0 comments on commit dae7248

Please sign in to comment.