From b2ed0a7a37c90b7e72765190db34b490cdfc5570 Mon Sep 17 00:00:00 2001
From: Povilas Versockas
Date: Tue, 1 Oct 2024 11:41:40 +0300
Subject: [PATCH] feat: [TKC-2581] add testworkflow / template cloud client
---
cmd/api-server/main.go | 10 ++-
internal/app/api/v1/server.go | 4 +-
pkg/cloud/data/testworkflow/commands.go | 11 +++
pkg/cloud/data/testworkflow/execution.go | 18 ++++
.../data/testworkflow/execution_models.go | 24 +++++
pkg/cloud/data/testworkflow/templates.go | 77 ++++++++++++++++
pkg/cloud/data/testworkflow/workflows.go | 87 +++++++++++++++++++
7 files changed, 227 insertions(+), 4 deletions(-)
create mode 100644 pkg/cloud/data/testworkflow/templates.go
create mode 100644 pkg/cloud/data/testworkflow/workflows.go
diff --git a/cmd/api-server/main.go b/cmd/api-server/main.go
index ad57c53c700..a323a22e125 100644
--- a/cmd/api-server/main.go
+++ b/cmd/api-server/main.go
@@ -235,8 +235,10 @@ func main() {
testsourcesClient := testsourcesclientv1.NewClient(kubeClient, cfg.TestkubeNamespace)
testExecutionsClient := testexecutionsclientv1.NewClient(kubeClient, cfg.TestkubeNamespace)
testsuiteExecutionsClient := testsuiteexecutionsclientv1.NewClient(kubeClient, cfg.TestkubeNamespace)
- testWorkflowsClient := testworkflowsclientv1.NewClient(kubeClient, cfg.TestkubeNamespace)
- testWorkflowTemplatesClient := testworkflowsclientv1.NewTestWorkflowTemplatesClient(kubeClient, cfg.TestkubeNamespace)
+ var testWorkflowsClient testworkflowsclientv1.Interface
+ testWorkflowsClient = testworkflowsclientv1.NewClient(kubeClient, cfg.TestkubeNamespace)
+ var testWorkflowTemplatesClient testworkflowsclientv1.TestWorkflowTemplatesInterface
+ testWorkflowTemplatesClient = testworkflowsclientv1.NewTestWorkflowTemplatesClient(kubeClient, cfg.TestkubeNamespace)
testWorkflowExecutionsClient := testworkflowsclientv1.NewTestWorkflowExecutionsClient(kubeClient, cfg.TestkubeNamespace)
templatesClient := templatesclientv1.NewClient(kubeClient, cfg.TestkubeNamespace)
@@ -274,6 +276,10 @@ func main() {
resultsRepository = cloudresult.NewCloudResultRepository(grpcClient, grpcConn, cfg.TestkubeProAPIKey)
testResultsRepository = cloudtestresult.NewCloudRepository(grpcClient, grpcConn, cfg.TestkubeProAPIKey)
configRepository = cloudconfig.NewCloudResultRepository(grpcClient, grpcConn, cfg.TestkubeProAPIKey)
+
+ //TODO add some flag
+ testWorkflowsClient = cloudtestworkflow.NewCloudTestWorkflowRepository(grpcClient, grpcConn, cfg.TestkubeProAPIKey)
+ testWorkflowTemplatesClient = cloudtestworkflow.NewCloudTestWorkflowTemplateRepository(grpcClient, grpcConn, cfg.TestkubeProAPIKey)
// Pro edition only (tcl protected code)
testWorkflowResultsRepository = cloudtestworkflow.NewCloudRepository(grpcClient, grpcConn, cfg.TestkubeProAPIKey)
var opts []cloudtestworkflow.Option
diff --git a/internal/app/api/v1/server.go b/internal/app/api/v1/server.go
index 688a6a0ab78..9f52d2b0646 100644
--- a/internal/app/api/v1/server.go
+++ b/internal/app/api/v1/server.go
@@ -82,8 +82,8 @@ func NewTestkubeAPI(
clientset kubernetes.Interface,
testkubeClientset testkubeclientset.Interface,
testsourcesClient *testsourcesclientv1.TestSourcesClient,
- testWorkflowsClient *testworkflowsv1.TestWorkflowsClient,
- testWorkflowTemplatesClient *testworkflowsv1.TestWorkflowTemplatesClient,
+ testWorkflowsClient testworkflowsv1.Interface,
+ testWorkflowTemplatesClient testworkflowsv1.TestWorkflowTemplatesInterface,
configMap repoConfig.Repository,
clusterId string,
eventsEmitter *event.Emitter,
diff --git a/pkg/cloud/data/testworkflow/commands.go b/pkg/cloud/data/testworkflow/commands.go
index 611e7dcf750..76671386878 100644
--- a/pkg/cloud/data/testworkflow/commands.go
+++ b/pkg/cloud/data/testworkflow/commands.go
@@ -29,6 +29,10 @@ const (
CmdTestWorkflowOutputHasLog executor.Command = "workflow_output_has_log"
CmdTestWorkflowOutputDeleteByTestWorkflow executor.Command = "workflow_output_delete_by_test_workflow"
CmdTestworkflowOutputDeleteForTestWorkflows executor.Command = "workflow_output_delete_for_test_workflows"
+
+ CmdTestWorkflowList executor.Command = "workflow_list"
+ CmdTestWorkflowGet executor.Command = "workflow_get"
+ CmdTestWorkflowTemplateGet executor.Command = "workflow_template_get"
)
func command(v interface{}) executor.Command {
@@ -82,6 +86,13 @@ func command(v interface{}) executor.Command {
return CmdTestWorkflowOutputDeleteByTestWorkflow
case ExecutionDeleteOutputForTestWorkflowsRequest:
return CmdTestworkflowOutputDeleteForTestWorkflows
+
+ case TestWorkflowGetRequest:
+ return CmdTestWorkflowGet
+ case TestWorkflowListRequest:
+ return CmdTestWorkflowList
+ case TestWorkflowTemplateGetRequest:
+ return CmdTestWorkflowTemplateGet
}
panic("unknown test workflows Cloud request")
}
diff --git a/pkg/cloud/data/testworkflow/execution.go b/pkg/cloud/data/testworkflow/execution.go
index 46b0c17c6de..7ce4120de7b 100644
--- a/pkg/cloud/data/testworkflow/execution.go
+++ b/pkg/cloud/data/testworkflow/execution.go
@@ -7,6 +7,7 @@ import (
"google.golang.org/grpc"
+ testworkflowsv1 "github.com/kubeshop/testkube-operator/api/testworkflows/v1"
testworkflow2 "github.com/kubeshop/testkube/pkg/repository/testworkflow"
"github.com/kubeshop/testkube/pkg/api/v1/testkube"
@@ -177,3 +178,20 @@ func (r *CloudRepository) GetExecutionTags(ctx context.Context, testWorkflowName
}
return pass(r.executor, ctx, req, process)
}
+
+func (r *CloudRepository) List(selector string) (*testworkflowsv1.TestWorkflowList, error) {
+ req := TestWorkflowListRequest{Selector: selector}
+ response, err := r.executor.Execute(context.Background(), CmdTestWorkflowList, req)
+ if err != nil {
+ return nil, err
+ }
+ var commandResponse TestWorkflowListResponse
+ if err := json.Unmarshal(response, &commandResponse); err != nil {
+ return nil, err
+ }
+ var list testworkflowsv1.TestWorkflowList
+ for _, tw := range commandResponse.TestWorkflows {
+ _ = tw
+ }
+ return &list, nil
+}
diff --git a/pkg/cloud/data/testworkflow/execution_models.go b/pkg/cloud/data/testworkflow/execution_models.go
index 38f04323033..58f170465d3 100644
--- a/pkg/cloud/data/testworkflow/execution_models.go
+++ b/pkg/cloud/data/testworkflow/execution_models.go
@@ -186,3 +186,27 @@ type ExecutionGetExecutionTagsRequest struct {
type ExecutionGetExecutionTagsResponse struct {
Tags map[string][]string `json:"tags"`
}
+
+type TestWorkflowListRequest struct {
+ Selector string `json:"selector"`
+}
+
+type TestWorkflowListResponse struct {
+ TestWorkflows []testkube.TestWorkflow `json:"testWorkflows"`
+}
+
+type TestWorkflowGetRequest struct {
+ Name string `json:"name"`
+}
+
+type TestWorkflowGetResponse struct {
+ TestWorkflow testkube.TestWorkflow `json:"testWorkflow"`
+}
+
+type TestWorkflowTemplateGetRequest struct {
+ Name string `json:"name"`
+}
+
+type TestWorkflowTemplateGetResponse struct {
+ TestWorkflowTemplate testkube.TestWorkflowTemplate `json:"testWorkflowTemplate"`
+}
diff --git a/pkg/cloud/data/testworkflow/templates.go b/pkg/cloud/data/testworkflow/templates.go
new file mode 100644
index 00000000000..cfdae086d46
--- /dev/null
+++ b/pkg/cloud/data/testworkflow/templates.go
@@ -0,0 +1,77 @@
+package testworkflow
+
+import (
+ "context"
+ "encoding/json"
+
+ testworkflowsv1 "github.com/kubeshop/testkube-operator/api/testworkflows/v1"
+ testworkflowsclientv1 "github.com/kubeshop/testkube-operator/pkg/client/testworkflows/v1"
+ "github.com/kubeshop/testkube/pkg/cloud"
+ "github.com/kubeshop/testkube/pkg/cloud/data/executor"
+ testworkflowmappers "github.com/kubeshop/testkube/pkg/mapper/testworkflows"
+
+ "github.com/pkg/errors"
+ "google.golang.org/grpc"
+)
+
+var _ testworkflowsclientv1.TestWorkflowTemplatesInterface = (*CloudTestWorkflowTemplateRepository)(nil)
+
+type CloudTestWorkflowTemplateRepository struct {
+ executor executor.Executor
+}
+
+func NewCloudTestWorkflowTemplateRepository(client cloud.TestKubeCloudAPIClient, grpcConn *grpc.ClientConn, apiKey string) *CloudTestWorkflowTemplateRepository {
+ return &CloudTestWorkflowTemplateRepository{executor: executor.NewCloudGRPCExecutor(client, grpcConn, apiKey)}
+}
+
+func (r *CloudTestWorkflowTemplateRepository) List(selector string) (*testworkflowsv1.TestWorkflowTemplateList, error) {
+ return nil, errors.New("unimplemented")
+}
+
+func (r *CloudTestWorkflowTemplateRepository) ListLabels() (map[string][]string, error) {
+ return make(map[string][]string), nil
+}
+
+func (r *CloudTestWorkflowTemplateRepository) Get(name string) (*testworkflowsv1.TestWorkflowTemplate, error) {
+ req := TestWorkflowTemplateGetRequest{Name: name}
+ response, err := r.executor.Execute(context.Background(), CmdTestWorkflowTemplateGet, req)
+ if err != nil {
+ return nil, err
+ }
+ var commandResponse TestWorkflowTemplateGetResponse
+ if err := json.Unmarshal(response, &commandResponse); err != nil {
+ return nil, err
+ }
+ return testworkflowmappers.MapTemplateAPIToKube(&commandResponse.TestWorkflowTemplate), nil
+}
+
+// Create creates new TestWorkflow
+func (r *CloudTestWorkflowTemplateRepository) Create(workflow *testworkflowsv1.TestWorkflowTemplate) (*testworkflowsv1.TestWorkflowTemplate, error) {
+ return nil, errors.New("unimplemented")
+}
+
+func (r *CloudTestWorkflowTemplateRepository) Update(workflow *testworkflowsv1.TestWorkflowTemplate) (*testworkflowsv1.TestWorkflowTemplate, error) {
+ return nil, errors.New("unimplemented")
+}
+
+func (r *CloudTestWorkflowTemplateRepository) Apply(workflow *testworkflowsv1.TestWorkflowTemplate) error {
+ return errors.New("unimplemented")
+}
+
+func (r *CloudTestWorkflowTemplateRepository) Delete(name string) error {
+ return errors.New("unimplemented")
+}
+
+func (r *CloudTestWorkflowTemplateRepository) DeleteAll() error {
+ return errors.New("unimplemented")
+}
+
+func (r *CloudTestWorkflowTemplateRepository) DeleteByLabels(selector string) error {
+ return errors.New("unimplemented")
+}
+
+func (r *CloudTestWorkflowTemplateRepository) UpdateStatus(workflow *testworkflowsv1.TestWorkflowTemplate) error {
+ // This is the actual implementation, as update status
+ // should update k8s crd's status field, but we don't have it when stored in mongo
+ return nil
+}
diff --git a/pkg/cloud/data/testworkflow/workflows.go b/pkg/cloud/data/testworkflow/workflows.go
new file mode 100644
index 00000000000..109eedff86f
--- /dev/null
+++ b/pkg/cloud/data/testworkflow/workflows.go
@@ -0,0 +1,87 @@
+package testworkflow
+
+import (
+ "context"
+ "encoding/json"
+
+ testworkflowsv1 "github.com/kubeshop/testkube-operator/api/testworkflows/v1"
+ testworkflowsclientv1 "github.com/kubeshop/testkube-operator/pkg/client/testworkflows/v1"
+ "github.com/kubeshop/testkube/pkg/cloud"
+ "github.com/kubeshop/testkube/pkg/cloud/data/executor"
+ testworkflowmappers "github.com/kubeshop/testkube/pkg/mapper/testworkflows"
+
+ "github.com/pkg/errors"
+ "google.golang.org/grpc"
+)
+
+var _ testworkflowsclientv1.Interface = (*CloudTestWorkflowRepository)(nil)
+
+type CloudTestWorkflowRepository struct {
+ executor executor.Executor
+}
+
+func NewCloudTestWorkflowRepository(client cloud.TestKubeCloudAPIClient, grpcConn *grpc.ClientConn, apiKey string) *CloudTestWorkflowRepository {
+ return &CloudTestWorkflowRepository{executor: executor.NewCloudGRPCExecutor(client, grpcConn, apiKey)}
+}
+
+func (r *CloudTestWorkflowRepository) List(selector string) (*testworkflowsv1.TestWorkflowList, error) {
+ req := TestWorkflowListRequest{Selector: selector}
+ response, err := r.executor.Execute(context.Background(), CmdTestWorkflowList, req)
+ if err != nil {
+ return nil, err
+ }
+ var commandResponse TestWorkflowListResponse
+ if err := json.Unmarshal(response, &commandResponse); err != nil {
+ return nil, err
+ }
+ list := testworkflowmappers.MapListAPIToKube(commandResponse.TestWorkflows)
+ return &list, nil
+}
+
+func (r *CloudTestWorkflowRepository) ListLabels() (map[string][]string, error) {
+ return make(map[string][]string), errors.New("unimplemented")
+}
+
+func (r *CloudTestWorkflowRepository) Get(name string) (*testworkflowsv1.TestWorkflow, error) {
+ req := TestWorkflowGetRequest{Name: name}
+ response, err := r.executor.Execute(context.Background(), CmdTestWorkflowGet, req)
+ if err != nil {
+ return nil, err
+ }
+ var commandResponse TestWorkflowGetResponse
+ if err := json.Unmarshal(response, &commandResponse); err != nil {
+ return nil, err
+ }
+ return testworkflowmappers.MapAPIToKube(&commandResponse.TestWorkflow), nil
+}
+
+// Create creates new TestWorkflow
+func (r *CloudTestWorkflowRepository) Create(workflow *testworkflowsv1.TestWorkflow) (*testworkflowsv1.TestWorkflow, error) {
+ return nil, errors.New("unimplemented")
+}
+
+func (r *CloudTestWorkflowRepository) Update(workflow *testworkflowsv1.TestWorkflow) (*testworkflowsv1.TestWorkflow, error) {
+ return nil, errors.New("unimplemented")
+}
+
+func (r *CloudTestWorkflowRepository) Apply(workflow *testworkflowsv1.TestWorkflow) error {
+ return errors.New("unimplemented")
+}
+
+func (r *CloudTestWorkflowRepository) Delete(name string) error {
+ return errors.New("unimplemented")
+}
+
+func (r *CloudTestWorkflowRepository) DeleteAll() error {
+ return errors.New("unimplemented")
+}
+
+func (r *CloudTestWorkflowRepository) DeleteByLabels(selector string) error {
+ return errors.New("unimplemented")
+}
+
+func (r *CloudTestWorkflowRepository) UpdateStatus(workflow *testworkflowsv1.TestWorkflow) error {
+ // This is the actual implementation, as update status
+ // should update k8s crd's status field, but we don't have it when stored in mongo
+ return nil
+}