diff --git a/lib/live_cluster/client/node.py b/lib/live_cluster/client/node.py index dabdc869..509f97bc 100644 --- a/lib/live_cluster/client/node.py +++ b/lib/live_cluster/client/node.py @@ -94,7 +94,7 @@ async def wrapper(*args, raise_exception=False, **kwargs): except OSError as e: args[0].alive = False exception = e - except (ASInfoError, ASProtocolError, Exception) as e: + except Exception as e: exception = e if raise_exception: diff --git a/lib/live_cluster/manage_controller.py b/lib/live_cluster/manage_controller.py index 40178b6a..69e5682a 100644 --- a/lib/live_cluster/manage_controller.py +++ b/lib/live_cluster/manage_controller.py @@ -41,7 +41,10 @@ CDTContext, ) from .live_cluster_command_controller import LiveClusterCommandController -from lib.live_cluster.get_controller import GetJobsController +from lib.live_cluster.get_controller import ( + GetClusterMetadataController, + GetJobsController, +) logger = logging.getLogger(__name__) logger.setLevel(logging.CRITICAL) @@ -1082,6 +1085,7 @@ class ManageSIndexCreateController(ManageLeafCommandController): def __init__(self): self.required_modifiers = set(["line", "ns", "bin"]) self.modifiers = set(["set", "in", "ctx"]) + self.meta_getter = GetClusterMetadataController(self.cluster) @staticmethod def _split_ctx_list(ctx_str: str) -> list[str]: @@ -1267,7 +1271,7 @@ async def _do_create(self, line, bin_type: str): cdt_ctx = None if ctx_list: - builds = await self.cluster.info_build(nodes=self.nodes) + builds = await self.meta_getter.get_builds(nodes=self.nodes) if not all( [ @@ -1323,6 +1327,22 @@ async def do_string(self, line): async def do_geo2dsphere(self, line): await self._do_create(line, "geo2dsphere") + # Hack for auto-complete + async def do_blob(self, line): + builds = await self.meta_getter.get_builds() + if any( + [ + version.LooseVersion(build) + < version.LooseVersion(constants.SERVER_SINDEX_BLOB_TYPE_FIRST_VERSION) + for build in builds.values() + ] + ): + raise ShellException( + f"Blob type secondary index is not supported on server version < {constants.SERVER_SINDEX_BLOB_TYPE_FIRST_VERSION}." + ) + + await self._do_create(line, "blob") + @CommandHelp( "Delete a secondary index", diff --git a/lib/utils/constants.py b/lib/utils/constants.py index 9e289aa4..61e0fe92 100644 --- a/lib/utils/constants.py +++ b/lib/utils/constants.py @@ -154,6 +154,7 @@ class JobType: # server versions with critical changes # TODO: Change to functions on the node SERVER_INFO_BINS_REMOVAL_VERSION = "7.0" +SERVER_SINDEX_BLOB_TYPE_FIRST_VERSION = "7.0" SERVER_SINDEX_ON_CDT_FIRST_VERSION = "6.1" SERVER_QUERIES_ABORT_ALL_FIRST_VERSION = "6.0" SERVER_39_BYTE_OVERHEAD_FIRST_VERSION = "6.0" diff --git a/lib/view/view.py b/lib/view/view.py index a16fdb5b..a9e1d327 100644 --- a/lib/view/view.py +++ b/lib/view/view.py @@ -2051,15 +2051,6 @@ def print_health_output( ########################### - @staticmethod - def get_summary_line_prefix(index, key): - s = " " * 3 - s += (str(index) + ".").ljust(3) - s += " " * 2 - s += key.ljust(19) - s += ":" + (" " * 2) - return s - @staticmethod def _summary_cluster_table_view(stats: SummaryClusterDict, **ignore): title = "Cluster Summary" diff --git a/test/e2e/live_cluster/test_manage.py b/test/e2e/live_cluster/test_manage.py index 051b07bb..7b919071 100644 --- a/test/e2e/live_cluster/test_manage.py +++ b/test/e2e/live_cluster/test_manage.py @@ -768,6 +768,21 @@ def test_can_create_geo2dspehere_sindex(self): self.assertEqual(exp_stdout, actual.stdout) self.assertStdErrEqual(exp_stderr, actual.stderr) + def test_can_create_blob_sindex(self): + exp_stdout = self.success_msg + exp_stderr = "" + + actual = test_util.run_asadm( + self.get_args( + "manage sindex create blob {} ns {} set {} bin {}".format( + self.exp_sindex, self.exp_ns, self.exp_set, self.exp_bin + ) + ) + ) + + self.assertEqual(exp_stdout, actual.stdout) + self.assertStdErrEqual(exp_stderr, actual.stderr) + def test_can_create_sindex_in_list(self): exp_stdout = self.success_msg exp_stderr = "" diff --git a/test/unit/live_cluster/test_manage_controller.py b/test/unit/live_cluster/test_manage_controller.py index 78ef98b5..7ab56cc6 100644 --- a/test/unit/live_cluster/test_manage_controller.py +++ b/test/unit/live_cluster/test_manage_controller.py @@ -21,7 +21,7 @@ ModifierHelp, ShellException, ) -from mock import MagicMock, patch +from mock import MagicMock, create_autospec, patch from mock.mock import AsyncMock, call from parameterized import parameterized @@ -36,6 +36,7 @@ from lib.live_cluster.client.config_handler import JsonDynamicConfigHandler from lib.live_cluster.client.ctx import ASValues, CDTContext, CTXItems from lib.live_cluster.client.node import Node +from lib.live_cluster.get_controller import GetClusterMetadataController from lib.live_cluster.live_cluster_command_controller import ( LiveClusterCommandController, ) @@ -57,7 +58,6 @@ ManageRosterRemoveController, ManageRosterStageNodesController, ManageRosterStageObservedController, - ManageSIndexController, ManageSIndexCreateController, ManageSIndexDeleteController, ManageTruncateController, @@ -1693,8 +1693,9 @@ def setUp(self) -> None: self.prompt_mock = patch( "lib.live_cluster.manage_controller.ManageSIndexCreateController.prompt_challenge" ).start() - - self.cluster_mock.info_build.return_value = {"principal": "6.1.0.0"} + self.meta_mock = self.controller.meta_getter = create_autospec( + GetClusterMetadataController + ) self.addCleanup(patch.stopall) @@ -1702,6 +1703,7 @@ async def test_prompt_challenge_fails(self): line = "numeric a-index ns test bin a ctx list_value(1)".split() self.controller.warn = True self.prompt_mock.return_value = False + self.meta_mock.get_builds.return_value = {"principal": "6.1.0.0"} await self.controller.execute(line) @@ -1709,11 +1711,13 @@ async def test_prompt_challenge_fails(self): "Adding a secondary index will cause longer restart times." ) - async def test_create_successful(self): - line = "numeric a-index ns test set testset bin a in mapkeys ctx list_value(int(1))".split() + @parameterized.expand([("numeric",), ("string",), ("geo2dsphere",), ("blob",)]) + async def test_create_successful(self, bin_type): + line = f"{bin_type} a-index ns test set testset bin a in mapkeys ctx list_value(int(1))".split() self.cluster_mock.info_sindex_create.return_value = { "1.1.1.1": ASINFO_RESPONSE_OK } + self.meta_mock.get_builds.return_value = {"principal": "7.0.0.0"} await self.controller.execute(line) @@ -1721,7 +1725,7 @@ async def test_create_successful(self): "a-index", "test", "a", - "numeric", + bin_type, "mapkeys", "testset", CDTContext([CTXItems.ListValue(ASValues.ASInt(1))]), @@ -1733,6 +1737,7 @@ async def test_create_successful(self): async def test_create_fails_with_asinfo_error(self): line = "numeric a-index ns test bin a ctx list_value(1)".split() + self.meta_mock.get_builds.return_value = {"principal": "6.1.0.0"} self.cluster_mock.info_sindex_create.return_value = { "1.1.1.1": ASInfoResponseError("foo", "ERROR::bar") } @@ -1743,7 +1748,7 @@ async def test_create_fails_with_asinfo_error(self): async def test_ctx_invalid_format(self): line = "numeric a-index ns test bin a ctx foo".split() - self.cluster_mock.info_build.return_value = {"principal": "6.1.0.0"} + self.meta_mock.get_builds.return_value = {"principal": "6.1.0.0"} await self.assertAsyncRaisesRegex( ShellException, @@ -1753,7 +1758,7 @@ async def test_ctx_invalid_format(self): async def test_ctx_not_supported(self): line = "numeric a-index ns test bin a ctx [foo]".split() - self.cluster_mock.info_build.return_value = {"principal": "6.0.0.0"} + self.meta_mock.get_builds.return_value = {"principal": "6.0.0.0"} await self.assertAsyncRaisesRegex( ShellException, @@ -1761,6 +1766,16 @@ async def test_ctx_not_supported(self): self.controller.execute(line), ) + async def test_blob_not_supported(self): + line = "blob a-index ns test bin a ctx [foo]".split() + self.meta_mock.get_builds.return_value = {"principal": "6.4.0.0"} + + await self.assertAsyncRaisesRegex( + ShellException, + "Blob type secondary index is not supported on server version < 7.0", + self.controller.execute(line), + ) + class ManageSIndexDeleteControllerTest(asynctest.TestCase): def setUp(self) -> None: