Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion internal/flink/command_detached_savepoint.go
Original file line number Diff line number Diff line change
Expand Up @@ -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(),

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not:

CreationTimestamp: sdkSavepoint.Metadata.GetCreationTimestamp() for the line below and similar fields?

The idea is try to be consistent across the table everywhere.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Repo-wide GetCreationTimestamp() is used where the target is a value string (the flat *Out table structs). Here the target is the structured LocalSavepointMetadata, where those fields are *string+omitempty, so they're copied as pointers directly — same as the ComputePool/Catalog/Statement converters.

CreationTimestamp: sdkSavepoint.Metadata.CreationTimestamp,
Uid: sdkSavepoint.Metadata.Uid,
Labels: sdkSavepoint.Metadata.Labels,
Expand Down
25 changes: 15 additions & 10 deletions internal/flink/command_detached_savepoint_create.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
2 changes: 1 addition & 1 deletion internal/flink/command_savepoint.go
Original file line number Diff line number Diff line change
Expand Up @@ -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(),

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please check the above comment and see if we can apply the same idea here.

CreationTimestamp: sdkSavepoint.Metadata.CreationTimestamp,
Uid: sdkSavepoint.Metadata.Uid,
Labels: sdkSavepoint.Metadata.Labels,
Expand Down
29 changes: 17 additions & 12 deletions internal/flink/command_savepoint_create.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Comment on lines +131 to +132

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you please check if the nil check can be handled elegantly using the SDK in some way.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is handled by the SDK's own getter. Both converters now use sdkSavepoint.Metadata.GetName(), and GetName() is nil-safe

}
27 changes: 16 additions & 11 deletions internal/flink/command_savepoint_detach.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
2 changes: 1 addition & 1 deletion pkg/flink/cmf_rest_client.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
Expand Down
Original file line number Diff line number Diff line change
@@ -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"
}
}
Original file line number Diff line number Diff line change
@@ -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
Original file line number Diff line number Diff line change
@@ -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": ""
}
}
Original file line number Diff line number Diff line change
@@ -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": ""
}
}
Original file line number Diff line number Diff line change
@@ -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: ""
Original file line number Diff line number Diff line change
@@ -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": ""
}
}
Original file line number Diff line number Diff line change
@@ -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 |
+---------------+----------------+
Original file line number Diff line number Diff line change
@@ -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: ""
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
+-----------+------------+
| Name | savepointS |
| Statement | test-stmt |
| Format | CANONICAL |
+-----------+------------+
+-----------+----------------+
| Name | savepoint-stmt |
| Statement | test-stmt |
| Format | CANONICAL |
+-----------+----------------+
Original file line number Diff line number Diff line change
@@ -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: ""
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Error: failed to detach savepoint in the environment "default": The savepoint is invalid
Original file line number Diff line number Diff line change
@@ -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"
}
}
Original file line number Diff line number Diff line change
@@ -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
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
+---------------+--------------+
| Name | savepoint1 |
| Application | application1 |
| Path | abc/def |
| Format | CANONICAL |
| Backoff Limit | 10 |
+---------------+--------------+
24 changes: 22 additions & 2 deletions test/flink_onprem_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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},
Expand All @@ -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
Expand Down Expand Up @@ -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},
}

Expand Down
30 changes: 30 additions & 0 deletions test/test-server/flink_onprem_handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
1 change: 1 addition & 0 deletions test/test-server/flink_onprem_router.go
Original file line number Diff line number Diff line change
Expand Up @@ -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},
Expand Down