diff --git a/internal/flink/command_detached_savepoint.go b/internal/flink/command_detached_savepoint.go index 919b9f225f..35205202df 100644 --- a/internal/flink/command_detached_savepoint.go +++ b/internal/flink/command_detached_savepoint.go @@ -37,7 +37,7 @@ func convertSdkDetachedSavepointToLocalSavepoint(sdkSavepoint cmfsdk.Savepoint) ApiVersion: sdkSavepoint.ApiVersion, Kind: sdkSavepoint.Kind, Metadata: LocalSavepointMetadata{ - Name: *sdkSavepoint.Metadata.Name, + Name: sdkSavepoint.Metadata.GetName(), CreationTimestamp: sdkSavepoint.Metadata.CreationTimestamp, Uid: sdkSavepoint.Metadata.Uid, Labels: sdkSavepoint.Metadata.Labels, diff --git a/internal/flink/command_detached_savepoint_create.go b/internal/flink/command_detached_savepoint_create.go index f5d60f156b..61a0823af8 100644 --- a/internal/flink/command_detached_savepoint_create.go +++ b/internal/flink/command_detached_savepoint_create.go @@ -65,14 +65,19 @@ func (c *command) detachedSavepointCreate(cmd *cobra.Command, args []string) err return err } - table := output.NewTable(cmd) - table.Add(&detachedSavepointOut{ - Name: detachedSavepoint.Metadata.GetName(), - Path: detachedSavepoint.Spec.GetPath(), - Format: detachedSavepoint.Spec.GetFormatType(), - BackoffLimit: detachedSavepoint.Spec.GetBackoffLimit(), - CreationTimestamp: detachedSavepoint.Metadata.GetCreationTimestamp(), - Uid: detachedSavepoint.Metadata.GetUid(), - }) - return table.Print() + if output.GetFormat(cmd) == output.Human { + table := output.NewTable(cmd) + table.Add(&detachedSavepointOut{ + Name: detachedSavepoint.Metadata.GetName(), + Path: detachedSavepoint.Spec.GetPath(), + Format: detachedSavepoint.Spec.GetFormatType(), + BackoffLimit: detachedSavepoint.Spec.GetBackoffLimit(), + CreationTimestamp: detachedSavepoint.Metadata.GetCreationTimestamp(), + Uid: detachedSavepoint.Metadata.GetUid(), + }) + return table.Print() + } + + localDetachedSavepoint := convertSdkDetachedSavepointToLocalSavepoint(detachedSavepoint) + return output.SerializedOutput(cmd, localDetachedSavepoint) } diff --git a/internal/flink/command_savepoint.go b/internal/flink/command_savepoint.go index 7e383bd0e2..e44582d94f 100644 --- a/internal/flink/command_savepoint.go +++ b/internal/flink/command_savepoint.go @@ -40,7 +40,7 @@ func convertSdkSavepointToLocalSavepoint(sdkSavepoint cmfsdk.Savepoint) LocalSav ApiVersion: sdkSavepoint.ApiVersion, Kind: sdkSavepoint.Kind, Metadata: LocalSavepointMetadata{ - Name: *sdkSavepoint.Metadata.Name, + Name: sdkSavepoint.Metadata.GetName(), CreationTimestamp: sdkSavepoint.Metadata.CreationTimestamp, Uid: sdkSavepoint.Metadata.Uid, Labels: sdkSavepoint.Metadata.Labels, diff --git a/internal/flink/command_savepoint_create.go b/internal/flink/command_savepoint_create.go index 543c1e01c2..7d5b2c3cbf 100644 --- a/internal/flink/command_savepoint_create.go +++ b/internal/flink/command_savepoint_create.go @@ -113,16 +113,21 @@ func (c *command) savepointCreate(cmd *cobra.Command, args []string) error { } } - table := output.NewTable(cmd) - table.Add(&savepointOut{ - Name: savepointCreated.Metadata.GetName(), - Statement: statement, - Application: application, - Path: savepointCreated.Spec.GetPath(), - Format: savepointCreated.Spec.GetFormatType(), - BackoffLimit: savepointCreated.Spec.GetBackoffLimit(), - Uid: savepointCreated.Metadata.GetUid(), - State: savepointCreated.Status.GetState(), - }) - return table.Print() + if output.GetFormat(cmd) == output.Human { + table := output.NewTable(cmd) + table.Add(&savepointOut{ + Name: savepointCreated.Metadata.GetName(), + Statement: statement, + Application: application, + Path: savepointCreated.Spec.GetPath(), + Format: savepointCreated.Spec.GetFormatType(), + BackoffLimit: savepointCreated.Spec.GetBackoffLimit(), + Uid: savepointCreated.Metadata.GetUid(), + State: savepointCreated.Status.GetState(), + }) + return table.Print() + } + + localSavepoint := convertSdkSavepointToLocalSavepoint(savepointCreated) + return output.SerializedOutput(cmd, localSavepoint) } diff --git a/internal/flink/command_savepoint_detach.go b/internal/flink/command_savepoint_detach.go index efaeaf1968..f2293b23ac 100644 --- a/internal/flink/command_savepoint_detach.go +++ b/internal/flink/command_savepoint_detach.go @@ -50,15 +50,20 @@ func (c *command) savepointDetach(cmd *cobra.Command, args []string) error { return err } - table := output.NewTable(cmd) - table.Add(&savepointOut{ - Name: cmfSavepoint.Metadata.GetName(), - Application: application, - Path: cmfSavepoint.Spec.GetPath(), - Format: cmfSavepoint.Spec.GetFormatType(), - BackoffLimit: cmfSavepoint.Spec.GetBackoffLimit(), - Uid: cmfSavepoint.Metadata.GetUid(), - State: cmfSavepoint.Status.GetState(), - }) - return table.Print() + if output.GetFormat(cmd) == output.Human { + table := output.NewTable(cmd) + table.Add(&savepointOut{ + Name: cmfSavepoint.Metadata.GetName(), + Application: application, + Path: cmfSavepoint.Spec.GetPath(), + Format: cmfSavepoint.Spec.GetFormatType(), + BackoffLimit: cmfSavepoint.Spec.GetBackoffLimit(), + Uid: cmfSavepoint.Metadata.GetUid(), + State: cmfSavepoint.Status.GetState(), + }) + return table.Print() + } + + localSavepoint := convertSdkSavepointToLocalSavepoint(cmfSavepoint) + return output.SerializedOutput(cmd, localSavepoint) } diff --git a/pkg/flink/cmf_rest_client.go b/pkg/flink/cmf_rest_client.go index 8518ad1423..44c0a8b075 100644 --- a/pkg/flink/cmf_rest_client.go +++ b/pkg/flink/cmf_rest_client.go @@ -356,7 +356,7 @@ func (cmfClient *CmfRestClient) DescribeSavepoint(ctx context.Context, environme func (cmfClient *CmfRestClient) DetachSavepointApplication(ctx context.Context, savepoint, environment, application string) (cmfsdk.Savepoint, error) { outputSavepoint, httpResponse, err := cmfClient.SavepointsApi.DetachSavepointFromFlinkApplication(ctx, environment, application, savepoint).Execute() if parsedErr := parseSdkError(httpResponse, err); parsedErr != nil { - return cmfsdk.Savepoint{}, fmt.Errorf(`failed to create savepoint in the environment "%s": %s`, environment, parsedErr) + return cmfsdk.Savepoint{}, fmt.Errorf(`failed to detach savepoint in the environment "%s": %s`, environment, parsedErr) } return outputSavepoint, nil } diff --git a/test/fixtures/output/flink/detached-savepoint/create-savepoint-json.golden b/test/fixtures/output/flink/detached-savepoint/create-savepoint-json.golden new file mode 100644 index 0000000000..553ae594eb --- /dev/null +++ b/test/fixtures/output/flink/detached-savepoint/create-savepoint-json.golden @@ -0,0 +1,17 @@ +{ + "apiVersion": "cmf.confluent.io/v1", + "kind": "Savepoint", + "metadata": { + "name": "savepoint1", + "creationTimestamp": "2025-03-12 23:42:00 +0000 UTC", + "uid": "id1" + }, + "spec": { + "path": "abc/def", + "backoffLimit": 10, + "formatType": "Canonical" + }, + "status": { + "path": "abc/def" + } +} diff --git a/test/fixtures/output/flink/detached-savepoint/create-savepoint-yaml.golden b/test/fixtures/output/flink/detached-savepoint/create-savepoint-yaml.golden new file mode 100644 index 0000000000..148f9810a2 --- /dev/null +++ b/test/fixtures/output/flink/detached-savepoint/create-savepoint-yaml.golden @@ -0,0 +1,12 @@ +apiVersion: cmf.confluent.io/v1 +kind: Savepoint +metadata: + name: savepoint1 + creationTimestamp: 2025-03-12 23:42:00 +0000 UTC + uid: id1 +spec: + path: abc/def + backoffLimit: 10 + formatType: Canonical +status: + path: abc/def diff --git a/test/fixtures/output/flink/savepoint/create-savepoint-json.golden b/test/fixtures/output/flink/savepoint/create-savepoint-json.golden new file mode 100644 index 0000000000..9f26d5174d --- /dev/null +++ b/test/fixtures/output/flink/savepoint/create-savepoint-json.golden @@ -0,0 +1,15 @@ +{ + "apiVersion": "cmf.confluent.io/v1", + "kind": "Savepoint", + "metadata": { + "name": "savepoint1", + "creationTimestamp": "2025-03-12 23:42:00 +0000 UTC" + }, + "spec": { + "backoffLimit": 0, + "formatType": "CANONICAL" + }, + "status": { + "path": "" + } +} diff --git a/test/fixtures/output/flink/savepoint/create-savepoint-no-name-json.golden b/test/fixtures/output/flink/savepoint/create-savepoint-no-name-json.golden new file mode 100644 index 0000000000..da93058350 --- /dev/null +++ b/test/fixtures/output/flink/savepoint/create-savepoint-no-name-json.golden @@ -0,0 +1,15 @@ +{ + "apiVersion": "cmf.confluent.io/v1", + "kind": "Savepoint", + "metadata": { + "name": "", + "creationTimestamp": "2025-03-12 23:42:00 +0000 UTC" + }, + "spec": { + "backoffLimit": 0, + "formatType": "CANONICAL" + }, + "status": { + "path": "" + } +} diff --git a/test/fixtures/output/flink/savepoint/create-savepoint-no-name-yaml.golden b/test/fixtures/output/flink/savepoint/create-savepoint-no-name-yaml.golden new file mode 100644 index 0000000000..ec1c6d6954 --- /dev/null +++ b/test/fixtures/output/flink/savepoint/create-savepoint-no-name-yaml.golden @@ -0,0 +1,10 @@ +apiVersion: cmf.confluent.io/v1 +kind: Savepoint +metadata: + name: "" + creationTimestamp: 2025-03-12 23:42:00 +0000 UTC +spec: + backoffLimit: 0 + formatType: CANONICAL +status: + path: "" diff --git a/test/fixtures/output/flink/savepoint/create-savepoint-statement-json.golden b/test/fixtures/output/flink/savepoint/create-savepoint-statement-json.golden new file mode 100644 index 0000000000..64ffb4d7c9 --- /dev/null +++ b/test/fixtures/output/flink/savepoint/create-savepoint-statement-json.golden @@ -0,0 +1,15 @@ +{ + "apiVersion": "cmf.confluent.io/v1", + "kind": "Savepoint", + "metadata": { + "name": "savepoint-stmt", + "creationTimestamp": "2025-03-12 23:42:00 +0000 UTC" + }, + "spec": { + "backoffLimit": 0, + "formatType": "CANONICAL" + }, + "status": { + "path": "" + } +} diff --git a/test/fixtures/output/flink/savepoint/create-savepoint-statement-values.golden b/test/fixtures/output/flink/savepoint/create-savepoint-statement-values.golden index a01e888e8d..d660939d6d 100644 --- a/test/fixtures/output/flink/savepoint/create-savepoint-statement-values.golden +++ b/test/fixtures/output/flink/savepoint/create-savepoint-statement-values.golden @@ -1,7 +1,7 @@ -+---------------+------------+ -| Name | savepointS | -| Statement | test-stmt | -| Path | abc/def | -| Format | NATIVE | -| Backoff Limit | 10 | -+---------------+------------+ ++---------------+----------------+ +| Name | savepoint-stmt | +| Statement | test-stmt | +| Path | abc/def | +| Format | NATIVE | +| Backoff Limit | 10 | ++---------------+----------------+ diff --git a/test/fixtures/output/flink/savepoint/create-savepoint-statement-yaml.golden b/test/fixtures/output/flink/savepoint/create-savepoint-statement-yaml.golden new file mode 100644 index 0000000000..7f59c3877f --- /dev/null +++ b/test/fixtures/output/flink/savepoint/create-savepoint-statement-yaml.golden @@ -0,0 +1,10 @@ +apiVersion: cmf.confluent.io/v1 +kind: Savepoint +metadata: + name: savepoint-stmt + creationTimestamp: 2025-03-12 23:42:00 +0000 UTC +spec: + backoffLimit: 0 + formatType: CANONICAL +status: + path: "" diff --git a/test/fixtures/output/flink/savepoint/create-savepoint-statement.golden b/test/fixtures/output/flink/savepoint/create-savepoint-statement.golden index ed75ef1f7b..3b95323667 100644 --- a/test/fixtures/output/flink/savepoint/create-savepoint-statement.golden +++ b/test/fixtures/output/flink/savepoint/create-savepoint-statement.golden @@ -1,5 +1,5 @@ -+-----------+------------+ -| Name | savepointS | -| Statement | test-stmt | -| Format | CANONICAL | -+-----------+------------+ ++-----------+----------------+ +| Name | savepoint-stmt | +| Statement | test-stmt | +| Format | CANONICAL | ++-----------+----------------+ diff --git a/test/fixtures/output/flink/savepoint/create-savepoint-yaml.golden b/test/fixtures/output/flink/savepoint/create-savepoint-yaml.golden new file mode 100644 index 0000000000..c0fddf42e9 --- /dev/null +++ b/test/fixtures/output/flink/savepoint/create-savepoint-yaml.golden @@ -0,0 +1,10 @@ +apiVersion: cmf.confluent.io/v1 +kind: Savepoint +metadata: + name: savepoint1 + creationTimestamp: 2025-03-12 23:42:00 +0000 UTC +spec: + backoffLimit: 0 + formatType: CANONICAL +status: + path: "" diff --git a/test/fixtures/output/flink/savepoint/detach-savepoint-fail.golden b/test/fixtures/output/flink/savepoint/detach-savepoint-fail.golden new file mode 100644 index 0000000000..0ef09d42c8 --- /dev/null +++ b/test/fixtures/output/flink/savepoint/detach-savepoint-fail.golden @@ -0,0 +1 @@ +Error: failed to detach savepoint in the environment "default": The savepoint is invalid diff --git a/test/fixtures/output/flink/savepoint/detach-savepoint-json.golden b/test/fixtures/output/flink/savepoint/detach-savepoint-json.golden new file mode 100644 index 0000000000..ee813af357 --- /dev/null +++ b/test/fixtures/output/flink/savepoint/detach-savepoint-json.golden @@ -0,0 +1,13 @@ +{ + "apiVersion": "", + "kind": "", + "metadata": { + "name": "savepoint1", + "creationTimestamp": "2025-03-12 23:42:00 +0000 UTC" + }, + "spec": { + "path": "abc/def", + "backoffLimit": 10, + "formatType": "CANONICAL" + } +} diff --git a/test/fixtures/output/flink/savepoint/detach-savepoint-yaml.golden b/test/fixtures/output/flink/savepoint/detach-savepoint-yaml.golden new file mode 100644 index 0000000000..5f234794c0 --- /dev/null +++ b/test/fixtures/output/flink/savepoint/detach-savepoint-yaml.golden @@ -0,0 +1,9 @@ +apiVersion: "" +kind: "" +metadata: + name: savepoint1 + creationTimestamp: 2025-03-12 23:42:00 +0000 UTC +spec: + path: abc/def + backoffLimit: 10 + formatType: CANONICAL diff --git a/test/fixtures/output/flink/savepoint/detach-savepoint.golden b/test/fixtures/output/flink/savepoint/detach-savepoint.golden new file mode 100644 index 0000000000..5f064d72c3 --- /dev/null +++ b/test/fixtures/output/flink/savepoint/detach-savepoint.golden @@ -0,0 +1,7 @@ ++---------------+--------------+ +| Name | savepoint1 | +| Application | application1 | +| Path | abc/def | +| Format | CANONICAL | +| Backoff Limit | 10 | ++---------------+--------------+ diff --git a/test/flink_onprem_test.go b/test/flink_onprem_test.go index c98ca8c4b6..0bbfc46252 100644 --- a/test/flink_onprem_test.go +++ b/test/flink_onprem_test.go @@ -133,9 +133,15 @@ func (s *CLITestSuite) TestFlinkEnvironmentDelete() { func (s *CLITestSuite) TestFlinkSavepointCreate() { tests := []CLITest{ {args: "flink savepoint create savepoint1 --environment default --application application1", fixture: "flink/savepoint/create-savepoint.golden"}, + {args: "flink savepoint create savepoint1 --environment default --application application1 --output json", fixture: "flink/savepoint/create-savepoint-json.golden"}, + {args: "flink savepoint create savepoint1 --environment default --application application1 --output yaml", fixture: "flink/savepoint/create-savepoint-yaml.golden"}, {args: "flink savepoint create --environment default --application application2", fixture: "flink/savepoint/create-savepoint-no-name.golden"}, - {args: "flink savepoint create savepointS --environment default --statement test-stmt", fixture: "flink/savepoint/create-savepoint-statement.golden"}, - {args: "flink savepoint create savepointS --environment default --statement test-stmt --path abc/def --format NATIVE --backoff-limit 10", fixture: "flink/savepoint/create-savepoint-statement-values.golden"}, + {args: "flink savepoint create --environment default --application application2 --output json", fixture: "flink/savepoint/create-savepoint-no-name-json.golden"}, + {args: "flink savepoint create --environment default --application application2 --output yaml", fixture: "flink/savepoint/create-savepoint-no-name-yaml.golden"}, + {args: "flink savepoint create savepoint-stmt --environment default --statement test-stmt", fixture: "flink/savepoint/create-savepoint-statement.golden"}, + {args: "flink savepoint create savepoint-stmt --environment default --statement test-stmt --output json", fixture: "flink/savepoint/create-savepoint-statement-json.golden"}, + {args: "flink savepoint create savepoint-stmt --environment default --statement test-stmt --output yaml", fixture: "flink/savepoint/create-savepoint-statement-yaml.golden"}, + {args: "flink savepoint create savepoint-stmt --environment default --statement test-stmt --path abc/def --format NATIVE --backoff-limit 10", fixture: "flink/savepoint/create-savepoint-statement-values.golden"}, // fail {args: "flink savepoint create savepoint1 --environment default --application application1 --statement statement1", fixture: "flink/savepoint/create-savepoint-fail-both.golden", exitCode: 1}, {args: "flink savepoint create savepoint1 --environment default", fixture: "flink/savepoint/create-savepoint-fail-none.golden", exitCode: 1}, @@ -145,6 +151,18 @@ func (s *CLITestSuite) TestFlinkSavepointCreate() { runIntegrationTestsWithMultipleAuth(s, tests) } +func (s *CLITestSuite) TestFlinkSavepointDetach() { + tests := []CLITest{ + {args: "flink savepoint detach savepoint1 --environment default --application application1", fixture: "flink/savepoint/detach-savepoint.golden"}, + {args: "flink savepoint detach savepoint1 --environment default --application application1 --output json", fixture: "flink/savepoint/detach-savepoint-json.golden"}, + {args: "flink savepoint detach savepoint1 --environment default --application application1 --output yaml", fixture: "flink/savepoint/detach-savepoint-yaml.golden"}, + // fail + {args: "flink savepoint detach invalid-savepoint --environment default --application application1", fixture: "flink/savepoint/detach-savepoint-fail.golden", exitCode: 1}, + } + + runIntegrationTestsWithMultipleAuth(s, tests) +} + func (s *CLITestSuite) TestFlinkSavepointList() { tests := []CLITest{ // success scenarios @@ -184,6 +202,8 @@ func (s *CLITestSuite) TestFlinkSavepointDelete() { func (s *CLITestSuite) TestFlinkDetachedSavepointCreate() { tests := []CLITest{ {args: "flink detached-savepoint create savepoint1 --path abc/def", fixture: "flink/detached-savepoint/create-savepoint.golden"}, + {args: "flink detached-savepoint create savepoint1 --path abc/def --output json", fixture: "flink/detached-savepoint/create-savepoint-json.golden"}, + {args: "flink detached-savepoint create savepoint1 --path abc/def --output yaml", fixture: "flink/detached-savepoint/create-savepoint-yaml.golden"}, {args: "flink detached-savepoint create savepoint1", fixture: "flink/detached-savepoint/create-savepoint-nopath.golden", exitCode: 1}, } diff --git a/test/test-server/flink_onprem_handler.go b/test/test-server/flink_onprem_handler.go index d58b006ee8..0d8d2abafb 100644 --- a/test/test-server/flink_onprem_handler.go +++ b/test/test-server/flink_onprem_handler.go @@ -1036,6 +1036,36 @@ func handleCmfSavepoint(t *testing.T) http.HandlerFunc { } } +func handleCmfSavepointDetach(t *testing.T) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + handleLoginType(t, r) + + vars := mux.Vars(r) + environment := vars["envName"] + savepointName := vars["savepointName"] + + if environment == "non-exist" { + http.Error(w, "Environment not found", http.StatusNotFound) + return + } + + switch r.Method { + case http.MethodPost: + if savepointName == "invalid-savepoint" { + http.Error(w, "The savepoint is invalid", http.StatusNotFound) + return + } + + savepoint := createSavepoint(savepointName) + err := json.NewEncoder(w).Encode(savepoint) + require.NoError(t, err) + return + default: + require.Fail(t, fmt.Sprintf("Unexpected method %s", r.Method)) + } + } +} + func handleCmfDetachedSavepoints(t *testing.T) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { handleLoginType(t, r) diff --git a/test/test-server/flink_onprem_router.go b/test/test-server/flink_onprem_router.go index 49360810f6..0be3de7e71 100644 --- a/test/test-server/flink_onprem_router.go +++ b/test/test-server/flink_onprem_router.go @@ -27,6 +27,7 @@ var flinkRoutes = []route{ {"/cmf/api/v1/environments/{envName}/statements/{stmtName}/savepoints", handleCmfSavepoints}, {"/cmf/api/v1/environments/{envName}/applications/{appName}/savepoints/{savepointName}", handleCmfSavepoint}, {"/cmf/api/v1/environments/{envName}/statements/{stmtName}/savepoints/{savepointName}", handleCmfSavepoint}, + {"/cmf/api/v1/environments/{envName}/applications/{appName}/savepoints/{savepointName}/detach", handleCmfSavepointDetach}, {"/cmf/api/v1/environments/{envName}/secret-mappings", handleCmfSecretMappings}, {"/cmf/api/v1/environments/{envName}/secret-mappings/{name}", handleCmfSecretMapping}, {"/cmf/api/v1/secrets", handleCmfSecrets},