diff --git a/docs/protocol.md b/docs/protocol.md index 3bc28f2..ed0a122 100644 --- a/docs/protocol.md +++ b/docs/protocol.md @@ -1506,6 +1506,7 @@ through the kube-api server. | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | | cluster_definition | [bytes](#bytes) | | This field is REQUIRED. Value of this field is the JSON serialization of the Cluster. | +| check_empty_wal_archive | [bool](#bool) | optional | This field is OPTIONAL. The operator always sets it, to convey its decision on whether the plugin should verify that the backup destination is not already in use by a different cluster or timeline before restoring (protection against WAL/timeline divergence). If unset, the request comes from an operator that predates this field, and the plugin is free to handle that case as it sees fit. | @@ -1605,6 +1606,7 @@ Intentionally empty. | cluster_definition | [bytes](#bytes) | | This field is REQUIRED. Value of this field is the JSON serialization of the Cluster corresponding to the Pod being applied | | source_file_name | [string](#string) | | This field is REQUIRED. Value of this field is the full path of the WAL file that should be archived | | parameters | [WALArchiveRequest.ParametersEntry](#cnpgi-wal-v1-WALArchiveRequest-ParametersEntry) | repeated | This field is OPTIONAL. Values are opaque. | +| check_empty_wal_archive | [bool](#bool) | optional | This field is OPTIONAL. The operator always sets it, to convey its decision on whether the plugin should verify the WAL archive destination is empty before this upload. If unset, the request comes from an operator that predates this field, and the plugin is free to handle that case as it sees fit. | diff --git a/pkg/restore/job/restore_job.pb.go b/pkg/restore/job/restore_job.pb.go index 9e0401f..c60367a 100644 --- a/pkg/restore/job/restore_job.pb.go +++ b/pkg/restore/job/restore_job.pb.go @@ -218,8 +218,15 @@ type RestoreRequest struct { // This field is REQUIRED. Value of this field is the JSON // serialization of the Cluster. ClusterDefinition []byte `protobuf:"bytes,1,opt,name=cluster_definition,json=clusterDefinition,proto3" json:"cluster_definition,omitempty"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache + // This field is OPTIONAL. The operator always sets it, to convey its + // decision on whether the plugin should verify that the backup + // destination is not already in use by a different cluster or timeline + // before restoring (protection against WAL/timeline divergence). If + // unset, the request comes from an operator that predates this field, + // and the plugin is free to handle that case as it sees fit. + CheckEmptyWalArchive *bool `protobuf:"varint,2,opt,name=check_empty_wal_archive,json=checkEmptyWalArchive,proto3,oneof" json:"check_empty_wal_archive,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *RestoreRequest) Reset() { @@ -259,6 +266,13 @@ func (x *RestoreRequest) GetClusterDefinition() []byte { return nil } +func (x *RestoreRequest) GetCheckEmptyWalArchive() bool { + if x != nil && x.CheckEmptyWalArchive != nil { + return *x.CheckEmptyWalArchive + } + return false +} + type RestoreResponse struct { state protoimpl.MessageState `protogen:"open.v1"` // This field is REQUIRED. Value of this field is the string @@ -328,9 +342,11 @@ const file_proto_restore_job_proto_rawDesc = "" + "\x04kind\x18\x01 \x01(\x0e2,.cnpgi.wal.v1.RestoreJobHooksCapability.KindR\x04kind\".\n" + "\x04Kind\x12\x14\n" + "\x10KIND_UNSPECIFIED\x10\x00\x12\x10\n" + - "\fKIND_RESTORE\x10\x01\"?\n" + + "\fKIND_RESTORE\x10\x01\"\x97\x01\n" + "\x0eRestoreRequest\x12-\n" + - "\x12cluster_definition\x18\x01 \x01(\fR\x11clusterDefinition\"L\n" + + "\x12cluster_definition\x18\x01 \x01(\fR\x11clusterDefinition\x12:\n" + + "\x17check_empty_wal_archive\x18\x02 \x01(\bH\x00R\x14checkEmptyWalArchive\x88\x01\x01B\x1a\n" + + "\x18_check_empty_wal_archive\"L\n" + "\x0fRestoreResponse\x12%\n" + "\x0erestore_config\x18\x01 \x01(\tR\rrestoreConfig\x12\x12\n" + "\x04envs\x18\x02 \x03(\tR\x04envs2\xd3\x01\n" + @@ -379,6 +395,7 @@ func file_proto_restore_job_proto_init() { if File_proto_restore_job_proto != nil { return } + file_proto_restore_job_proto_msgTypes[3].OneofWrappers = []any{} type x struct{} out := protoimpl.TypeBuilder{ File: protoimpl.DescBuilder{ diff --git a/pkg/wal/wal.pb.go b/pkg/wal/wal.pb.go index 05ebcee..8c6c0a7 100644 --- a/pkg/wal/wal.pb.go +++ b/pkg/wal/wal.pb.go @@ -171,9 +171,15 @@ type WALArchiveRequest struct { // of the WAL file that should be archived SourceFileName string `protobuf:"bytes,2,opt,name=source_file_name,json=sourceFileName,proto3" json:"source_file_name,omitempty"` // This field is OPTIONAL. Values are opaque. - Parameters map[string]string `protobuf:"bytes,3,rep,name=parameters,proto3" json:"parameters,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache + Parameters map[string]string `protobuf:"bytes,3,rep,name=parameters,proto3" json:"parameters,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"` + // This field is OPTIONAL. The operator always sets it, to convey its + // decision on whether the plugin should verify the WAL archive + // destination is empty before this upload. If unset, the request comes + // from an operator that predates this field, and the plugin is free to + // handle that case as it sees fit. + CheckEmptyWalArchive *bool `protobuf:"varint,4,opt,name=check_empty_wal_archive,json=checkEmptyWalArchive,proto3,oneof" json:"check_empty_wal_archive,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *WALArchiveRequest) Reset() { @@ -227,6 +233,13 @@ func (x *WALArchiveRequest) GetParameters() map[string]string { return nil } +func (x *WALArchiveRequest) GetCheckEmptyWalArchive() bool { + if x != nil && x.CheckEmptyWalArchive != nil { + return *x.CheckEmptyWalArchive + } + return false +} + type WALArchiveResult struct { state protoimpl.MessageState `protogen:"open.v1"` unknownFields protoimpl.UnknownFields @@ -787,16 +800,18 @@ var File_proto_wal_proto protoreflect.FileDescriptor const file_proto_wal_proto_rawDesc = "" + "\n" + - "\x0fproto/wal.proto\x12\fcnpgi.wal.v1\"\xfc\x01\n" + + "\x0fproto/wal.proto\x12\fcnpgi.wal.v1\"\xd4\x02\n" + "\x11WALArchiveRequest\x12-\n" + "\x12cluster_definition\x18\x01 \x01(\fR\x11clusterDefinition\x12(\n" + "\x10source_file_name\x18\x02 \x01(\tR\x0esourceFileName\x12O\n" + "\n" + "parameters\x18\x03 \x03(\v2/.cnpgi.wal.v1.WALArchiveRequest.ParametersEntryR\n" + - "parameters\x1a=\n" + + "parameters\x12:\n" + + "\x17check_empty_wal_archive\x18\x04 \x01(\bH\x00R\x14checkEmptyWalArchive\x88\x01\x01\x1a=\n" + "\x0fParametersEntry\x12\x10\n" + "\x03key\x18\x01 \x01(\tR\x03key\x12\x14\n" + - "\x05value\x18\x02 \x01(\tR\x05value:\x028\x01\"\x12\n" + + "\x05value\x18\x02 \x01(\tR\x05value:\x028\x01B\x1a\n" + + "\x18_check_empty_wal_archive\"\x12\n" + "\x10WALArchiveResult\"\xaa\x03\n" + "\x11WALRestoreRequest\x12-\n" + "\x12cluster_definition\x18\x01 \x01(\fR\x11clusterDefinition\x12&\n" + @@ -911,6 +926,7 @@ func file_proto_wal_proto_init() { if File_proto_wal_proto != nil { return } + file_proto_wal_proto_msgTypes[0].OneofWrappers = []any{} file_proto_wal_proto_msgTypes[10].OneofWrappers = []any{ (*WALCapability_Rpc)(nil), } diff --git a/proto/restore_job.proto b/proto/restore_job.proto index 01f9b12..37e7492 100644 --- a/proto/restore_job.proto +++ b/proto/restore_job.proto @@ -54,6 +54,14 @@ message RestoreRequest { // This field is REQUIRED. Value of this field is the JSON // serialization of the Cluster. bytes cluster_definition = 1; + + // This field is OPTIONAL. The operator always sets it, to convey its + // decision on whether the plugin should verify that the backup + // destination is not already in use by a different cluster or timeline + // before restoring (protection against WAL/timeline divergence). If + // unset, the request comes from an operator that predates this field, + // and the plugin is free to handle that case as it sees fit. + optional bool check_empty_wal_archive = 2; } message RestoreResponse { diff --git a/proto/wal.proto b/proto/wal.proto index 2a21986..0d5baa8 100644 --- a/proto/wal.proto +++ b/proto/wal.proto @@ -48,6 +48,13 @@ message WALArchiveRequest { // This field is OPTIONAL. Values are opaque. map parameters = 3; + + // This field is OPTIONAL. The operator always sets it, to convey its + // decision on whether the plugin should verify the WAL archive + // destination is empty before this upload. If unset, the request comes + // from an operator that predates this field, and the plugin is free to + // handle that case as it sees fit. + optional bool check_empty_wal_archive = 4; } message WALArchiveResult {