diff --git a/.ci/run-repository.sh b/.ci/run-repository.sh index 7c89ec8f..fecf6e4b 100755 --- a/.ci/run-repository.sh +++ b/.ci/run-repository.sh @@ -34,6 +34,7 @@ docker run \ --network=${network_name} \ --env "STACK_VERSION=${STACK_VERSION}" \ --env "OPENSEARCH_URL=${opensearch_url}" \ + --env "OPENSEARCH_VERSION=${OPENSEARCH_VERSION}" \ --env "TEST_SUITE=${TEST_SUITE}" \ --env "PYTHON_CONNECTION_CLASS=${PYTHON_CONNECTION_CLASS}" \ --env "TEST_TYPE=server" \ diff --git a/noxfile.py b/noxfile.py index 5dcd9d81..895b4fa2 100644 --- a/noxfile.py +++ b/noxfile.py @@ -24,6 +24,7 @@ # specific language governing permissions and limitations # under the License. + import nox SOURCE_FILES = ( diff --git a/opensearchpy/__init__.py b/opensearchpy/__init__.py index ef7d385c..bd7f24b5 100644 --- a/opensearchpy/__init__.py +++ b/opensearchpy/__init__.py @@ -24,6 +24,7 @@ # specific language governing permissions and limitations # under the License. + # flake8: noqa from __future__ import absolute_import diff --git a/opensearchpy/_async/_extra_imports.py b/opensearchpy/_async/_extra_imports.py index 829c7cf1..5fd19461 100644 --- a/opensearchpy/_async/_extra_imports.py +++ b/opensearchpy/_async/_extra_imports.py @@ -24,6 +24,7 @@ # specific language governing permissions and limitations # under the License. + # type: ignore # This file exists for the sole reason of making mypy not diff --git a/opensearchpy/_async/client/__init__.py b/opensearchpy/_async/client/__init__.py index eaefa43d..8346b236 100644 --- a/opensearchpy/_async/client/__init__.py +++ b/opensearchpy/_async/client/__init__.py @@ -37,6 +37,7 @@ from .features import FeaturesClient from .indices import IndicesClient from .ingest import IngestClient from .nodes import NodesClient +from .plugins import PluginsClient from .remote import RemoteClient from .snapshot import SnapshotClient from .tasks import TasksClient @@ -197,6 +198,7 @@ class AsyncOpenSearch(object): self.remote = RemoteClient(self) self.snapshot = SnapshotClient(self) self.tasks = TasksClient(self) + self.plugins = PluginsClient(self) self.features = FeaturesClient(self) diff --git a/opensearchpy/_async/client/__init__.pyi b/opensearchpy/_async/client/__init__.pyi index cc423451..41ed2ba9 100644 --- a/opensearchpy/_async/client/__init__.pyi +++ b/opensearchpy/_async/client/__init__.pyi @@ -60,7 +60,7 @@ class AsyncOpenSearch(object): self, hosts: Any = ..., transport_class: Type[AsyncTransport] = ..., - **kwargs: Any, + **kwargs: Any ) -> None: ... def __repr__(self) -> str: ... async def __aenter__(self) -> "AsyncOpenSearch": ... diff --git a/opensearchpy/_async/client/cat.py b/opensearchpy/_async/client/cat.py index 378156fe..2499f3bf 100644 --- a/opensearchpy/_async/client/cat.py +++ b/opensearchpy/_async/client/cat.py @@ -24,6 +24,7 @@ # specific language governing permissions and limitations # under the License. + from .utils import NamespacedClient, _make_path, query_params diff --git a/opensearchpy/_async/client/cluster.py b/opensearchpy/_async/client/cluster.py index 52df4f28..084c8b75 100644 --- a/opensearchpy/_async/client/cluster.py +++ b/opensearchpy/_async/client/cluster.py @@ -24,6 +24,7 @@ # specific language governing permissions and limitations # under the License. + from .utils import SKIP_IN_PATH, NamespacedClient, _make_path, query_params diff --git a/opensearchpy/_async/client/dangling_indices.py b/opensearchpy/_async/client/dangling_indices.py index 761b20da..b3df7cb4 100644 --- a/opensearchpy/_async/client/dangling_indices.py +++ b/opensearchpy/_async/client/dangling_indices.py @@ -24,6 +24,7 @@ # specific language governing permissions and limitations # under the License. + from .utils import SKIP_IN_PATH, NamespacedClient, _make_path, query_params diff --git a/opensearchpy/_async/client/features.py b/opensearchpy/_async/client/features.py index 6b70c815..54eb38e6 100644 --- a/opensearchpy/_async/client/features.py +++ b/opensearchpy/_async/client/features.py @@ -24,6 +24,7 @@ # specific language governing permissions and limitations # under the License. + from .utils import NamespacedClient, query_params diff --git a/opensearchpy/_async/client/indices.py b/opensearchpy/_async/client/indices.py index a14765f7..7464b286 100644 --- a/opensearchpy/_async/client/indices.py +++ b/opensearchpy/_async/client/indices.py @@ -24,6 +24,7 @@ # specific language governing permissions and limitations # under the License. + from .utils import SKIP_IN_PATH, NamespacedClient, _make_path, query_params diff --git a/opensearchpy/_async/client/ingest.py b/opensearchpy/_async/client/ingest.py index fcd33e94..2d35fc97 100644 --- a/opensearchpy/_async/client/ingest.py +++ b/opensearchpy/_async/client/ingest.py @@ -24,6 +24,7 @@ # specific language governing permissions and limitations # under the License. + from .utils import SKIP_IN_PATH, NamespacedClient, _make_path, query_params diff --git a/opensearchpy/_async/client/nodes.py b/opensearchpy/_async/client/nodes.py index 9533aa32..d437fd17 100644 --- a/opensearchpy/_async/client/nodes.py +++ b/opensearchpy/_async/client/nodes.py @@ -24,6 +24,7 @@ # specific language governing permissions and limitations # under the License. + from .utils import NamespacedClient, _make_path, query_params diff --git a/opensearchpy/_async/client/plugins.py b/opensearchpy/_async/client/plugins.py new file mode 100644 index 00000000..8f639163 --- /dev/null +++ b/opensearchpy/_async/client/plugins.py @@ -0,0 +1,51 @@ +# SPDX-License-Identifier: Apache-2.0 +# +# The OpenSearch Contributors require contributions made to +# this file be licensed under the Apache-2.0 license or a +# compatible open source license. +# +# Modifications Copyright OpenSearch Contributors. See +# GitHub history for details. + +import warnings + +from ..plugins.alerting import AlertingClient +from .utils import NamespacedClient + + +class PluginsClient(NamespacedClient): + def __init__(self, client): + super(PluginsClient, self).__init__(client) + # self.query_workbench = QueryWorkbenchClient(client) + # self.reporting = ReportingClient(client) + # self.notebooks = NotebooksClient(client) + self.alerting = AlertingClient(client) + # self.anomaly_detection = AnomalyDetectionClient(client) + # self.trace_analytics = TraceAnalyticsClient(client) + # self.index_management = IndexManagementClient(client) + # self.security = SecurityClient(client) + + self._dynamic_lookup(client) + + def _dynamic_lookup(self, client): + # Issue : https://github.com/opensearch-project/opensearch-py/issues/90#issuecomment-1003396742 + + plugins = [ + # "query_workbench", + # "reporting", + # "notebooks", + "alerting", + # "anomaly_detection", + # "trace_analytics", + # "index_management", + # "security" + ] + for plugin in plugins: + if not hasattr(client, plugin): + setattr(client, plugin, getattr(self, plugin)) + else: + warnings.warn( + f"Cannot load `{plugin}` directly to AsyncOpenSearch. `{plugin}` already exists in AsyncOpenSearch. Please use `AsyncOpenSearch.plugin.{plugin}` instead.", + category=RuntimeWarning, + stacklevel=2, + ) diff --git a/opensearchpy/_async/client/plugins.pyi b/opensearchpy/_async/client/plugins.pyi new file mode 100644 index 00000000..ca55cb19 --- /dev/null +++ b/opensearchpy/_async/client/plugins.pyi @@ -0,0 +1,17 @@ +# SPDX-License-Identifier: Apache-2.0 +# +# The OpenSearch Contributors require contributions made to +# this file be licensed under the Apache-2.0 license or a +# compatible open source license. +# +# Modifications Copyright OpenSearch Contributors. See +# GitHub history for details. +from typing import Any + +from ..client import AsyncOpenSearch +from ..plugins.alerting import AlertingClient as AlertingClient +from .utils import NamespacedClient as NamespacedClient + +class PluginsClient(NamespacedClient): + alerting: Any + def __init__(self, client: AsyncOpenSearch) -> None: ... diff --git a/opensearchpy/_async/client/remote.py b/opensearchpy/_async/client/remote.py index 9f2f7aec..02aa931d 100644 --- a/opensearchpy/_async/client/remote.py +++ b/opensearchpy/_async/client/remote.py @@ -24,6 +24,7 @@ # specific language governing permissions and limitations # under the License. + from .utils import NamespacedClient, query_params diff --git a/opensearchpy/_async/client/snapshot.py b/opensearchpy/_async/client/snapshot.py index da0666d3..a8015e67 100644 --- a/opensearchpy/_async/client/snapshot.py +++ b/opensearchpy/_async/client/snapshot.py @@ -24,6 +24,7 @@ # specific language governing permissions and limitations # under the License. + from .utils import SKIP_IN_PATH, NamespacedClient, _make_path, query_params diff --git a/opensearchpy/_async/client/tasks.py b/opensearchpy/_async/client/tasks.py index 4373c09b..2b49ddc0 100644 --- a/opensearchpy/_async/client/tasks.py +++ b/opensearchpy/_async/client/tasks.py @@ -24,6 +24,7 @@ # specific language governing permissions and limitations # under the License. + import warnings from .utils import SKIP_IN_PATH, NamespacedClient, _make_path, query_params diff --git a/opensearchpy/_async/client/utils.py b/opensearchpy/_async/client/utils.py index 8a7ddf05..b9ea1894 100644 --- a/opensearchpy/_async/client/utils.py +++ b/opensearchpy/_async/client/utils.py @@ -24,6 +24,7 @@ # specific language governing permissions and limitations # under the License. + from ...client.utils import ( # noqa SKIP_IN_PATH, NamespacedClient, diff --git a/opensearchpy/_async/compat.py b/opensearchpy/_async/compat.py index eda8d104..d9c411d4 100644 --- a/opensearchpy/_async/compat.py +++ b/opensearchpy/_async/compat.py @@ -24,6 +24,7 @@ # specific language governing permissions and limitations # under the License. + import asyncio from ..compat import * # noqa diff --git a/opensearchpy/_async/helpers.py b/opensearchpy/_async/helpers.py index b39b816f..3eecc65e 100644 --- a/opensearchpy/_async/helpers.py +++ b/opensearchpy/_async/helpers.py @@ -24,6 +24,7 @@ # specific language governing permissions and limitations # under the License. + # Licensed to Elasticsearch B.V.under one or more agreements. # Elasticsearch B.V.licenses this file to you under the Apache 2.0 License. # See the LICENSE file in the project root for more information @@ -203,7 +204,7 @@ async def async_streaming_bulk( raise_on_error, ignore_status, *args, - **kwargs, + **kwargs ), ): @@ -470,5 +471,5 @@ async def async_reindex( target_client, _change_doc_index(docs, target_index), chunk_size=chunk_size, - **kwargs, + **kwargs ) diff --git a/opensearchpy/_async/http_aiohttp.py b/opensearchpy/_async/http_aiohttp.py index db96d001..c5353067 100644 --- a/opensearchpy/_async/http_aiohttp.py +++ b/opensearchpy/_async/http_aiohttp.py @@ -24,6 +24,7 @@ # specific language governing permissions and limitations # under the License. + import asyncio import os import ssl @@ -97,7 +98,7 @@ class AIOHttpConnection(AsyncConnection): http_compress=None, opaque_id=None, loop=None, - **kwargs, + **kwargs ): """ Default connection class for ``AsyncOpenSearch`` using the `aiohttp` library and the http protocol. @@ -142,7 +143,7 @@ class AIOHttpConnection(AsyncConnection): headers=headers, http_compress=http_compress, opaque_id=opaque_id, - **kwargs, + **kwargs ) if http_auth is not None: diff --git a/opensearchpy/_async/http_aiohttp.pyi b/opensearchpy/_async/http_aiohttp.pyi index 23dde998..c82a7ee8 100644 --- a/opensearchpy/_async/http_aiohttp.pyi +++ b/opensearchpy/_async/http_aiohttp.pyi @@ -64,5 +64,5 @@ class AIOHttpConnection(AsyncConnection): http_compress: Optional[bool] = ..., opaque_id: Optional[str] = ..., loop: Any = ..., - **kwargs: Any, + **kwargs: Any ) -> None: ... diff --git a/opensearchpy/_async/plugins/__init__.py b/opensearchpy/_async/plugins/__init__.py new file mode 100644 index 00000000..6c0097cd --- /dev/null +++ b/opensearchpy/_async/plugins/__init__.py @@ -0,0 +1,8 @@ +# SPDX-License-Identifier: Apache-2.0 +# +# The OpenSearch Contributors require contributions made to +# this file be licensed under the Apache-2.0 license or a +# compatible open source license. +# +# Modifications Copyright OpenSearch Contributors. See +# GitHub history for details. diff --git a/opensearchpy/_async/plugins/__init__.pyi b/opensearchpy/_async/plugins/__init__.pyi new file mode 100644 index 00000000..6c0097cd --- /dev/null +++ b/opensearchpy/_async/plugins/__init__.pyi @@ -0,0 +1,8 @@ +# SPDX-License-Identifier: Apache-2.0 +# +# The OpenSearch Contributors require contributions made to +# this file be licensed under the Apache-2.0 license or a +# compatible open source license. +# +# Modifications Copyright OpenSearch Contributors. See +# GitHub history for details. diff --git a/opensearchpy/_async/plugins/alerting.py b/opensearchpy/_async/plugins/alerting.py new file mode 100644 index 00000000..d8b27937 --- /dev/null +++ b/opensearchpy/_async/plugins/alerting.py @@ -0,0 +1,200 @@ +# SPDX-License-Identifier: Apache-2.0 +# +# The OpenSearch Contributors require contributions made to +# this file be licensed under the Apache-2.0 license or a +# compatible open source license. +# +# Modifications Copyright OpenSearch Contributors. See +# GitHub history for details. + +from ..client.utils import NamespacedClient, _make_path, query_params + + +class AlertingClient(NamespacedClient): + @query_params() + async def search_monitor(self, body, params=None, headers=None): + """ + Returns the search result for a monitor. + + :arg monitor_id: The configuration for the monitor we are trying to search + """ + return await self.transport.perform_request( + "GET", + _make_path("_plugins", "_alerting", "monitors", "_search"), + params=params, + headers=headers, + body=body, + ) + + @query_params() + async def get_monitor(self, monitor_id, params=None, headers=None): + """ + Returns the details of a specific monitor. + + :arg monitor_id: The id of the monitor we are trying to fetch + """ + return await self.transport.perform_request( + "GET", + _make_path("_plugins", "_alerting", "monitors", monitor_id), + params=params, + headers=headers, + ) + + @query_params("dryrun") + async def run_monitor(self, monitor_id, params=None, headers=None): + """ + Runs/Executes a specific monitor. + + :arg monitor_id: The id of the monitor we are trying to execute + :arg dryrun: Shows the results of a run without actions sending any message + """ + return await self.transport.perform_request( + "POST", + _make_path("_plugins", "_alerting", "monitors", monitor_id, "_execute"), + params=params, + headers=headers, + ) + + @query_params() + async def create_monitor(self, body=None, params=None, headers=None): + """ + Creates a monitor with inputs, triggers, and actions. + + :arg body: The configuration for the monitor (`inputs`, `triggers`, and `actions`) + """ + return await self.transport.perform_request( + "POST", + _make_path("_plugins", "_alerting", "monitors"), + params=params, + headers=headers, + body=body, + ) + + @query_params() + async def update_monitor(self, monitor_id, body=None, params=None, headers=None): + """ + Updates a monitor's inputs, triggers, and actions. + + :arg monitor_id: The id of the monitor we are trying to update + :arg body: The configuration for the monitor (`inputs`, `triggers`, and `actions`) + """ + return await self.transport.perform_request( + "PUT", + _make_path("_plugins", "_alerting", "monitors", monitor_id), + params=params, + headers=headers, + body=body, + ) + + @query_params() + async def delete_monitor(self, monitor_id, params=None, headers=None): + """ + Deletes a specific monitor. + + :arg monitor_id: The id of the monitor we are trying to delete + """ + return await self.transport.perform_request( + "DELETE", + _make_path("_plugins", "_alerting", "monitors", monitor_id), + params=params, + headers=headers, + ) + + @query_params() + async def get_destination(self, destination_id=None, params=None, headers=None): + """ + Returns the details of a specific destination. + + :arg destination_id: The id of the destination we are trying to fetch. If None, returns all destinations + """ + return await self.transport.perform_request( + "GET", + _make_path("_plugins", "_alerting", "destinations", destination_id) + if destination_id + else _make_path("_plugins", "_alerting", "destinations"), + params=params, + headers=headers, + ) + + @query_params() + async def create_destination(self, body=None, params=None, headers=None): + """ + Creates a destination for slack, mail, or custom-webhook. + + :arg body: The configuration for the destination + """ + return await self.transport.perform_request( + "POST", + _make_path("_plugins", "_alerting", "destinations"), + params=params, + headers=headers, + body=body, + ) + + @query_params() + async def update_destination( + self, destination_id, body=None, params=None, headers=None + ): + """ + Updates a destination's inputs, triggers, and actions. + + :arg destination_id: The id of the destination we are trying to update + :arg body: The configuration for the destination + """ + return await self.transport.perform_request( + "PUT", + _make_path("_plugins", "_alerting", "destinations", destination_id), + params=params, + headers=headers, + body=body, + ) + + @query_params() + async def delete_destination(self, destination_id, params=None, headers=None): + """ + Deletes a specific destination. + + :arg destination_id: The id of the destination we are trying to delete + """ + return await self.transport.perform_request( + "DELETE", + _make_path("_plugins", "_alerting", "destinations", destination_id), + params=params, + headers=headers, + ) + + @query_params() + async def get_alerts(self, params=None, headers=None): + """ + Returns all alerts. + + """ + return await self.transport.perform_request( + "GET", + _make_path("_plugins", "_alerting", "monitors", "alerts"), + params=params, + headers=headers, + ) + + @query_params() + async def acknowledge_alert(self, monitor_id, body=None, params=None, headers=None): + """ + Acknowledges an alert. + + :arg monitor_id: The id of the monitor, the alert belongs to + :arg body: The alerts to be acknowledged + """ + return await self.transport.perform_request( + "POST", + _make_path( + "_plugins", + "_alerting", + "monitors", + monitor_id, + "_acknowledge", + "alerts", + ), + params=params, + headers=headers, + body=body, + ) diff --git a/opensearchpy/_async/plugins/alerting.pyi b/opensearchpy/_async/plugins/alerting.pyi new file mode 100644 index 00000000..50392224 --- /dev/null +++ b/opensearchpy/_async/plugins/alerting.pyi @@ -0,0 +1,82 @@ +# SPDX-License-Identifier: Apache-2.0 +# +# The OpenSearch Contributors require contributions made to +# this file be licensed under the Apache-2.0 license or a +# compatible open source license. +# +# Modifications Copyright OpenSearch Contributors. See +# GitHub history for details. +from typing import Any, Union + +from ..client.utils import NamespacedClient as NamespacedClient + +class AlertingClient(NamespacedClient): + def search_monitor( + self, body: Any, params: Union[Any, None] = ..., headers: Union[Any, None] = ... + ) -> Union[bool, Any]: ... + def get_monitor( + self, + monitor_id: Any, + params: Union[Any, None] = ..., + headers: Union[Any, None] = ..., + ) -> Union[bool, Any]: ... + def run_monitor( + self, + monitor_id: Any, + params: Union[Any, None] = ..., + headers: Union[Any, None] = ..., + ) -> Union[bool, Any]: ... + def create_monitor( + self, + body: Union[Any, None] = ..., + params: Union[Any, None] = ..., + headers: Union[Any, None] = ..., + ) -> Union[bool, Any]: ... + def update_monitor( + self, + monitor_id: Any, + body: Union[Any, None] = ..., + params: Union[Any, None] = ..., + headers: Union[Any, None] = ..., + ) -> Union[bool, Any]: ... + def delete_monitor( + self, + monitor_id: Any, + params: Union[Any, None] = ..., + headers: Union[Any, None] = ..., + ) -> Union[bool, Any]: ... + def get_destination( + self, + destination_id: Union[Any, None] = ..., + params: Union[Any, None] = ..., + headers: Union[Any, None] = ..., + ) -> Union[bool, Any]: ... + def create_destination( + self, + body: Union[Any, None] = ..., + params: Union[Any, None] = ..., + headers: Union[Any, None] = ..., + ) -> Union[bool, Any]: ... + def update_destination( + self, + destination_id: Any, + body: Union[Any, None] = ..., + params: Union[Any, None] = ..., + headers: Union[Any, None] = ..., + ) -> Union[bool, Any]: ... + def delete_destination( + self, + destination_id: Any, + params: Union[Any, None] = ..., + headers: Union[Any, None] = ..., + ) -> Union[bool, Any]: ... + def get_alerts( + self, params: Union[Any, None] = ..., headers: Union[Any, None] = ... + ) -> Union[bool, Any]: ... + def acknowledge_alert( + self, + monitor_id: Any, + body: Union[Any, None] = ..., + params: Union[Any, None] = ..., + headers: Union[Any, None] = ..., + ) -> Union[bool, Any]: ... diff --git a/opensearchpy/_async/transport.py b/opensearchpy/_async/transport.py index c71cd267..5c7b8d8b 100644 --- a/opensearchpy/_async/transport.py +++ b/opensearchpy/_async/transport.py @@ -24,6 +24,7 @@ # specific language governing permissions and limitations # under the License. + import asyncio import logging import sys diff --git a/opensearchpy/_version.py b/opensearchpy/_version.py index cf96b3f6..9573bb65 100644 --- a/opensearchpy/_version.py +++ b/opensearchpy/_version.py @@ -24,4 +24,5 @@ # specific language governing permissions and limitations # under the License. + __versionstr__ = "2.0.0" diff --git a/opensearchpy/client/__init__.py b/opensearchpy/client/__init__.py index 96f8d449..d517a505 100644 --- a/opensearchpy/client/__init__.py +++ b/opensearchpy/client/__init__.py @@ -25,6 +25,7 @@ # specific language governing permissions and limitations # under the License. + from __future__ import unicode_literals import logging @@ -37,6 +38,7 @@ from .features import FeaturesClient from .indices import IndicesClient from .ingest import IngestClient from .nodes import NodesClient +from .plugins import PluginsClient from .remote import RemoteClient from .snapshot import SnapshotClient from .tasks import TasksClient @@ -200,6 +202,8 @@ class OpenSearch(object): self.features = FeaturesClient(self) + self.plugins = PluginsClient(self) + def __repr__(self): try: # get a list of all connections diff --git a/opensearchpy/client/__init__.pyi b/opensearchpy/client/__init__.pyi index 7af71e06..893738a2 100644 --- a/opensearchpy/client/__init__.pyi +++ b/opensearchpy/client/__init__.pyi @@ -57,10 +57,7 @@ class OpenSearch(object): snapshot: SnapshotClient tasks: TasksClient def __init__( - self, - hosts: Any = ..., - transport_class: Type[Transport] = ..., - **kwargs: Any, + self, hosts: Any = ..., transport_class: Type[Transport] = ..., **kwargs: Any ) -> None: ... def __repr__(self) -> str: ... def __enter__(self) -> "OpenSearch": ... diff --git a/opensearchpy/client/cat.py b/opensearchpy/client/cat.py index f3cfbd98..b8c4ad5e 100644 --- a/opensearchpy/client/cat.py +++ b/opensearchpy/client/cat.py @@ -24,6 +24,7 @@ # specific language governing permissions and limitations # under the License. + from .utils import NamespacedClient, _make_path, query_params diff --git a/opensearchpy/client/cluster.py b/opensearchpy/client/cluster.py index 1d615148..7200608f 100644 --- a/opensearchpy/client/cluster.py +++ b/opensearchpy/client/cluster.py @@ -24,6 +24,7 @@ # specific language governing permissions and limitations # under the License. + from .utils import SKIP_IN_PATH, NamespacedClient, _make_path, query_params diff --git a/opensearchpy/client/dangling_indices.py b/opensearchpy/client/dangling_indices.py index edc7369b..cf779a28 100644 --- a/opensearchpy/client/dangling_indices.py +++ b/opensearchpy/client/dangling_indices.py @@ -24,6 +24,7 @@ # specific language governing permissions and limitations # under the License. + from .utils import SKIP_IN_PATH, NamespacedClient, _make_path, query_params diff --git a/opensearchpy/client/features.py b/opensearchpy/client/features.py index 37fe2f86..ef29113b 100644 --- a/opensearchpy/client/features.py +++ b/opensearchpy/client/features.py @@ -24,6 +24,7 @@ # specific language governing permissions and limitations # under the License. + from .utils import NamespacedClient, query_params diff --git a/opensearchpy/client/indices.py b/opensearchpy/client/indices.py index d34c089d..d78fc06b 100644 --- a/opensearchpy/client/indices.py +++ b/opensearchpy/client/indices.py @@ -24,6 +24,7 @@ # specific language governing permissions and limitations # under the License. + from .utils import SKIP_IN_PATH, NamespacedClient, _make_path, query_params diff --git a/opensearchpy/client/ingest.py b/opensearchpy/client/ingest.py index 54b2cada..46131a5e 100644 --- a/opensearchpy/client/ingest.py +++ b/opensearchpy/client/ingest.py @@ -24,6 +24,7 @@ # specific language governing permissions and limitations # under the License. + from .utils import SKIP_IN_PATH, NamespacedClient, _make_path, query_params diff --git a/opensearchpy/client/nodes.py b/opensearchpy/client/nodes.py index b3f57f2d..2773002b 100644 --- a/opensearchpy/client/nodes.py +++ b/opensearchpy/client/nodes.py @@ -24,6 +24,7 @@ # specific language governing permissions and limitations # under the License. + from .utils import NamespacedClient, _make_path, query_params diff --git a/opensearchpy/client/plugins.py b/opensearchpy/client/plugins.py new file mode 100644 index 00000000..eb55c8b1 --- /dev/null +++ b/opensearchpy/client/plugins.py @@ -0,0 +1,54 @@ +# SPDX-License-Identifier: Apache-2.0 +# +# The OpenSearch Contributors require contributions made to +# this file be licensed under the Apache-2.0 license or a +# compatible open source license. +# +# Modifications Copyright OpenSearch Contributors. See +# GitHub history for details. + + +import warnings + +from ..plugins.alerting import AlertingClient +from .utils import NamespacedClient + + +class PluginsClient(NamespacedClient): + def __init__(self, client): + super(PluginsClient, self).__init__(client) + # self.query_workbench = QueryWorkbenchClient(client) + # self.reporting = ReportingClient(client) + # self.notebooks = NotebooksClient(client) + self.alerting = AlertingClient(client) + # self.anomaly_detection = AnomalyDetectionClient(client) + # self.trace_analytics = TraceAnalyticsClient(client) + # self.index_management = IndexManagementClient(client) + # self.security = SecurityClient(client) + + self._dynamic_lookup(client) + + def _dynamic_lookup(self, client): + # Issue : https://github.com/opensearch-project/opensearch-py/issues/90#issuecomment-1003396742 + + plugins = [ + # "query_workbench", + # "reporting", + # "notebooks", + "alerting", + # "anomaly_detection", + # "trace_analytics", + # "index_management", + # "security" + ] + for plugin in plugins: + if not hasattr(client, plugin): + setattr(client, plugin, getattr(self, plugin)) + else: + warnings.warn( + "Cannot load `{plugin}` directly to OpenSearch. `{plugin}` already exists in OpenSearch. Please use `OpenSearch.plugin.{plugin}` instead.".format( + plugin=plugin + ), + category=RuntimeWarning, + stacklevel=2, + ) diff --git a/opensearchpy/client/plugins.pyi b/opensearchpy/client/plugins.pyi new file mode 100644 index 00000000..27d16b8f --- /dev/null +++ b/opensearchpy/client/plugins.pyi @@ -0,0 +1,17 @@ +# SPDX-License-Identifier: Apache-2.0 +# +# The OpenSearch Contributors require contributions made to +# this file be licensed under the Apache-2.0 license or a +# compatible open source license. +# +# Modifications Copyright OpenSearch Contributors. See +# GitHub history for details. +from typing import Any + +from ..client import OpenSearch +from ..plugins.alerting import AlertingClient as AlertingClient +from .utils import NamespacedClient as NamespacedClient + +class PluginsClient(NamespacedClient): + alerting: Any + def __init__(self, client: OpenSearch) -> None: ... diff --git a/opensearchpy/client/remote.py b/opensearchpy/client/remote.py index d6d0b79b..3f483697 100644 --- a/opensearchpy/client/remote.py +++ b/opensearchpy/client/remote.py @@ -24,6 +24,7 @@ # specific language governing permissions and limitations # under the License. + from .utils import NamespacedClient, query_params diff --git a/opensearchpy/client/snapshot.py b/opensearchpy/client/snapshot.py index 482c5cfe..96adb5eb 100644 --- a/opensearchpy/client/snapshot.py +++ b/opensearchpy/client/snapshot.py @@ -24,6 +24,7 @@ # specific language governing permissions and limitations # under the License. + from .utils import SKIP_IN_PATH, NamespacedClient, _make_path, query_params diff --git a/opensearchpy/client/tasks.py b/opensearchpy/client/tasks.py index 522dade3..fff32dd7 100644 --- a/opensearchpy/client/tasks.py +++ b/opensearchpy/client/tasks.py @@ -24,6 +24,7 @@ # specific language governing permissions and limitations # under the License. + import warnings from .utils import SKIP_IN_PATH, NamespacedClient, _make_path, query_params diff --git a/opensearchpy/client/utils.py b/opensearchpy/client/utils.py index cfbd9610..e79b6e9e 100644 --- a/opensearchpy/client/utils.py +++ b/opensearchpy/client/utils.py @@ -24,6 +24,7 @@ # specific language governing permissions and limitations # under the License. + from __future__ import unicode_literals import base64 diff --git a/opensearchpy/compat.py b/opensearchpy/compat.py index ca24da85..a5169050 100644 --- a/opensearchpy/compat.py +++ b/opensearchpy/compat.py @@ -24,6 +24,7 @@ # specific language governing permissions and limitations # under the License. + import sys PY2 = sys.version_info[0] == 2 diff --git a/opensearchpy/connection/__init__.py b/opensearchpy/connection/__init__.py index 03030ed0..61342241 100644 --- a/opensearchpy/connection/__init__.py +++ b/opensearchpy/connection/__init__.py @@ -24,6 +24,7 @@ # specific language governing permissions and limitations # under the License. + from .base import Connection from .http_requests import RequestsHttpConnection from .http_urllib3 import Urllib3HttpConnection, create_ssl_context diff --git a/opensearchpy/connection/base.py b/opensearchpy/connection/base.py index 5a6327f5..b2f2ef23 100644 --- a/opensearchpy/connection/base.py +++ b/opensearchpy/connection/base.py @@ -24,6 +24,7 @@ # specific language governing permissions and limitations # under the License. + import gzip import io import logging diff --git a/opensearchpy/connection/http_requests.py b/opensearchpy/connection/http_requests.py index 9462bfaf..e4e5cb38 100644 --- a/opensearchpy/connection/http_requests.py +++ b/opensearchpy/connection/http_requests.py @@ -24,6 +24,7 @@ # specific language governing permissions and limitations # under the License. + import time import warnings diff --git a/opensearchpy/connection/http_urllib3.py b/opensearchpy/connection/http_urllib3.py index 7ae756e2..c57a6190 100644 --- a/opensearchpy/connection/http_urllib3.py +++ b/opensearchpy/connection/http_urllib3.py @@ -24,6 +24,7 @@ # specific language governing permissions and limitations # under the License. + import ssl import time import warnings diff --git a/opensearchpy/connection/pooling.py b/opensearchpy/connection/pooling.py index 1fbdb39f..bd9fe5f9 100644 --- a/opensearchpy/connection/pooling.py +++ b/opensearchpy/connection/pooling.py @@ -24,6 +24,7 @@ # specific language governing permissions and limitations # under the License. + from .base import Connection try: diff --git a/opensearchpy/connection_pool.py b/opensearchpy/connection_pool.py index 7f4a4ade..0416fbec 100644 --- a/opensearchpy/connection_pool.py +++ b/opensearchpy/connection_pool.py @@ -24,6 +24,7 @@ # specific language governing permissions and limitations # under the License. + import logging import random import threading diff --git a/opensearchpy/exceptions.py b/opensearchpy/exceptions.py index 9490b519..d79caee2 100644 --- a/opensearchpy/exceptions.py +++ b/opensearchpy/exceptions.py @@ -24,6 +24,7 @@ # specific language governing permissions and limitations # under the License. + __all__ = [ "ImproperlyConfigured", "OpenSearchException", diff --git a/opensearchpy/helpers/__init__.py b/opensearchpy/helpers/__init__.py index afacc2f2..4b08807b 100644 --- a/opensearchpy/helpers/__init__.py +++ b/opensearchpy/helpers/__init__.py @@ -24,6 +24,7 @@ # specific language governing permissions and limitations # under the License. + import sys from .actions import ( diff --git a/opensearchpy/helpers/actions.py b/opensearchpy/helpers/actions.py index 92c53413..9f2ddfd2 100644 --- a/opensearchpy/helpers/actions.py +++ b/opensearchpy/helpers/actions.py @@ -24,6 +24,7 @@ # specific language governing permissions and limitations # under the License. + import logging import time from operator import methodcaller diff --git a/opensearchpy/helpers/errors.py b/opensearchpy/helpers/errors.py index 9c688d82..dc9e62da 100644 --- a/opensearchpy/helpers/errors.py +++ b/opensearchpy/helpers/errors.py @@ -24,6 +24,7 @@ # specific language governing permissions and limitations # under the License. + from ..exceptions import OpenSearchException diff --git a/opensearchpy/helpers/test.py b/opensearchpy/helpers/test.py index ae306b11..06be4e00 100644 --- a/opensearchpy/helpers/test.py +++ b/opensearchpy/helpers/test.py @@ -24,6 +24,7 @@ # specific language governing permissions and limitations # under the License. + # type: ignore import os @@ -100,3 +101,12 @@ def _get_version(version_string): def opensearch_version(client): return _get_version(client.info()["version"]["number"]) + + +if "OPENSEARCH_VERSION" in os.environ: + OPENSEARCH_VERSION = _get_version(os.environ["OPENSEARCH_VERSION"]) +else: + client = OpenSearch( + OPENSEARCH_URL, + ) + OPENSEARCH_VERSION = opensearch_version(client) diff --git a/opensearchpy/plugins/__init__.py b/opensearchpy/plugins/__init__.py new file mode 100644 index 00000000..2f42da79 --- /dev/null +++ b/opensearchpy/plugins/__init__.py @@ -0,0 +1,9 @@ +# SPDX-License-Identifier: Apache-2.0 +# +# The OpenSearch Contributors require contributions made to +# this file be licensed under the Apache-2.0 license or a +# compatible open source license. +# +# Modifications Copyright OpenSearch Contributors. See +# GitHub history for details. +# diff --git a/opensearchpy/plugins/__init__.pyi b/opensearchpy/plugins/__init__.pyi new file mode 100644 index 00000000..6c0097cd --- /dev/null +++ b/opensearchpy/plugins/__init__.pyi @@ -0,0 +1,8 @@ +# SPDX-License-Identifier: Apache-2.0 +# +# The OpenSearch Contributors require contributions made to +# this file be licensed under the Apache-2.0 license or a +# compatible open source license. +# +# Modifications Copyright OpenSearch Contributors. See +# GitHub history for details. diff --git a/opensearchpy/plugins/alerting.py b/opensearchpy/plugins/alerting.py new file mode 100644 index 00000000..defbf326 --- /dev/null +++ b/opensearchpy/plugins/alerting.py @@ -0,0 +1,199 @@ +# SPDX-License-Identifier: Apache-2.0 +# +# The OpenSearch Contributors require contributions made to +# this file be licensed under the Apache-2.0 license or a +# compatible open source license. +# +# Modifications Copyright OpenSearch Contributors. See +# GitHub history for details. + + +from ..client.utils import NamespacedClient, _make_path, query_params + + +class AlertingClient(NamespacedClient): + @query_params() + def search_monitor(self, body, params=None, headers=None): + """ + Returns the search result for a monitor. + + :arg monitor_id: The configuration for the monitor we are trying to search + """ + return self.transport.perform_request( + "GET", + _make_path("_plugins", "_alerting", "monitors", "_search"), + params=params, + headers=headers, + body=body, + ) + + @query_params() + def get_monitor(self, monitor_id, params=None, headers=None): + """ + Returns the details of a specific monitor. + + :arg monitor_id: The id of the monitor we are trying to fetch + """ + return self.transport.perform_request( + "GET", + _make_path("_plugins", "_alerting", "monitors", monitor_id), + params=params, + headers=headers, + ) + + @query_params("dryrun") + def run_monitor(self, monitor_id, params=None, headers=None): + """ + Runs/Executes a specific monitor. + + :arg monitor_id: The id of the monitor we are trying to execute + :arg dryrun: Shows the results of a run without actions sending any message + """ + return self.transport.perform_request( + "POST", + _make_path("_plugins", "_alerting", "monitors", monitor_id, "_execute"), + params=params, + headers=headers, + ) + + @query_params() + def create_monitor(self, body=None, params=None, headers=None): + """ + Creates a monitor with inputs, triggers, and actions. + + :arg body: The configuration for the monitor (`inputs`, `triggers`, and `actions`) + """ + return self.transport.perform_request( + "POST", + _make_path("_plugins", "_alerting", "monitors"), + params=params, + headers=headers, + body=body, + ) + + @query_params() + def update_monitor(self, monitor_id, body=None, params=None, headers=None): + """ + Updates a monitor's inputs, triggers, and actions. + + :arg monitor_id: The id of the monitor we are trying to update + :arg body: The configuration for the monitor (`inputs`, `triggers`, and `actions`) + """ + return self.transport.perform_request( + "PUT", + _make_path("_plugins", "_alerting", "monitors", monitor_id), + params=params, + headers=headers, + body=body, + ) + + @query_params() + def delete_monitor(self, monitor_id, params=None, headers=None): + """ + Deletes a specific monitor. + + :arg monitor_id: The id of the monitor we are trying to delete + """ + return self.transport.perform_request( + "DELETE", + _make_path("_plugins", "_alerting", "monitors", monitor_id), + params=params, + headers=headers, + ) + + @query_params() + def get_destination(self, destination_id=None, params=None, headers=None): + """ + Returns the details of a specific destination. + + :arg destination_id: The id of the destination we are trying to fetch. If None, returns all destinations + """ + return self.transport.perform_request( + "GET", + _make_path("_plugins", "_alerting", "destinations", destination_id) + if destination_id + else _make_path("_plugins", "_alerting", "destinations"), + params=params, + headers=headers, + ) + + @query_params() + def create_destination(self, body=None, params=None, headers=None): + """ + Creates a destination for slack, mail, or custom-webhook. + + :arg body: The configuration for the destination + """ + return self.transport.perform_request( + "POST", + _make_path("_plugins", "_alerting", "destinations"), + params=params, + headers=headers, + body=body, + ) + + @query_params() + def update_destination(self, destination_id, body=None, params=None, headers=None): + """ + Updates a destination's inputs, triggers, and actions. + + :arg destination_id: The id of the destination we are trying to update + :arg body: The configuration for the destination + """ + return self.transport.perform_request( + "PUT", + _make_path("_plugins", "_alerting", "destinations", destination_id), + params=params, + headers=headers, + body=body, + ) + + @query_params() + def delete_destination(self, destination_id, params=None, headers=None): + """ + Deletes a specific destination. + + :arg destination_id: The id of the destination we are trying to delete + """ + return self.transport.perform_request( + "DELETE", + _make_path("_plugins", "_alerting", "destinations", destination_id), + params=params, + headers=headers, + ) + + @query_params() + def get_alerts(self, params=None, headers=None): + """ + Returns all alerts. + + """ + return self.transport.perform_request( + "GET", + _make_path("_plugins", "_alerting", "monitors", "alerts"), + params=params, + headers=headers, + ) + + @query_params() + def acknowledge_alert(self, monitor_id, body=None, params=None, headers=None): + """ + Acknowledges an alert. + + :arg monitor_id: The id of the monitor, the alert belongs to + :arg body: The alerts to be acknowledged + """ + return self.transport.perform_request( + "POST", + _make_path( + "_plugins", + "_alerting", + "monitors", + monitor_id, + "_acknowledge", + "alerts", + ), + params=params, + headers=headers, + body=body, + ) diff --git a/opensearchpy/plugins/alerting.pyi b/opensearchpy/plugins/alerting.pyi new file mode 100644 index 00000000..7912ceef --- /dev/null +++ b/opensearchpy/plugins/alerting.pyi @@ -0,0 +1,73 @@ +# SPDX-License-Identifier: Apache-2.0 +# +# The OpenSearch Contributors require contributions made to +# this file be licensed under the Apache-2.0 license or a +# compatible open source license. +# +# Modifications Copyright OpenSearch Contributors. See +# GitHub history for details. +# + +from typing import Any, Union + +from ..client.utils import NamespacedClient as NamespacedClient +from ..client.utils import query_params as query_params + +class AlertingClient(NamespacedClient): + def search_monitor( + self, body: Any, params: Any | None = ..., headers: Any | None = ... + ) -> Union[bool, Any]: ... + def get_monitor( + self, monitor_id: Any, params: Any | None = ..., headers: Any | None = ... + ) -> Union[bool, Any]: ... + def run_monitor( + self, monitor_id: Any, params: Any | None = ..., headers: Any | None = ... + ) -> Union[bool, Any]: ... + def create_monitor( + self, + body: Any | None = ..., + params: Any | None = ..., + headers: Any | None = ..., + ) -> Union[bool, Any]: ... + def update_monitor( + self, + monitor_id: Any, + body: Any | None = ..., + params: Any | None = ..., + headers: Any | None = ..., + ) -> Union[bool, Any]: ... + def delete_monitor( + self, monitor_id: Any, params: Any | None = ..., headers: Any | None = ... + ) -> Union[bool, Any]: ... + def get_destination( + self, + destination_id: Any | None = ..., + params: Any | None = ..., + headers: Any | None = ..., + ) -> Union[bool, Any]: ... + def create_destination( + self, + body: Any | None = ..., + params: Any | None = ..., + headers: Any | None = ..., + ) -> Union[bool, Any]: ... + def update_destination( + self, + destination_id: Any, + body: Any | None = ..., + params: Any | None = ..., + headers: Any | None = ..., + ) -> Union[bool, Any]: ... + def delete_destination( + self, destination_id: Any, params: Any | None = ..., headers: Any | None = ... + ) -> Union[bool, Any]: ... + def get_alerts( + self, params: Any | None = ..., headers: Any | None = ... + ) -> Union[bool, Any]: ... + def acknowledge_alert( + self, + monitor_id: Any, + body: Any | None = ..., + params: Any | None = ..., + headers: Any | None = ..., + ) -> Union[bool, Any]: ... diff --git a/opensearchpy/serializer.py b/opensearchpy/serializer.py index 391cf92d..c6198e31 100644 --- a/opensearchpy/serializer.py +++ b/opensearchpy/serializer.py @@ -24,6 +24,7 @@ # specific language governing permissions and limitations # under the License. + try: import simplejson as json except ImportError: diff --git a/opensearchpy/transport.py b/opensearchpy/transport.py index 9af74a89..3ea0301c 100644 --- a/opensearchpy/transport.py +++ b/opensearchpy/transport.py @@ -24,6 +24,7 @@ # specific language governing permissions and limitations # under the License. + import time from itertools import chain diff --git a/out/opensearchpy/client/plugins.pyi b/out/opensearchpy/client/plugins.pyi new file mode 100644 index 00000000..255e1efd --- /dev/null +++ b/out/opensearchpy/client/plugins.pyi @@ -0,0 +1,16 @@ +# SPDX-License-Identifier: Apache-2.0 +# +# The OpenSearch Contributors require contributions made to +# this file be licensed under the Apache-2.0 license or a +# compatible open source license. +# +# Modifications Copyright OpenSearch Contributors. See +# GitHub history for details. + +from ..plugins.alerting import AlertingClient as AlertingClient +from .utils import NamespacedClient as NamespacedClient +from typing import Any + +class PluginsClient(NamespacedClient): + alerting: Any + def __init__(self, client) -> None: ... diff --git a/out/opensearchpy/plugins/__init__.pyi b/out/opensearchpy/plugins/__init__.pyi new file mode 100644 index 00000000..33728435 --- /dev/null +++ b/out/opensearchpy/plugins/__init__.pyi @@ -0,0 +1,8 @@ +# SPDX-License-Identifier: Apache-2.0 +# +# The OpenSearch Contributors require contributions made to +# this file be licensed under the Apache-2.0 license or a +# compatible open source license. +# +# Modifications Copyright OpenSearch Contributors. See +# GitHub history for details. \ No newline at end of file diff --git a/out/opensearchpy/plugins/alerting.pyi b/out/opensearchpy/plugins/alerting.pyi new file mode 100644 index 00000000..2fc203a5 --- /dev/null +++ b/out/opensearchpy/plugins/alerting.pyi @@ -0,0 +1,25 @@ +# SPDX-License-Identifier: Apache-2.0 +# +# The OpenSearch Contributors require contributions made to +# this file be licensed under the Apache-2.0 license or a +# compatible open source license. +# +# Modifications Copyright OpenSearch Contributors. See +# GitHub history for details. + +from ..client.utils import NamespacedClient as NamespacedClient, query_params as query_params +from typing import Any, Union + +class AlertingClient(NamespacedClient): + def search_monitor(self, body, params: Any | None = ..., headers: Any | None = ...) -> Union[bool, Any]: ... + def get_monitor(self, monitor_id, params: Any | None = ..., headers: Any | None = ...) -> Union[bool, Any]: ... + def run_monitor(self, monitor_id, params: Any | None = ..., headers: Any | None = ...) -> Union[bool, Any]: ... + def create_monitor(self, body: Any | None = ..., params: Any | None = ..., headers: Any | None = ...) -> Union[bool, Any]: ... + def update_monitor(self, monitor_id, body: Any | None = ..., params: Any | None = ..., headers: Any | None = ...) -> Union[bool, Any]: ... + def delete_monitor(self, monitor_id, params: Any | None = ..., headers: Any | None = ...) -> Union[bool, Any]: ... + def get_destination(self, destination_id: Any | None = ..., params: Any | None = ..., headers: Any | None = ...) -> Union[bool, Any]: ... + def create_destination(self, body: Any | None = ..., params: Any | None = ..., headers: Any | None = ...) -> Union[bool, Any]: ... + def update_destination(self, destination_id, body: Any | None = ..., params: Any | None = ..., headers: Any | None = ...) -> Union[bool, Any]: ... + def delete_destination(self, destination_id, params: Any | None = ..., headers: Any | None = ...) -> Union[bool, Any]: ... + def get_alerts(self, params: Any | None = ..., headers: Any | None = ...) -> Union[bool, Any]: ... + def acknowledge_alert(self, monitor_id, body: Any | None = ..., params: Any | None = ..., headers: Any | None = ...) -> Union[bool, Any]: ... diff --git a/setup.py b/setup.py index 71588baf..50a01f36 100644 --- a/setup.py +++ b/setup.py @@ -25,6 +25,7 @@ # specific language governing permissions and limitations # under the License. + import re from os.path import abspath, dirname, join diff --git a/test_opensearchpy/run_tests.py b/test_opensearchpy/run_tests.py index 5f9c17fe..e978eea3 100755 --- a/test_opensearchpy/run_tests.py +++ b/test_opensearchpy/run_tests.py @@ -25,6 +25,7 @@ # specific language governing permissions and limitations # under the License. + from __future__ import print_function import subprocess diff --git a/test_opensearchpy/test_async/test_connection.py b/test_opensearchpy/test_async/test_connection.py index 7b719827..fb8ca660 100644 --- a/test_opensearchpy/test_async/test_connection.py +++ b/test_opensearchpy/test_async/test_connection.py @@ -25,6 +25,7 @@ # specific language governing permissions and limitations # under the License. + import gzip import io import json diff --git a/test_opensearchpy/test_async/test_server/conftest.py b/test_opensearchpy/test_async/test_server/conftest.py index 2b8cb1a3..42c37edb 100644 --- a/test_opensearchpy/test_async/test_server/conftest.py +++ b/test_opensearchpy/test_async/test_server/conftest.py @@ -24,6 +24,7 @@ # specific language governing permissions and limitations # under the License. + import asyncio import pytest diff --git a/test_opensearchpy/test_async/test_server/test_clients.py b/test_opensearchpy/test_async/test_server/test_clients.py index 40c550cb..17104312 100644 --- a/test_opensearchpy/test_async/test_server/test_clients.py +++ b/test_opensearchpy/test_async/test_server/test_clients.py @@ -25,6 +25,7 @@ # specific language governing permissions and limitations # under the License. + from __future__ import unicode_literals import pytest diff --git a/test_opensearchpy/test_async/test_server/test_helpers.py b/test_opensearchpy/test_async/test_server/test_helpers.py index 9e83aba8..387d0a96 100644 --- a/test_opensearchpy/test_async/test_server/test_helpers.py +++ b/test_opensearchpy/test_async/test_server/test_helpers.py @@ -24,6 +24,7 @@ # specific language governing permissions and limitations # under the License. + # Licensed to Elasticsearch B.V.under one or more agreements. # Elasticsearch B.V.licenses this file to you under the Apache 2.0 License. # See the LICENSE file in the project root for more information diff --git a/test_opensearchpy/test_async/test_server/test_rest_api_spec.py b/test_opensearchpy/test_async/test_server/test_rest_api_spec.py index 8740fd95..27b20113 100644 --- a/test_opensearchpy/test_async/test_server/test_rest_api_spec.py +++ b/test_opensearchpy/test_async/test_server/test_rest_api_spec.py @@ -24,6 +24,7 @@ # specific language governing permissions and limitations # under the License. + """ Dynamically generated set of TestCases based on set of yaml files decribing some integration tests. These files are shared among all official OpenSearch diff --git a/test_opensearchpy/test_async/test_transport.py b/test_opensearchpy/test_async/test_transport.py index 44599cd5..1d463dc3 100644 --- a/test_opensearchpy/test_async/test_transport.py +++ b/test_opensearchpy/test_async/test_transport.py @@ -25,6 +25,7 @@ # specific language governing permissions and limitations # under the License. + from __future__ import unicode_literals import asyncio diff --git a/test_opensearchpy/test_cases.py b/test_opensearchpy/test_cases.py index 61b402b9..c41b86a8 100644 --- a/test_opensearchpy/test_cases.py +++ b/test_opensearchpy/test_cases.py @@ -24,6 +24,7 @@ # specific language governing permissions and limitations # under the License. + from collections import defaultdict from unittest import SkipTest # noqa: F401 from unittest import TestCase diff --git a/test_opensearchpy/test_client/__init__.py b/test_opensearchpy/test_client/__init__.py index fb334def..0a5747ca 100644 --- a/test_opensearchpy/test_client/__init__.py +++ b/test_opensearchpy/test_client/__init__.py @@ -24,6 +24,7 @@ # specific language governing permissions and limitations # under the License. + from __future__ import unicode_literals import warnings diff --git a/test_opensearchpy/test_client/test_cluster.py b/test_opensearchpy/test_client/test_cluster.py index 359a527c..15c43d5f 100644 --- a/test_opensearchpy/test_client/test_cluster.py +++ b/test_opensearchpy/test_client/test_cluster.py @@ -24,6 +24,7 @@ # specific language governing permissions and limitations # under the License. + from test_opensearchpy.test_cases import OpenSearchTestCase diff --git a/test_opensearchpy/test_client/test_indices.py b/test_opensearchpy/test_client/test_indices.py index 44bd524b..d6737378 100644 --- a/test_opensearchpy/test_client/test_indices.py +++ b/test_opensearchpy/test_client/test_indices.py @@ -24,6 +24,7 @@ # specific language governing permissions and limitations # under the License. + from test_opensearchpy.test_cases import OpenSearchTestCase diff --git a/test_opensearchpy/test_client/test_overrides.py b/test_opensearchpy/test_client/test_overrides.py index 182c7c88..4ce0931e 100644 --- a/test_opensearchpy/test_client/test_overrides.py +++ b/test_opensearchpy/test_client/test_overrides.py @@ -25,6 +25,7 @@ # specific language governing permissions and limitations # under the License. + import pytest from test_opensearchpy.test_cases import OpenSearchTestCase diff --git a/test_opensearchpy/test_client/test_plugins.py b/test_opensearchpy/test_client/test_plugins.py new file mode 100644 index 00000000..62827655 --- /dev/null +++ b/test_opensearchpy/test_client/test_plugins.py @@ -0,0 +1,77 @@ +# SPDX-License-Identifier: Apache-2.0 +# +# The OpenSearch Contributors require contributions made to +# this file be licensed under the Apache-2.0 license or a +# compatible open source license. +# +# Modifications Copyright OpenSearch Contributors. See +# GitHub history for details. + +from test_opensearchpy.test_cases import OpenSearchTestCase + + +class TestAlerting(OpenSearchTestCase): + def test_create_monitor(self): + # Test Post Method + self.client.alerting.create_monitor({}) + self.assert_url_called("POST", "/_plugins/_alerting/monitors") + + def test_run_monitor(self): + self.client.alerting.run_monitor("...") + self.assert_url_called("POST", "/_plugins/_alerting/monitors/.../_execute") + + def test_get_monitor(self): + # Test Get Method + self.client.alerting.get_monitor("...") + self.assert_url_called("GET", "/_plugins/_alerting/monitors/...") + + def test_search_monitor(self): + # Test Search Method + self.client.alerting.search_monitor({}) + self.assert_url_called("GET", "/_plugins/_alerting/monitors/_search") + + def test_update_monitor(self): + # Test Update Method + self.client.alerting.update_monitor("...") + self.assert_url_called("PUT", "/_plugins/_alerting/monitors/...") + + def test_delete_monitor(self): + # Test Delete Method + self.client.alerting.delete_monitor("...") + self.assert_url_called("DELETE", "/_plugins/_alerting/monitors/...") + + def test_create_destination(self): + # Test Post Method + self.client.alerting.create_destination({}) + self.assert_url_called("POST", "/_plugins/_alerting/destinations") + + def test_get_destination(self): + # Test Get Method + + # Get a specific destination + self.client.alerting.get_destination("...") + self.assert_url_called("GET", "/_plugins/_alerting/destinations/...") + + # Get all destinations + self.client.alerting.get_destination() + self.assert_url_called("GET", "/_plugins/_alerting/destinations") + + def test_update_destination(self): + # Test Update Method + self.client.alerting.update_destination("...") + self.assert_url_called("PUT", "/_plugins/_alerting/destinations/...") + + def test_delete_destination(self): + # Test Delete Method + self.client.alerting.delete_destination("...") + self.assert_url_called("DELETE", "/_plugins/_alerting/destinations/...") + + def test_get_alerts(self): + self.client.alerting.get_alerts() + self.assert_url_called("GET", "/_plugins/_alerting/monitors/alerts") + + def test_acknowledge_alerts(self): + self.client.alerting.acknowledge_alert("...") + self.assert_url_called( + "POST", "/_plugins/_alerting/monitors/.../_acknowledge/alerts" + ) diff --git a/test_opensearchpy/test_client/test_utils.py b/test_opensearchpy/test_client/test_utils.py index 43d48d18..2b5e5a39 100644 --- a/test_opensearchpy/test_client/test_utils.py +++ b/test_opensearchpy/test_client/test_utils.py @@ -25,6 +25,7 @@ # specific language governing permissions and limitations # under the License. + from __future__ import unicode_literals from opensearchpy.client.utils import _bulk_body, _escape, _make_path, query_params diff --git a/test_opensearchpy/test_connection.py b/test_opensearchpy/test_connection.py index 1f9181a3..31b8f756 100644 --- a/test_opensearchpy/test_connection.py +++ b/test_opensearchpy/test_connection.py @@ -25,6 +25,7 @@ # specific language governing permissions and limitations # under the License. + import gzip import io import json @@ -784,7 +785,8 @@ class TestConnectionHttpbin: def test_urllib3_connection(self): # Defaults - conn = Urllib3HttpConnection("httpbin.org", port=443, use_ssl=True) + # httpbin.org can be slow sometimes. Hence the timeout + conn = Urllib3HttpConnection("httpbin.org", port=443, use_ssl=True, timeout=60) user_agent = conn._get_default_user_agent() status, data = self.httpbin_anything(conn) assert status == 200 @@ -798,7 +800,7 @@ class TestConnectionHttpbin: # http_compress=False conn = Urllib3HttpConnection( - "httpbin.org", port=443, use_ssl=True, http_compress=False + "httpbin.org", port=443, use_ssl=True, http_compress=False, timeout=60 ) status, data = self.httpbin_anything(conn) assert status == 200 @@ -812,7 +814,7 @@ class TestConnectionHttpbin: # http_compress=True conn = Urllib3HttpConnection( - "httpbin.org", port=443, use_ssl=True, http_compress=True + "httpbin.org", port=443, use_ssl=True, http_compress=True, timeout=60 ) status, data = self.httpbin_anything(conn) assert status == 200 @@ -830,6 +832,7 @@ class TestConnectionHttpbin: use_ssl=True, http_compress=True, headers={"header1": "value1"}, + timeout=60, ) status, data = self.httpbin_anything( conn, headers={"header2": "value2", "header1": "override!"} @@ -851,7 +854,7 @@ class TestConnectionHttpbin: def test_requests_connection(self): # Defaults - conn = RequestsHttpConnection("httpbin.org", port=443, use_ssl=True) + conn = RequestsHttpConnection("httpbin.org", port=443, use_ssl=True, timeout=60) user_agent = conn._get_default_user_agent() status, data = self.httpbin_anything(conn) assert status == 200 @@ -865,7 +868,7 @@ class TestConnectionHttpbin: # http_compress=False conn = RequestsHttpConnection( - "httpbin.org", port=443, use_ssl=True, http_compress=False + "httpbin.org", port=443, use_ssl=True, http_compress=False, timeout=60 ) status, data = self.httpbin_anything(conn) assert status == 200 @@ -879,7 +882,7 @@ class TestConnectionHttpbin: # http_compress=True conn = RequestsHttpConnection( - "httpbin.org", port=443, use_ssl=True, http_compress=True + "httpbin.org", port=443, use_ssl=True, http_compress=True, timeout=60 ) status, data = self.httpbin_anything(conn) assert status == 200 @@ -897,6 +900,7 @@ class TestConnectionHttpbin: use_ssl=True, http_compress=True, headers={"header1": "value1"}, + timeout=60, ) status, data = self.httpbin_anything( conn, headers={"header2": "value2", "header1": "override!"} diff --git a/test_opensearchpy/test_connection_pool.py b/test_opensearchpy/test_connection_pool.py index b70703be..02686e44 100644 --- a/test_opensearchpy/test_connection_pool.py +++ b/test_opensearchpy/test_connection_pool.py @@ -24,6 +24,7 @@ # specific language governing permissions and limitations # under the License. + import time from opensearchpy.connection import Connection diff --git a/test_opensearchpy/test_exceptions.py b/test_opensearchpy/test_exceptions.py index 2171b1c6..77a97a91 100644 --- a/test_opensearchpy/test_exceptions.py +++ b/test_opensearchpy/test_exceptions.py @@ -24,6 +24,7 @@ # specific language governing permissions and limitations # under the License. + from opensearchpy.exceptions import TransportError from .test_cases import TestCase diff --git a/test_opensearchpy/test_helpers.py b/test_opensearchpy/test_helpers.py index c4183c65..fcf57e6e 100644 --- a/test_opensearchpy/test_helpers.py +++ b/test_opensearchpy/test_helpers.py @@ -25,6 +25,7 @@ # specific language governing permissions and limitations # under the License. + import threading import time diff --git a/test_opensearchpy/test_serializer.py b/test_opensearchpy/test_serializer.py index 20c5f6f1..b324b53c 100644 --- a/test_opensearchpy/test_serializer.py +++ b/test_opensearchpy/test_serializer.py @@ -25,6 +25,7 @@ # specific language governing permissions and limitations # under the License. + import sys import uuid from datetime import datetime diff --git a/test_opensearchpy/test_server/__init__.py b/test_opensearchpy/test_server/__init__.py index 70e93499..78d29958 100644 --- a/test_opensearchpy/test_server/__init__.py +++ b/test_opensearchpy/test_server/__init__.py @@ -24,6 +24,7 @@ # specific language governing permissions and limitations # under the License. + from unittest import SkipTest from opensearchpy.helpers import test diff --git a/test_opensearchpy/test_server/conftest.py b/test_opensearchpy/test_server/conftest.py index 1baa77e8..03306fcf 100644 --- a/test_opensearchpy/test_server/conftest.py +++ b/test_opensearchpy/test_server/conftest.py @@ -24,6 +24,7 @@ # specific language governing permissions and limitations # under the License. + import os import time diff --git a/test_opensearchpy/test_server/test_clients.py b/test_opensearchpy/test_server/test_clients.py index 243c0b8a..2d5c4155 100644 --- a/test_opensearchpy/test_server/test_clients.py +++ b/test_opensearchpy/test_server/test_clients.py @@ -25,6 +25,7 @@ # specific language governing permissions and limitations # under the License. + from __future__ import unicode_literals from . import OpenSearchTestCase diff --git a/test_opensearchpy/test_server/test_helpers.py b/test_opensearchpy/test_server/test_helpers.py index 1ffcc668..11c8faaa 100644 --- a/test_opensearchpy/test_server/test_helpers.py +++ b/test_opensearchpy/test_server/test_helpers.py @@ -24,6 +24,7 @@ # specific language governing permissions and limitations # under the License. + from mock import patch from opensearchpy import TransportError, helpers diff --git a/test_opensearchpy/test_server/test_plugins.py b/test_opensearchpy/test_server/test_plugins.py new file mode 100644 index 00000000..4ece75e9 --- /dev/null +++ b/test_opensearchpy/test_server/test_plugins.py @@ -0,0 +1,183 @@ +# -*- coding: utf-8 -*- +# SPDX-License-Identifier: Apache-2.0 +# +# The OpenSearch Contributors require contributions made to +# this file be licensed under the Apache-2.0 license or a +# compatible open source license. +# +# Modifications Copyright OpenSearch Contributors. See +# GitHub history for details. + + +from __future__ import unicode_literals + +import unittest + +from opensearchpy.helpers.test import OPENSEARCH_VERSION + +from . import OpenSearchTestCase + + +class TestAlertingPlugin(OpenSearchTestCase): + @unittest.skipUnless( + (OPENSEARCH_VERSION) and (OPENSEARCH_VERSION < (2, 0, 0)), + "Plugin not supported for opensearch version", + ) + def test_create_destination(self): + # Test to create alert destination + dummy_destination = { + "name": "my-destination", + "type": "slack", + "slack": {"url": "http://www.example.com"}, + } + response = self.client.alerting.create_destination(dummy_destination) + + self.assertNotIn("errors", response) + self.assertIn("_id", response) + + @unittest.skipUnless( + (OPENSEARCH_VERSION) and (OPENSEARCH_VERSION < (2, 0, 0)), + "Plugin not supported for opensearch version", + ) + def test_get_destination(self): + # Create a dummy destination + self.test_create_destination() + + # Try fetching the destination + response = self.client.alerting.get_destination() + + self.assertNotIn("errors", response) + self.assertGreaterEqual(response["totalDestinations"], 1) + self.assertEqual(response["totalDestinations"], len(response["destinations"])) + + @unittest.skipUnless( + (OPENSEARCH_VERSION) and (OPENSEARCH_VERSION < (2, 0, 0)), + "Plugin not supported for opensearch version", + ) + def test_create_monitor(self): + # Create a dummy destination + self.test_create_destination() + + # Try fetching the destination + destination = self.client.alerting.get_destination() + self.assertGreaterEqual( + destination["totalDestinations"], + 1, + "No destination entries found in the database.", + ) + + # Select the first destination available + destination = destination["destinations"][0] + + # A dummy schedule for 1 minute interval + schedule = {"period": {"interval": 1, "unit": "MINUTES"}} + + # A dummy query fetching everything + query = {"query": {"query_string": {"query": "*"}}} + + # A dummy action with the dummy destination + action = { + "name": "test-action", + "destination_id": destination["id"], + "message_template": {"source": "This is my message body."}, + "throttle_enabled": True, + "throttle": {"value": 27, "unit": "MINUTES"}, + "subject_template": {"source": "TheSubject"}, + } + + # A dummy trigger with the dummy action + triggers = { + "name": "test-trigger", + "severity": "1", + "condition": { + "script": { + "source": "ctx.results[0].hits.total.value > 0", + "lang": "painless", + } + }, + "actions": [action], + } + + # A dummy monitor with the dummy schedule, dummy query, dummy trigger + monitor = { + "type": "monitor", + "name": "test-monitor", + "monitor_type": "query_level_monitor", + "enabled": True, + "schedule": schedule, + "inputs": [{"search": {"indices": ["*"], "query": query}}], + "triggers": [triggers], + } + + response = self.client.alerting.create_monitor(monitor) + + self.assertNotIn("errors", response) + self.assertIn("_id", response) + self.assertIn("monitor", response) + + @unittest.skipUnless( + (OPENSEARCH_VERSION) and (OPENSEARCH_VERSION < (2, 0, 0)), + "Plugin not supported for opensearch version", + ) + def test_search_monitor(self): + # Create a dummy monitor + self.test_create_monitor() + + # Create a monitor search query by it's name + query = {"query": {"match": {"monitor.name": "test-monitor"}}} + + # Perform the search with the above query + response = self.client.alerting.search_monitor(query) + + self.assertNotIn("errors", response) + self.assertIn("hits", response) + self.assertEqual(response["hits"]["total"]["value"], 1, "No monitor found.") + + @unittest.skipUnless( + (OPENSEARCH_VERSION) and (OPENSEARCH_VERSION < (2, 0, 0)), + "Plugin not supported for opensearch version", + ) + def test_get_monitor(self): + # Create a dummy monitor + self.test_create_monitor() + + # Create a monitor search query by it's name + query = {"query": {"match": {"monitor.name": "test-monitor"}}} + + # Perform the search with the above query + response = self.client.alerting.search_monitor(query) + + # Select the first monitor + monitor = response["hits"]["hits"][0] + + # Fetch the monitor by id + response = self.client.alerting.get_monitor(monitor["_id"]) + + self.assertNotIn("errors", response) + self.assertIn("_id", response) + self.assertIn("monitor", response) + + @unittest.skipUnless( + (OPENSEARCH_VERSION) and (OPENSEARCH_VERSION < (2, 0, 0)), + "Plugin not supported for opensearch version", + ) + def test_run_monitor(self): + # Create a dummy monitor + self.test_create_monitor() + + # Create a monitor search query by it's name + query = {"query": {"match": {"monitor.name": "test-monitor"}}} + + # Perform the search with the above query + response = self.client.alerting.search_monitor(query) + + # Select the first monitor + monitor = response["hits"]["hits"][0] + + # Run the monitor by id + response = self.client.alerting.run_monitor(monitor["_id"]) + + self.assertEqual(response["error"], None) + self.assertIn("monitor_name", response) + self.assertIn("period_start", response) + self.assertIn("period_end", response) diff --git a/test_opensearchpy/test_server/test_rest_api_spec.py b/test_opensearchpy/test_server/test_rest_api_spec.py index ef58b79e..ca358dd9 100644 --- a/test_opensearchpy/test_server/test_rest_api_spec.py +++ b/test_opensearchpy/test_server/test_rest_api_spec.py @@ -24,6 +24,7 @@ # specific language governing permissions and limitations # under the License. + """ Dynamically generated set of TestCases based on set of yaml files describing some integration tests. These files are shared among all official OpenSearch diff --git a/test_opensearchpy/test_transport.py b/test_opensearchpy/test_transport.py index 29192366..4effb611 100644 --- a/test_opensearchpy/test_transport.py +++ b/test_opensearchpy/test_transport.py @@ -25,6 +25,7 @@ # specific language governing permissions and limitations # under the License. + from __future__ import unicode_literals import json diff --git a/test_opensearchpy/test_types/aliased_types.py b/test_opensearchpy/test_types/aliased_types.py index 94fb7a15..f7a93e09 100644 --- a/test_opensearchpy/test_types/aliased_types.py +++ b/test_opensearchpy/test_types/aliased_types.py @@ -24,6 +24,7 @@ # specific language governing permissions and limitations # under the License. + from typing import Any, AsyncGenerator, Dict, Generator from opensearchpy1 import ( diff --git a/test_opensearchpy/test_types/async_types.py b/test_opensearchpy/test_types/async_types.py index ae4cef5d..b26b5d67 100644 --- a/test_opensearchpy/test_types/async_types.py +++ b/test_opensearchpy/test_types/async_types.py @@ -24,6 +24,7 @@ # specific language governing permissions and limitations # under the License. + from typing import Any, AsyncGenerator, Dict from opensearchpy import ( diff --git a/test_opensearchpy/test_types/sync_types.py b/test_opensearchpy/test_types/sync_types.py index 82dce82d..d772342b 100644 --- a/test_opensearchpy/test_types/sync_types.py +++ b/test_opensearchpy/test_types/sync_types.py @@ -24,6 +24,7 @@ # specific language governing permissions and limitations # under the License. + from typing import Any, Dict, Generator from opensearchpy import ConnectionPool, OpenSearch, RequestsHttpConnection, Transport diff --git a/test_opensearchpy/utils.py b/test_opensearchpy/utils.py index 17a1c379..0c07a012 100644 --- a/test_opensearchpy/utils.py +++ b/test_opensearchpy/utils.py @@ -24,6 +24,7 @@ # specific language governing permissions and limitations # under the License. + import time from opensearchpy import OpenSearch diff --git a/utils/build-dists.py b/utils/build-dists.py index 11ede687..276b4385 100644 --- a/utils/build-dists.py +++ b/utils/build-dists.py @@ -24,6 +24,7 @@ # specific language governing permissions and limitations # under the License. + """A command line tool for building and verifying releases Can be used for building both 'opensearchpy' and 'opensearchpyX' dists. Only requires 'name' in 'setup.py' and the directory to be changed. diff --git a/utils/generate-api.py b/utils/generate-api.py index 7ba7299b..07a620ee 100644 --- a/utils/generate-api.py +++ b/utils/generate-api.py @@ -25,6 +25,7 @@ # specific language governing permissions and limitations # under the License. + import contextlib import io import json diff --git a/utils/license-headers.py b/utils/license-headers.py index 66cb5ab9..255097d8 100644 --- a/utils/license-headers.py +++ b/utils/license-headers.py @@ -24,6 +24,7 @@ # specific language governing permissions and limitations # under the License. + """Script which verifies that all source files have a license header. Has two modes: 'fix' and 'check'. 'fix' fixes problems, 'check' will error out if 'fix' would have changed the file.