Skip to content

Commit

Permalink
Register opensearch-knn as a plugin
Browse files Browse the repository at this point in the history
  • Loading branch information
phvalguima committed Sep 11, 2023
1 parent c650e52 commit a022fb8
Show file tree
Hide file tree
Showing 4 changed files with 170 additions and 1 deletion.
8 changes: 8 additions & 0 deletions config.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# Copyright 2023 Canonical Ltd.
# See LICENSE file for licensing details.

options:
plugin_opensearch_knn:
default: false
type: boolean
description: Enable opensearch-knn
65 changes: 65 additions & 0 deletions lib/charms/opensearch/v0/opensearch_ml_plugins.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
# Copyright 2023 Canonical Ltd.
# See LICENSE file for licensing details.

"""Implements the KNN and ML-Commons plugins for OpenSearch."""

import logging
from typing import Any, Dict

from charms.opensearch.v0.opensearch_plugins import OpenSearchPlugin

logger = logging.getLogger(__name__)


# The unique Charmhub library identifier, never change it
LIBID = "71166db20ab244099ae966c8055db2df"

# Increment this major API version when introducing breaking changes
LIBAPI = 0

# Increment this PATCH version before using `charmcraft publish-lib` or reset
# to 0 if you are raising the major API version
LIBPATCH = 1


class OpenSearchKnn(OpenSearchPlugin):
"""Implements the opensearch-knn plugin."""

def __init__(
self,
plugins_path: str,
):
super().__init__(plugins_path)

def config(self) -> Dict[str, Dict[str, str]]:
"""Returns a dict containing all the configuration needed to be applied in the form.
Format:
{
"opensearch.yml": {...},
"keystore": {...},
}
"""
return {self.CONFIG_YML: {"knn.plugin.enabled": "true"}, "keystore": {}}

def _is_enabled(self, opensearch_config: Dict[str, Any]) -> None:
self._enabled = opensearch_config.get("knn.plugin.enabled", "false") == "true"

def disable(self) -> Dict[str, Any]:
"""Returns a dict containing different config changes.
The dict should return:
(1) all the configs to remove
(2) all the configs to add
(3) all the keystore values to be remmoved.
"""
return {
"to_remove_opensearch": ["knn.plugin.enabled"],
"to_add_opensearch": [],
"to_remove_keystore": [],
}

@property
def name(self) -> str:
"""Returns the name of the plugin."""
return "opensearch-knn"
9 changes: 8 additions & 1 deletion lib/charms/opensearch/v0/opensearch_plugin_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
from typing import List

from charms.opensearch.v0.opensearch_exceptions import OpenSearchCmdError
from charms.opensearch.v0.opensearch_ml_plugins import OpenSearchKnn
from charms.opensearch.v0.opensearch_plugins import (
OpenSearchPlugin,
OpenSearchPluginError,
Expand All @@ -34,7 +35,13 @@
logger = logging.getLogger(__name__)


ConfigExposedPlugins = {}
ConfigExposedPlugins = {
"opensearch-knn": {
"class": OpenSearchKnn,
"config-name": "plugin_opensearch_knn",
"relation-name": None,
}
}


class OpenSearchPluginManager:
Expand Down
89 changes: 89 additions & 0 deletions tests/unit/lib/test_ml_plugins.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
# Copyright 2023 Canonical Ltd.
# See LICENSE file for licensing details.

"""Unit test for the opensearch_plugins library."""
import unittest
from unittest.mock import MagicMock, PropertyMock, call, patch

import charms
from charms.opensearch.v0.opensearch_ml_plugins import OpenSearchKnn
from charms.rolling_ops.v0.rollingops import RollingOpsManager
from ops.testing import Harness

from charm import OpenSearchOperatorCharm

RETURN_LIST_PLUGINS = """opensearch-alerting
opensearch-anomaly-detection
opensearch-asynchronous-search
opensearch-cross-cluster-replication
opensearch-geospatial
opensearch-index-management
opensearch-job-scheduler
opensearch-knn
opensearch-ml
opensearch-notifications
opensearch-notifications-core
opensearch-observability
opensearch-performance-analyzer
opensearch-reports-scheduler
opensearch-security
opensearch-sql
"""


class TestOpenSearchKNN(unittest.TestCase):
def setUp(self) -> None:
self.harness = Harness(OpenSearchOperatorCharm)
self.addCleanup(self.harness.cleanup)
self.harness.begin()
self.charm = self.harness.charm
self.charm.opensearch.paths.plugins = "tests/unit/resources"
self.plugin_manager = self.charm.plugin_manager
self.plugin_manager._plugins_path = self.charm.opensearch.paths.plugins
# Override the ConfigExposedPlugins and ensure one single plugin exists
charms.opensearch.v0.opensearch_plugin_manager.ConfigExposedPlugins = {
"opensearch-knn": {
"class": OpenSearchKnn,
"config-name": "plugin_opensearch_knn",
"relation-name": None,
}
}

@patch.object(RollingOpsManager, "_on_acquire_lock")
@patch(
"charms.opensearch.v0.opensearch_distro.OpenSearchDistribution.version",
new_callable=PropertyMock,
)
@patch("charms.opensearch.v0.opensearch_plugin_manager.OpenSearchPluginManager.is_installed")
@patch("charms.opensearch.v0.opensearch_distro.OpenSearchDistribution.is_started")
@patch("charms.opensearch.v0.opensearch_config.OpenSearchConfig.load_node")
@patch("charms.opensearch.v0.helper_conf_setter.YamlConfigSetter.put")
def test_config_changed(
self, _, mock_load, mock_is_started, mock_is_installed, mock_version, mock_acquire_lock
) -> None:
"""Tests config_changed with KNN plugin."""
mock_is_installed.return_value = True
mock_is_started.return_value = True
mock_version.return_value = "2.9.0"
self.plugin_manager._keystore.add = MagicMock()
self.plugin_manager._add_plugin = MagicMock()
self.charm.opensearch.run_bin = MagicMock(return_value=RETURN_LIST_PLUGINS)
mock_load.side_effect = [
{},
{},
{},
{},
{"knn.plugin.enabled": "true"},
{"knn.plugin.enabled": "true"},
{"knn.plugin.enabled": "true"},
{"knn.plugin.enabled": "true"},
{"knn.plugin.enabled": "true"},
]

self.harness.update_config({"plugin_opensearch_knn": True})
self.charm.opensearch.config.put.assert_has_calls(
[call(self.charm.opensearch_config.CONFIG_YML, "knn.plugin.enabled", "true")]
)
self.charm.opensearch.run_bin.assert_called_once_with("opensearch-plugin", "list")
self.plugin_manager._add_plugin.assert_not_called()
mock_acquire_lock.assert_called_once()

0 comments on commit a022fb8

Please sign in to comment.