@@ -129,7 +129,8 @@ def setUpClass(cls):
129
129
"infrastructure-roles.yaml" ,
130
130
"infrastructure-roles-new.yaml" ,
131
131
"custom-team-membership.yaml" ,
132
- "e2e-storage-class.yaml" ]:
132
+ "e2e-storage-class.yaml" ,
133
+ "fes.crd.yaml" ]:
133
134
result = k8s .create_with_kubectl ("manifests/" + filename )
134
135
print ("stdout: {}, stderr: {}" .format (result .stdout , result .stderr ))
135
136
@@ -199,6 +200,7 @@ def test_additional_owner_roles(self):
199
200
self .eventuallyEqual (lambda : len (self .query_database (leader .metadata .name , "postgres" , owner_query )), 3 ,
200
201
"Not all additional users found in database" , 10 , 5 )
201
202
203
+
202
204
@timeout_decorator .timeout (TEST_TIMEOUT_SEC )
203
205
def test_additional_pod_capabilities (self ):
204
206
'''
@@ -1203,7 +1205,7 @@ def check_version_14():
1203
1205
version = p ["server_version" ][0 :2 ]
1204
1206
return version
1205
1207
1206
- self .evantuallyEqual (check_version_14 , "14" , "Version was not upgrade to 14" )
1208
+ self .eventuallyEqual (check_version_14 , "14" , "Version was not upgrade to 14" )
1207
1209
1208
1210
@timeout_decorator .timeout (TEST_TIMEOUT_SEC )
1209
1211
def test_persistent_volume_claim_retention_policy (self ):
@@ -1989,6 +1991,123 @@ def test_standby_cluster(self):
1989
1991
"acid.zalan.do" , "v1" , "default" , "postgresqls" , "acid-standby-cluster" )
1990
1992
time .sleep (5 )
1991
1993
1994
+ @timeout_decorator .timeout (TEST_TIMEOUT_SEC )
1995
+ def test_stream_resources (self ):
1996
+ '''
1997
+ Create and delete fabric event streaming resources.
1998
+ '''
1999
+ k8s = self .k8s
2000
+ self .eventuallyEqual (lambda : k8s .get_operator_state (), {"0" : "idle" },
2001
+ "Operator does not get in sync" )
2002
+ leader = k8s .get_cluster_leader_pod ()
2003
+
2004
+ # patch ClusterRole with CRUD privileges on FES resources
2005
+ cluster_role = k8s .api .rbac_api .read_cluster_role ("postgres-operator" )
2006
+ fes_cluster_role_rule = client .V1PolicyRule (
2007
+ api_groups = ["zalando.org" ],
2008
+ resources = ["fabriceventstreams" ],
2009
+ verbs = ["create" , "delete" , "deletecollection" , "get" , "list" , "patch" , "update" , "watch" ]
2010
+ )
2011
+ cluster_role .rules .append (fes_cluster_role_rule )
2012
+ k8s .api .rbac_api .patch_cluster_role ("postgres-operator" , cluster_role )
2013
+
2014
+ # create a table in one of the database of acid-minimal-cluster
2015
+ create_stream_table = """
2016
+ CREATE TABLE test_table (id int, payload jsonb);
2017
+ """
2018
+ self .query_database (leader .metadata .name , "foo" , create_stream_table )
2019
+
2020
+ # update the manifest with the streams section
2021
+ patch_streaming_config = {
2022
+ "spec" : {
2023
+ "patroni" : {
2024
+ "slots" : {
2025
+ "manual_slot" : {
2026
+ "type" : "physical"
2027
+ }
2028
+ }
2029
+ },
2030
+ "streams" : [
2031
+ {
2032
+ "applicationId" : "test-app" ,
2033
+ "batchSize" : 100 ,
2034
+ "database" : "foo" ,
2035
+ "enableRecovery" : True ,
2036
+ "tables" : {
2037
+ "test_table" : {
2038
+ "eventType" : "test-event" ,
2039
+ "idColumn" : "id" ,
2040
+ "payloadColumn" : "payload" ,
2041
+ "recoveryEventType" : "test-event-dlq"
2042
+ }
2043
+ }
2044
+ }
2045
+ ]
2046
+ }
2047
+ }
2048
+ k8s .api .custom_objects_api .patch_namespaced_custom_object (
2049
+ 'acid.zalan.do' , 'v1' , 'default' , 'postgresqls' , 'acid-minimal-cluster' , patch_streaming_config )
2050
+ self .eventuallyEqual (lambda : k8s .get_operator_state (), {"0" : "idle" }, "Operator does not get in sync" )
2051
+
2052
+ # check if publication, slot, and fes resource are created
2053
+ get_publication_query = """
2054
+ SELECT * FROM pg_publication WHERE pubname = 'fes_foo_test_app';
2055
+ """
2056
+ get_slot_query = """
2057
+ SELECT * FROM pg_replication_slots WHERE slot_name = 'fes_foo_test_app';
2058
+ """
2059
+ self .eventuallyEqual (lambda : len (self .query_database (leader .metadata .name , "foo" , get_publication_query )), 1 ,
2060
+ "Publication is not created" , 10 , 5 )
2061
+ self .eventuallyEqual (lambda : len (self .query_database (leader .metadata .name , "foo" , get_slot_query )), 1 ,
2062
+ "Replication slot is not created" , 10 , 5 )
2063
+ self .eventuallyEqual (lambda : len (k8s .api .custom_objects_api .list_namespaced_custom_object (
2064
+ "zalando.org" , "v1" , "default" , "fabriceventstreams" , label_selector = "cluster-name=acid-minimal-cluster" )["items" ]), 1 ,
2065
+ "Could not find Fabric Event Stream resource" , 10 , 5 )
2066
+
2067
+ # grant create and ownership of test_table to foo_user, reset search path to default
2068
+ grant_permission_foo_user = """
2069
+ GRANT CREATE ON DATABASE foo TO foo_user;
2070
+ ALTER TABLE test_table OWNER TO foo_user;
2071
+ ALTER ROLE foo_user RESET search_path;
2072
+ """
2073
+ self .query_database (leader .metadata .name , "foo" , grant_permission_foo_user )
2074
+ # non-postgres user creates a publication
2075
+ create_nonstream_publication = """
2076
+ CREATE PUBLICATION mypublication FOR TABLE test_table;
2077
+ """
2078
+ self .query_database_with_user (leader .metadata .name , "foo" , create_nonstream_publication , "foo_user" )
2079
+
2080
+ # remove the streams section from the manifest
2081
+ patch_streaming_config_removal = {
2082
+ "spec" : {
2083
+ "streams" : []
2084
+ }
2085
+ }
2086
+ k8s .api .custom_objects_api .patch_namespaced_custom_object (
2087
+ 'acid.zalan.do' , 'v1' , 'default' , 'postgresqls' , 'acid-minimal-cluster' , patch_streaming_config_removal )
2088
+ self .eventuallyEqual (lambda : k8s .get_operator_state (), {"0" : "idle" }, "Operator does not get in sync" )
2089
+
2090
+ # check if publication, slot, and fes resource are removed
2091
+ self .eventuallyEqual (lambda : len (k8s .api .custom_objects_api .list_namespaced_custom_object (
2092
+ "zalando.org" , "v1" , "default" , "fabriceventstreams" , label_selector = "cluster-name=acid-minimal-cluster" )["items" ]), 0 ,
2093
+ 'Could not delete Fabric Event Stream resource' , 10 , 5 )
2094
+ self .eventuallyEqual (lambda : len (self .query_database (leader .metadata .name , "foo" , get_publication_query )), 0 ,
2095
+ "Publication is not deleted" , 10 , 5 )
2096
+ self .eventuallyEqual (lambda : len (self .query_database (leader .metadata .name , "foo" , get_slot_query )), 0 ,
2097
+ "Replication slot is not deleted" , 10 , 5 )
2098
+
2099
+ # check the manual_slot and mypublication should not get deleted
2100
+ get_manual_slot_query = """
2101
+ SELECT * FROM pg_replication_slots WHERE slot_name = 'manual_slot';
2102
+ """
2103
+ get_nonstream_publication_query = """
2104
+ SELECT * FROM pg_publication WHERE pubname = 'mypublication';
2105
+ """
2106
+ self .eventuallyEqual (lambda : len (self .query_database (leader .metadata .name , "postgres" , get_manual_slot_query )), 1 ,
2107
+ "Slot defined in patroni config is deleted" , 10 , 5 )
2108
+ self .eventuallyEqual (lambda : len (self .query_database (leader .metadata .name , "foo" , get_nonstream_publication_query )), 1 ,
2109
+ "Publication defined not in stream section is deleted" , 10 , 5 )
2110
+
1992
2111
@timeout_decorator .timeout (TEST_TIMEOUT_SEC )
1993
2112
def test_taint_based_eviction (self ):
1994
2113
'''
@@ -2115,7 +2234,7 @@ def test_zz_cluster_deletion(self):
2115
2234
self .eventuallyEqual (lambda : k8s .count_statefulsets_with_label (cluster_label ), 0 , "Statefulset not deleted" )
2116
2235
self .eventuallyEqual (lambda : k8s .count_deployments_with_label (cluster_label ), 0 , "Deployments not deleted" )
2117
2236
self .eventuallyEqual (lambda : k8s .count_pdbs_with_label (cluster_label ), 0 , "Pod disruption budget not deleted" )
2118
- self .eventuallyEqual (lambda : k8s .count_secrets_with_label (cluster_label ), 7 , "Secrets were deleted although disabled in config" )
2237
+ self .eventuallyEqual (lambda : k8s .count_secrets_with_label (cluster_label ), 8 , "Secrets were deleted although disabled in config" )
2119
2238
self .eventuallyEqual (lambda : k8s .count_pvcs_with_label (cluster_label ), 3 , "PVCs were deleted although disabled in config" )
2120
2239
2121
2240
except timeout_decorator .TimeoutError :
0 commit comments