adc-streaming 2.4.0__tar.gz → 2.6.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {adc-streaming-2.4.0 → adc_streaming-2.6.0}/.github/workflows/build.yml +1 -1
- {adc-streaming-2.4.0 → adc_streaming-2.6.0}/PKG-INFO +30 -3
- {adc-streaming-2.4.0 → adc_streaming-2.6.0}/adc/auth.py +6 -0
- {adc-streaming-2.4.0 → adc_streaming-2.6.0}/adc/consumer.py +4 -5
- {adc-streaming-2.4.0 → adc_streaming-2.6.0}/adc/producer.py +25 -10
- {adc-streaming-2.4.0 → adc_streaming-2.6.0}/adc_streaming.egg-info/PKG-INFO +30 -3
- {adc-streaming-2.4.0 → adc_streaming-2.6.0}/adc_streaming.egg-info/SOURCES.txt +0 -1
- {adc-streaming-2.4.0 → adc_streaming-2.6.0}/adc_streaming.egg-info/requires.txt +1 -3
- {adc-streaming-2.4.0 → adc_streaming-2.6.0}/setup.py +1 -3
- {adc-streaming-2.4.0 → adc_streaming-2.6.0}/tests/test_auth.py +1 -1
- {adc-streaming-2.4.0 → adc_streaming-2.6.0}/tests/test_kafka_integration.py +79 -12
- adc-streaming-2.4.0/adc/oidc.py +0 -27
- {adc-streaming-2.4.0 → adc_streaming-2.6.0}/.gitignore +0 -0
- {adc-streaming-2.4.0 → adc_streaming-2.6.0}/LICENSE +0 -0
- {adc-streaming-2.4.0 → adc_streaming-2.6.0}/Makefile +0 -0
- {adc-streaming-2.4.0 → adc_streaming-2.6.0}/README.md +0 -0
- {adc-streaming-2.4.0 → adc_streaming-2.6.0}/adc/__init__.py +0 -0
- {adc-streaming-2.4.0 → adc_streaming-2.6.0}/adc/errors.py +0 -0
- {adc-streaming-2.4.0 → adc_streaming-2.6.0}/adc/io.py +0 -0
- {adc-streaming-2.4.0 → adc_streaming-2.6.0}/adc/kafka.py +0 -0
- {adc-streaming-2.4.0 → adc_streaming-2.6.0}/adc_streaming.egg-info/dependency_links.txt +0 -0
- {adc-streaming-2.4.0 → adc_streaming-2.6.0}/adc_streaming.egg-info/not-zip-safe +0 -0
- {adc-streaming-2.4.0 → adc_streaming-2.6.0}/adc_streaming.egg-info/top_level.txt +0 -0
- {adc-streaming-2.4.0 → adc_streaming-2.6.0}/doc/Makefile +0 -0
- {adc-streaming-2.4.0 → adc_streaming-2.6.0}/doc/_static/css/my_theme.css +0 -0
- {adc-streaming-2.4.0 → adc_streaming-2.6.0}/doc/_templates/layout.html +0 -0
- {adc-streaming-2.4.0 → adc_streaming-2.6.0}/doc/api/api.rst +0 -0
- {adc-streaming-2.4.0 → adc_streaming-2.6.0}/doc/api/streaming.rst +0 -0
- {adc-streaming-2.4.0 → adc_streaming-2.6.0}/doc/conf.py +0 -0
- {adc-streaming-2.4.0 → adc_streaming-2.6.0}/doc/index.rst +0 -0
- {adc-streaming-2.4.0 → adc_streaming-2.6.0}/doc/user/installation.rst +0 -0
- {adc-streaming-2.4.0 → adc_streaming-2.6.0}/doc/user/quickstart.rst +0 -0
- {adc-streaming-2.4.0 → adc_streaming-2.6.0}/pyproject.toml +0 -0
- {adc-streaming-2.4.0 → adc_streaming-2.6.0}/recipe/meta.yaml +0 -0
- {adc-streaming-2.4.0 → adc_streaming-2.6.0}/setup.cfg +0 -0
- {adc-streaming-2.4.0 → adc_streaming-2.6.0}/tests/test_kafka.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
2
|
Name: adc-streaming
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.6.0
|
|
4
4
|
Summary: Astronomy Data Commons streaming client libraries
|
|
5
5
|
Home-page: https://github.com/astronomy-commons/adc-streaming
|
|
6
6
|
Author: Astronomy Data Commons Team
|
|
@@ -12,8 +12,35 @@ Classifier: Development Status :: 3 - Alpha
|
|
|
12
12
|
Classifier: Operating System :: POSIX :: Linux
|
|
13
13
|
Classifier: Operating System :: MacOS :: MacOS X
|
|
14
14
|
Description-Content-Type: text/markdown
|
|
15
|
-
Provides-Extra: dev
|
|
16
15
|
License-File: LICENSE
|
|
16
|
+
Requires-Dist: confluent-kafka>=2.11.0
|
|
17
|
+
Requires-Dist: dataclasses; python_version < "3.7"
|
|
18
|
+
Requires-Dist: importlib-metadata; python_version < "3.8"
|
|
19
|
+
Requires-Dist: tqdm
|
|
20
|
+
Requires-Dist: certifi>=2020.04.05.1
|
|
21
|
+
Requires-Dist: typing-extensions; python_version < "3.8"
|
|
22
|
+
Provides-Extra: dev
|
|
23
|
+
Requires-Dist: autopep8; extra == "dev"
|
|
24
|
+
Requires-Dist: docker; extra == "dev"
|
|
25
|
+
Requires-Dist: flake8; extra == "dev"
|
|
26
|
+
Requires-Dist: isort; extra == "dev"
|
|
27
|
+
Requires-Dist: pytest; extra == "dev"
|
|
28
|
+
Requires-Dist: pytest-timeout; extra == "dev"
|
|
29
|
+
Requires-Dist: pytest-integration; extra == "dev"
|
|
30
|
+
Requires-Dist: sphinx; extra == "dev"
|
|
31
|
+
Requires-Dist: sphinx_rtd_theme; extra == "dev"
|
|
32
|
+
Requires-Dist: twine; extra == "dev"
|
|
33
|
+
Dynamic: author
|
|
34
|
+
Dynamic: author-email
|
|
35
|
+
Dynamic: classifier
|
|
36
|
+
Dynamic: description
|
|
37
|
+
Dynamic: description-content-type
|
|
38
|
+
Dynamic: home-page
|
|
39
|
+
Dynamic: license
|
|
40
|
+
Dynamic: license-file
|
|
41
|
+
Dynamic: provides-extra
|
|
42
|
+
Dynamic: requires-dist
|
|
43
|
+
Dynamic: summary
|
|
17
44
|
|
|
18
45
|
# Astronomy Data Commons Streaming Client Libraries
|
|
19
46
|
|
|
@@ -38,6 +38,8 @@ class SASLAuth(object):
|
|
|
38
38
|
ssl_ca_location : `str`, optional
|
|
39
39
|
If using SSL via a self-signed cert, a path/location
|
|
40
40
|
to the certificate.
|
|
41
|
+
ssl_endpoint_identification_algorithm : `str`, optional
|
|
42
|
+
If using SSL, the algorithm used to verify that certificate is valid for the endpoint.
|
|
41
43
|
token_endpoint : `str`, optional
|
|
42
44
|
The OpenID Connect token endpoint URL.
|
|
43
45
|
Required for OAUTHBEARER / OpenID Connect, otherwise ignored.
|
|
@@ -62,7 +64,11 @@ class SASLAuth(object):
|
|
|
62
64
|
self._config = {
|
|
63
65
|
"security.protocol": "SASL_SSL",
|
|
64
66
|
"ssl.ca.location": ssl_cert,
|
|
67
|
+
"https.ca.location": ssl_cert,
|
|
65
68
|
}
|
|
69
|
+
if "ssl_endpoint_identification_algorithm" in kwargs:
|
|
70
|
+
self._config["ssl.endpoint.identification.algorithm"] = \
|
|
71
|
+
kwargs["ssl_endpoint_identification_algorithm"]
|
|
66
72
|
else:
|
|
67
73
|
self._config = {"security.protocol": "SASL_PLAINTEXT"}
|
|
68
74
|
|
|
@@ -14,7 +14,6 @@ import confluent_kafka.admin # type: ignore
|
|
|
14
14
|
|
|
15
15
|
from .auth import SASLAuth
|
|
16
16
|
from .errors import ErrorCallback, log_client_errors
|
|
17
|
-
from .oidc import set_oauth_cb
|
|
18
17
|
|
|
19
18
|
|
|
20
19
|
class LogicalOffset(enum.IntEnum):
|
|
@@ -38,7 +37,8 @@ class Consumer:
|
|
|
38
37
|
self.logger = logging.getLogger("adc-streaming.consumer")
|
|
39
38
|
self.conf = conf
|
|
40
39
|
self._consumer = confluent_kafka.Consumer(conf._to_confluent_kafka())
|
|
41
|
-
# Workaround for
|
|
40
|
+
# Workaround for
|
|
41
|
+
# https://github.com/confluentinc/librdkafka/issues/3753#issuecomment-1058272987.
|
|
42
42
|
# FIXME: Remove once fixed upstream, or on removal of oauth_cb.
|
|
43
43
|
self._consumer.poll(0)
|
|
44
44
|
self._stop_event = threading.Event()
|
|
@@ -196,7 +196,7 @@ class Consumer:
|
|
|
196
196
|
self.mark_done(m, asynchronous=True)
|
|
197
197
|
yield m
|
|
198
198
|
else:
|
|
199
|
-
raise(confluent_kafka.KafkaException(err))
|
|
199
|
+
raise (confluent_kafka.KafkaException(err))
|
|
200
200
|
finally:
|
|
201
201
|
if autocommit:
|
|
202
202
|
self._consumer.commit(asynchronous=True)
|
|
@@ -242,7 +242,7 @@ class Consumer:
|
|
|
242
242
|
# Done with all partitions for the topic, remove it
|
|
243
243
|
del active_partitions[m.topic()]
|
|
244
244
|
else:
|
|
245
|
-
raise(confluent_kafka.KafkaException(err))
|
|
245
|
+
raise (confluent_kafka.KafkaException(err))
|
|
246
246
|
finally:
|
|
247
247
|
if autocommit:
|
|
248
248
|
self._consumer.commit(asynchronous=True)
|
|
@@ -359,5 +359,4 @@ class ConsumerConfig:
|
|
|
359
359
|
|
|
360
360
|
if self.auth is not None:
|
|
361
361
|
config.update(self.auth())
|
|
362
|
-
set_oauth_cb(config)
|
|
363
362
|
return config
|
|
@@ -14,7 +14,6 @@ import confluent_kafka # type: ignore
|
|
|
14
14
|
from .auth import SASLAuth
|
|
15
15
|
from .errors import (DeliveryCallback, ErrorCallback, log_client_errors,
|
|
16
16
|
log_delivery_errors)
|
|
17
|
-
from .oidc import set_oauth_cb
|
|
18
17
|
|
|
19
18
|
|
|
20
19
|
class Producer:
|
|
@@ -27,7 +26,8 @@ class Producer:
|
|
|
27
26
|
self.conf = conf
|
|
28
27
|
self.logger.debug(f"connecting to producer with config {conf._to_confluent_kafka()}")
|
|
29
28
|
self._producer = confluent_kafka.Producer(conf._to_confluent_kafka())
|
|
30
|
-
# Workaround for
|
|
29
|
+
# Workaround for
|
|
30
|
+
# https://github.com/confluentinc/librdkafka/issues/3753#issuecomment-1058272987.
|
|
31
31
|
# FIXME: Remove once fixed upstream, or on removal of oauth_cb.
|
|
32
32
|
self._producer.poll(0)
|
|
33
33
|
|
|
@@ -35,7 +35,8 @@ class Producer:
|
|
|
35
35
|
msg: Union[bytes, 'Serializable'],
|
|
36
36
|
headers: Optional[Union[dict, list]] = None,
|
|
37
37
|
delivery_callback: Optional[DeliveryCallback] = log_delivery_errors,
|
|
38
|
-
topic: Optional[str] = None
|
|
38
|
+
topic: Optional[str] = None,
|
|
39
|
+
key: Optional[Union[str, bytes]] = None) -> None:
|
|
39
40
|
if isinstance(msg, Serializable):
|
|
40
41
|
msg = msg.serialize()
|
|
41
42
|
if topic is None:
|
|
@@ -46,11 +47,26 @@ class Producer:
|
|
|
46
47
|
"Either configure a topic when constructing the Producer, "
|
|
47
48
|
"or specify the topic argument to write()")
|
|
48
49
|
self.logger.debug("writing message to %s", topic)
|
|
50
|
+
produce_kwargs = {"headers": headers, "key": key}
|
|
49
51
|
if delivery_callback is not None:
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
52
|
+
produce_kwargs["on_delivery"] = delivery_callback
|
|
53
|
+
while True:
|
|
54
|
+
try:
|
|
55
|
+
self._producer.produce(topic, msg, **produce_kwargs)
|
|
56
|
+
break
|
|
57
|
+
except BufferError:
|
|
58
|
+
# It's hard to know what the size limit on the buffer is, so we will try to
|
|
59
|
+
# wait until the number of items in it decreases (or it is empty, in case all
|
|
60
|
+
# messages were successfully sent in the time it took to handle the error).
|
|
61
|
+
buffer_len = len(self._producer)
|
|
62
|
+
self.logger.debug(f"Blocking due to BufferError, buffer size: {buffer_len}")
|
|
63
|
+
while buffer_len > 0 and len(self._producer) == buffer_len:
|
|
64
|
+
self._producer.poll(0.01)
|
|
65
|
+
|
|
66
|
+
def queued_message_count(self):
|
|
67
|
+
"""Get the number of messages waiting to be sent to the broker.
|
|
68
|
+
"""
|
|
69
|
+
return len(self._producer)
|
|
54
70
|
|
|
55
71
|
def flush(self, timeout: timedelta = timedelta(seconds=10)) -> int:
|
|
56
72
|
"""Attempt to flush enqueued messages. Return the number of messages still
|
|
@@ -64,9 +80,9 @@ class Producer:
|
|
|
64
80
|
self.logger.debug("flushed all messages")
|
|
65
81
|
return n
|
|
66
82
|
|
|
67
|
-
def close(self) -> int:
|
|
83
|
+
def close(self, timeout: timedelta = timedelta(seconds=10)) -> int:
|
|
68
84
|
self.logger.debug("shutting down producer")
|
|
69
|
-
return self.flush()
|
|
85
|
+
return self.flush(timeout)
|
|
70
86
|
|
|
71
87
|
def __enter__(self) -> 'Producer':
|
|
72
88
|
return self
|
|
@@ -140,7 +156,6 @@ class ProducerConfig:
|
|
|
140
156
|
config["error_cb"] = self.error_callback
|
|
141
157
|
if self.auth is not None:
|
|
142
158
|
config.update(self.auth())
|
|
143
|
-
set_oauth_cb(config)
|
|
144
159
|
return config
|
|
145
160
|
|
|
146
161
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
2
|
Name: adc-streaming
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.6.0
|
|
4
4
|
Summary: Astronomy Data Commons streaming client libraries
|
|
5
5
|
Home-page: https://github.com/astronomy-commons/adc-streaming
|
|
6
6
|
Author: Astronomy Data Commons Team
|
|
@@ -12,8 +12,35 @@ Classifier: Development Status :: 3 - Alpha
|
|
|
12
12
|
Classifier: Operating System :: POSIX :: Linux
|
|
13
13
|
Classifier: Operating System :: MacOS :: MacOS X
|
|
14
14
|
Description-Content-Type: text/markdown
|
|
15
|
-
Provides-Extra: dev
|
|
16
15
|
License-File: LICENSE
|
|
16
|
+
Requires-Dist: confluent-kafka>=2.11.0
|
|
17
|
+
Requires-Dist: dataclasses; python_version < "3.7"
|
|
18
|
+
Requires-Dist: importlib-metadata; python_version < "3.8"
|
|
19
|
+
Requires-Dist: tqdm
|
|
20
|
+
Requires-Dist: certifi>=2020.04.05.1
|
|
21
|
+
Requires-Dist: typing-extensions; python_version < "3.8"
|
|
22
|
+
Provides-Extra: dev
|
|
23
|
+
Requires-Dist: autopep8; extra == "dev"
|
|
24
|
+
Requires-Dist: docker; extra == "dev"
|
|
25
|
+
Requires-Dist: flake8; extra == "dev"
|
|
26
|
+
Requires-Dist: isort; extra == "dev"
|
|
27
|
+
Requires-Dist: pytest; extra == "dev"
|
|
28
|
+
Requires-Dist: pytest-timeout; extra == "dev"
|
|
29
|
+
Requires-Dist: pytest-integration; extra == "dev"
|
|
30
|
+
Requires-Dist: sphinx; extra == "dev"
|
|
31
|
+
Requires-Dist: sphinx_rtd_theme; extra == "dev"
|
|
32
|
+
Requires-Dist: twine; extra == "dev"
|
|
33
|
+
Dynamic: author
|
|
34
|
+
Dynamic: author-email
|
|
35
|
+
Dynamic: classifier
|
|
36
|
+
Dynamic: description
|
|
37
|
+
Dynamic: description-content-type
|
|
38
|
+
Dynamic: home-page
|
|
39
|
+
Dynamic: license
|
|
40
|
+
Dynamic: license-file
|
|
41
|
+
Dynamic: provides-extra
|
|
42
|
+
Dynamic: requires-dist
|
|
43
|
+
Dynamic: summary
|
|
17
44
|
|
|
18
45
|
# Astronomy Data Commons Streaming Client Libraries
|
|
19
46
|
|
|
@@ -3,11 +3,9 @@ from setuptools import setup
|
|
|
3
3
|
|
|
4
4
|
# requirements
|
|
5
5
|
install_requires = [
|
|
6
|
-
"
|
|
7
|
-
"confluent-kafka >= 1.6.1, != 2.1.0, != 2.1.1",
|
|
6
|
+
"confluent-kafka >= 2.11.0",
|
|
8
7
|
"dataclasses ; python_version < '3.7'",
|
|
9
8
|
"importlib-metadata ; python_version < '3.8'",
|
|
10
|
-
"requests", # FIXME: drop after next release of confluent-kafka with OIDC support
|
|
11
9
|
"tqdm",
|
|
12
10
|
"certifi>=2020.04.05.1",
|
|
13
11
|
"typing-extensions ; python_version < '3.8'",
|
|
@@ -2,8 +2,8 @@ import logging
|
|
|
2
2
|
import tempfile
|
|
3
3
|
import time
|
|
4
4
|
import unittest
|
|
5
|
-
from datetime import datetime, timedelta
|
|
6
|
-
from typing import List
|
|
5
|
+
from datetime import datetime, timedelta
|
|
6
|
+
from typing import List, Optional
|
|
7
7
|
|
|
8
8
|
import docker
|
|
9
9
|
import pytest
|
|
@@ -59,6 +59,69 @@ class KafkaIntegrationTestCase(unittest.TestCase):
|
|
|
59
59
|
self.assertEqual(msg.topic(), topic)
|
|
60
60
|
self.assertEqual(msg.value(), b"can you hear me?")
|
|
61
61
|
|
|
62
|
+
def test_message_with_key(self):
|
|
63
|
+
"""Try writing a message into the Kafka broker, and try pulling the same
|
|
64
|
+
message back out.
|
|
65
|
+
|
|
66
|
+
"""
|
|
67
|
+
topic = "test_message_with_key"
|
|
68
|
+
# Push one message in...
|
|
69
|
+
simple_write_msg(self.kafka, topic, "can you hear me?", key="test_msg")
|
|
70
|
+
# ... and pull it back out.
|
|
71
|
+
consumer = adc.consumer.Consumer(adc.consumer.ConsumerConfig(
|
|
72
|
+
broker_urls=[self.kafka.address],
|
|
73
|
+
group_id="test_consumer",
|
|
74
|
+
auth=self.kafka.auth,
|
|
75
|
+
))
|
|
76
|
+
consumer.subscribe(topic)
|
|
77
|
+
stream = consumer.stream()
|
|
78
|
+
|
|
79
|
+
msg = next(stream)
|
|
80
|
+
if msg.error() is not None:
|
|
81
|
+
raise Exception(msg.error())
|
|
82
|
+
|
|
83
|
+
self.assertEqual(msg.topic(), topic)
|
|
84
|
+
self.assertEqual(msg.value(), b"can you hear me?")
|
|
85
|
+
self.assertEqual(msg.key(), b"test_msg")
|
|
86
|
+
|
|
87
|
+
def test_message_with_callback(self):
|
|
88
|
+
"""Try writing a message into the Kafka broker, with a delivery callback.
|
|
89
|
+
"""
|
|
90
|
+
topic = "test_message_with_callback"
|
|
91
|
+
callback_called = False
|
|
92
|
+
callback_error = False
|
|
93
|
+
|
|
94
|
+
def callback(err, msg):
|
|
95
|
+
nonlocal callback_called
|
|
96
|
+
nonlocal callback_error
|
|
97
|
+
callback_called = True
|
|
98
|
+
callback_error = err is not None
|
|
99
|
+
|
|
100
|
+
ap = adc.producer
|
|
101
|
+
with ap.Producer(ap.ProducerConfig(broker_urls=[self.kafka.address],
|
|
102
|
+
topic=topic, auth=self.kafka.auth)) as producer:
|
|
103
|
+
producer.write("message data", delivery_callback=callback)
|
|
104
|
+
producer.flush()
|
|
105
|
+
consumer = adc.consumer.Consumer(adc.consumer.ConsumerConfig(
|
|
106
|
+
broker_urls=[self.kafka.address],
|
|
107
|
+
group_id="test_consumer",
|
|
108
|
+
auth=self.kafka.auth,
|
|
109
|
+
))
|
|
110
|
+
consumer.subscribe(topic)
|
|
111
|
+
stream = consumer.stream()
|
|
112
|
+
|
|
113
|
+
msg = next(stream)
|
|
114
|
+
if msg.error() is not None:
|
|
115
|
+
raise Exception(msg.error())
|
|
116
|
+
# give the producer's background thread time to notice the ack from the broker and
|
|
117
|
+
# fire the callback
|
|
118
|
+
producer._producer.poll(0.1)
|
|
119
|
+
|
|
120
|
+
self.assertEqual(msg.topic(), topic)
|
|
121
|
+
self.assertEqual(msg.value(), b"message data")
|
|
122
|
+
self.assertEqual(callback_called, True)
|
|
123
|
+
self.assertEqual(callback_error, False)
|
|
124
|
+
|
|
62
125
|
def test_reset_to_end(self):
|
|
63
126
|
# Write a few messages.
|
|
64
127
|
topic = "test_reset_to_end"
|
|
@@ -283,7 +346,7 @@ class KafkaIntegrationTestCase(unittest.TestCase):
|
|
|
283
346
|
"message 1",
|
|
284
347
|
"message 2",
|
|
285
348
|
"message 3",
|
|
286
|
-
])
|
|
349
|
+
])
|
|
287
350
|
# Wait a while, write, and wait some more
|
|
288
351
|
time.sleep(2)
|
|
289
352
|
client_middle_time = datetime.now()
|
|
@@ -390,8 +453,8 @@ class KafkaIntegrationTestCase(unittest.TestCase):
|
|
|
390
453
|
topic=None,
|
|
391
454
|
auth=self.kafka.auth,
|
|
392
455
|
))
|
|
393
|
-
for i in range(0,8):
|
|
394
|
-
producer.write(str(i), topic=topics[i%2])
|
|
456
|
+
for i in range(0, 8):
|
|
457
|
+
producer.write(str(i), topic=topics[i % 2])
|
|
395
458
|
producer.flush()
|
|
396
459
|
logger.info("messages sent")
|
|
397
460
|
|
|
@@ -403,12 +466,12 @@ class KafkaIntegrationTestCase(unittest.TestCase):
|
|
|
403
466
|
))
|
|
404
467
|
consumer.subscribe(topics)
|
|
405
468
|
stream = consumer.stream()
|
|
406
|
-
total_messages = 0
|
|
469
|
+
total_messages = 0
|
|
407
470
|
for msg in stream:
|
|
408
471
|
if msg.error() is not None:
|
|
409
472
|
raise Exception(msg.error())
|
|
410
473
|
idx = int(msg.value())
|
|
411
|
-
self.assertEqual(msg.topic(), topics[idx%2])
|
|
474
|
+
self.assertEqual(msg.topic(), topics[idx % 2])
|
|
412
475
|
total_messages += 1
|
|
413
476
|
if total_messages == 8:
|
|
414
477
|
break
|
|
@@ -451,13 +514,17 @@ class KafkaDockerConnection:
|
|
|
451
514
|
self.auth = adc.auth.SASLAuth(
|
|
452
515
|
user="test", password="test-pass",
|
|
453
516
|
ssl_ca_location=self.certfile.name,
|
|
517
|
+
# disable endpoint verification because the docker service generates a certificate with
|
|
518
|
+
# a useless subject (the container ID) which can never match the hostname used to
|
|
519
|
+
# connect (typically 0.0.0.0)
|
|
520
|
+
ssl_endpoint_identification_algorithm="none",
|
|
454
521
|
)
|
|
455
522
|
|
|
456
523
|
def poll_for_kafka_broker_address(self, maxiter=20, sleep=timedelta(milliseconds=500)):
|
|
457
524
|
"""Block until the Docker daemon tells us the IP and Port of the Kafa broker.
|
|
458
525
|
|
|
459
526
|
Returns the ip and port as a string in the form "ip:port."
|
|
460
|
-
"""
|
|
527
|
+
"""
|
|
461
528
|
i = 0
|
|
462
529
|
while (not self.query_kafka_broker_address()) and i < maxiter:
|
|
463
530
|
logger.info("polling to wait for container to acquire port...")
|
|
@@ -479,7 +546,7 @@ class KafkaDockerConnection:
|
|
|
479
546
|
port = addrs[0]['HostPort']
|
|
480
547
|
return f"{ip}:{port}"
|
|
481
548
|
|
|
482
|
-
def poll_for_kafka_active(self, maxiter=
|
|
549
|
+
def poll_for_kafka_active(self, maxiter=40, sleep=timedelta(milliseconds=500)):
|
|
483
550
|
"""Block until Kafka's network listener is accepting connections."""
|
|
484
551
|
i = 0
|
|
485
552
|
while (not self.query_kafka_active()) and i < maxiter:
|
|
@@ -550,7 +617,7 @@ class KafkaDockerConnection:
|
|
|
550
617
|
# these tests cannot run if there is already an instance of Kafka running on
|
|
551
618
|
# the same host.
|
|
552
619
|
ports={"9092/tcp": 9092},
|
|
553
|
-
command=["/root/runServer","--advertisedListener","SASL_SSL://localhost:9092"],
|
|
620
|
+
command=["/root/runServer", "--advertisedListener", "SASL_SSL://localhost:9092"],
|
|
554
621
|
)
|
|
555
622
|
|
|
556
623
|
def get_or_create_docker_network(self):
|
|
@@ -565,13 +632,13 @@ class KafkaDockerConnection:
|
|
|
565
632
|
return self.docker_client.networks.create(name="adc-integration-test")
|
|
566
633
|
|
|
567
634
|
|
|
568
|
-
def simple_write_msg(conn: KafkaDockerConnection, topic: str, msg: str):
|
|
635
|
+
def simple_write_msg(conn: KafkaDockerConnection, topic: str, msg: str, key: Optional[str] = None):
|
|
569
636
|
producer = adc.producer.Producer(adc.producer.ProducerConfig(
|
|
570
637
|
broker_urls=[conn.address],
|
|
571
638
|
topic=topic,
|
|
572
639
|
auth=conn.auth,
|
|
573
640
|
))
|
|
574
|
-
producer.write(msg)
|
|
641
|
+
producer.write(msg, key=key)
|
|
575
642
|
producer.flush()
|
|
576
643
|
|
|
577
644
|
|
adc-streaming-2.4.0/adc/oidc.py
DELETED
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
def set_oauth_cb(config):
|
|
2
|
-
"""Implement client support for KIP-768 OpenID Connect.
|
|
3
|
-
|
|
4
|
-
Apache Kafka 3.1.0 supports authentication using OpenID Client Credentials.
|
|
5
|
-
Native support for Python is still incomplete due to this issue:
|
|
6
|
-
https://github.com/confluentinc/librdkafka/issues/3751
|
|
7
|
-
|
|
8
|
-
Meanwhile, this is a pure Python implementation of the refresh token
|
|
9
|
-
callback.
|
|
10
|
-
"""
|
|
11
|
-
if config.pop('sasl.oauthbearer.method', None) != 'oidc':
|
|
12
|
-
return
|
|
13
|
-
|
|
14
|
-
client_id = config.pop('sasl.oauthbearer.client.id')
|
|
15
|
-
client_secret = config.pop('sasl.oauthbearer.client.secret')
|
|
16
|
-
scope = config.pop('sasl.oauthbearer.scope', None)
|
|
17
|
-
token_endpoint = config.pop('sasl.oauthbearer.token.endpoint.url')
|
|
18
|
-
|
|
19
|
-
from authlib.integrations.requests_client import OAuth2Session
|
|
20
|
-
session = OAuth2Session(client_id, client_secret, scope=scope)
|
|
21
|
-
|
|
22
|
-
def oauth_cb(*_, **__):
|
|
23
|
-
token = session.fetch_token(
|
|
24
|
-
token_endpoint, grant_type='client_credentials')
|
|
25
|
-
return token['access_token'], token['expires_at']
|
|
26
|
-
|
|
27
|
-
config['oauth_cb'] = oauth_cb
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|