Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for Elasticsearch 7.x #19

Open
wants to merge 7 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,12 @@ st2 run elasticsearch.snapshots.delete host=elk repository=my_backup all_indices

### Querying Elasticsearch

On successful search (*total hits > 0*) query actions exit with *return code* == 0, if no documents have been found *return code* == 1. In all other case such as execution exceptions *return code* is 99.
| Return Code | Reason |
|-------------|-------------------------------------------------------------|
| `0` | Successful search (total hits > 0 or returned hits > 0) |
| `1` | No documents found (total hits == 0) |
| `2` | `hits.total` not present in response and returned hits == 0 |
| `99` | Other execution errors |

Let's look at a few examples:

Expand Down
2 changes: 1 addition & 1 deletion actions/lib/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
from curator.utils import get_version, is_master_node

# Elasticsearch versions supported
version_max = (7, 0, 0)
version_max = (8, 0, 0)
version_min = (5, 0, 0)
logger = logging.getLogger(__name__)

Expand Down
22 changes: 18 additions & 4 deletions actions/search.py
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,21 @@ def _pp_exit(self, data):
kwargs = {'indent': 4}
print(json.dumps(data, **kwargs))

if data['hits']['total'] > 0:
sys.exit(0)
else:
sys.exit(1)
# in ElasticSearch 7.0 hits.total becomes an object and may not even
# be present when track_total_hits is false see:
# https://www.elastic.co/guide/en/elasticsearch/reference/current/breaking-changes-7.0.html#hits-total-now-object-search-response # noqa
if 'total' in data['hits']:
if isinstance(data['hits']['total'], int):
hit_value = data['hits']['total']
elif isinstance(data['hits']['total'], dict):
hit_value = data['hits']['total']['value']
else:
print('Unsupported data type for `hits.total`', file=sys.stderr)
sys.exit(99)

if hit_value == 0:
sys.exit(1)
elif len(data['hits']['hits']) == 0:
sys.exit(2)

sys.exit(0)
21 changes: 19 additions & 2 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -1,2 +1,19 @@
elasticsearch-curator==5.4.0
easydict
boto3==1.14.17
botocore==1.17.17
certifi==2020.6.20
chardet==3.0.4
click==6.7
docutils==0.15.2
easydict==1.9
elasticsearch==7.8.0
elasticsearch-curator==5.8.1
idna==2.10
jmespath==0.10.0
python-dateutil==2.8.1
PyYAML==3.13
requests==2.24.0
requests-aws4auth==1.0
s3transfer==0.3.3
six==1.15.0
urllib3==1.24.3
voluptuous==0.11.7
30 changes: 23 additions & 7 deletions sensors/count_sensor.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,9 @@ class ElasticsearchCountSensor(PollingSensor):

def setup(self):
self.host = self.config.get('host', None)
self.port = self.config.get('port', None)
self.http_auth = self.config.get('http_auth', None)
self.use_ssl = self.config.get('use_ssl', False)
self.port = self.config.get('port', None)
self.http_auth = self.config.get('http_auth', None)
self.use_ssl = self.config.get('use_ssl', False)
self.query_window = self.config.get('query_window', 60)
self.query_string = self.config.get('query_string', '{}')
self.cooldown_multiplier = self.config.get('cooldown_multiplier', 0)
Expand All @@ -22,9 +22,9 @@ def setup(self):
self.es = None

try:
self.es = Elasticsearch([{'host': self.host, 'port': self.port,
'http_auth': self.http_auth,
'use_ssl': self.use_ssl}])
self.es = Elasticsearch([{'host': self.host, 'port': self.port,
'http_auth': self.http_auth,
'use_ssl': self.use_ssl}])
except Exception:
raise

Expand All @@ -40,7 +40,23 @@ def poll(self):
data = self.es.search(index=self.index, body=query_payload)

hits = data.get('hits', None)
if hits.get('total', 0) > self.count_threshold:
if hits is None:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would be great to see some unit tests for these new conditions.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@nmaludy I was unable to find any tests apart from the bash scripts in /test. I tried to use Docker Compose but I believe that is broken because there is no st2 image on DockerHub. From the CI output, it doesn't look like that script is being run. Where and how should I add tests?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@AbhyudayaSharma Unit tests go in the tests/ folder. These use the standard python unittest2 framework. Some examples can be seen in the vSphere pack here: https://github.com/StackStorm-Exchange/stackstorm-vsphere/blob/master/tests/test_action_affinity_rule_create.py

raise RuntimeError('No hits in search response.')

total = hits.get('total', None)
if total is None:
raise RuntimeError('Total not present in search response.' +
'Did you disable track_total_hits?\n' +
'https://www.elastic.co/guide/en/elasticsearch/reference/current/breaking-changes-7.0.html#hits-total-omitted-if-disabled') # noqa

if isinstance(int, total):
hit_count = total
elif isinstance(dict, total): # for Elasticsearch >= 7.0
hit_count = total['value']
else:
raise RuntimeError('Unsupported type of hit.total')

if hit_count > self.count_threshold:
payload = dict()
payload['results'] = hits
payload['results']['query'] = query_payload
Expand Down