Skip to content

Commit e575850

Browse files
authored
Add disable auto register schemas (@dpfeif, confluentinc#718)
1 parent 531c0e2 commit e575850

File tree

7 files changed

+81
-2
lines changed

7 files changed

+81
-2
lines changed

confluent_kafka/avro/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ def __init__(self, config, default_key_schema=None,
3636
sr_conf['sasl.mechanisms'] = config.get('sasl.mechanisms', '')
3737
sr_conf['sasl.username'] = config.get('sasl.username', '')
3838
sr_conf['sasl.password'] = config.get('sasl.password', '')
39+
sr_conf['auto.register.schemas'] = config.get('auto.register.schemas', True)
3940

4041
ap_conf = {key: value
4142
for key, value in config.items() if not key.startswith("schema.registry")}

confluent_kafka/avro/cached_schema_registry_client.py

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,8 @@ def __init__(self, url, max_schemas_per_subject=1000, ca_location=None, cert_loc
111111

112112
self._session = s
113113

114+
self.auto_register_schemas = conf.pop("auto.register.schemas", True)
115+
114116
if len(conf) > 0:
115117
raise ValueError("Unrecognized configuration properties: {}".format(conf.keys()))
116118

@@ -227,6 +229,44 @@ def register(self, subject, avro_schema):
227229
self._cache_schema(avro_schema, schema_id, subject)
228230
return schema_id
229231

232+
def check_registration(self, subject, avro_schema):
233+
"""
234+
POST /subjects/(string: subject)
235+
Check if a schema has already been registered under the specified subject.
236+
If so, returns the schema id. Otherwise, raises a ClientError.
237+
238+
avro_schema must be a parsed schema from the python avro library
239+
240+
Multiple instances of the same schema will result in inconsistencies.
241+
242+
:param str subject: subject name
243+
:param schema avro_schema: Avro schema to be checked
244+
:returns: schema_id
245+
:rtype: int
246+
"""
247+
248+
schemas_to_id = self.subject_to_schema_ids[subject]
249+
schema_id = schemas_to_id.get(avro_schema, None)
250+
if schema_id is not None:
251+
return schema_id
252+
# send it up
253+
url = '/'.join([self.url, 'subjects', subject])
254+
# body is { schema : json_string }
255+
256+
body = {'schema': json.dumps(avro_schema.to_json())}
257+
result, code = self._send_request(url, method='POST', body=body)
258+
if code == 401 or code == 403:
259+
raise ClientError("Unauthorized access. Error code:" + str(code))
260+
elif code == 404:
261+
raise ClientError("Schema or subject not found:" + str(code))
262+
elif not 200 <= code <= 299:
263+
raise ClientError("Unable to check schema registration. Error code:" + str(code))
264+
# result is a dict
265+
schema_id = result['id']
266+
# cache it
267+
self._cache_schema(avro_schema, schema_id, subject)
268+
return schema_id
269+
230270
def delete_subject(self, subject):
231271
"""
232272
DELETE /subjects/(string: subject)

confluent_kafka/avro/serializer/message_serializer.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -103,8 +103,11 @@ def encode_record_with_schema(self, topic, schema, record, is_key=False):
103103
subject_suffix = ('-key' if is_key else '-value')
104104
# get the latest schema for the subject
105105
subject = topic + subject_suffix
106-
# register it
107-
schema_id = self.registry_client.register(subject, schema)
106+
if self.registry_client.auto_register_schemas:
107+
# register it
108+
schema_id = self.registry_client.register(subject, schema)
109+
else:
110+
schema_id = self.registry_client.check_registration(subject, schema)
108111
if not schema_id:
109112
message = "Unable to retrieve schema id for subject %s" % (subject)
110113
raise serialize_err(message)

tests/avro/mock_registry.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,12 @@ def register(self, req, groups):
133133
schema_id = self.registry.register(subject, avro_schema)
134134
return (200, {'id': schema_id})
135135

136+
def check_registration(self, req, groups):
137+
avro_schema = self._get_schema_from_body(req)
138+
subject = groups[0]
139+
schema_id = self.registry.check_registration(subject, avro_schema)
140+
return (200, {'id': schema_id})
141+
136142
def get_version(self, req, groups):
137143
avro_schema = self._get_schema_from_body(req)
138144
if not avro_schema:

tests/avro/mock_schema_registry_client.py

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,8 @@ def __init__(self, max_schemas_per_subject=1000):
4545
self.next_id = 1
4646
self.schema_to_id = {}
4747

48+
self.auto_register_schemas = True
49+
4850
def _get_next_id(self, schema):
4951
if schema in self.schema_to_id:
5052
return self.schema_to_id[schema]
@@ -109,6 +111,26 @@ def register(self, subject, avro_schema):
109111
self._cache_schema(avro_schema, schema_id, subject, version)
110112
return schema_id
111113

114+
def check_registration(self, subject, avro_schema):
115+
"""
116+
Check if a schema has already been registered under the specified subject.
117+
If so, returns the schema id. Otherwise, raises a ClientError.
118+
119+
avro_schema must be a parsed schema from the python avro library
120+
121+
Multiple instances of the same schema will result in inconsistencies.
122+
"""
123+
schemas_to_id = self.subject_to_schema_ids.get(subject, {})
124+
schema_id = schemas_to_id.get(avro_schema, -1)
125+
if schema_id != -1:
126+
return schema_id
127+
128+
version = self._get_next_version(subject) - 1
129+
130+
# cache it
131+
self._cache_schema(avro_schema, schema_id, subject, version)
132+
return schema_id
133+
112134
def get_by_id(self, schema_id):
113135
"""Retrieve a parsed avro schema by id or None if not found"""
114136
return self.id_to_schema.get(schema_id, None)

tests/avro/test_cached_client.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,12 @@ def test_register(self):
4545
self.assertTrue(schema_id > 0)
4646
self.assertEqual(len(client.id_to_schema), 1)
4747

48+
def test_check_registration(self):
49+
parsed = avro.loads(data_gen.BASIC_SCHEMA)
50+
client = self.client
51+
schema_id = client.register('test', parsed)
52+
self.assertEqual(schema_id, client.check_registration('test', parsed))
53+
4854
def test_multi_subject_register(self):
4955
parsed = avro.loads(data_gen.BASIC_SCHEMA)
5056
client = self.client

tests/integration/integration_test.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -746,6 +746,7 @@ def verify_schema_registry_client():
746746
schema = avro.load(os.path.join(avsc_dir, "primitive_float.avsc"))
747747

748748
schema_id = sr.register(subject, schema)
749+
assert schema_id == sr.check_registration(subject, schema)
749750
assert schema == sr.get_by_id(schema_id)
750751
latest_id, latest_schema, latest_version = sr.get_latest_schema(subject)
751752
assert schema == latest_schema

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy