make id and payload columns configurable
This commit is contained in:
		
							parent
							
								
									837969ed76
								
							
						
					
					
						commit
						bde522ba2a
					
				|  | @ -489,7 +489,16 @@ spec: | |||
|                     tables: | ||||
|                       type: object | ||||
|                       additionalProperties: | ||||
|                         type: string | ||||
|                         type: object | ||||
|                         required: | ||||
|                           - evenType | ||||
|                         properties: | ||||
|                           eventType: | ||||
|                             type: string | ||||
|                           idColumn: | ||||
|                             type: string | ||||
|                           payloadColumn: | ||||
|                             type: string | ||||
|               teamId: | ||||
|                 type: string | ||||
|               tls: | ||||
|  |  | |||
|  | @ -530,11 +530,15 @@ Each stream object can have the following properties: | |||
|   replication user). Required. | ||||
| 
 | ||||
| * **tables** | ||||
|   Defines a map of (outbox) table names and event types. The CDC operator is following | ||||
|   the [outbox pattern](https://debezium.io/blog/2019/02/19/reliable-microservices-data-exchange-with-the-outbox-pattern/). | ||||
|   This means that the application will put events into a column in the outbox table | ||||
|   in the structure of the target event type, and the CDC operator will capture them | ||||
|   shortly after the transaction is committed. Required. | ||||
|   Defines a map of table names and their properties (`eventType`, `idColumn` | ||||
|   and `payloadColumn`). The CDC operator is following the [outbox pattern](https://debezium.io/blog/2019/02/19/reliable-microservices-data-exchange-with-the-outbox-pattern/). | ||||
|   The application is responsible for putting events into a (JSON/B or VARCHAR) | ||||
|   payload column of the outbox table in the structure of the specified target | ||||
|   event type. The the CDC operator will consume them shortly after the | ||||
|   transaction is committed. The `idColumn` will be used in telemetry for the | ||||
|   CDC operator. The names for `idColumn` and `payloadColumn` can be configured. | ||||
|   Defaults are `id` and `payload`. The target `eventType` has to be defined. | ||||
|   Required. | ||||
| 
 | ||||
| * **filter** | ||||
|   Streamed events can be filtered by a jsonpath expression for each table. | ||||
|  |  | |||
|  | @ -200,8 +200,12 @@ spec: | |||
| #  streams: | ||||
| #  - database: foo | ||||
| #    tables: | ||||
| #      data.ta: event_type_a | ||||
| #      data.tb: event_type_b | ||||
| #      data.ta: | ||||
| #        eventType: event_type_a | ||||
| #      data.tb: | ||||
| #        eventType: event_type_b | ||||
| #        idColumn: tb_id | ||||
| #        payloadColumn: tb_payload | ||||
| #    # Optional. Filter ignores events before a certain txnId and lsn. Can be used to skip bad events | ||||
| #    filter: | ||||
| #      data.ta: "[?(@.source.txId > 500 && @.source.lsn > 123456)]" | ||||
|  |  | |||
|  | @ -487,7 +487,16 @@ spec: | |||
|                     tables: | ||||
|                       type: object | ||||
|                       additionalProperties: | ||||
|                         type: string | ||||
|                         type: object | ||||
|                         required: | ||||
|                           - evenType | ||||
|                         properties: | ||||
|                           eventType: | ||||
|                             type: string | ||||
|                           idColumn: | ||||
|                             type: string | ||||
|                           payloadColumn: | ||||
|                             type: string | ||||
|               teamId: | ||||
|                 type: string | ||||
|               tls: | ||||
|  |  | |||
|  | @ -682,7 +682,19 @@ var PostgresCRDResourceValidation = apiextv1.CustomResourceValidation{ | |||
| 										Type: "object", | ||||
| 										AdditionalProperties: &apiextv1.JSONSchemaPropsOrBool{ | ||||
| 											Schema: &apiextv1.JSONSchemaProps{ | ||||
| 												Type: "string", | ||||
| 												Type:     "object", | ||||
| 												Required: []string{"eventType"}, | ||||
| 												Properties: map[string]apiextv1.JSONSchemaProps{ | ||||
| 													"eventType": { | ||||
| 														Type: "string", | ||||
| 													}, | ||||
| 													"idColumn": { | ||||
| 														Type: "string", | ||||
| 													}, | ||||
| 													"payloadColumn": { | ||||
| 														Type: "string", | ||||
| 													}, | ||||
| 												}, | ||||
| 											}, | ||||
| 										}, | ||||
| 									}, | ||||
|  |  | |||
|  | @ -229,8 +229,14 @@ type ConnectionPooler struct { | |||
| } | ||||
| 
 | ||||
| type Stream struct { | ||||
| 	Database  string            `json:"database"` | ||||
| 	Tables    map[string]string `json:"tables"` | ||||
| 	Filter    map[string]string `json:"filter,omitempty"` | ||||
| 	BatchSize uint32            `json:"batchSize,omitempty"` | ||||
| 	Database  string                 `json:"database"` | ||||
| 	Tables    map[string]StreamTable `json:"tables"` | ||||
| 	Filter    map[string]string      `json:"filter,omitempty"` | ||||
| 	BatchSize uint32                 `json:"batchSize,omitempty"` | ||||
| } | ||||
| 
 | ||||
| type StreamTable struct { | ||||
| 	EventType     string `json:"eventType"` | ||||
| 	IdColumn      string `json:"idColumn,omitempty" defaults:"id"` | ||||
| 	PayloadColumn string `json:"payloadColumn,omitempty" defaults:"payload"` | ||||
| } | ||||
|  |  | |||
|  | @ -1143,7 +1143,7 @@ func (in *Stream) DeepCopyInto(out *Stream) { | |||
| 	*out = *in | ||||
| 	if in.Tables != nil { | ||||
| 		in, out := &in.Tables, &out.Tables | ||||
| 		*out = make(map[string]string, len(*in)) | ||||
| 		*out = make(map[string]StreamTable, len(*in)) | ||||
| 		for key, val := range *in { | ||||
| 			(*out)[key] = val | ||||
| 		} | ||||
|  | @ -1168,6 +1168,22 @@ func (in *Stream) DeepCopy() *Stream { | |||
| 	return out | ||||
| } | ||||
| 
 | ||||
| // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
 | ||||
| func (in *StreamTable) DeepCopyInto(out *StreamTable) { | ||||
| 	*out = *in | ||||
| 	return | ||||
| } | ||||
| 
 | ||||
| // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new StreamTable.
 | ||||
| func (in *StreamTable) DeepCopy() *StreamTable { | ||||
| 	if in == nil { | ||||
| 		return nil | ||||
| 	} | ||||
| 	out := new(StreamTable) | ||||
| 	in.DeepCopyInto(out) | ||||
| 	return out | ||||
| } | ||||
| 
 | ||||
| // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
 | ||||
| func (in *TLSDescription) DeepCopyInto(out *TLSDescription) { | ||||
| 	*out = *in | ||||
|  |  | |||
|  | @ -9,14 +9,11 @@ import ( | |||
| 	acidv1 "github.com/zalando/postgres-operator/pkg/apis/acid.zalan.do/v1" | ||||
| 	zalandov1alpha1 "github.com/zalando/postgres-operator/pkg/apis/zalando.org/v1alpha1" | ||||
| 	"github.com/zalando/postgres-operator/pkg/util" | ||||
| 	"github.com/zalando/postgres-operator/pkg/util/config" | ||||
| 	"github.com/zalando/postgres-operator/pkg/util/constants" | ||||
| 	"github.com/zalando/postgres-operator/pkg/util/k8sutil" | ||||
| 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" | ||||
| ) | ||||
| 
 | ||||
| var outboxTableNameTemplate config.StringTemplate = "{table}_{eventtype}_outbox" | ||||
| 
 | ||||
| func (c *Cluster) createStreams() error { | ||||
| 	c.setProcessName("creating streams") | ||||
| 
 | ||||
|  | @ -114,10 +111,10 @@ func (c *Cluster) generateFabricEventStream() *zalandov1alpha1.FabricEventStream | |||
| 	eventStreams := make([]zalandov1alpha1.EventStream, 0) | ||||
| 
 | ||||
| 	for _, stream := range c.Spec.Streams { | ||||
| 		for table, eventType := range stream.Tables { | ||||
| 			streamSource := c.getEventStreamSource(stream, table, eventType) | ||||
| 			streamFlow := getEventStreamFlow(stream) | ||||
| 			streamSink := getEventStreamSink(stream, eventType) | ||||
| 		for tableName, table := range stream.Tables { | ||||
| 			streamSource := c.getEventStreamSource(stream, tableName, table.IdColumn) | ||||
| 			streamFlow := getEventStreamFlow(stream, table.PayloadColumn) | ||||
| 			streamSink := getEventStreamSink(stream, table.EventType) | ||||
| 
 | ||||
| 			eventStreams = append(eventStreams, zalandov1alpha1.EventStream{ | ||||
| 				EventStreamFlow:   streamFlow, | ||||
|  | @ -145,21 +142,22 @@ func (c *Cluster) generateFabricEventStream() *zalandov1alpha1.FabricEventStream | |||
| 	} | ||||
| } | ||||
| 
 | ||||
| func (c *Cluster) getEventStreamSource(stream acidv1.Stream, table, eventType string) zalandov1alpha1.EventStreamSource { | ||||
| 	_, schema := getTableSchema(table) | ||||
| 	streamFilter := stream.Filter[table] | ||||
| func (c *Cluster) getEventStreamSource(stream acidv1.Stream, tableName, idColumn string) zalandov1alpha1.EventStreamSource { | ||||
| 	_, schema := getTableSchema(tableName) | ||||
| 	streamFilter := stream.Filter[tableName] | ||||
| 	return zalandov1alpha1.EventStreamSource{ | ||||
| 		Type:             constants.EventStreamSourcePGType, | ||||
| 		Schema:           schema, | ||||
| 		EventStreamTable: getOutboxTable(table, eventType), | ||||
| 		EventStreamTable: getOutboxTable(tableName, idColumn), | ||||
| 		Filter:           streamFilter, | ||||
| 		Connection:       c.getStreamConnection(stream.Database, constants.EventStreamSourceSlotPrefix+constants.UserRoleNameSuffix), | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func getEventStreamFlow(stream acidv1.Stream) zalandov1alpha1.EventStreamFlow { | ||||
| func getEventStreamFlow(stream acidv1.Stream, payloadColumn string) zalandov1alpha1.EventStreamFlow { | ||||
| 	return zalandov1alpha1.EventStreamFlow{ | ||||
| 		Type: constants.EventStreamFlowPgGenericType, | ||||
| 		Type:          constants.EventStreamFlowPgGenericType, | ||||
| 		PayloadColumn: payloadColumn, | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
|  | @ -182,9 +180,10 @@ func getTableSchema(fullTableName string) (tableName, schemaName string) { | |||
| 	return tableName, schemaName | ||||
| } | ||||
| 
 | ||||
| func getOutboxTable(tableName, eventType string) zalandov1alpha1.EventStreamTable { | ||||
| func getOutboxTable(tableName, idColumn string) zalandov1alpha1.EventStreamTable { | ||||
| 	return zalandov1alpha1.EventStreamTable{ | ||||
| 		Name: outboxTableNameTemplate.Format("table", tableName, "eventtype", eventType), | ||||
| 		Name:     tableName, | ||||
| 		IDColumn: idColumn, | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
|  |  | |||
|  | @ -48,8 +48,12 @@ var ( | |||
| 			Streams: []acidv1.Stream{ | ||||
| 				{ | ||||
| 					Database: "foo", | ||||
| 					Tables: map[string]string{ | ||||
| 						"bar": "stream_type_a", | ||||
| 					Tables: map[string]acidv1.StreamTable{ | ||||
| 						"bar": acidv1.StreamTable{ | ||||
| 							EventType:     "stream_type_a", | ||||
| 							IdColumn:      "b_id", | ||||
| 							PayloadColumn: "b_payload", | ||||
| 						}, | ||||
| 					}, | ||||
| 					BatchSize: uint32(100), | ||||
| 				}, | ||||
|  | @ -124,8 +128,12 @@ func TestUpdateFabricEventStream(t *testing.T) { | |||
| 	pgSpec.Streams = []acidv1.Stream{ | ||||
| 		{ | ||||
| 			Database: "foo", | ||||
| 			Tables: map[string]string{ | ||||
| 				"bar": "stream_type_b", | ||||
| 			Tables: map[string]acidv1.StreamTable{ | ||||
| 				"bar": acidv1.StreamTable{ | ||||
| 					EventType:     "stream_type_b", | ||||
| 					IdColumn:      "b_id", | ||||
| 					PayloadColumn: "b_payload", | ||||
| 				}, | ||||
| 			}, | ||||
| 			BatchSize: uint32(250), | ||||
| 		}, | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue