Skip to content

Commit 0f81da8

Browse files
committed
feat: (WIP) refactor query api to use options class
1 parent 8028386 commit 0f81da8

File tree

3 files changed

+174
-3
lines changed

3 files changed

+174
-3
lines changed

influxdb_client_3/__init__.py

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
import pyarrow as pa
33
import importlib.util
44

5-
from influxdb_client_3.query.query_api import QueryApi as _QueryApi
5+
from influxdb_client_3.query.query_api import QueryApi as _QueryApi, QueryApiOptionsBuilder
66
from influxdb_client_3.read_file import UploadFile
77
from influxdb_client_3.write_client import InfluxDBClient as _InfluxDBClient, WriteOptions, Point
88
from influxdb_client_3.write_client.client.exceptions import InfluxDBError
@@ -165,9 +165,18 @@ def __init__(
165165
connection_string = f"grpc+tls://{hostname}:{port}"
166166
else:
167167
connection_string = f"grpc+tcp://{hostname}:{port}"
168+
169+
print(f"\nDEBUG kwargs.keys {kwargs.keys()}")
170+
q_opts_builder = QueryApiOptionsBuilder()
171+
if kwargs.keys().__contains__('ssl_ca_cert'):
172+
q_opts_builder.root_certs(kwargs.get('ssl_ca_cert', None))
173+
if kwargs.keys().__contains__('verify_ssl'):
174+
q_opts_builder.tls_verify(kwargs.get('verify_ssl', True))
175+
if kwargs.keys().__contains__('proxy'):
176+
q_opts_builder.proxy(kwargs.get('proxy', None))
168177
self._query_api = _QueryApi(connection_string=connection_string, token=token,
169178
flight_client_options=flight_client_options,
170-
proxy=kwargs.get("proxy", None))
179+
proxy=kwargs.get("proxy", None), options=q_opts_builder.build())
171180

172181
def write(self, record=None, database=None, **kwargs):
173182
"""

influxdb_client_3/query/query_api.py

Lines changed: 59 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,55 @@
66
from pyarrow.flight import FlightClient, Ticket, FlightCallOptions, FlightStreamReader
77
from influxdb_client_3.version import USER_AGENT
88

9+
class QueryApiOptions(object):
10+
tls_root_certs = None
11+
tls_verify = True
12+
proxy = None
13+
flight_client_options = None
14+
15+
def __init__(self, root_certs_path, verify, proxy, flight_client_options):
16+
if root_certs_path:
17+
self.tls_root_certs = self._read_certs(root_certs_path)
18+
self.tls_verify = verify
19+
self.proxy = proxy
20+
self.flight_client_options = flight_client_options
21+
22+
def _read_certs(self, path):
23+
with open(path, "rb") as certs_file:
24+
return certs_file.read()
25+
26+
27+
class QueryApiOptionsBuilder(object):
28+
29+
_root_certs_path = None
30+
_tls_verify = True
31+
_proxy = None
32+
_flight_client_options = None
33+
34+
def root_certs(self, path):
35+
self._root_certs_path = path
36+
return self
37+
38+
def tls_verify(self, verify):
39+
self._tls_verify = verify
40+
return self
41+
42+
def proxy(self, proxy):
43+
self._proxy = proxy
44+
return self
45+
46+
def flight_client_options(self, flight_client_options):
47+
self._flight_client_options = flight_client_options
48+
return self
49+
50+
def build(self):
51+
return QueryApiOptions(
52+
root_certs_path=self._root_certs_path,
53+
verify=self._tls_verify,
54+
proxy=self._proxy,
55+
flight_client_options=self._flight_client_options
56+
)
57+
958

1059
class QueryApi(object):
1160
"""
@@ -26,7 +75,7 @@ def __init__(self,
2675
connection_string,
2776
token,
2877
flight_client_options,
29-
proxy=None) -> None:
78+
proxy=None, options=None) -> None:
3079
"""
3180
Initialize defaults.
3281
@@ -37,6 +86,15 @@ def __init__(self,
3786
self._token = token
3887
self._flight_client_options = flight_client_options or {}
3988
self._proxy = proxy
89+
print(f"\nDEBUG options {options}")
90+
if options:
91+
if options.flight_client_options:
92+
self._flight_client_options = options.flight_client_options
93+
if options.tls_root_certs:
94+
self._flight_client_options["tls_root_certs"] = options.tls_root_certs
95+
if options.proxy:
96+
self._proxy = options.proxy
97+
self._flight_client_options["disable_server_verification"] = not options.tls_verify
4098
self._flight_client_options["generic_options"] = [
4199
("grpc.secondary_user_agent", USER_AGENT)
42100
]

tests/test_query.py

Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import unittest
22
import struct
3+
import os
34
from unittest.mock import Mock, ANY
45

56
from pyarrow import (
@@ -18,6 +19,7 @@
1819
)
1920

2021
from influxdb_client_3 import InfluxDBClient3
22+
from influxdb_client_3.query.query_api import QueryApiOptionsBuilder, QueryApi
2123
from influxdb_client_3.version import USER_AGENT
2224

2325

@@ -115,6 +117,27 @@ def test_influx_default_query_headers():
115117

116118
class TestQuery(unittest.TestCase):
117119

120+
sample_cert = """-----BEGIN CERTIFICATE-----
121+
MIIDUzCCAjugAwIBAgIUZB55ULutbc9gy6xLp1BkTQU7siowDQYJKoZIhvcNAQEL
122+
BQAwNjE0MDIGA1UEAwwraW5mbHV4ZGIzLWNsdXN0ZXJlZC1zd2FuLmJyYW1ib3Jh
123+
LnpvbmEtYi5ldTAeFw0yNTAyMTgxNTIyMTJaFw0yNjAyMTgxNTIyMTJaMDYxNDAy
124+
BgNVBAMMK2luZmx1eGRiMy1jbHVzdGVyZWQtc3dhbi5icmFtYm9yYS56b25hLWIu
125+
ZXUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCugeNrx0ZfyyP8H4e0
126+
zDSkKWnEXlVdjMi+ZSHhMbjvvqMkUQGLc/W59AEmMJ0Uiljka9d+F7jdu+oqDq9p
127+
4kGPhO3Oh7zIG0IGbncj8AwIXMGDNkNyL8s7C1+LoYotlSWDpWwkEKXUeAzdqS63
128+
CSJFqSJM2dss8qe9BpM6zHWJAKS1I30QT3SXQFEsF5m2F62dXCEEI6pO7jlik8/w
129+
aI47dTM20QyimVzea48SC/ELO/T4AjbmMeBGlTyCm39KOElOKRTJvB4KESEWaL3r
130+
EvPZbTh+72PUyrjxiDa56+RmtDPo7EN3uxuRVFX/HWiNnFk7orQLKZg5Kr8wE46R
131+
KmVvAgMBAAGjWTBXMDYGA1UdEQQvMC2CK2luZmx1eGRiMy1jbHVzdGVyZWQtc3dh
132+
bi5icmFtYm9yYS56b25hLWIuZXUwHQYDVR0OBBYEFH8et6JCzGD7Ny84aNRtq5Nj
133+
hvS/MA0GCSqGSIb3DQEBCwUAA4IBAQCuDwARea/Xr3+hmte9A0H+XB8wMPAJ64e8
134+
QA0qi0oy0gGdLfQHhsBWWmKSYLv7HygTNzb+7uFOTtq1UPLt18F+POPeLIj74QZV
135+
z89Pbo1TwUMzQ2pgbu0yRvraXIpqXGrPm5GWYp5mopX0rBWKdimbmEMkhZA0sVeH
136+
IdKIRUY6EyIVG+Z/nbuVqUlgnIWOMp0yg4RRC91zHy3Xvykf3Vai25H/jQpa6cbU
137+
//MIodzUIqT8Tja5cHXE51bLdUkO1rtNKdM7TUdjzkZ+bAOpqKl+c0FlYZI+F7Ly
138+
+MdCcNgKFc8o8jGiyP6uyAJeg+tSICpFDw00LyuKmU62c7VKuyo7
139+
-----END CERTIFICATE-----"""
140+
118141
def setUp(self):
119142
self.client = InfluxDBClient3(
120143
host="localhost",
@@ -164,3 +187,84 @@ def test_query_proxy_base_client(self):
164187
assert client._query_api._proxy == test_proxy
165188
assert ('grpc.http_proxy', test_proxy) in\
166189
client._query_api._flight_client_options.get('generic_options')
190+
191+
def create_cert_file(self, file_name):
192+
f = open(file_name, "w")
193+
f.write(self.sample_cert)
194+
f.close()
195+
196+
def remove_cert_file(self, file_name):
197+
os.remove(file_name)
198+
199+
def test_query_api_options_builder(self):
200+
proxy_name = "http://my.proxy.org"
201+
cert_file = "cert_test.pem"
202+
self.create_cert_file(cert_file)
203+
builder = QueryApiOptionsBuilder()
204+
options = builder.proxy(proxy_name)\
205+
.root_certs(cert_file)\
206+
.tls_verify(False)\
207+
.build()
208+
209+
print(f"\nDEBUG options {vars(options)}")
210+
try:
211+
assert(options.tls_root_certs.decode('utf-8') == self.sample_cert)
212+
assert(options.tls_verify == False)
213+
assert(options.proxy == proxy_name)
214+
finally:
215+
self.remove_cert_file(cert_file)
216+
217+
def test_query_client_with_options(self):
218+
connection = "grpc+tls://localhost:9999"
219+
token = "my_token"
220+
proxy_name = "http://my.proxy.org"
221+
cert_file = "cert_test.pem"
222+
self.create_cert_file(cert_file)
223+
options = QueryApiOptionsBuilder()\
224+
.proxy(proxy_name) \
225+
.root_certs(cert_file) \
226+
.tls_verify(False) \
227+
.build()
228+
229+
client = QueryApi(connection,
230+
token,
231+
None,
232+
None,
233+
options
234+
)
235+
236+
print(f"\nDEBUG client {vars(client)}")
237+
try:
238+
assert(client._token == token)
239+
assert(client._flight_client_options['tls_root_certs'].decode('utf-8') == self.sample_cert)
240+
assert(client._proxy == proxy_name)
241+
# print(f"DEBUG client._flight_client_options['generic_options'] {dict(client._flight_client_options['generic_options'])['grpc.secondary_user_agent']}")
242+
assert(dict(client._flight_client_options['generic_options'])['grpc.secondary_user_agent'].startswith('influxdb3-python/'))
243+
assert(dict(client._flight_client_options['generic_options'])['grpc.http_proxy'] == proxy_name)
244+
finally:
245+
self.remove_cert_file(cert_file)
246+
247+
def test_client_with_ssl_args(self):
248+
cert_name = "cert-test.pem"
249+
self.create_cert_file(cert_name)
250+
proxy = "http://localhost:9999"
251+
local_client = InfluxDBClient3(
252+
host="localhost",
253+
org="my_org",
254+
database="my_db",
255+
token="my_token",
256+
proxy=proxy,
257+
ssl_ca_cert = cert_name,
258+
verify_ssl = False
259+
)
260+
261+
try:
262+
qapi = local_client._query_api
263+
fc_opts = qapi._flight_client_options
264+
assert(qapi._proxy == proxy)
265+
assert(fc_opts['tls_root_certs'].decode('utf-8') == self.sample_cert)
266+
assert(fc_opts['disable_server_verification'] == True)
267+
assert(dict(fc_opts['generic_options'])['grpc.secondary_user_agent'].startswith('influxdb3-python/'))
268+
assert(dict(fc_opts['generic_options'])['grpc.http_proxy'] == proxy)
269+
finally:
270+
self.remove_cert_file(cert_name)

0 commit comments

Comments
 (0)