diff --git a/LICENSE-3rdparty.csv b/LICENSE-3rdparty.csv index 3d993d8b3260a..ca107005dc5df 100644 --- a/LICENSE-3rdparty.csv +++ b/LICENSE-3rdparty.csv @@ -22,7 +22,6 @@ clickhouse-driver,PyPI,MIT,Konstantin Lebedev contextlib2,PyPI,PSF,Nick Coghlan cryptography,PyPI,Apache-2.0,The Python Cryptographic Authority and individual contributors | The cryptography developers cryptography,PyPI,BSD-3-Clause,The Python Cryptographic Authority and individual contributors | The cryptography developers -cx-Oracle,PyPI,BSD-3-Clause,""Anthony Tuininga", | Anthony Tuininga" ddtrace,PyPI,BSD-3-Clause,"Datadog, Inc." dnspython,PyPI,ISC,Bob Halley enum34,PyPI,BSD-3-Clause,Ethan Furman @@ -45,6 +44,8 @@ lz4,PyPI,BSD-3-Clause,Jonathan Underwood mmh3,PyPI,CC0-1.0,Hajime Senuma oauthlib,PyPI,BSD-3-Clause,The OAuthlib Community openstacksdk,PyPI,Apache-2.0,OpenStack +oracledb,PyPI,Apache-2.0,Anthony Tuininga +oracledb,PyPI,UPL,Anthony Tuininga orjson,PyPI,Apache-2.0,ijl orjson,PyPI,MIT,ijl packaging,PyPI,Apache-2.0,Donald Stufft and individual contributors diff --git a/datadog_checks_base/datadog_checks/base/data/agent_requirements.in b/datadog_checks_base/datadog_checks/base/data/agent_requirements.in index a9a71ebd5a40a..9b71c04e46af0 100644 --- a/datadog_checks_base/datadog_checks/base/data/agent_requirements.in +++ b/datadog_checks_base/datadog_checks/base/data/agent_requirements.in @@ -18,8 +18,6 @@ clickhouse-driver==0.2.3; python_version > '3.0' contextlib2==0.6.0.post1; python_version < '3.0' cryptography==3.3.2; python_version < '3.0' cryptography==38.0.3; python_version > '3.0' -cx-oracle==7.3.0; python_version < '3.0' -cx-oracle==8.3.0; python_version > '3.0' ddtrace==0.32.2; sys_platform == 'win32' and python_version < '3.0' ddtrace==0.53.2; sys_platform != 'win32' or python_version > '3.0' dnspython==1.16.0 @@ -34,7 +32,6 @@ in-toto==1.0.1 ipaddress==1.0.23; python_version < '3.0' jaydebeapi==1.2.3 jellyfish==0.9.0; python_version > '3.0' -jpype1==0.7.0; python_version < '3.0' jpype1==1.4.0; python_version > '3.0' kafka-python==2.0.2 kazoo==2.9.0 @@ -50,6 +47,7 @@ oauthlib==3.1.0; python_version < '3.0' oauthlib==3.2.2; python_version > '3.0' openstacksdk==0.39.0; python_version < '3.0' openstacksdk==0.61.0; python_version > '3.0' +oracledb==1.2.0; python_version >= '3.8' orjson==3.8.1; python_version > '3.0' packaging==20.9; python_version < '3.0' packaging==21.3; python_version > '3.0' diff --git a/oracle/README.md b/oracle/README.md index debf4ce484231..133666c76f8bd 100644 --- a/oracle/README.md +++ b/oracle/README.md @@ -12,56 +12,13 @@ Get metrics from Oracle Database servers in real time to visualize and monitor a #### Prerequisite -To use the Oracle integration, either install the Oracle Instant Client libraries, or download the Oracle JDBC driver (Linux only). -Due to licensing restrictions, these libraries are not included in the Datadog Agent, but can be downloaded directly from Oracle. +To use the Oracle integration you can either use the native client (no additional install steps required) or download the Oracle JDBC driver (Linux only). To use the Oracle integration with JDBC, download the Oracle JDBC driver. If not using the JDBC method, the minimun [supported version][2] is Oracle 12c. +Due to licensing restrictions, the JDBC library is not included in the Datadog Agent, but can be downloaded directly from Oracle. -##### Oracle Instant Client +With Agent v7.42.x, the Agent no longer requires or supports installing the Instant Client libraries. If you're on an older version of the Agent and want to use the Instant Client, refer to the [Oracle Instant Client][3] setup instructions. - - -###### Linux - -1. Follow the [Oracle Instant Client installation for Linux][2]. - -2. Verify the following: - - Both the *Instant Client Basic* and *SDK* packages are installed. Find them on Oracle's [download page][3]. - - After the Instant Client libraries are installed, ensure the runtime linker can find the libraries. For example, using `ldconfig`: - - ```shell - # Put the library location in an ld configuration file. - - sudo sh -c "echo /usr/lib/oracle/12.2/client64/lib > \ - /etc/ld.so.conf.d/oracle-instantclient.conf" - - # Update the bindings. - - sudo ldconfig - ``` - - - Both packages are decompressed into a single directory that is available to all users on the given machine (for example, `/opt/oracle`): - ```shell - mkdir -p /opt/oracle/ && cd /opt/oracle/ - unzip /opt/oracle/instantclient-basic-linux.x64-12.1.0.2.0.zip - unzip /opt/oracle/instantclient-sdk-linux.x64-12.1.0.2.0.zip - ``` - - - -###### Windows - -1. Follow the [Oracle Windows installation guide][4] to configure your Oracle Instant Client. - -2. Verify the following: - - The [Microsoft Visual Studio 2017 Redistributable][5] or the appropriate version is installed for the Oracle Instant Client. +*NOTE*: Starting in v7.42.x, the Oracle integration only supports Python 3. - - Both the *Instant Client Basic* and *SDK* packages from Oracle's [download page][3] are installed. - - - Both packages are extracted into a single directory that is available to all users on the given machine (for example, `C:\oracle`). - - - - ##### JDBC driver @@ -71,8 +28,8 @@ Java 8 or higher is required on your system for JPype, one of the libraries used Once it is installed, complete the following steps: -1. [Download the JDBC Driver][6] JAR file. -2. Add the path to the downloaded file in your `$CLASSPATH` or the check configuration file under `jdbc_driver_path` (see the [sample oracle.yaml][7]). +1. [Download the JDBC Driver][4] JAR file. +2. Add the path to the downloaded file in your `$CLASSPATH` or the check configuration file under `jdbc_driver_path` (see the [sample oracle.yaml][5]). #### Datadog user creation @@ -131,7 +88,7 @@ GRANT SELECT ON gv_$sysmetric TO c##datadog CONTAINER=ALL; To configure this check for an Agent running on a host: -1. Edit the `oracle.d/conf.yaml` file, in the `conf.d/` folder at the root of your [Agent's configuration directory][8]. Update the `server` and `port` to set the masters to monitor. See the [sample oracle.d/conf.yaml][7] for all available configuration options. +1. Edit the `oracle.d/conf.yaml` file, in the `conf.d/` folder at the root of your [Agent's configuration directory][6]. Update the `server` and `port` to set the masters to monitor. See the [sample oracle.d/conf.yaml][5] for all available configuration options. ```yaml init_config: @@ -159,7 +116,7 @@ To configure this check for an Agent running on a host: password: ``` -2. [Restart the Agent][9]. +2. [Restart the Agent][7]. #### Only custom queries @@ -242,9 +199,9 @@ instances: 2. Update the `sqlnet.ora`, `listener.ora`, and `tnsnames.ora` to allow TCPS connections on your Oracle Database. -##### TCPS through the Oracle Instant Client +##### TCPS through Oracle without JDBC -If you are connecting to Oracle Database using the Oracle Instant Client, verify that the Datadog Agent is able to connect to your database. Use the `sqlplus` command line tool with the information inputted in your configuration options: +If you are not using JDBC, verify that the Datadog Agent is able to connect to your database. Use the `sqlplus` command line tool with the information inputted in your configuration options: ```shell sqlplus /@(DESCRIPTION=(ADDRESS_LIST=(ADDRESS=(PROTOCOL=TCPS)(HOST=)(PORT=))(SERVICE_NAME=))) @@ -276,14 +233,14 @@ If you are connecting to Oracle Database using JDBC, you also need to specify `j # jdbc_truststore_password: ``` -For more information about connecting to the Oracle Database through TCPS on JDBC, see the official [Oracle whitepaper][17]. +For more information about connecting to the Oracle Database through TCPS on JDBC, see the official [Oracle whitepaper][15]. #### Containerized -For containerized environments, see the [Autodiscovery Integration Templates][10] for guidance on applying the parameters below. +For containerized environments, see the [Autodiscovery Integration Templates][8] for guidance on applying the parameters below. | Parameter | Value | | -------------------- | --------------------------------------------------------------------------------------------------------- | @@ -297,7 +254,7 @@ For containerized environments, see the [Autodiscovery Integration Templates][10 ### Validation -[Run the Agent's status subcommand][11] and look for `oracle` under the Checks section. +[Run the Agent's status subcommand][9] and look for `oracle` under the Checks section. ## Custom query @@ -339,7 +296,7 @@ is what the following example configuration would become: - tester:oracle ``` -See the [sample oracle.d/conf.yaml][7] for all available configuration options. +See the [sample oracle.d/conf.yaml][5] for all available configuration options. ### Example @@ -403,13 +360,13 @@ SQL> select blocking_session,username,osuser, sid, serial#, wait_class, seconds_ where blocking_session is not NULL order by blocking_session; ``` -3. Once configured, you can create a [monitor][12] based on `oracle.custom_query.locks` metrics. +3. Once configured, you can create a [monitor][10] based on `oracle.custom_query.locks` metrics. ## Data Collected ### Metrics -See [metadata.csv][13] for a list of metrics provided by this integration. +See [metadata.csv][11] for a list of metrics provided by this integration. ### Events @@ -417,57 +374,11 @@ The Oracle Database check does not include any events. ### Service Checks -See [service_checks.json][14] for a list of service checks provided by this integration. +See [service_checks.json][12] for a list of service checks provided by this integration. ## Troubleshooting -### Common problems -#### Oracle Instant Client -- Verify that both the Oracle Instant Client and SDK files are located in the same directory. -The structure of the directory should look similar: - -```text -|____sdk/ -|____network/ -|____libociei.dylib -|____libocci.dylib -|____libocci.dylib.10.1 -|____adrci -|____uidrvci -|____libclntsh.dylib.19.1 -|____ojdbc8.jar -|____BASIC_README -|____liboramysql19.dylib -|____libocijdbc19.dylib -|____libocci.dylib.19.1 -|____libclntsh.dylib -|____xstreams.jar -|____libclntsh.dylib.10.1 -|____libnnz19.dylib -|____libclntshcore.dylib.19.1 -|____libocci.dylib.12.1 -|____libocci.dylib.18.1 -|____libclntsh.dylib.11.1 -|____BASIC_LICENSE -|____SDK_LICENSE -|____libocci.dylib.11.1 -|____libclntsh.dylib.12.1 -|____libclntsh.dylib.18.1 -|____ucp.jar -|____genezi -|____SDK_README - -``` - -##### Linux -- See further Linux installation documentation on [Oracle][2]. - -##### Windows -- Verify the Microsoft Visual Studio `` Redistributable requirement is met for your version. See the [Windows downloads page][15] for more details. -- See further Windows installation documentation on [Oracle][4]. - - -#### JDBC driver (Linux only) +### JDBC driver (Linux only) - If you encounter a `JVMNotFoundException`: ```text @@ -492,22 +403,20 @@ Ensure the displayed output matches the correct value. sudo -u dd-agent -- /opt/datadog-agent/embedded/bin/python -c "import os; print(\"JAVA_HOME:{}\".format(os.environ.get(\"JAVA_HOME\")))" ``` -Need help? Contact [Datadog support][16]. +Need help? Contact [Datadog support][14]. [1]: https://raw.githubusercontent.com/DataDog/integrations-core/master/oracle/images/oracle_dashboard.png -[2]: https://docs.oracle.com/en/database/oracle/oracle-database/21/lacli/install-instant-client-using-zip.html -[3]: https://www.oracle.com/technetwork/database/features/instant-client/index.htm -[4]: https://www.oracle.com/database/technologies/instant-client/winx64-64-downloads.html#ic_winx64_inst -[5]: https://support.microsoft.com/en-us/topic/the-latest-supported-visual-c-downloads-2647da03-1eea-4433-9aff-95f26a218cc0 -[6]: https://www.oracle.com/technetwork/database/application-development/jdbc/downloads/index.html -[7]: https://github.com/DataDog/integrations-core/blob/master/oracle/datadog_checks/oracle/data/conf.yaml.example -[8]: https://docs.datadoghq.com/agent/guide/agent-configuration-files/#agent-configuration-directory -[9]: https://docs.datadoghq.com/agent/guide/agent-commands/#start-stop-and-restart-the-agent -[10]: https://docs.datadoghq.com/agent/kubernetes/integrations/ -[11]: https://docs.datadoghq.com/agent/guide/agent-commands/#agent-status-and-information -[12]: https://docs.datadoghq.com/monitors/monitor_types/metric/?tab=threshold -[13]: https://github.com/DataDog/integrations-core/blob/master/oracle/metadata.csv -[14]: https://github.com/DataDog/integrations-core/blob/master/oracle/assets/service_checks.json -[15]: https://www.oracle.com/database/technologies/instant-client/winx64-64-downloads.html -[16]: https://docs.datadoghq.com/help/ -[17]: https://www.oracle.com/technetwork/topics/wp-oracle-jdbc-thin-ssl-130128.pdf +[2]: https://oracle.github.io/python-oracledb/ +[3]: https://github.com/DataDog/integrations-core/tree/7.41.x/oracle#oracle-instant-client +[4]: https://www.oracle.com/technetwork/database/application-development/jdbc/downloads/index.html +[5]: https://github.com/DataDog/integrations-core/blob/master/oracle/datadog_checks/oracle/data/conf.yaml.example +[6]: https://docs.datadoghq.com/agent/guide/agent-configuration-files/#agent-configuration-directory +[7]: https://docs.datadoghq.com/agent/guide/agent-commands/#start-stop-and-restart-the-agent +[8]: https://docs.datadoghq.com/agent/kubernetes/integrations/ +[9]: https://docs.datadoghq.com/agent/guide/agent-commands/#agent-status-and-information +[10]: https://docs.datadoghq.com/monitors/monitor_types/metric/?tab=threshold +[11]: https://github.com/DataDog/integrations-core/blob/master/oracle/metadata.csv +[12]: https://github.com/DataDog/integrations-core/blob/master/oracle/assets/service_checks.json +[13]: https://www.oracle.com/database/technologies/instant-client/winx64-64-downloads.html +[14]: https://docs.datadoghq.com/help/ +[15]: https://www.oracle.com/technetwork/topics/wp-oracle-jdbc-thin-ssl-130128.pdf \ No newline at end of file diff --git a/oracle/datadog_checks/oracle/oracle.py b/oracle/datadog_checks/oracle/oracle.py index 7691e55d12130..bb448dd22acfa 100644 --- a/oracle/datadog_checks/oracle/oracle.py +++ b/oracle/datadog_checks/oracle/oracle.py @@ -5,7 +5,7 @@ import threading from contextlib import closing -import cx_Oracle +import oracledb from six import PY2 from datadog_checks.base import AgentCheck, ConfigurationError @@ -50,6 +50,12 @@ class Oracle(AgentCheck): SERVICE_CHECK_CAN_QUERY = "can_query" def __init__(self, name, init_config, instances): + if PY2: + raise ConfigurationError( + "This version of the integration is only available when using py3. " + "Check https://docs.datadoghq.com/agent/guide/agent-v6-python-3 " + "for more information." + ) super(Oracle, self).__init__(name, init_config, instances) self._server = self.instance.get('server') self._user = self.instance.get('username') or self.instance.get('user') @@ -80,10 +86,8 @@ def __init__(self, name, init_config, instances): tags=self._tags, ) - # Runtime validations are only py3, so this is for manually validating config on py2 - if PY2: - self.check_initializations.append(self.validate_config) self.check_initializations.append(self._query_manager.compile_queries) + self.check_initializations.append(self.can_use_jdbc) self._query_errors = 0 self._connection_errors = 0 @@ -104,26 +108,6 @@ def _fix_custom_queries(self): if column.get('type') != 'tag' and column.get('name'): column['name'] = '{}.{}'.format(prefix, column['name']) - def validate_config(self): - if not self._server or not self._user: - raise ConfigurationError("Oracle host and user are needed") - - if not self._protocol or self._protocol.upper() not in VALID_PROTOCOLS: - raise ConfigurationError("Protocol %s is not valid, must either be TCP or TCPS" % self._protocol) - - if self._jdbc_driver and self._protocol.upper() == PROTOCOL_TCPS: - if not (self._jdbc_truststore_type and self._jdbc_truststore_path): - raise ConfigurationError( - "TCPS connections to Oracle via JDBC requires both `jdbc_truststore_type` and " - "`jdbc_truststore_path` configuration options " - ) - - if self._jdbc_truststore_type and self._jdbc_truststore_type.upper() not in VALID_TRUSTSTORE_TYPES: - raise ConfigurationError( - "Truststore type %s is not valid, must be one of %s" - % (self._jdbc_truststore_type, VALID_TRUSTSTORE_TYPES) - ) - def execute_query_raw(self, query): with closing(self._connection.cursor()) as cursor: cursor.execute(query) @@ -165,44 +149,40 @@ def check(self, _): @property def _connection(self): - """Creates a connection or raises an exception""" if self._cached_connection is None: - if self.can_use_oracle_client(): - self._cached_connection = self._oracle_client_connect() - elif JDBC_IMPORT_ERROR: - self._connection_errors += 1 + if self.can_use_jdbc(): + try: + self._cached_connection = self._jdbc_connect() + except Exception as e: + self.log.error("The JDBC connection failed with the following error: %s", str(e)) + self._connection_errors += 1 + else: + self._cached_connection = self._oracle_connect() + return self._cached_connection + + def can_use_jdbc(self): + if self._jdbc_driver: + if JDBC_IMPORT_ERROR is not None: self.log.error( - "Oracle client is unavailable and the integration is unable to import JDBC libraries. You may not " - "have the Microsoft Visual C++ Runtime 2015 installed on your system. Please double check your " + "The integration is unable to import JDBC libraries. Please double check your " "installation and refer to the Datadog documentation for more information." ) raise JDBC_IMPORT_ERROR else: - self._cached_connection = self._jdbc_connect() - return self._cached_connection - - def can_use_oracle_client(self): - try: - # Check if the instantclient is available - cx_Oracle.clientversion() - except cx_Oracle.DatabaseError as e: - # Fallback to JDBC - self.log.debug('Oracle instant client unavailable, falling back to JDBC: %s', e) - return False + return True else: - self.log.debug('Running cx_Oracle version %s', cx_Oracle.version) - return True + return False - def _oracle_client_connect(self): + def _oracle_connect(self): dsn = self._get_dsn() - self.log.debug("Connecting via Oracle Instant Client with DSN: %s", dsn) + self.log.debug("Connecting to Oracle with DSN: %s", dsn) try: - connection = cx_Oracle.connect(user=self._user, password=self._password, dsn=dsn) - self.log.debug("Connected to Oracle DB using Oracle Instant Client") + connection = oracledb.connect(user=self._user, password=self._password, dsn=dsn) + self.log.debug("Connected to Oracle DB using Python Oracle") return connection - except cx_Oracle.DatabaseError as e: + except oracledb.DatabaseError as e: self._connection_errors += 1 - self.log.error("Failed to connect to Oracle DB using Oracle Instant Client, error: %s", str(e)) + self.log.error("Failed to connect to Oracle DB, error: %s", str(e)) raise def _get_dsn(self): @@ -222,7 +202,7 @@ def _get_dsn(self): ) return dsn else: - return cx_Oracle.makedsn(host, port, service_name=self._service) + return oracledb.makedsn(host, port, service_name=self._service) def _jdbc_connect(self): jdbc_connect_properties = {'user': self._user, 'password': self._password} diff --git a/oracle/pyproject.toml b/oracle/pyproject.toml index 9eb8a2e1c0d1c..c8d0ed81cff69 100644 --- a/oracle/pyproject.toml +++ b/oracle/pyproject.toml @@ -9,6 +9,7 @@ build-backend = "hatchling.build" name = "datadog-oracle" description = "The Oracle Database check" readme = "README.md" +requires-python = ">=3.8" keywords = [ "datadog", "datadog agent", @@ -23,7 +24,6 @@ classifiers = [ "Intended Audience :: Developers", "Intended Audience :: System Administrators", "License :: OSI Approved :: BSD License", - "Programming Language :: Python :: 2.7", "Programming Language :: Python :: 3.8", "Topic :: System :: Monitoring", "Private :: Do Not Upload", @@ -40,10 +40,8 @@ text = "BSD-3-Clause" [project.optional-dependencies] deps = [ - "cx-oracle==7.3.0; python_version < '3.0'", - "cx-oracle==8.3.0; python_version > '3.0'", + "oracledb==1.2.0; python_version >= '3.8'", "jaydebeapi==1.2.3", - "jpype1==0.7.0; python_version < '3.0'", "jpype1==1.4.0; python_version > '3.0'", ] diff --git a/oracle/setup.py b/oracle/setup.py index bc3d542949ca7..35b51f1daba2a 100644 --- a/oracle/setup.py +++ b/oracle/setup.py @@ -68,8 +68,6 @@ def parse_pyproject_array(name): 'Intended Audience :: System Administrators', 'Topic :: System :: Monitoring', 'License :: OSI Approved :: BSD License', - 'Programming Language :: Python :: 2', - 'Programming Language :: Python :: 2.7', 'Programming Language :: Python :: 3', 'Programming Language :: Python :: 3.8', ], diff --git a/oracle/tests/conftest.py b/oracle/tests/conftest.py index df1264b638237..3b0a01d06e8a8 100644 --- a/oracle/tests/conftest.py +++ b/oracle/tests/conftest.py @@ -24,38 +24,41 @@ USER, ) -E2E_METADATA_ORACLE_CLIENT = { +E2E_METADATA_JDBC_CLIENT = { + # The integration will use to JDBC client + 'use_jmx': True, # Using jmx to have a ready to use java runtime 'docker_volumes': [ - '{}/scripts/install_instant_client.sh:/tmp/install_instant_client.sh'.format(HERE), + '{}/scripts/install_jdbc_client.sh:/tmp/install_jdbc_client.sh'.format(HERE), '{}/docker/client/client_wallet:/opt/oracle/instantclient_19_3/client_wallet'.format(HERE), '{}/docker/client/sqlnet.ora:/opt/oracle/instantclient_19_3/sqlnet.ora'.format(HERE), '{}/docker/client/tnsnames.ora:/opt/oracle/instantclient_19_3/tnsnames.ora'.format(HERE), '{}/docker/client/listener.ora:/opt/oracle/instantclient_19_3/listener.ora'.format(HERE), + '{}/docker/client/oraclepki.jar:/opt/oracle/instantclient_19_3/oraclepki.jar'.format(HERE), + '{}/docker/client/osdt_cert.jar:/opt/oracle/instantclient_19_3/osdt_cert.jar'.format(HERE), + '{}/docker/client/osdt_core.jar:/opt/oracle/instantclient_19_3/osdt_core.jar'.format(HERE), ], 'start_commands': [ - 'bash /tmp/install_instant_client.sh', + 'bash /tmp/install_jdbc_client.sh', # Still needed to set up the database ], - 'env_vars': {'LD_LIBRARY_PATH': '/opt/oracle/instantclient_19_3', 'TNS_ADMIN': '/opt/oracle/instantclient_19_3'}, + 'env_vars': {'TNS_ADMIN': '/opt/oracle/instantclient_19_3'}, } -E2E_METADATA_JDBC_CLIENT = { - # Since we don't include Oracle instantclient to `LD_LIBRARY_PATH` env var, - # the integration will fallback to JDBC client - 'use_jmx': True, # Using jmx to have a ready to use java runtime +E2E_METADATA_ORACLE_CLIENT = { + 'use_jmx': True, # update-ca-certificates fails without this 'docker_volumes': [ - '{}/scripts/install_instant_client.sh:/tmp/install_instant_client.sh'.format(HERE), + '{}/scripts/install_jdbc_client.sh:/tmp/install_jdbc_client.sh'.format(HERE), '{}/docker/client/client_wallet:/opt/oracle/instantclient_19_3/client_wallet'.format(HERE), '{}/docker/client/sqlnet.ora:/opt/oracle/instantclient_19_3/sqlnet.ora'.format(HERE), '{}/docker/client/tnsnames.ora:/opt/oracle/instantclient_19_3/tnsnames.ora'.format(HERE), '{}/docker/client/listener.ora:/opt/oracle/instantclient_19_3/listener.ora'.format(HERE), - '{}/docker/client/oraclepki.jar:/opt/oracle/instantclient_19_3/oraclepki.jar'.format(HERE), - '{}/docker/client/osdt_cert.jar:/opt/oracle/instantclient_19_3/osdt_cert.jar'.format(HERE), - '{}/docker/client/osdt_core.jar:/opt/oracle/instantclient_19_3/osdt_core.jar'.format(HERE), ], 'start_commands': [ - 'bash /tmp/install_instant_client.sh', # Still needed to set up the database + 'bash /tmp/install_jdbc_client.sh', + 'mkdir -p /usr/local/share/ca-certificates', + 'touch /usr/local/share/ca-certificates/ca-cert.crt', + 'cp /opt/oracle/instantclient_19_3/client_wallet/cert.pem /usr/local/share/ca-certificates/ca-certificate.crt', + 'update-ca-certificates', ], - 'env_vars': {'TNS_ADMIN': '/opt/oracle/instantclient_19_3'}, } @@ -99,6 +102,7 @@ def tcps_instance(): @pytest.fixture(scope='session') def dd_environment(): + instance = { 'server': '{}:{}'.format(HOST, PORT), 'username': USER, diff --git a/oracle/tests/docker/client/client_wallet/cert.pem b/oracle/tests/docker/client/client_wallet/cert.pem new file mode 100644 index 0000000000000..9a0bc8dc80c7f --- /dev/null +++ b/oracle/tests/docker/client/client_wallet/cert.pem @@ -0,0 +1,11 @@ +-----BEGIN CERTIFICATE----- +MIIBpzCCARACEQDTNH1g6mLOBQkxZ1b47RQiMA0GCSqGSIb3DQEBCwUAMBQxEjAQ +BgNVBAMTCWxvY2FsaG9zdDAeFw0yMTExMTYyMTI3MDZaFw0zMTExMTQyMTI3MDZa +MBQxEjAQBgNVBAMTCWxvY2FsaG9zdDCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkC +gYEAiBMONZ5qn7gdjL0iJr8OZgc/lX51f4bAF/bfOTWs4D6ZIth29mnY0DaNXHKc +LTtkRlZQTIwuLHSx78oaOG9DhMRAKrrOQxDNcg4nHMmS50kMgx4NZo0pO/idRS0J +Cz7JzU9scGwegkyK8/y4op98D5FSYrAIj1G+OhezIEpYRIkCAwEAATANBgkqhkiG +9w0BAQsFAAOBgQAhzh6gDNxRXCVEKwk+myRGXqvA3BEukyLRNcgBDv4taCldX8de ++UyELzJQzjKojNlI7/KfH4PAmldSsgNLXCmmimD0YBGQIkVXb7MMP9loHPkQoSaY +wl/h2ROJszQ62gMipqw0jH5Il5xkXqlYUqJJA0YlkCGx8HDstUfEhafhQQ== +-----END CERTIFICATE----- \ No newline at end of file diff --git a/oracle/tests/scripts/install_instant_client.sh b/oracle/tests/scripts/install_jdbc_client.sh similarity index 100% rename from oracle/tests/scripts/install_instant_client.sh rename to oracle/tests/scripts/install_jdbc_client.sh diff --git a/oracle/tests/test_config.py b/oracle/tests/test_config.py index 58d2778ddcf5b..dbd7f336737a6 100644 --- a/oracle/tests/test_config.py +++ b/oracle/tests/test_config.py @@ -3,7 +3,9 @@ # Licensed under a 3-clause BSD style license (see LICENSE) import pytest +from mock import patch +from datadog_checks.base.errors import ConfigurationError from datadog_checks.oracle import Oracle from .common import CHECK_NAME @@ -76,3 +78,11 @@ def test_check_misconfig_invalid_truststore_type(dd_run_check, instance): check = Oracle(CHECK_NAME, {}, [instance]) with pytest.raises(Exception): dd_run_check(check) + + +@patch('datadog_checks.oracle.oracle.PY2', True) +def test_py2(dd_run_check, instance): + # Test to ensure that a ConfigurationError is raised when running with Python 2. + with pytest.raises(ConfigurationError, match="This version of the integration is only available when using py3."): + check = Oracle('oracle', {}, [instance]) + dd_run_check(check) diff --git a/oracle/tests/test_jdbc.py b/oracle/tests/test_jdbc.py index 6a020926347f4..da7381e352a8d 100644 --- a/oracle/tests/test_jdbc.py +++ b/oracle/tests/test_jdbc.py @@ -60,18 +60,15 @@ def test__get_connection_jdbc(instance, dd_run_check, aggregator, expected_tags, Test the _get_connection method using the JDBC client """ check = Oracle(CHECK_NAME, {}, [instance]) - check.use_oracle_client = False - con = mock.MagicMock() + check.can_use_jdbc = mock.Mock(return_value=True) - cx = mock.MagicMock(DatabaseError=RuntimeError) - cx.clientversion.side_effect = cx.DatabaseError() + con = mock.MagicMock() jdb = mock.MagicMock() jdb.connect.return_value = con jpype = mock.MagicMock(isJVMStarted=lambda: False) mocks = [ - ('datadog_checks.oracle.oracle.cx_Oracle', cx), ('datadog_checks.oracle.oracle.jdb', jdb), ('datadog_checks.oracle.oracle.jpype', jpype), ('datadog_checks.oracle.oracle.JDBC_IMPORT_ERROR', None), @@ -93,13 +90,11 @@ def test__get_connection_jdbc_query_fail(check, dd_run_check, aggregator): """ Test the _get_connection method using the JDBC client and unsuccessfully query DB """ - check.use_oracle_client = False + check.can_use_jdbc = mock.Mock(return_value=True) con = mock.MagicMock() expected_tags = ['server:localhost:1521', 'optional:tag1'] check._query_manager.executor = mock_bad_executor() - cx = mock.MagicMock(DatabaseError=RuntimeError) - cx.clientversion.side_effect = cx.DatabaseError() jdb = mock.MagicMock() jdb.connect.return_value = con @@ -108,7 +103,6 @@ def test__get_connection_jdbc_query_fail(check, dd_run_check, aggregator): check._query_errors = 1 mocks = [ - ('datadog_checks.oracle.oracle.cx_Oracle', cx), ('datadog_checks.oracle.oracle.jdb', jdb), ('datadog_checks.oracle.oracle.jpype', jpype), ('datadog_checks.oracle.oracle.JDBC_IMPORT_ERROR', None), diff --git a/oracle/tests/test_instant_client.py b/oracle/tests/test_oracledb.py similarity index 75% rename from oracle/tests/test_instant_client.py rename to oracle/tests/test_oracledb.py index ed25701bac815..bfbabfa3ff320 100644 --- a/oracle/tests/test_instant_client.py +++ b/oracle/tests/test_oracledb.py @@ -39,50 +39,47 @@ ), ], ) -def test__get_connection_instant_client(instance, dd_run_check, aggregator, expected_tags): +def test__get_connection_oracledb(instance, dd_run_check, aggregator, expected_tags): """ Test the _get_connection method using the instant client """ check = Oracle(CHECK_NAME, {}, [instance]) - check.use_oracle_client = True con = mock.MagicMock() - with mock.patch('datadog_checks.oracle.oracle.cx_Oracle') as cx: - cx.connect.return_value = con + with mock.patch('datadog_checks.oracle.oracle.oracledb') as pyoradb: + pyoradb.connect.return_value = con dd_run_check(check) assert check._cached_connection == con - cx.connect.assert_called_with(user='system', password='oracle', dsn=check._get_dsn()) + pyoradb.connect.assert_called_with(user='system', password='oracle', dsn=check._get_dsn()) aggregator.assert_service_check("oracle.can_connect", check.OK, count=1, tags=expected_tags) aggregator.assert_service_check("oracle.can_query", check.OK, count=1, tags=expected_tags) -def test__get_connection_instant_client_query_fail(check, dd_run_check, aggregator): +def test__get_connection_oracldb_query_fail(check, dd_run_check, aggregator): """ Test the _get_connection method using the oracle client and unsuccessfully query DB """ - check.use_oracle_client = True con = mock.MagicMock() check._query_manager.executor = mock_bad_executor() expected_tags = ['server:localhost:1521', 'optional:tag1'] - with mock.patch('datadog_checks.oracle.oracle.cx_Oracle') as cx: - cx.connect.return_value = con + with mock.patch('datadog_checks.oracle.oracle.oracledb') as pyoradb: + pyoradb.connect.return_value = con dd_run_check(check) aggregator.assert_service_check("oracle.can_connect", check.OK, count=1, tags=expected_tags) aggregator.assert_service_check("oracle.can_query", check.CRITICAL, count=1, tags=expected_tags) -def test__get_connection_instant_client_server_incorrect_formatting(instance, dd_run_check, aggregator): +def test__get_connection_oracledb_server_incorrect_formatting(instance, dd_run_check, aggregator): """ Test the _get_connection method using the instant client when the server is formatted incorrectly """ con = mock.MagicMock() instance['server'] = 'localhost:1521a' check = Oracle(CHECK_NAME, {}, [instance]) - check.use_oracle_client = True expected_tags = ['server:localhost:1521a', 'optional:tag1'] - with mock.patch('datadog_checks.oracle.oracle.cx_Oracle') as cx: - cx.connect.return_value = con + with mock.patch('datadog_checks.oracle.oracle.oracledb') as pyoradb: + pyoradb.connect.return_value = con dd_run_check(check) aggregator.assert_service_check("oracle.can_connect", check.CRITICAL, count=1, tags=expected_tags) aggregator.assert_service_check("oracle.can_query", check.CRITICAL, count=1, tags=expected_tags) diff --git a/oracle/tox.ini b/oracle/tox.ini index 37f1177eb8bb1..bc86577768cb6 100644 --- a/oracle/tox.ini +++ b/oracle/tox.ini @@ -3,15 +3,14 @@ isolated_build = true minversion = 2.0 basepython = py38 envlist = - py{27,38}-{12.2}-{oracle,jdbc}{,-tcps} + py{38}-{12.2}-{oracle,jdbc}{,-tcps} [testenv] ensure_default_envdir = true envdir = - py27: {toxworkdir}/py27 py38: {toxworkdir}/py38 description = - py{27,38}: e2e ready + py{38}: e2e ready dd_check_style = true usedevelop = true platform = darwin|linux|win32