diff --git a/CHANGELOG.md b/CHANGELOG.md index 7a9dd6ed..2d02592f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,8 @@ ## 1.10.0 [unreleased] +### Features +1. [#136](https://github.com/influxdata/influxdb-client-python/pull/136): Allows users to skip of verifying SSL certificate + ## 1.9.0 [2020-07-17] ### Features diff --git a/influxdb_client/client/influxdb_client.py b/influxdb_client/client/influxdb_client.py index 0c63c1fa..08a37bc7 100644 --- a/influxdb_client/client/influxdb_client.py +++ b/influxdb_client/client/influxdb_client.py @@ -21,7 +21,7 @@ class InfluxDBClient(object): """InfluxDBClient is client for InfluxDB v2.""" def __init__(self, url, token, debug=None, timeout=10000, enable_gzip=False, org: str = None, - default_tags: dict = None) -> None: + default_tags: dict = None, **kwargs) -> None: """ Initialize defaults. @@ -32,6 +32,7 @@ def __init__(self, url, token, debug=None, timeout=10000, enable_gzip=False, org :param enable_gzip: Enable Gzip compression for http requests. Currently only the "Write" and "Query" endpoints supports the Gzip compression. :param org: organization name (used as a default in query and write API) + :key verify_ssl: Set this to false to skip verifying SSL certificate when calling API from https server. """ self.url = url @@ -48,6 +49,7 @@ def __init__(self, url, token, debug=None, timeout=10000, enable_gzip=False, org conf.host = self.url conf.enable_gzip = enable_gzip conf.debug = debug + conf.verify_ssl = kwargs.get('verify_ssl', True) auth_token = self.token auth_header_name = "Authorization" diff --git a/influxdb_client/client/write_api.py b/influxdb_client/client/write_api.py index c54e26bd..f60cc06c 100644 --- a/influxdb_client/client/write_api.py +++ b/influxdb_client/client/write_api.py @@ -204,8 +204,8 @@ def write(self, bucket: str, org: str = None, the body line-protocol. The precision specified on a Point has precedes and is use for write. :param record: Points, line protocol, Pandas DataFrame, RxPY Observable to write - :param data_frame_measurement_name: name of measurement for writing Pandas DataFrame - :param data_frame_tag_columns: list of DataFrame columns which are tags, rest columns will be fields + :key data_frame_measurement_name: name of measurement for writing Pandas DataFrame + :key data_frame_tag_columns: list of DataFrame columns which are tags, rest columns will be fields """ if org is None: org = self._influxdb_client.org diff --git a/tests/server.pem b/tests/server.pem new file mode 100644 index 00000000..67a4c60f --- /dev/null +++ b/tests/server.pem @@ -0,0 +1,83 @@ +-----BEGIN CERTIFICATE----- +MIIFZjCCA04CCQCMEn5e+4xmLTANBgkqhkiG9w0BAQsFADB1MQswCQYDVQQGEwJV +UzEQMA4GA1UECAwHTmV3WW9yazEQMA4GA1UEBwwHTmV3WW9yazEdMBsGA1UECgwU +SW5mbHV4REJQeXRob25DbGllbnQxDzANBgNVBAsMBkNsaWVudDESMBAGA1UEAwwJ +bG9jYWxob3N0MB4XDTIwMDcyMDA2MzA0OVoXDTQ3MTIwNjA2MzA0OVowdTELMAkG +A1UEBhMCVVMxEDAOBgNVBAgMB05ld1lvcmsxEDAOBgNVBAcMB05ld1lvcmsxHTAb +BgNVBAoMFEluZmx1eERCUHl0aG9uQ2xpZW50MQ8wDQYDVQQLDAZDbGllbnQxEjAQ +BgNVBAMMCWxvY2FsaG9zdDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIB +AMoqURng8JwLYe4IHyIAGlI80utBLq6XbDETY93Pr6ZdHePr2jM+UIfFtdkpqdJw +56ZxnJPtM1kDQJTsGfkf0/ePKZpnunNk+lkz9l5uQPVcujydplhJgJeHEj49s3Yy +mWYetcR1Oejnqxgh+9Ev79r1Napu3s80SACPgvTP45CLp1hOGFySRaW7jcG3i+V4 +ljQWVAEse9Vy3e7E1EY2p6z/Zvj2UVOMqdHsivR1XLy5hts5ubIqOqvOCPocJ+0/ +m0AjwCXO4QPy7pLAAa7DA9rWDpzx8jpdfe54NOHuj4SVP45+PPsWvvkN2ZOkC/vb +zz4DcYVwIqtqej8mvO2kkPIFLdRSKUc5N3xmdvF5awBGfHhb4l/KIDlhRle+L9kF +LxRgkmBb2FFfL0/GtQlpH0bHHwPij4jPcOY+ueLKmAMgwWdqYae0HS01F7nYeZuP +StDG+YuCjglOH8xugcV9GBXrRTijyjuml4st3Wl4tPpQClmdoZ2LXp5h/6Zq1aoc +QlraKjwuTuzQBBHIFh9KXLZANLtMLpGGepFSMqE6YIWl17gi/2NruP8MGXNk+7GM +ylczKu/Ny67qQ8JCnRLSNUXPg18LjU2voLuzgXWtuTUgRnQBdir6ZB5Bwc2zi0vx +DNl0yzDhGNFdR5Rng5lAcmclA4QWi7Oc4h/OLN0ma0UzAgMBAAEwDQYJKoZIhvcN +AQELBQADggIBADsWOWIMvynE2Iwtpv471kROYdqrj6Zj5P8Ye5/0lqedRxIYWDsc +XDii+ePem+cMhnty8tAqCeHIdBUN86ibP+oqlwySbvdvW121RfedsWpa+TPC+Rnj +8n5w0urVNpnYuep2f8SOpQ1WdXFMLIsKqcnV5KK3/rxOAUY9cNVumA55/terQMOZ +RSGfjtoKVkMSOxNlaj4frLNy+I7nyWYrZ9UmUirvGLce5LJ1nrmo2I46FA0XDwu8 +xJqe4mB3GT/t9kFujd3Q/MtgD4J/MjWBfSYV0vlzI+VuoRctikw2SWQckQWNlIhs +LPafo6D+lOxJtH58WksCxdb8C8sBbRl+irv/ZAlvIiOkmcpHcOQ7AbLTtosZs6nX +p0ptWENlTM3lkt/Xma8txWXfe29tlf/9oheqXKdYunRyvFPL/gBjjR/VWzIS5sT5 +T6z0Vdk7uW9/wzv45vzjES8a8AAFvEkaRS4JBoTCW69mc8RFR89Vp9axRHY/3ohQ +8pS9K00FLMTObb8qlW31LfKpCUSxHmU00BhGPduMYQF28Xj02zQ5UaeGOnSO5EjU +pG0N7yqaVwGv9jYQfmnnD7M5LYVweEZ3OzCbfZuNJ4+EHNdZKcJiu2TaOsyxK25q +AJvDAFTSr5A9GSjJ3OyIeKoI8Q6xuaQBitpZR90P/Ah/Ymg490rpXavk +-----END CERTIFICATE----- +-----BEGIN PRIVATE KEY----- +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 +EyqjJVOYUopmtejzqNMx6o2AA2jSc/oI +-----END PRIVATE KEY----- diff --git a/tests/test_InfluxDBClient.py b/tests/test_InfluxDBClient.py index 1e8da1da..6efef670 100644 --- a/tests/test_InfluxDBClient.py +++ b/tests/test_InfluxDBClient.py @@ -1,3 +1,6 @@ +import http.server +import json +import threading import unittest from influxdb_client import InfluxDBClient @@ -5,9 +8,57 @@ class InfluxDBClientTest(unittest.TestCase): + def tearDown(self) -> None: + if self.client: + self.client.close() + if hasattr(self, 'httpd'): + self.httpd.shutdown() + if hasattr(self, 'httpd_thread'): + self.httpd_thread.join() + def test_TrailingSlashInUrl(self): - client = InfluxDBClient(url="http://localhost:9999", token="my-token", org="my-org") - self.assertEqual('http://localhost:9999', client.api_client.configuration.host) + self.client = InfluxDBClient(url="http://localhost:9999", token="my-token", org="my-org") + self.assertEqual('http://localhost:9999', self.client.api_client.configuration.host) + + self.client = InfluxDBClient(url="http://localhost:9999/", token="my-token", org="my-org") + self.assertEqual('http://localhost:9999', self.client.api_client.configuration.host) + + def test_ConnectToSelfSignedServer(self): + import http.server + import ssl + import os + + # Disable unverified HTTPS requests + import urllib3 + urllib3.disable_warnings() + + # Configure HTTP server + self.httpd = http.server.HTTPServer(('localhost', 0), ServerWithSelfSingedSSL) + self.httpd.socket = ssl.wrap_socket(self.httpd.socket, certfile=f'{os.path.dirname(__file__)}/server.pem', + server_side=True) + + # Start server at background + self.httpd_thread = threading.Thread(target=self.httpd.serve_forever) + self.httpd_thread.start() + + self.client = InfluxDBClient(f"https://localhost:{self.httpd.server_address[1]}", + token="my-token", verify_ssl=False) + health = self.client.health() + + self.assertEqual(health.message, 'ready for queries and writes') + self.assertEqual(health.status, "pass") + self.assertEqual(health.name, "influxdb") + + +class ServerWithSelfSingedSSL(http.server.SimpleHTTPRequestHandler): + def _set_headers(self): + self.send_response(200) + self.send_header('Content-type', 'application/json') + self.end_headers() - client = InfluxDBClient(url="http://localhost:9999/", token="my-token", org="my-org") - self.assertEqual('http://localhost:9999', client.api_client.configuration.host) + def do_GET(self): + self._set_headers() + response = json.dumps( + dict(name="influxdb", message="ready for queries and writes", status="pass", checks=[], version="2.0.0", + commit="abcdefgh")).encode('utf-8') + self.wfile.write(response)