Skip to content

Commit

Permalink
Implement indexes command
Browse files Browse the repository at this point in the history
Why these changes are being introduced:
We want the indexes command to display information about all of the
indexes in an OpenSearch instance.

How this addresses that need:
* Adds a list_indexes function to the opensearch module that retrieves
  information about all of the indexes in an instance and formats the
  results as a string for display.
* Calls the list_indexes function from the cli indexes command.
* Adds tests for new functionality.
* Moves all logic for the ping function to the opensearch module for
  consistency and reformats the output slightly.
* Updates ping tests as needed to reflect changes.

Relevant ticket(s):
* https://mitlibraries.atlassian.net/browse/TIMX-74
  • Loading branch information
hakbailey committed Aug 19, 2022
1 parent d2ccd16 commit 9feacb9
Show file tree
Hide file tree
Showing 8 changed files with 152 additions and 16 deletions.
7 changes: 7 additions & 0 deletions tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
import pytest
from click.testing import CliRunner

from tim.opensearch import configure_opensearch_client


@pytest.fixture(autouse=True)
def test_env():
Expand All @@ -17,6 +19,11 @@ def test_env():
yield


@pytest.fixture()
def test_opensearch_client():
return configure_opensearch_client("localhost")


@pytest.fixture()
def runner():
return CliRunner()
22 changes: 22 additions & 0 deletions tests/fixtures/cassettes/list_indexes.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
interactions:
- request:
body: null
headers:
content-type:
- application/json
user-agent:
- opensearch-py/2.0.0 (Python 3.10.6)
method: GET
uri: http://localhost:9200/_cat/indices?format=json
response:
body:
string: '[{"health":"yellow","status":"open","index":"test-index","uuid":"CutX-ZdNRa-Novw8vdTXIg","pri":"1","rep":"1","docs.count":"0","docs.deleted":"0","store.size":"208b","pri.store.size":"208b"}]'
headers:
content-length:
- '190'
content-type:
- application/json; charset=UTF-8
status:
code: 200
message: OK
version: 1
22 changes: 22 additions & 0 deletions tests/fixtures/cassettes/list_indexes_none_present.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
interactions:
- request:
body: null
headers:
content-type:
- application/json
user-agent:
- opensearch-py/2.0.0 (Python 3.10.6)
method: GET
uri: http://localhost:9200/_cat/indices?format=json
response:
body:
string: '[]'
headers:
content-length:
- '2'
content-type:
- application/json; charset=UTF-8
status:
code: 200
message: OK
version: 1
22 changes: 22 additions & 0 deletions tests/fixures/cassettes/list_indexes.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
interactions:
- request:
body: null
headers:
content-type:
- application/json
user-agent:
- opensearch-py/2.0.0 (Python 3.10.6)
method: GET
uri: http://localhost:9200/_cat/indices?format=json
response:
body:
string: '[{"health":"yellow","status":"open","index":"test-index","uuid":"xERdq2rbQUy1IgtP5-ydVg","pri":"1","rep":"1","docs.count":"0","docs.deleted":"0","store.size":"208b","pri.store.size":"208b"}]'
headers:
content-length:
- '190'
content-type:
- application/json; charset=UTF-8
status:
code: 200
message: OK
version: 1
9 changes: 5 additions & 4 deletions tests/test_cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,17 +44,18 @@ def test_aliases(caplog, runner):
assert "'aliases' command not yet implemented" in caplog.text


def test_indexes(caplog, runner):
@vcr.use_cassette("tests/fixtures/cassettes/list_indexes.yaml")
def test_indexes(runner):
result = runner.invoke(main, ["indexes"])
assert result.exit_code == 0
assert "'indexes' command not yet implemented" in caplog.text
assert "Name: test-index" in result.stdout


@vcr.use_cassette("tests/fixtures/cassettes/ping_localhost.yaml")
def test_ping(caplog, runner):
def test_ping(runner):
result = runner.invoke(main, ["ping"])
assert result.exit_code == 0
assert "'cluster_name': 'docker-cluster'" in caplog.text
assert "Name: docker-cluster" in result.stdout


def test_ingest_no_options(caplog, runner):
Expand Down
36 changes: 35 additions & 1 deletion tests/test_opensearch.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
from unittest import mock

from tim.opensearch import configure_opensearch_client
import vcr

from tim.opensearch import configure_opensearch_client, get_info, list_indexes


def test_configure_opensearch_client_for_localhost():
Expand All @@ -15,3 +17,35 @@ def test_configure_opensearch_client_for_aws(mocked_boto3_session): # noqa
str(result) == "<OpenSearch([{'host': 'fake-dev.us-east-1.es.amazonaws.com', "
"'port': '443'}])>"
)


@vcr.use_cassette("tests/fixtures/cassettes/ping_localhost.yaml")
def test_get_info(test_opensearch_client):
assert get_info(test_opensearch_client) == (
"\nName: docker-cluster"
"\nUUID: j7tpRLtKTsSRlyng3RELug"
"\nOpenSearch version: 1.3.3"
"\nLucene version: 8.10.1"
"\n"
)


@vcr.use_cassette("tests/fixures/cassettes/list_indexes.yaml")
def test_list_indexes(test_opensearch_client):
assert list_indexes(test_opensearch_client) == (
"\nName: test-index"
"\n\tStatus: open"
"\n\tHealth: yellow"
"\n\tDocuments: 0"
"\n\tPrimary store size: 208b"
"\n\tTotal store size: 208b"
"\n\tUUID: xERdq2rbQUy1IgtP5-ydVg"
"\n"
)


@vcr.use_cassette("tests/fixtures/cassettes/list_indexes_none_present.yaml")
def test_list_indexes_no_indexes_present(test_opensearch_client):
assert list_indexes(test_opensearch_client) == (
"No indexes present in OpenSearch cluster."
)
20 changes: 9 additions & 11 deletions tim/cli.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
import logging
import pprint
from datetime import timedelta
from time import perf_counter
from typing import Optional

import click

from tim.config import configure_logger, configure_sentry
from tim.opensearch import configure_opensearch_client
from tim.opensearch import configure_opensearch_client, get_info, list_indexes

logger = logging.getLogger(__name__)

Expand Down Expand Up @@ -62,24 +61,23 @@ def aliases() -> None:


@main.command()
def indexes() -> None:
@click.pass_context
def indexes(ctx: click.Context) -> None:
"""
List all OpenSearch indexes.
Display summary information about all indexes in the cluster.
Find all indexes in the OpenSearch cluster. List the indexes in alphabetical order
by name. For each index, display: index name, number of documents, health, status,
UUID, size.
Prints all indexes in the cluster in alphabetical order by name. For each index,
displays information including its status, health, number of documents, primary
store size, total store size, and UUID.
"""
logger.info("'indexes' command not yet implemented")
click.echo(list_indexes(ctx.obj["CLIENT"]))


@main.command()
@click.pass_context
def ping(ctx: click.Context) -> None:
"""Ping OpenSearch and display information about the cluster."""
client = ctx.obj["CLIENT"]
output = pprint.pformat(client.info(), indent=2)
logger.info(output)
click.echo(get_info(ctx.obj["CLIENT"]))


# Index commands
Expand Down
30 changes: 30 additions & 0 deletions tim/opensearch.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import os
from operator import itemgetter

import boto3
from opensearchpy import AWSV4SignerAuth, OpenSearch, RequestsHttpConnection
Expand All @@ -22,3 +23,32 @@ def configure_opensearch_client(url: str) -> OpenSearch:
verify_certs=True,
connection_class=RequestsHttpConnection,
)


def get_info(client: OpenSearch) -> str:
response = client.info()
return (
f"\nName: {response['cluster_name']}\n"
f"UUID: {response['cluster_uuid']}\n"
f"OpenSearch version: {response['version']['number']}\n"
f"Lucene version: {response['version']['lucene_version']}\n"
)


def list_indexes(client: OpenSearch) -> str:
response = client.cat.indices(format="json")
if not response:
return "No indexes present in OpenSearch cluster."
indices = sorted(response, key=itemgetter("index"))
output = ""
for index in indices:
output += (
f"\nName: {index['index']}\n"
f"\tStatus: {index['status']}\n"
f"\tHealth: {index['health']}\n"
f"\tDocuments: {int(index['docs.count']):,}\n"
f"\tPrimary store size: {index['pri.store.size']}\n"
f"\tTotal store size: {index['store.size']}\n"
f"\tUUID: {index['uuid']}\n"
)
return output

0 comments on commit 9feacb9

Please sign in to comment.