1"""
2Elasticsearch - A distributed RESTful search and analytics server
3
4Module to provide Elasticsearch compatibility to Salt
5(compatible with Elasticsearch version 1.5.2+)
6
7.. versionadded:: 2015.8.0
8
9:depends:       `elasticsearch-py <http://elasticsearch-py.readthedocs.org/en/latest/>`_
10
11:configuration: This module accepts connection configuration details either as
12    parameters or as configuration settings in /etc/salt/minion on the relevant
13    minions:
14
15    .. code-block:: yaml
16
17        elasticsearch:
18          host: '10.10.10.100:9200'
19
20        elasticsearch-cluster:
21          hosts:
22            - '10.10.10.100:9200'
23            - '10.10.10.101:9200'
24            - '10.10.10.102:9200'
25
26        elasticsearch-extra:
27          hosts:
28            - '10.10.10.100:9200'
29          use_ssl: True
30          verify_certs: True
31          ca_certs: /path/to/custom_ca_bundle.pem
32          number_of_shards: 1
33          number_of_replicas: 0
34          functions_blacklist:
35            - 'saltutil.find_job'
36            - 'pillar.items'
37            - 'grains.items'
38          proxies:
39            - http: http://proxy:3128
40            - https: http://proxy:1080
41
42    When specifying proxies the requests backend will be used and the 'proxies'
43    data structure is passed as-is to that module.
44
45    This data can also be passed into pillar. Options passed into opts will
46    overwrite options passed into pillar.
47
48    Some functionality might be limited by elasticsearch-py and Elasticsearch server versions.
49"""
50
51
52import logging
53
54from salt.exceptions import CommandExecutionError, SaltInvocationError
55
56log = logging.getLogger(__name__)
57
58try:
59    import elasticsearch
60
61    # pylint: disable=no-name-in-module
62    from elasticsearch import RequestsHttpConnection
63
64    # pylint: enable=no-name-in-module
65
66    logging.getLogger("elasticsearch").setLevel(logging.CRITICAL)
67    HAS_ELASTICSEARCH = True
68except ImportError:
69    HAS_ELASTICSEARCH = False
70
71
72def __virtual__():
73    """
74    Only load if elasticsearch libraries exist.
75    """
76    if not HAS_ELASTICSEARCH:
77        return (
78            False,
79            "Cannot load module elasticsearch: elasticsearch libraries not found",
80        )
81    return True
82
83
84def _get_instance(hosts=None, profile=None):
85    """
86    Return the elasticsearch instance
87    """
88    es = None
89    proxies = None
90    use_ssl = False
91    ca_certs = None
92    verify_certs = True
93    http_auth = None
94    timeout = 10
95
96    if profile is None:
97        profile = "elasticsearch"
98
99    if isinstance(profile, str):
100        _profile = __salt__["config.option"](profile, None)
101    elif isinstance(profile, dict):
102        _profile = profile
103    if _profile:
104        hosts = _profile.get("host", hosts)
105        if not hosts:
106            hosts = _profile.get("hosts", hosts)
107        proxies = _profile.get("proxies", None)
108        use_ssl = _profile.get("use_ssl", False)
109        ca_certs = _profile.get("ca_certs", None)
110        verify_certs = _profile.get("verify_certs", True)
111        username = _profile.get("username", None)
112        password = _profile.get("password", None)
113        timeout = _profile.get("timeout", 10)
114
115        if username and password:
116            http_auth = (username, password)
117
118    if not hosts:
119        hosts = ["127.0.0.1:9200"]
120    if isinstance(hosts, str):
121        hosts = [hosts]
122    try:
123        if proxies:
124            # Custom connection class to use requests module with proxies
125            class ProxyConnection(RequestsHttpConnection):
126                def __init__(self, *args, **kwargs):
127                    proxies = kwargs.pop("proxies", {})
128                    super().__init__(*args, **kwargs)
129                    self.session.proxies = proxies
130
131            es = elasticsearch.Elasticsearch(
132                hosts,
133                connection_class=ProxyConnection,
134                proxies=proxies,
135                use_ssl=use_ssl,
136                ca_certs=ca_certs,
137                verify_certs=verify_certs,
138                http_auth=http_auth,
139                timeout=timeout,
140            )
141        else:
142            es = elasticsearch.Elasticsearch(
143                hosts,
144                use_ssl=use_ssl,
145                ca_certs=ca_certs,
146                verify_certs=verify_certs,
147                http_auth=http_auth,
148                timeout=timeout,
149            )
150
151        # Try the connection
152        es.info()
153    except elasticsearch.exceptions.TransportError as err:
154        raise CommandExecutionError(
155            "Could not connect to Elasticsearch host/ cluster {} due to {}".format(
156                hosts, err
157            )
158        )
159    return es
160
161
162def ping(allow_failure=False, hosts=None, profile=None):
163    """
164    .. versionadded:: 2017.7.0
165
166    Test connection to Elasticsearch instance. This method does not fail if not explicitly specified.
167
168    allow_failure
169        Throw exception if ping fails
170
171    CLI Example:
172
173    .. code-block:: bash
174
175        salt myminion elasticsearch.ping allow_failure=True
176        salt myminion elasticsearch.ping profile=elasticsearch-extra
177    """
178    try:
179        _get_instance(hosts, profile)
180    except CommandExecutionError as e:
181        if allow_failure:
182            raise
183        return False
184    return True
185
186
187def info(hosts=None, profile=None):
188    """
189    .. versionadded:: 2017.7.0
190
191    Return Elasticsearch information.
192
193    CLI Example:
194
195    .. code-block:: bash
196
197        salt myminion elasticsearch.info
198        salt myminion elasticsearch.info profile=elasticsearch-extra
199    """
200    es = _get_instance(hosts, profile)
201
202    try:
203        return es.info()
204    except elasticsearch.TransportError as e:
205        raise CommandExecutionError(
206            "Cannot retrieve server information, server returned code {} with"
207            " message {}".format(e.status_code, e.error)
208        )
209
210
211def node_info(nodes=None, flat_settings=False, hosts=None, profile=None):
212    """
213    .. versionadded:: 2017.7.0
214
215    Return Elasticsearch node information.
216
217    nodes
218        List of cluster nodes (id or name) to display stats for. Use _local for connected node, empty for all
219    flat_settings
220        Flatten settings keys
221
222    CLI Example:
223
224    .. code-block:: bash
225
226        salt myminion elasticsearch.node_info flat_settings=True
227    """
228    es = _get_instance(hosts, profile)
229
230    try:
231        return es.nodes.info(node_id=nodes, flat_settings=flat_settings)
232    except elasticsearch.TransportError as e:
233        raise CommandExecutionError(
234            "Cannot retrieve node information, server returned code {} with message {}".format(
235                e.status_code, e.error
236            )
237        )
238
239
240def cluster_health(index=None, level="cluster", local=False, hosts=None, profile=None):
241    """
242    .. versionadded:: 2017.7.0
243
244    Return Elasticsearch cluster health.
245
246    index
247        Limit the information returned to a specific index
248    level
249        Specify the level of detail for returned information, default 'cluster', valid choices are: 'cluster', 'indices', 'shards'
250    local
251        Return local information, do not retrieve the state from master node
252
253    CLI Example:
254
255    .. code-block:: bash
256
257        salt myminion elasticsearch.cluster_health
258    """
259    es = _get_instance(hosts, profile)
260
261    try:
262        return es.cluster.health(index=index, level=level, local=local)
263    except elasticsearch.TransportError as e:
264        raise CommandExecutionError(
265            "Cannot retrieve health information, server returned code {} with"
266            " message {}".format(e.status_code, e.error)
267        )
268
269
270def cluster_stats(nodes=None, hosts=None, profile=None):
271    """
272    .. versionadded:: 2017.7.0
273
274    Return Elasticsearch cluster stats.
275
276    nodes
277        List of cluster nodes (id or name) to display stats for. Use _local for connected node, empty for all
278
279    CLI Example:
280
281    .. code-block:: bash
282
283        salt myminion elasticsearch.cluster_stats
284    """
285    es = _get_instance(hosts, profile)
286
287    try:
288        return es.cluster.stats(node_id=nodes)
289    except elasticsearch.TransportError as e:
290        raise CommandExecutionError(
291            "Cannot retrieve cluster stats, server returned code {} with message {}".format(
292                e.status_code, e.error
293            )
294        )
295
296
297def cluster_get_settings(
298    flat_settings=False, include_defaults=False, hosts=None, profile=None
299):
300    """
301    .. versionadded:: 3000
302
303    Return Elasticsearch cluster settings.
304
305    flat_settings
306        Return settings in flat format.
307
308    include_defaults
309        Whether to return all default clusters setting.
310
311    CLI Example:
312
313    .. code-block:: bash
314
315        salt myminion elasticsearch.cluster_get_settings
316    """
317    es = _get_instance(hosts, profile)
318
319    try:
320        return es.cluster.get_settings(
321            flat_settings=flat_settings, include_defaults=include_defaults
322        )
323    except elasticsearch.TransportError as e:
324        raise CommandExecutionError(
325            "Cannot retrieve cluster settings, server returned code {} with message {}".format(
326                e.status_code, e.error
327            )
328        )
329
330
331def cluster_put_settings(body=None, flat_settings=False, hosts=None, profile=None):
332    """
333    .. versionadded:: 3000
334
335    Set Elasticsearch cluster settings.
336
337    body
338        The settings to be updated. Can be either 'transient' or 'persistent' (survives cluster restart)
339        http://www.elastic.co/guide/en/elasticsearch/reference/current/cluster-update-settings.html
340
341    flat_settings
342        Return settings in flat format.
343
344    CLI Example:
345
346    .. code-block:: bash
347
348        salt myminion elasticsearch.cluster_put_settings '{"persistent": {"indices.recovery.max_bytes_per_sec": "50mb"}}'
349        salt myminion elasticsearch.cluster_put_settings '{"transient": {"indices.recovery.max_bytes_per_sec": "50mb"}}'
350    """
351    if not body:
352        message = "You must provide a body with settings"
353        raise SaltInvocationError(message)
354    es = _get_instance(hosts, profile)
355
356    try:
357        return es.cluster.put_settings(body=body, flat_settings=flat_settings)
358    except elasticsearch.TransportError as e:
359        raise CommandExecutionError(
360            "Cannot update cluster settings, server returned code {} with message {}".format(
361                e.status_code, e.error
362            )
363        )
364
365
366def alias_create(indices, alias, hosts=None, body=None, profile=None, source=None):
367    """
368    Create an alias for a specific index/indices
369
370    indices
371        Single or multiple indices separated by comma, use _all to perform the operation on all indices.
372    alias
373        Alias name
374    body
375        Optional definition such as routing or filter as defined in https://www.elastic.co/guide/en/elasticsearch/reference/current/indices-aliases.html
376    source
377        URL of file specifying optional definition such as routing or filter. Cannot be used in combination with ``body``.
378
379    CLI Example:
380
381    .. code-block:: bash
382
383        salt myminion elasticsearch.alias_create testindex_v1 testindex
384    """
385    es = _get_instance(hosts, profile)
386    if source and body:
387        message = "Either body or source should be specified but not both."
388        raise SaltInvocationError(message)
389    if source:
390        body = __salt__["cp.get_file_str"](
391            source, saltenv=__opts__.get("saltenv", "base")
392        )
393    try:
394        result = es.indices.put_alias(index=indices, name=alias, body=body)
395        return result.get("acknowledged", False)
396    except elasticsearch.TransportError as e:
397        raise CommandExecutionError(
398            "Cannot create alias {} in index {}, server returned code {} with"
399            " message {}".format(alias, indices, e.status_code, e.error)
400        )
401
402
403def alias_delete(indices, aliases, hosts=None, body=None, profile=None, source=None):
404    """
405    Delete an alias of an index
406
407    indices
408        Single or multiple indices separated by comma, use _all to perform the operation on all indices.
409    aliases
410        Alias names separated by comma
411
412    CLI Example:
413
414    .. code-block:: bash
415
416        salt myminion elasticsearch.alias_delete testindex_v1 testindex
417    """
418    es = _get_instance(hosts, profile)
419    if source and body:
420        message = "Either body or source should be specified but not both."
421        raise SaltInvocationError(message)
422    if source:
423        body = __salt__["cp.get_file_str"](
424            source, saltenv=__opts__.get("saltenv", "base")
425        )
426    try:
427        result = es.indices.delete_alias(index=indices, name=aliases)
428
429        return result.get("acknowledged", False)
430    except elasticsearch.exceptions.NotFoundError:
431        return True
432    except elasticsearch.TransportError as e:
433        raise CommandExecutionError(
434            "Cannot delete alias {} in index {}, server returned code {} with"
435            " message {}".format(aliases, indices, e.status_code, e.error)
436        )
437
438
439def alias_exists(aliases, indices=None, hosts=None, profile=None):
440    """
441    Return a boolean indicating whether given alias exists
442
443    indices
444        Single or multiple indices separated by comma, use _all to perform the operation on all indices.
445    aliases
446        Alias names separated by comma
447
448    CLI Example:
449
450    .. code-block:: bash
451
452        salt myminion elasticsearch.alias_exists None testindex
453    """
454    es = _get_instance(hosts, profile)
455    try:
456        return es.indices.exists_alias(name=aliases, index=indices)
457    except elasticsearch.exceptions.NotFoundError:
458        return False
459    except elasticsearch.TransportError as e:
460        raise CommandExecutionError(
461            "Cannot get alias {} in index {}, server returned code {} with message {}".format(
462                aliases, indices, e.status_code, e.error
463            )
464        )
465
466
467def alias_get(indices=None, aliases=None, hosts=None, profile=None):
468    """
469    Check for the existence of an alias and if it exists, return it
470
471    indices
472        Single or multiple indices separated by comma, use _all to perform the operation on all indices.
473    aliases
474        Alias names separated by comma
475
476    CLI Example:
477
478    .. code-block:: bash
479
480        salt myminion elasticsearch.alias_get testindex
481    """
482    es = _get_instance(hosts, profile)
483
484    try:
485        return es.indices.get_alias(index=indices, name=aliases)
486    except elasticsearch.exceptions.NotFoundError:
487        return None
488    except elasticsearch.TransportError as e:
489        raise CommandExecutionError(
490            "Cannot get alias {} in index {}, server returned code {} with message {}".format(
491                aliases, indices, e.status_code, e.error
492            )
493        )
494
495
496def document_create(
497    index, doc_type, body=None, id=None, hosts=None, profile=None, source=None
498):
499    """
500    Create a document in a specified index
501
502    index
503        Index name where the document should reside
504    doc_type
505        Type of the document
506    body
507        Document to store
508    source
509        URL of file specifying document to store. Cannot be used in combination with ``body``.
510    id
511        Optional unique document identifier for specified doc_type (empty for random)
512
513    CLI Example:
514
515    .. code-block:: bash
516
517        salt myminion elasticsearch.document_create testindex doctype1 '{}'
518    """
519    es = _get_instance(hosts, profile)
520    if source and body:
521        message = "Either body or source should be specified but not both."
522        raise SaltInvocationError(message)
523    if source:
524        body = __salt__["cp.get_file_str"](
525            source, saltenv=__opts__.get("saltenv", "base")
526        )
527    try:
528        return es.index(index=index, doc_type=doc_type, body=body, id=id)
529    except elasticsearch.TransportError as e:
530        raise CommandExecutionError(
531            "Cannot create document in index {}, server returned code {} with"
532            " message {}".format(index, e.status_code, e.error)
533        )
534
535
536def document_delete(index, doc_type, id, hosts=None, profile=None):
537    """
538    Delete a document from an index
539
540    index
541        Index name where the document resides
542    doc_type
543        Type of the document
544    id
545        Document identifier
546
547    CLI Example:
548
549    .. code-block:: bash
550
551        salt myminion elasticsearch.document_delete testindex doctype1 AUx-384m0Bug_8U80wQZ
552    """
553    es = _get_instance(hosts, profile)
554
555    try:
556        return es.delete(index=index, doc_type=doc_type, id=id)
557    except elasticsearch.exceptions.NotFoundError:
558        return None
559    except elasticsearch.TransportError as e:
560        raise CommandExecutionError(
561            "Cannot delete document {} in index {}, server returned code {} with"
562            " message {}".format(id, index, e.status_code, e.error)
563        )
564
565
566def document_exists(index, id, doc_type="_all", hosts=None, profile=None):
567    """
568    Return a boolean indicating whether given document exists
569
570    index
571        Index name where the document resides
572    id
573        Document identifier
574    doc_type
575        Type of the document, use _all to fetch the first document matching the ID across all types
576
577    CLI Example:
578
579    .. code-block:: bash
580
581        salt myminion elasticsearch.document_exists testindex AUx-384m0Bug_8U80wQZ
582    """
583    es = _get_instance(hosts, profile)
584
585    try:
586        return es.exists(index=index, id=id, doc_type=doc_type)
587    except elasticsearch.exceptions.NotFoundError:
588        return False
589    except elasticsearch.TransportError as e:
590        raise CommandExecutionError(
591            "Cannot retrieve document {} from index {}, server returned code {} with"
592            " message {}".format(id, index, e.status_code, e.error)
593        )
594
595
596def document_get(index, id, doc_type="_all", hosts=None, profile=None):
597    """
598    Check for the existence of a document and if it exists, return it
599
600    index
601        Index name where the document resides
602    id
603        Document identifier
604    doc_type
605        Type of the document, use _all to fetch the first document matching the ID across all types
606
607    CLI Example:
608
609    .. code-block:: bash
610
611        salt myminion elasticsearch.document_get testindex AUx-384m0Bug_8U80wQZ
612    """
613    es = _get_instance(hosts, profile)
614
615    try:
616        return es.get(index=index, id=id, doc_type=doc_type)
617    except elasticsearch.exceptions.NotFoundError:
618        return None
619    except elasticsearch.TransportError as e:
620        raise CommandExecutionError(
621            "Cannot retrieve document {} from index {}, server returned code {} with"
622            " message {}".format(id, index, e.status_code, e.error)
623        )
624
625
626def index_create(index, body=None, hosts=None, profile=None, source=None):
627    """
628    Create an index
629
630    index
631        Index name
632    body
633        Index definition, such as settings and mappings as defined in https://www.elastic.co/guide/en/elasticsearch/reference/current/indices-create-index.html
634    source
635        URL to file specifying index definition. Cannot be used in combination with ``body``.
636
637    CLI Example:
638
639    .. code-block:: bash
640
641        salt myminion elasticsearch.index_create testindex
642        salt myminion elasticsearch.index_create testindex2 '{"settings" : {"index" : {"number_of_shards" : 3, "number_of_replicas" : 2}}}'
643    """
644    es = _get_instance(hosts, profile)
645    if source and body:
646        message = "Either body or source should be specified but not both."
647        raise SaltInvocationError(message)
648    if source:
649        body = __salt__["cp.get_file_str"](
650            source, saltenv=__opts__.get("saltenv", "base")
651        )
652    try:
653        result = es.indices.create(index=index, body=body)
654        return result.get("acknowledged", False) and result.get(
655            "shards_acknowledged", True
656        )
657    except elasticsearch.TransportError as e:
658        if "index_already_exists_exception" == e.error:
659            return True
660
661        raise CommandExecutionError(
662            "Cannot create index {}, server returned code {} with message {}".format(
663                index, e.status_code, e.error
664            )
665        )
666
667
668def index_delete(index, hosts=None, profile=None):
669    """
670    Delete an index
671
672    index
673        Index name
674
675    CLI Example:
676
677    .. code-block:: bash
678
679        salt myminion elasticsearch.index_delete testindex
680    """
681    es = _get_instance(hosts, profile)
682
683    try:
684        result = es.indices.delete(index=index)
685
686        return result.get("acknowledged", False)
687    except elasticsearch.exceptions.NotFoundError:
688        return True
689    except elasticsearch.TransportError as e:
690        raise CommandExecutionError(
691            "Cannot delete index {}, server returned code {} with message {}".format(
692                index, e.status_code, e.error
693            )
694        )
695
696
697def index_exists(index, hosts=None, profile=None):
698    """
699    Return a boolean indicating whether given index exists
700
701    index
702        Index name
703
704    CLI Example:
705
706    .. code-block:: bash
707
708        salt myminion elasticsearch.index_exists testindex
709    """
710    es = _get_instance(hosts, profile)
711
712    try:
713        return es.indices.exists(index=index)
714    except elasticsearch.exceptions.NotFoundError:
715        return False
716    except elasticsearch.TransportError as e:
717        raise CommandExecutionError(
718            "Cannot retrieve index {}, server returned code {} with message {}".format(
719                index, e.status_code, e.error
720            )
721        )
722
723
724def index_get(index, hosts=None, profile=None):
725    """
726    Check for the existence of an index and if it exists, return it
727
728    index
729        Index name
730
731    CLI Example:
732
733    .. code-block:: bash
734
735        salt myminion elasticsearch.index_get testindex
736    """
737    es = _get_instance(hosts, profile)
738
739    try:
740        return es.indices.get(index=index)
741    except elasticsearch.exceptions.NotFoundError:
742        return None
743    except elasticsearch.TransportError as e:
744        raise CommandExecutionError(
745            "Cannot retrieve index {}, server returned code {} with message {}".format(
746                index, e.status_code, e.error
747            )
748        )
749
750
751def index_open(
752    index,
753    allow_no_indices=True,
754    expand_wildcards="closed",
755    ignore_unavailable=True,
756    hosts=None,
757    profile=None,
758):
759    """
760    .. versionadded:: 2017.7.0
761
762    Open specified index.
763
764    index
765        Index to be opened
766    allow_no_indices
767        Whether to ignore if a wildcard indices expression resolves into no concrete indices. (This includes _all string or when no indices have been specified)
768    expand_wildcards
769        Whether to expand wildcard expression to concrete indices that are open, closed or both., default ‘closed’, valid choices are: ‘open’, ‘closed’, ‘none’, ‘all’
770    ignore_unavailable
771        Whether specified concrete indices should be ignored when unavailable (missing or closed)
772
773    CLI Example:
774
775    .. code-block:: bash
776
777        salt myminion elasticsearch.index_open testindex
778    """
779    es = _get_instance(hosts, profile)
780
781    try:
782        result = es.indices.open(
783            index=index,
784            allow_no_indices=allow_no_indices,
785            expand_wildcards=expand_wildcards,
786            ignore_unavailable=ignore_unavailable,
787        )
788
789        return result.get("acknowledged", False)
790    except elasticsearch.TransportError as e:
791        raise CommandExecutionError(
792            "Cannot open index {}, server returned code {} with message {}".format(
793                index, e.status_code, e.error
794            )
795        )
796
797
798def index_close(
799    index,
800    allow_no_indices=True,
801    expand_wildcards="open",
802    ignore_unavailable=True,
803    hosts=None,
804    profile=None,
805):
806    """
807    .. versionadded:: 2017.7.0
808
809    Close specified index.
810
811    index
812        Index to be closed
813    allow_no_indices
814        Whether to ignore if a wildcard indices expression resolves into no concrete indices. (This includes _all string or when no indices have been specified)
815    expand_wildcards
816        Whether to expand wildcard expression to concrete indices that are open, closed or both., default ‘open’, valid choices are: ‘open’, ‘closed’, ‘none’, ‘all’
817    ignore_unavailable
818        Whether specified concrete indices should be ignored when unavailable (missing or closed)
819
820    CLI Example:
821
822    .. code-block:: bash
823
824        salt myminion elasticsearch.index_close testindex
825    """
826    es = _get_instance(hosts, profile)
827
828    try:
829        result = es.indices.close(
830            index=index,
831            allow_no_indices=allow_no_indices,
832            expand_wildcards=expand_wildcards,
833            ignore_unavailable=ignore_unavailable,
834        )
835
836        return result.get("acknowledged", False)
837    except elasticsearch.TransportError as e:
838        raise CommandExecutionError(
839            "Cannot close index {}, server returned code {} with message {}".format(
840                index, e.status_code, e.error
841            )
842        )
843
844
845def index_get_settings(hosts=None, profile=None, **kwargs):
846    """
847    .. versionadded:: 3000
848
849    Check for the existence of an index and if it exists, return its settings
850    http://www.elastic.co/guide/en/elasticsearch/reference/current/indices-get-settings.html
851
852    index
853        (Optional, string) A comma-separated list of index names; use _all or empty string for all indices. Defaults to '_all'.
854    name
855        (Optional, string) The name of the settings that should be included
856    allow_no_indices
857        (Optional, boolean) Whether to ignore if a wildcard indices expression resolves into no concrete indices.
858        (This includes _all string or when no indices have been specified)
859    expand_wildcards
860        (Optional, string) Whether to expand wildcard expression to concrete indices that are open, closed or both.
861        Valid choices are: ‘open’, ‘closed’, ‘none’, ‘all’
862    flat_settings
863        (Optional, boolean) Return settings in flat format
864    ignore_unavailable
865        (Optional, boolean) Whether specified concrete indices should be ignored when unavailable (missing or closed)
866    include_defaults
867        (Optional, boolean) Whether to return all default setting for each of the indices.
868    local
869        (Optional, boolean) Return local information, do not retrieve the state from master node
870
871    The defaults settings for the above parameters depend on the API version being used.
872
873    CLI Example:
874
875    .. code-block:: bash
876
877        salt myminion elasticsearch.index_get_settings index=testindex
878    """
879
880    es = _get_instance(hosts, profile)
881
882    # Filtering Salt internal keys
883    filtered_kwargs = kwargs.copy()
884    for k in kwargs:
885        if k.startswith("__"):
886            filtered_kwargs.pop(k)
887
888    try:
889        return es.indices.get_settings(**filtered_kwargs)
890    except elasticsearch.exceptions.NotFoundError:
891        return None
892    except elasticsearch.TransportError as e:
893        raise CommandExecutionError(
894            "Cannot retrieve index settings {}, server returned code {} with message {}".format(
895                kwargs, e.status_code, e.error
896            )
897        )
898
899
900def index_put_settings(body=None, hosts=None, profile=None, source=None, **kwargs):
901    """
902    .. versionadded:: 3000
903
904    Update existing index settings
905    https://www.elastic.co/guide/en/elasticsearch/reference/current/indices-update-settings.html
906
907    body
908        The index settings to be updated.
909    source
910        URL to file specifying index definition. Cannot be used in combination with ``body``.
911    index
912        (Optional, string) A comma-separated list of index names; use _all or empty string to perform the operation on all indices
913    allow_no_indices
914        (Optional, boolean) Whether to ignore if a wildcard indices expression resolves into no concrete indices.
915        (This includes _all string or when no indices have been specified)
916    expand_wildcards
917        (Optional, string) Whether to expand wildcard expression to concrete indices that are open, closed or both.
918        Valid choices are: ‘open’, ‘closed’, ‘none’, ‘all’
919    flat_settings
920        (Optional, boolean) Return settings in flat format (default: false)
921    ignore_unavailable
922        (Optional, boolean) Whether specified concrete indices should be ignored when unavailable (missing or closed)
923    master_timeout
924        (Optional, time units) Explicit operation timeout for connection to master node
925    preserve_existing
926        (Optional, boolean) Whether to update existing settings. If set to true existing settings on an index remain unchanged, the default is false
927
928    The defaults settings for the above parameters depend on the API version being used.
929
930    .. note::
931        Elasticsearch time units can be found here:
932        https://www.elastic.co/guide/en/elasticsearch/reference/current/common-options.html#time-units
933
934    CLI Example:
935
936    .. code-block:: bash
937
938        salt myminion elasticsearch.index_put_settings index=testindex body='{"settings" : {"index" : {"number_of_replicas" : 2}}}'
939    """
940    es = _get_instance(hosts, profile)
941    if source and body:
942        message = "Either body or source should be specified but not both."
943        raise SaltInvocationError(message)
944    if source:
945        body = __salt__["cp.get_file_str"](
946            source, saltenv=__opts__.get("saltenv", "base")
947        )
948
949    # Filtering Salt internal keys
950    filtered_kwargs = kwargs.copy()
951    for k in kwargs:
952        if k.startswith("__"):
953            filtered_kwargs.pop(k)
954
955    try:
956        result = es.indices.put_settings(body=body, **filtered_kwargs)
957        return result.get("acknowledged", False)
958    except elasticsearch.exceptions.NotFoundError:
959        return None
960    except elasticsearch.TransportError as e:
961        raise CommandExecutionError(
962            "Cannot update index settings {}, server returned code {} with message {}".format(
963                kwargs, e.status_code, e.error
964            )
965        )
966
967
968def mapping_create(index, doc_type, body=None, hosts=None, profile=None, source=None):
969    """
970    Create a mapping in a given index
971
972    index
973        Index for the mapping
974    doc_type
975        Name of the document type
976    body
977        Mapping definition as specified in https://www.elastic.co/guide/en/elasticsearch/reference/current/indices-put-mapping.html
978    source
979        URL to file specifying mapping definition. Cannot be used in combination with ``body``.
980
981    CLI Example:
982
983    .. code-block:: bash
984
985        salt myminion elasticsearch.mapping_create testindex user '{ "user" : { "properties" : { "message" : {"type" : "string", "store" : true } } } }'
986    """
987    es = _get_instance(hosts, profile)
988    if source and body:
989        message = "Either body or source should be specified but not both."
990        raise SaltInvocationError(message)
991    if source:
992        body = __salt__["cp.get_file_str"](
993            source, saltenv=__opts__.get("saltenv", "base")
994        )
995    try:
996        result = es.indices.put_mapping(index=index, doc_type=doc_type, body=body)
997
998        return result.get("acknowledged", False)
999    except elasticsearch.TransportError as e:
1000        raise CommandExecutionError(
1001            "Cannot create mapping {}, server returned code {} with message {}".format(
1002                index, e.status_code, e.error
1003            )
1004        )
1005
1006
1007def mapping_delete(index, doc_type, hosts=None, profile=None):
1008    """
1009    Delete a mapping (type) along with its data. As of Elasticsearch 5.0 this is no longer available.
1010
1011    index
1012        Index for the mapping
1013    doc_type
1014        Name of the document type
1015
1016    CLI Example:
1017
1018    .. code-block:: bash
1019
1020        salt myminion elasticsearch.mapping_delete testindex user
1021    """
1022    es = _get_instance(hosts, profile)
1023    try:
1024        result = es.indices.delete_mapping(index=index, doc_type=doc_type)
1025
1026        return result.get("acknowledged", False)
1027    except elasticsearch.exceptions.NotFoundError:
1028        return True
1029    except elasticsearch.TransportError as e:
1030        raise CommandExecutionError(
1031            "Cannot delete mapping {}, server returned code {} with message {}".format(
1032                index, e.status_code, e.error
1033            )
1034        )
1035    except AttributeError:
1036        raise CommandExecutionError("Method is not applicable for Elasticsearch 5.0+")
1037
1038
1039def mapping_get(index, doc_type, hosts=None, profile=None):
1040    """
1041    Retrieve mapping definition of index or index/type
1042
1043    index
1044        Index for the mapping
1045    doc_type
1046        Name of the document type
1047
1048    CLI Example:
1049
1050    .. code-block:: bash
1051
1052        salt myminion elasticsearch.mapping_get testindex user
1053    """
1054    es = _get_instance(hosts, profile)
1055
1056    try:
1057        return es.indices.get_mapping(index=index, doc_type=doc_type)
1058    except elasticsearch.exceptions.NotFoundError:
1059        return None
1060    except elasticsearch.TransportError as e:
1061        raise CommandExecutionError(
1062            "Cannot retrieve mapping {}, server returned code {} with message {}".format(
1063                index, e.status_code, e.error
1064            )
1065        )
1066
1067
1068def index_template_create(name, body=None, hosts=None, profile=None, source=None):
1069    """
1070    Create an index template
1071
1072    name
1073        Index template name
1074
1075    body
1076        Template definition as specified in http://www.elastic.co/guide/en/elasticsearch/reference/current/indices-templates.html
1077
1078    source
1079        URL to file specifying template definition. Cannot be used in combination with ``body``.
1080
1081    CLI Example:
1082
1083    .. code-block:: bash
1084
1085        salt myminion elasticsearch.index_template_create testindex_templ '{ "template": "logstash-*", "order": 1, "settings": { "number_of_shards": 1 } }'
1086    """
1087    es = _get_instance(hosts, profile)
1088    if source and body:
1089        message = "Either body or source should be specified but not both."
1090        raise SaltInvocationError(message)
1091    if source:
1092        body = __salt__["cp.get_file_str"](
1093            source, saltenv=__opts__.get("saltenv", "base")
1094        )
1095    try:
1096        result = es.indices.put_template(name=name, body=body)
1097        return result.get("acknowledged", False)
1098    except elasticsearch.TransportError as e:
1099        raise CommandExecutionError(
1100            "Cannot create template {}, server returned code {} with message {}".format(
1101                name, e.status_code, e.error
1102            )
1103        )
1104
1105
1106def index_template_delete(name, hosts=None, profile=None):
1107    """
1108    Delete an index template (type) along with its data
1109
1110    name
1111        Index template name
1112
1113    CLI Example:
1114
1115    .. code-block:: bash
1116
1117        salt myminion elasticsearch.index_template_delete testindex_templ user
1118    """
1119    es = _get_instance(hosts, profile)
1120    try:
1121        result = es.indices.delete_template(name=name)
1122
1123        return result.get("acknowledged", False)
1124    except elasticsearch.exceptions.NotFoundError:
1125        return True
1126    except elasticsearch.TransportError as e:
1127        raise CommandExecutionError(
1128            "Cannot delete template {}, server returned code {} with message {}".format(
1129                name, e.status_code, e.error
1130            )
1131        )
1132
1133
1134def index_template_exists(name, hosts=None, profile=None):
1135    """
1136    Return a boolean indicating whether given index template exists
1137
1138    name
1139        Index template name
1140
1141    CLI Example:
1142
1143    .. code-block:: bash
1144
1145        salt myminion elasticsearch.index_template_exists testindex_templ
1146    """
1147    es = _get_instance(hosts, profile)
1148    try:
1149        return es.indices.exists_template(name=name)
1150    except elasticsearch.TransportError as e:
1151        raise CommandExecutionError(
1152            "Cannot retrieve template {}, server returned code {} with message {}".format(
1153                name, e.status_code, e.error
1154            )
1155        )
1156
1157
1158def index_template_get(name, hosts=None, profile=None):
1159    """
1160    Retrieve template definition of index or index/type
1161
1162    name
1163        Index template name
1164
1165    CLI Example:
1166
1167    .. code-block:: bash
1168
1169        salt myminion elasticsearch.index_template_get testindex_templ
1170    """
1171    es = _get_instance(hosts, profile)
1172
1173    try:
1174        return es.indices.get_template(name=name)
1175    except elasticsearch.exceptions.NotFoundError:
1176        return None
1177    except elasticsearch.TransportError as e:
1178        raise CommandExecutionError(
1179            "Cannot retrieve template {}, server returned code {} with message {}".format(
1180                name, e.status_code, e.error
1181            )
1182        )
1183
1184
1185def pipeline_get(id, hosts=None, profile=None):
1186    """
1187    .. versionadded:: 2017.7.0
1188
1189    Retrieve Ingest pipeline definition. Available since Elasticsearch 5.0.
1190
1191    id
1192        Pipeline id
1193
1194    CLI Example:
1195
1196    .. code-block:: bash
1197
1198        salt myminion elasticsearch.pipeline_get mypipeline
1199    """
1200    es = _get_instance(hosts, profile)
1201
1202    try:
1203        return es.ingest.get_pipeline(id=id)
1204    except elasticsearch.NotFoundError:
1205        return None
1206    except elasticsearch.TransportError as e:
1207        raise CommandExecutionError(
1208            "Cannot create pipeline {}, server returned code {} with message {}".format(
1209                id, e.status_code, e.error
1210            )
1211        )
1212    except AttributeError:
1213        raise CommandExecutionError("Method is applicable only for Elasticsearch 5.0+")
1214
1215
1216def pipeline_delete(id, hosts=None, profile=None):
1217    """
1218    .. versionadded:: 2017.7.0
1219
1220    Delete Ingest pipeline. Available since Elasticsearch 5.0.
1221
1222    id
1223        Pipeline id
1224
1225    CLI Example:
1226
1227    .. code-block:: bash
1228
1229        salt myminion elasticsearch.pipeline_delete mypipeline
1230    """
1231    es = _get_instance(hosts, profile)
1232
1233    try:
1234        ret = es.ingest.delete_pipeline(id=id)
1235        return ret.get("acknowledged", False)
1236    except elasticsearch.NotFoundError:
1237        return True
1238    except elasticsearch.TransportError as e:
1239        raise CommandExecutionError(
1240            "Cannot delete pipeline {}, server returned code {} with message {}".format(
1241                id, e.status_code, e.error
1242            )
1243        )
1244    except AttributeError:
1245        raise CommandExecutionError("Method is applicable only for Elasticsearch 5.0+")
1246
1247
1248def pipeline_create(id, body, hosts=None, profile=None):
1249    """
1250    .. versionadded:: 2017.7.0
1251
1252    Create Ingest pipeline by supplied definition. Available since Elasticsearch 5.0.
1253
1254    id
1255        Pipeline id
1256    body
1257        Pipeline definition as specified in https://www.elastic.co/guide/en/elasticsearch/reference/master/pipeline.html
1258
1259    CLI Example:
1260
1261    .. code-block:: bash
1262
1263        salt myminion elasticsearch.pipeline_create mypipeline '{"description": "my custom pipeline", "processors": [{"set" : {"field": "collector_timestamp_millis", "value": "{{_ingest.timestamp}}"}}]}'
1264    """
1265    es = _get_instance(hosts, profile)
1266    try:
1267        out = es.ingest.put_pipeline(id=id, body=body)
1268        return out.get("acknowledged", False)
1269    except elasticsearch.TransportError as e:
1270        raise CommandExecutionError(
1271            "Cannot create pipeline {}, server returned code {} with message {}".format(
1272                id, e.status_code, e.error
1273            )
1274        )
1275    except AttributeError:
1276        raise CommandExecutionError("Method is applicable only for Elasticsearch 5.0+")
1277
1278
1279def pipeline_simulate(id, body, verbose=False, hosts=None, profile=None):
1280    """
1281    .. versionadded:: 2017.7.0
1282
1283    Simulate existing Ingest pipeline on provided data. Available since Elasticsearch 5.0.
1284
1285    id
1286        Pipeline id
1287    body
1288        Pipeline definition as specified in https://www.elastic.co/guide/en/elasticsearch/reference/master/pipeline.html
1289    verbose
1290        Specify if the output should be more verbose
1291
1292    CLI Example:
1293
1294    .. code-block:: bash
1295
1296        salt myminion elasticsearch.pipeline_simulate mypipeline '{"docs":[{"_index":"index","_type":"type","_id":"id","_source":{"foo":"bar"}},{"_index":"index","_type":"type","_id":"id","_source":{"foo":"rab"}}]}' verbose=True
1297    """
1298    es = _get_instance(hosts, profile)
1299    try:
1300        return es.ingest.simulate(id=id, body=body, verbose=verbose)
1301    except elasticsearch.TransportError as e:
1302        raise CommandExecutionError(
1303            "Cannot simulate pipeline {}, server returned code {} with message {}".format(
1304                id, e.status_code, e.error
1305            )
1306        )
1307    except AttributeError:
1308        raise CommandExecutionError("Method is applicable only for Elasticsearch 5.0+")
1309
1310
1311def search_template_get(id, hosts=None, profile=None):
1312    """
1313    .. versionadded:: 2017.7.0
1314
1315    Obtain existing search template definition.
1316
1317    id
1318        Template ID
1319
1320    CLI Example:
1321
1322    .. code-block:: bash
1323
1324        salt myminion elasticsearch.search_template_get mytemplate
1325    """
1326    es = _get_instance(hosts, profile)
1327
1328    try:
1329        return es.get_template(id=id)
1330    except elasticsearch.NotFoundError:
1331        return None
1332    except elasticsearch.TransportError as e:
1333        raise CommandExecutionError(
1334            "Cannot obtain search template {}, server returned code {} with message {}".format(
1335                id, e.status_code, e.error
1336            )
1337        )
1338
1339
1340def search_template_create(id, body, hosts=None, profile=None):
1341    """
1342    .. versionadded:: 2017.7.0
1343
1344    Create search template by supplied definition
1345
1346    id
1347        Template ID
1348    body
1349        Search template definition
1350
1351    CLI Example:
1352
1353    .. code-block:: bash
1354
1355        salt myminion elasticsearch.search_template_create mytemplate '{"template":{"query":{"match":{"title":"{{query_string}}"}}}}'
1356    """
1357    es = _get_instance(hosts, profile)
1358
1359    try:
1360        result = es.put_template(id=id, body=body)
1361
1362        return result.get("acknowledged", False)
1363    except elasticsearch.TransportError as e:
1364        raise CommandExecutionError(
1365            "Cannot create search template {}, server returned code {} with message {}".format(
1366                id, e.status_code, e.error
1367            )
1368        )
1369
1370
1371def search_template_delete(id, hosts=None, profile=None):
1372    """
1373    .. versionadded:: 2017.7.0
1374
1375    Delete existing search template definition.
1376
1377    id
1378        Template ID
1379
1380    CLI Example:
1381
1382    .. code-block:: bash
1383
1384        salt myminion elasticsearch.search_template_delete mytemplate
1385    """
1386    es = _get_instance(hosts, profile)
1387
1388    try:
1389        result = es.delete_template(id=id)
1390
1391        return result.get("acknowledged", False)
1392    except elasticsearch.NotFoundError:
1393        return True
1394    except elasticsearch.TransportError as e:
1395        raise CommandExecutionError(
1396            "Cannot delete search template {}, server returned code {} with message {}".format(
1397                id, e.status_code, e.error
1398            )
1399        )
1400
1401
1402def repository_get(name, local=False, hosts=None, profile=None):
1403    """
1404    .. versionadded:: 2017.7.0
1405
1406    Get existing repository details.
1407
1408    name
1409        Repository name
1410    local
1411        Retrieve only local information, default is false
1412
1413    CLI Example:
1414
1415    .. code-block:: bash
1416
1417        salt myminion elasticsearch.repository_get testrepo
1418    """
1419    es = _get_instance(hosts, profile)
1420
1421    try:
1422        return es.snapshot.get_repository(repository=name, local=local)
1423    except elasticsearch.NotFoundError:
1424        return None
1425    except elasticsearch.TransportError as e:
1426        raise CommandExecutionError(
1427            "Cannot obtain repository {}, server returned code {} with message {}".format(
1428                name, e.status_code, e.error
1429            )
1430        )
1431
1432
1433def repository_create(name, body, hosts=None, profile=None):
1434    """
1435    .. versionadded:: 2017.7.0
1436
1437    Create repository for storing snapshots. Note that shared repository paths have to be specified in path.repo Elasticsearch configuration option.
1438
1439    name
1440        Repository name
1441    body
1442        Repository definition as in https://www.elastic.co/guide/en/elasticsearch/reference/current/modules-snapshots.html
1443
1444    CLI Example:
1445
1446    .. code-block:: bash
1447
1448        salt myminion elasticsearch.repository_create testrepo '{"type":"fs","settings":{"location":"/tmp/test","compress":true}}'
1449    """
1450    es = _get_instance(hosts, profile)
1451
1452    try:
1453        result = es.snapshot.create_repository(repository=name, body=body)
1454
1455        return result.get("acknowledged", False)
1456    except elasticsearch.TransportError as e:
1457        raise CommandExecutionError(
1458            "Cannot create repository {}, server returned code {} with message {}".format(
1459                name, e.status_code, e.error
1460            )
1461        )
1462
1463
1464def repository_delete(name, hosts=None, profile=None):
1465    """
1466    .. versionadded:: 2017.7.0
1467
1468    Delete existing repository.
1469
1470    name
1471        Repository name
1472
1473    CLI Example:
1474
1475    .. code-block:: bash
1476
1477        salt myminion elasticsearch.repository_delete testrepo
1478    """
1479    es = _get_instance(hosts, profile)
1480
1481    try:
1482        result = es.snapshot.delete_repository(repository=name)
1483
1484        return result.get("acknowledged", False)
1485    except elasticsearch.NotFoundError:
1486        return True
1487    except elasticsearch.TransportError as e:
1488        raise CommandExecutionError(
1489            "Cannot delete repository {}, server returned code {} with message {}".format(
1490                name, e.status_code, e.error
1491            )
1492        )
1493
1494
1495def repository_verify(name, hosts=None, profile=None):
1496    """
1497    .. versionadded:: 2017.7.0
1498
1499    Obtain list of cluster nodes which successfully verified this repository.
1500
1501    name
1502        Repository name
1503
1504    CLI Example:
1505
1506    .. code-block:: bash
1507
1508        salt myminion elasticsearch.repository_verify testrepo
1509    """
1510    es = _get_instance(hosts, profile)
1511
1512    try:
1513        return es.snapshot.verify_repository(repository=name)
1514    except elasticsearch.NotFoundError:
1515        return None
1516    except elasticsearch.TransportError as e:
1517        raise CommandExecutionError(
1518            "Cannot verify repository {}, server returned code {} with message {}".format(
1519                name, e.status_code, e.error
1520            )
1521        )
1522
1523
1524def snapshot_status(
1525    repository=None, snapshot=None, ignore_unavailable=False, hosts=None, profile=None
1526):
1527    """
1528    .. versionadded:: 2017.7.0
1529
1530    Obtain status of all currently running snapshots.
1531
1532    repository
1533        Particular repository to look for snapshots
1534    snapshot
1535        Snapshot name
1536    ignore_unavailable
1537        Ignore unavailable snapshots
1538
1539    CLI Example:
1540
1541    .. code-block:: bash
1542
1543        salt myminion elasticsearch.snapshot_status ignore_unavailable=True
1544    """
1545    es = _get_instance(hosts, profile)
1546
1547    try:
1548        return es.snapshot.status(
1549            repository=repository,
1550            snapshot=snapshot,
1551            ignore_unavailable=ignore_unavailable,
1552        )
1553    except elasticsearch.TransportError as e:
1554        raise CommandExecutionError(
1555            "Cannot obtain snapshot status, server returned code {} with message {}".format(
1556                e.status_code, e.error
1557            )
1558        )
1559
1560
1561def snapshot_get(
1562    repository, snapshot, ignore_unavailable=False, hosts=None, profile=None
1563):
1564    """
1565    .. versionadded:: 2017.7.0
1566
1567    Obtain snapshot residing in specified repository.
1568
1569    repository
1570        Repository name
1571    snapshot
1572        Snapshot name, use _all to obtain all snapshots in specified repository
1573    ignore_unavailable
1574        Ignore unavailable snapshots
1575
1576    CLI Example:
1577
1578    .. code-block:: bash
1579
1580        salt myminion elasticsearch.snapshot_get testrepo testsnapshot
1581    """
1582    es = _get_instance(hosts, profile)
1583
1584    try:
1585        return es.snapshot.get(
1586            repository=repository,
1587            snapshot=snapshot,
1588            ignore_unavailable=ignore_unavailable,
1589        )
1590    except elasticsearch.TransportError as e:
1591        raise CommandExecutionError(
1592            "Cannot obtain details of snapshot {} in repository {}, server returned"
1593            " code {} with message {}".format(
1594                snapshot, repository, e.status_code, e.error
1595            )
1596        )
1597
1598
1599def snapshot_create(repository, snapshot, body=None, hosts=None, profile=None):
1600    """
1601    .. versionadded:: 2017.7.0
1602
1603    Create snapshot in specified repository by supplied definition.
1604
1605    repository
1606        Repository name
1607    snapshot
1608        Snapshot name
1609    body
1610        Snapshot definition as in https://www.elastic.co/guide/en/elasticsearch/reference/current/modules-snapshots.html
1611
1612    CLI Example:
1613
1614    .. code-block:: bash
1615
1616        salt myminion elasticsearch.snapshot_create testrepo testsnapshot '{"indices":"index_1,index_2","ignore_unavailable":true,"include_global_state":false}'
1617    """
1618    es = _get_instance(hosts, profile)
1619
1620    try:
1621        response = es.snapshot.create(
1622            repository=repository, snapshot=snapshot, body=body
1623        )
1624
1625        return response.get("accepted", False)
1626    except elasticsearch.TransportError as e:
1627        raise CommandExecutionError(
1628            "Cannot create snapshot {} in repository {}, server returned code {} with"
1629            " message {}".format(snapshot, repository, e.status_code, e.error)
1630        )
1631
1632
1633def snapshot_restore(repository, snapshot, body=None, hosts=None, profile=None):
1634    """
1635    .. versionadded:: 2017.7.0
1636
1637    Restore existing snapshot in specified repository by supplied definition.
1638
1639    repository
1640        Repository name
1641    snapshot
1642        Snapshot name
1643    body
1644        Restore definition as in https://www.elastic.co/guide/en/elasticsearch/reference/current/modules-snapshots.html
1645
1646    CLI Example:
1647
1648    .. code-block:: bash
1649
1650        salt myminion elasticsearch.snapshot_restore testrepo testsnapshot '{"indices":"index_1,index_2","ignore_unavailable":true,"include_global_state":true}'
1651    """
1652    es = _get_instance(hosts, profile)
1653
1654    try:
1655        response = es.snapshot.restore(
1656            repository=repository, snapshot=snapshot, body=body
1657        )
1658
1659        return response.get("accepted", False)
1660    except elasticsearch.TransportError as e:
1661        raise CommandExecutionError(
1662            "Cannot restore snapshot {} in repository {}, server returned code {} with"
1663            " message {}".format(snapshot, repository, e.status_code, e.error)
1664        )
1665
1666
1667def snapshot_delete(repository, snapshot, hosts=None, profile=None):
1668    """
1669    .. versionadded:: 2017.7.0
1670
1671    Delete snapshot from specified repository.
1672
1673    repository
1674        Repository name
1675    snapshot
1676        Snapshot name
1677
1678    CLI Example:
1679
1680    .. code-block:: bash
1681
1682        salt myminion elasticsearch.snapshot_delete testrepo testsnapshot
1683    """
1684    es = _get_instance(hosts, profile)
1685
1686    try:
1687        result = es.snapshot.delete(repository=repository, snapshot=snapshot)
1688
1689        return result.get("acknowledged", False)
1690    except elasticsearch.NotFoundError:
1691        return True
1692    except elasticsearch.TransportError as e:
1693        raise CommandExecutionError(
1694            "Cannot delete snapshot {} from repository {}, server returned code {} with"
1695            " message {}".format(snapshot, repository, e.status_code, e.error)
1696        )
1697
1698
1699def flush_synced(hosts=None, profile=None, **kwargs):
1700    """
1701    .. versionadded:: 3000
1702
1703    Perform a normal flush, then add a generated unique marker (sync_id) to all shards.
1704    http://www.elastic.co/guide/en/elasticsearch/reference/current/indices-synced-flush.html
1705
1706    index
1707        (Optional, string) A comma-separated list of index names; use _all or empty string for all indices. Defaults to '_all'.
1708
1709    ignore_unavailable
1710        (Optional, boolean) If true, missing or closed indices are not included in the response. Defaults to false.
1711
1712    allow_no_indices
1713        (Optional, boolean) If true, the request does not return an error if a wildcard expression or _all value retrieves only missing or closed indices.
1714        This parameter also applies to index aliases that point to a missing or closed index.
1715
1716    expand_wildcards
1717        (Optional, string) Controls what kind of indices that wildcard expressions can expand to.
1718
1719        Valid values are::
1720
1721            all - Expand to open and closed indices.
1722            open - Expand only to open indices.
1723            closed - Expand only to closed indices.
1724            none - Wildcard expressions are not accepted.
1725
1726    The defaults settings for the above parameters depend on the API being used.
1727
1728    CLI Example:
1729
1730    .. code-block:: bash
1731
1732        salt myminion elasticsearch.flush_synced index='index1,index2' ignore_unavailable=True allow_no_indices=True expand_wildcards='all'
1733    """
1734    es = _get_instance(hosts, profile)
1735
1736    try:
1737        return es.indices.flush_synced(kwargs)
1738    except elasticsearch.TransportError as e:
1739        raise CommandExecutionError(
1740            "Cannot flush synced, server returned code {} with message {}".format(
1741                e.status_code, e.error
1742            )
1743        )
1744