1""" 2Connection module for Amazon Elasticsearch Service 3 4.. versionadded:: 3001 5 6:configuration: This module accepts explicit IAM credentials but can also 7 utilize IAM roles assigned to the instance trough Instance Profiles. 8 Dynamic credentials are then automatically obtained from AWS API and no 9 further configuration is necessary. More Information available at: 10 11 .. code-block:: text 12 13 http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/iam-roles-for-amazon-ec2.html 14 15 If IAM roles are not used you need to specify them either in a pillar or 16 in the minion's config file: 17 18 .. code-block:: yaml 19 20 es.keyid: GKTADJGHEIQSXMKKRBJ08H 21 es.key: askdjghsdfjkghWupUjasdflkdfklgjsdfjajkghs 22 23 A region may also be specified in the configuration: 24 25 .. code-block:: yaml 26 27 es.region: us-east-1 28 29 If a region is not specified, the default is us-east-1. 30 31 It's also possible to specify key, keyid and region via a profile, either 32 as a passed in dict, or as a string to pull from pillars or minion config: 33 34 .. code-block:: yaml 35 36 myprofile: 37 keyid: GKTADJGHEIQSXMKKRBJ08H 38 key: askdjghsdfjkghWupUjasdflkdfklgjsdfjajkghs 39 region: us-east-1 40 41 All methods return a dict with: 42 'result' key containing a boolean indicating success or failure, 43 'error' key containing the errormessage returned by boto on error, 44 'response' key containing the data of the response returned by boto on success. 45 46:codeauthor: Herbert Buurman <herbert.buurman@ogd.nl> 47:depends: boto3 48""" 49# keep lint from choking on _get_conn and _cache_id 50# pylint: disable=E0602 51 52 53import logging 54 55import salt.utils.compat 56import salt.utils.json 57import salt.utils.versions 58from salt.exceptions import SaltInvocationError 59from salt.utils.decorators import depends 60 61try: 62 # Disable unused import-errors as these are only used for dependency checking 63 # pylint: disable=unused-import 64 import boto3 65 import botocore 66 67 # pylint: enable=unused-import 68 from botocore.exceptions import ClientError, ParamValidationError, WaiterError 69 70 logging.getLogger("boto3").setLevel(logging.INFO) 71 HAS_BOTO = True 72except ImportError: 73 HAS_BOTO = False 74 75log = logging.getLogger(__name__) 76 77 78def __virtual__(): 79 """ 80 Only load if boto libraries exist and if boto libraries are greater than 81 a given version. 82 """ 83 return HAS_BOTO and salt.utils.versions.check_boto_reqs( 84 boto3_ver="1.2.7", check_boto=False 85 ) 86 87 88def __init__(opts): 89 _ = opts 90 if HAS_BOTO: 91 __utils__["boto3.assign_funcs"](__name__, "es") 92 93 94def add_tags( 95 domain_name=None, 96 arn=None, 97 tags=None, 98 region=None, 99 key=None, 100 keyid=None, 101 profile=None, 102): 103 """ 104 Attaches tags to an existing Elasticsearch domain. 105 Tags are a set of case-sensitive key value pairs. 106 An Elasticsearch domain may have up to 10 tags. 107 108 :param str domain_name: The name of the Elasticsearch domain you want to add tags to. 109 :param str arn: The ARN of the Elasticsearch domain you want to add tags to. 110 Specifying this overrides ``domain_name``. 111 :param dict tags: The dict of tags to add to the Elasticsearch domain. 112 113 :rtype: dict 114 :return: Dictionary with key 'result' and as value a boolean denoting success or failure. 115 Upon failure, also contains a key 'error' with the error message as value. 116 117 .. versionadded:: 3001 118 119 CLI Example: 120 121 .. code-block:: bash 122 123 salt myminion boto3_elasticsearch.add_tags domain_name=mydomain tags='{"foo": "bar", "baz": "qux"}' 124 """ 125 if not any((arn, domain_name)): 126 raise SaltInvocationError( 127 "At least one of domain_name or arn must be specified." 128 ) 129 ret = {"result": False} 130 if arn is None: 131 res = describe_elasticsearch_domain( 132 domain_name=domain_name, 133 region=region, 134 key=key, 135 keyid=keyid, 136 profile=profile, 137 ) 138 if "error" in res: 139 ret.update(res) 140 elif not res["result"]: 141 ret.update( 142 { 143 "error": 'The domain with name "{}" does not exist.'.format( 144 domain_name 145 ) 146 } 147 ) 148 else: 149 arn = res["response"].get("ARN") 150 if arn: 151 boto_params = { 152 "ARN": arn, 153 "TagList": [ 154 {"Key": k, "Value": value} for k, value in (tags or {}).items() 155 ], 156 } 157 try: 158 conn = _get_conn(region=region, key=key, keyid=keyid, profile=profile) 159 conn.add_tags(**boto_params) 160 ret["result"] = True 161 except (ParamValidationError, ClientError) as exp: 162 ret.update({"error": __utils__["boto3.get_error"](exp)["message"]}) 163 return ret 164 165 166@depends("botocore", version="1.12.21") 167def cancel_elasticsearch_service_software_update( 168 domain_name, region=None, keyid=None, key=None, profile=None 169): 170 """ 171 Cancels a scheduled service software update for an Amazon ES domain. You can 172 only perform this operation before the AutomatedUpdateDate and when the UpdateStatus 173 is in the PENDING_UPDATE state. 174 175 :param str domain_name: The name of the domain that you want to stop the latest 176 service software update on. 177 178 :rtype: dict 179 :return: Dictionary with key 'result' and as value a boolean denoting success or failure. 180 Upon success, also contains a key 'reponse' with the current service software options. 181 Upon failure, also contains a key 'error' with the error message as value. 182 183 .. versionadded:: 3001 184 185 """ 186 ret = {"result": False} 187 try: 188 conn = _get_conn(region=region, keyid=keyid, key=key, profile=profile) 189 res = conn.cancel_elasticsearch_service_software_update(DomainName=domain_name) 190 ret["result"] = True 191 res["response"] = res["ServiceSoftwareOptions"] 192 except (ParamValidationError, ClientError) as exp: 193 ret.update({"error": __utils__["boto3.get_error"](exp)["message"]}) 194 return ret 195 196 197def create_elasticsearch_domain( 198 domain_name, 199 elasticsearch_version=None, 200 elasticsearch_cluster_config=None, 201 ebs_options=None, 202 access_policies=None, 203 snapshot_options=None, 204 vpc_options=None, 205 cognito_options=None, 206 encryption_at_rest_options=None, 207 node_to_node_encryption_options=None, 208 advanced_options=None, 209 log_publishing_options=None, 210 blocking=False, 211 region=None, 212 key=None, 213 keyid=None, 214 profile=None, 215): 216 """ 217 Given a valid config, create a domain. 218 219 :param str domain_name: The name of the Elasticsearch domain that you are creating. 220 Domain names are unique across the domains owned by an account within an 221 AWS region. Domain names must start with a letter or number and can contain 222 the following characters: a-z (lowercase), 0-9, and - (hyphen). 223 :param str elasticsearch_version: String of format X.Y to specify version for 224 the Elasticsearch domain eg. "1.5" or "2.3". 225 :param dict elasticsearch_cluster_config: Dictionary specifying the configuration 226 options for an Elasticsearch domain. Keys (case sensitive) in here are: 227 228 - InstanceType (str): The instance type for an Elasticsearch cluster. 229 - InstanceCount (int): The instance type for an Elasticsearch cluster. 230 - DedicatedMasterEnabled (bool): Indicate whether a dedicated master 231 node is enabled. 232 - ZoneAwarenessEnabled (bool): Indicate whether zone awareness is enabled. 233 If this is not enabled, the Elasticsearch domain will only be in one 234 availability zone. 235 - ZoneAwarenessConfig (dict): Specifies the zone awareness configuration 236 for a domain when zone awareness is enabled. 237 Keys (case sensitive) in here are: 238 239 - AvailabilityZoneCount (int): An integer value to indicate the 240 number of availability zones for a domain when zone awareness is 241 enabled. This should be equal to number of subnets if VPC endpoints 242 is enabled. Allowed values: 2, 3 243 244 - DedicatedMasterType (str): The instance type for a dedicated master node. 245 - DedicatedMasterCount (int): Total number of dedicated master nodes, 246 active and on standby, for the cluster. 247 :param dict ebs_options: Dict specifying the options to enable or disable and 248 specifying the type and size of EBS storage volumes. 249 Keys (case sensitive) in here are: 250 251 - EBSEnabled (bool): Specifies whether EBS-based storage is enabled. 252 - VolumeType (str): Specifies the volume type for EBS-based storage. 253 - VolumeSize (int): Integer to specify the size of an EBS volume. 254 - Iops (int): Specifies the IOPD for a Provisioned IOPS EBS volume (SSD). 255 :type access_policies: str or dict 256 :param access_policies: Dict or JSON string with the IAM access policy. 257 :param dict snapshot_options: Dict specifying the snapshot options. 258 Keys (case sensitive) in here are: 259 260 - AutomatedSnapshotStartHour (int): Specifies the time, in UTC format, 261 when the service takes a daily automated snapshot of the specified 262 Elasticsearch domain. Default value is 0 hours. 263 :param dict vpc_options: Dict with the options to specify the subnets and security 264 groups for the VPC endpoint. 265 Keys (case sensitive) in here are: 266 267 - SubnetIds (list): The list of subnets for the VPC endpoint. 268 - SecurityGroupIds (list): The list of security groups for the VPC endpoint. 269 :param dict cognito_options: Dict with options to specify the cognito user and 270 identity pools for Kibana authentication. 271 Keys (case sensitive) in here are: 272 273 - Enabled (bool): Specifies the option to enable Cognito for Kibana authentication. 274 - UserPoolId (str): Specifies the Cognito user pool ID for Kibana authentication. 275 - IdentityPoolId (str): Specifies the Cognito identity pool ID for Kibana authentication. 276 - RoleArn (str): Specifies the role ARN that provides Elasticsearch permissions 277 for accessing Cognito resources. 278 :param dict encryption_at_rest_options: Dict specifying the encryption at rest 279 options. Keys (case sensitive) in here are: 280 281 - Enabled (bool): Specifies the option to enable Encryption At Rest. 282 - KmsKeyId (str): Specifies the KMS Key ID for Encryption At Rest options. 283 :param dict node_to_node_encryption_options: Dict specifying the node to node 284 encryption options. Keys (case sensitive) in here are: 285 286 - Enabled (bool): Specify True to enable node-to-node encryption. 287 :param dict advanced_options: Dict with option to allow references to indices 288 in an HTTP request body. Must be False when configuring access to individual 289 sub-resources. By default, the value is True. 290 See http://docs.aws.amazon.com/elasticsearch-service/latest/developerguide\ 291 /es-createupdatedomains.html#es-createdomain-configure-advanced-options 292 for more information. 293 :param dict log_publishing_options: Dict with options for various type of logs. 294 The keys denote the type of log file and can be one of the following: 295 296 - INDEX_SLOW_LOGS 297 - SEARCH_SLOW_LOGS 298 - ES_APPLICATION_LOGS 299 300 The value assigned to each key is a dict with the following case sensitive keys: 301 302 - CloudWatchLogsLogGroupArn (str): The ARN of the Cloudwatch log 303 group to which the log needs to be published. 304 - Enabled (bool): Specifies whether given log publishing option is enabled or not. 305 :param bool blocking: Whether or not to wait (block) until the Elasticsearch 306 domain has been created. 307 308 Note: Not all instance types allow enabling encryption at rest. See https://docs.aws.amazon.com\ 309 /elasticsearch-service/latest/developerguide/aes-supported-instance-types.html 310 311 :rtype: dict 312 :return: Dictionary with key 'result' and as value a boolean denoting success or failure. 313 Upon success, also contains a key 'reponse' with the domain status configuration. 314 Upon failure, also contains a key 'error' with the error message as value. 315 316 .. versionadded:: 3001 317 318 CLI Example: 319 320 .. code-block:: bash 321 322 salt myminion boto3_elasticsearch.create_elasticsearch_domain mydomain \\ 323 elasticsearch_cluster_config='{ \\ 324 "InstanceType": "t2.micro.elasticsearch", \\ 325 "InstanceCount": 1, \\ 326 "DedicatedMasterEnabled": False, \\ 327 "ZoneAwarenessEnabled": False}' \\ 328 ebs_options='{ \\ 329 "EBSEnabled": True, \\ 330 "VolumeType": "gp2", \\ 331 "VolumeSize": 10, \\ 332 "Iops": 0}' \\ 333 access_policies='{ \\ 334 "Version": "2012-10-17", \\ 335 "Statement": [ \\ 336 {"Effect": "Allow", \\ 337 "Principal": {"AWS": "*"}, \\ 338 "Action": "es:*", \\ 339 "Resource": "arn:aws:es:us-east-1:111111111111:domain/mydomain/*", \\ 340 "Condition": {"IpAddress": {"aws:SourceIp": ["127.0.0.1"]}}}]}' \\ 341 snapshot_options='{"AutomatedSnapshotStartHour": 0}' \\ 342 advanced_options='{"rest.action.multi.allow_explicit_index": "true"}' 343 """ 344 boto_kwargs = salt.utils.data.filter_falsey( 345 { 346 "DomainName": domain_name, 347 "ElasticsearchVersion": str(elasticsearch_version or ""), 348 "ElasticsearchClusterConfig": elasticsearch_cluster_config, 349 "EBSOptions": ebs_options, 350 "AccessPolicies": ( 351 salt.utils.json.dumps(access_policies) 352 if isinstance(access_policies, dict) 353 else access_policies 354 ), 355 "SnapshotOptions": snapshot_options, 356 "VPCOptions": vpc_options, 357 "CognitoOptions": cognito_options, 358 "EncryptionAtRestOptions": encryption_at_rest_options, 359 "NodeToNodeEncryptionOptions": node_to_node_encryption_options, 360 "AdvancedOptions": advanced_options, 361 "LogPublishingOptions": log_publishing_options, 362 } 363 ) 364 ret = {"result": False} 365 try: 366 conn = _get_conn(region=region, key=key, keyid=keyid, profile=profile) 367 res = conn.create_elasticsearch_domain(**boto_kwargs) 368 if res and "DomainStatus" in res: 369 ret["result"] = True 370 ret["response"] = res["DomainStatus"] 371 if blocking: 372 conn.get_waiter("ESDomainAvailable").wait(DomainName=domain_name) 373 except (ParamValidationError, ClientError, WaiterError) as exp: 374 ret.update({"error": __utils__["boto3.get_error"](exp)["message"]}) 375 return ret 376 377 378def delete_elasticsearch_domain( 379 domain_name, blocking=False, region=None, key=None, keyid=None, profile=None 380): 381 """ 382 Permanently deletes the specified Elasticsearch domain and all of its data. 383 Once a domain is deleted, it cannot be recovered. 384 385 :param str domain_name: The name of the domain to delete. 386 :param bool blocking: Whether or not to wait (block) until the Elasticsearch 387 domain has been deleted. 388 389 :rtype: dict 390 :return: Dictionary with key 'result' and as value a boolean denoting success or failure. 391 Upon failure, also contains a key 'error' with the error message as value. 392 393 .. versionadded:: 3001 394 395 """ 396 ret = {"result": False} 397 try: 398 conn = _get_conn(region=region, key=key, keyid=keyid, profile=profile) 399 conn.delete_elasticsearch_domain(DomainName=domain_name) 400 ret["result"] = True 401 if blocking: 402 conn.get_waiter("ESDomainDeleted").wait(DomainName=domain_name) 403 except (ParamValidationError, ClientError, WaiterError) as exp: 404 ret.update({"error": __utils__["boto3.get_error"](exp)["message"]}) 405 return ret 406 407 408@depends("botocore", version="1.7.30") 409def delete_elasticsearch_service_role(region=None, keyid=None, key=None, profile=None): 410 """ 411 Deletes the service-linked role that Elasticsearch Service uses to manage and 412 maintain VPC domains. Role deletion will fail if any existing VPC domains use 413 the role. You must delete any such Elasticsearch domains before deleting the role. 414 415 :rtype: dict 416 :return: Dictionary with key 'result' and as value a boolean denoting success or failure. 417 Upon failure, also contains a key 'error' with the error message as value. 418 419 .. versionadded:: 3001 420 421 """ 422 ret = {"result": False} 423 try: 424 conn = _get_conn(region=region, keyid=keyid, key=key, profile=profile) 425 conn.delete_elasticsearch_service_role() 426 ret["result"] = True 427 except (ParamValidationError, ClientError) as exp: 428 ret.update({"error": __utils__["boto3.get_error"](exp)["message"]}) 429 return ret 430 431 432def describe_elasticsearch_domain( 433 domain_name, region=None, keyid=None, key=None, profile=None 434): 435 """ 436 Given a domain name gets its status description. 437 438 :param str domain_name: The name of the domain to get the status of. 439 440 :rtype: dict 441 :return: Dictionary ith key 'result' and as value a boolean denoting success or failure. 442 Upon success, also contains a key 'reponse' with the domain status information. 443 Upon failure, also contains a key 'error' with the error message as value. 444 445 .. versionadded:: 3001 446 447 """ 448 ret = {"result": False} 449 try: 450 conn = _get_conn(region=region, key=key, keyid=keyid, profile=profile) 451 res = conn.describe_elasticsearch_domain(DomainName=domain_name) 452 if res and "DomainStatus" in res: 453 ret["result"] = True 454 ret["response"] = res["DomainStatus"] 455 except (ParamValidationError, ClientError) as exp: 456 ret.update({"error": __utils__["boto3.get_error"](exp)["message"]}) 457 return ret 458 459 460def describe_elasticsearch_domain_config( 461 domain_name, region=None, keyid=None, key=None, profile=None 462): 463 """ 464 Provides cluster configuration information about the specified Elasticsearch domain, 465 such as the state, creation date, update version, and update date for cluster options. 466 467 :param str domain_name: The name of the domain to describe. 468 469 :rtype: dict 470 :return: Dictionary with key 'result' and as value a boolean denoting success or failure. 471 Upon success, also contains a key 'reponse' with the current configuration information. 472 Upon failure, also contains a key 'error' with the error message as value. 473 474 .. versionadded:: 3001 475 476 """ 477 ret = {"result": False} 478 try: 479 conn = _get_conn(region=region, key=key, keyid=keyid, profile=profile) 480 res = conn.describe_elasticsearch_domain_config(DomainName=domain_name) 481 if res and "DomainConfig" in res: 482 ret["result"] = True 483 ret["response"] = res["DomainConfig"] 484 except (ParamValidationError, ClientError) as exp: 485 ret.update({"error": __utils__["boto3.get_error"](exp)["message"]}) 486 return ret 487 488 489def describe_elasticsearch_domains( 490 domain_names, region=None, keyid=None, key=None, profile=None 491): 492 """ 493 Returns domain configuration information about the specified Elasticsearch 494 domains, including the domain ID, domain endpoint, and domain ARN. 495 496 :param list domain_names: List of domain names to get information for. 497 498 :rtype: dict 499 :return: Dictionary with key 'result' and as value a boolean denoting success or failure. 500 Upon success, also contains a key 'reponse' with the list of domain status information. 501 Upon failure, also contains a key 'error' with the error message as value. 502 503 .. versionadded:: 3001 504 505 CLI Example: 506 507 .. code-block:: bash 508 509 salt myminion boto3_elasticsearch.describe_elasticsearch_domains '["domain_a", "domain_b"]' 510 """ 511 ret = {"result": False} 512 try: 513 conn = _get_conn(region=region, keyid=keyid, key=key, profile=profile) 514 res = conn.describe_elasticsearch_domains(DomainNames=domain_names) 515 if res and "DomainStatusList" in res: 516 ret["result"] = True 517 ret["response"] = res["DomainStatusList"] 518 except (ParamValidationError, ClientError) as exp: 519 ret.update({"error": __utils__["boto3.get_error"](exp)["message"]}) 520 return ret 521 522 523@depends("botocore", version="1.5.18") 524def describe_elasticsearch_instance_type_limits( 525 instance_type, 526 elasticsearch_version, 527 domain_name=None, 528 region=None, 529 keyid=None, 530 key=None, 531 profile=None, 532): 533 """ 534 Describe Elasticsearch Limits for a given InstanceType and ElasticsearchVersion. 535 When modifying existing Domain, specify the `` DomainName `` to know what Limits 536 are supported for modifying. 537 538 :param str instance_type: The instance type for an Elasticsearch cluster for 539 which Elasticsearch ``Limits`` are needed. 540 :param str elasticsearch_version: Version of Elasticsearch for which ``Limits`` 541 are needed. 542 :param str domain_name: Represents the name of the Domain that we are trying 543 to modify. This should be present only if we are querying for Elasticsearch 544 ``Limits`` for existing domain. 545 546 :rtype: dict 547 :return: Dictionary with key 'result' and as value a boolean denoting success or failure. 548 Upon success, also contains a key 'reponse' with the limits information. 549 Upon failure, also contains a key 'error' with the error message as value. 550 551 .. versionadded:: 3001 552 553 CLI Example: 554 555 .. code-block:: bash 556 557 salt myminion boto3_elasticsearch.describe_elasticsearch_instance_type_limits \\ 558 instance_type=r3.8xlarge.elasticsearch \\ 559 elasticsearch_version='6.2' 560 """ 561 ret = {"result": False} 562 boto_params = salt.utils.data.filter_falsey( 563 { 564 "DomainName": domain_name, 565 "InstanceType": instance_type, 566 "ElasticsearchVersion": str(elasticsearch_version), 567 } 568 ) 569 try: 570 conn = _get_conn(region=region, keyid=keyid, key=key, profile=profile) 571 res = conn.describe_elasticsearch_instance_type_limits(**boto_params) 572 if res and "LimitsByRole" in res: 573 ret["result"] = True 574 ret["response"] = res["LimitsByRole"] 575 except (ParamValidationError, ClientError) as exp: 576 ret.update({"error": __utils__["boto3.get_error"](exp)["message"]}) 577 return ret 578 579 580@depends("botocore", version="1.10.15") 581def describe_reserved_elasticsearch_instance_offerings( 582 reserved_elasticsearch_instance_offering_id=None, 583 region=None, 584 keyid=None, 585 key=None, 586 profile=None, 587): 588 """ 589 Lists available reserved Elasticsearch instance offerings. 590 591 :param str reserved_elasticsearch_instance_offering_id: The offering identifier 592 filter value. Use this parameter to show only the available offering that 593 matches the specified reservation identifier. 594 595 :rtype: dict 596 :return: Dictionary with key 'result' and as value a boolean denoting success or failure. 597 Upon success, also contains a key 'reponse' with the list of offerings information. 598 Upon failure, also contains a key 'error' with the error message as value. 599 600 .. versionadded:: 3001 601 602 """ 603 ret = {"result": False} 604 try: 605 conn = _get_conn(region=region, keyid=keyid, key=key, profile=profile) 606 boto_params = { 607 "ReservedElasticsearchInstanceOfferingId": reserved_elasticsearch_instance_offering_id 608 } 609 res = [] 610 for page in conn.get_paginator( 611 "describe_reserved_elasticsearch_instance_offerings" 612 ).paginate(**boto_params): 613 res.extend(page["ReservedElasticsearchInstanceOfferings"]) 614 if res: 615 ret["result"] = True 616 ret["response"] = res 617 except (ParamValidationError, ClientError) as exp: 618 ret.update({"error": __utils__["boto3.get_error"](exp)["message"]}) 619 return ret 620 621 622@depends("botocore", version="1.10.15") 623def describe_reserved_elasticsearch_instances( 624 reserved_elasticsearch_instance_id=None, 625 region=None, 626 keyid=None, 627 key=None, 628 profile=None, 629): 630 """ 631 Returns information about reserved Elasticsearch instances for this account. 632 633 :param str reserved_elasticsearch_instance_id: The reserved instance identifier 634 filter value. Use this parameter to show only the reservation that matches 635 the specified reserved Elasticsearch instance ID. 636 637 :rtype: dict 638 :return: Dictionary with key 'result' and as value a boolean denoting success or failure. 639 Upon success, also contains a key 'reponse' with a list of information on 640 reserved instances. 641 Upon failure, also contains a key 'error' with the error message as value. 642 643 :note: Version 1.9.174 of boto3 has a bug in that reserved_elasticsearch_instance_id 644 is considered a required argument, even though the documentation says otherwise. 645 646 .. versionadded:: 3001 647 648 """ 649 ret = {"result": False} 650 try: 651 conn = _get_conn(region=region, keyid=keyid, key=key, profile=profile) 652 boto_params = { 653 "ReservedElasticsearchInstanceId": reserved_elasticsearch_instance_id, 654 } 655 res = [] 656 for page in conn.get_paginator( 657 "describe_reserved_elasticsearch_instances" 658 ).paginate(**boto_params): 659 res.extend(page["ReservedElasticsearchInstances"]) 660 if res: 661 ret["result"] = True 662 ret["response"] = res 663 except (ParamValidationError, ClientError) as exp: 664 ret.update({"error": __utils__["boto3.get_error"](exp)["message"]}) 665 return ret 666 667 668@depends("botocore", version="1.10.77") 669def get_compatible_elasticsearch_versions( 670 domain_name=None, region=None, keyid=None, key=None, profile=None 671): 672 """ 673 Returns a list of upgrade compatible Elastisearch versions. You can optionally 674 pass a ``domain_name`` to get all upgrade compatible Elasticsearch versions 675 for that specific domain. 676 677 :param str domain_name: The name of an Elasticsearch domain. 678 679 :rtype: dict 680 :return: Dictionary with key 'result' and as value a boolean denoting success or failure. 681 Upon success, also contains a key 'reponse' with a list of compatible versions. 682 Upon failure, also contains a key 'error' with the error message as value. 683 684 .. versionadded:: 3001 685 686 """ 687 ret = {"result": False} 688 boto_params = salt.utils.data.filter_falsey({"DomainName": domain_name}) 689 try: 690 conn = _get_conn(region=region, keyid=keyid, key=key, profile=profile) 691 res = conn.get_compatible_elasticsearch_versions(**boto_params) 692 if res and "CompatibleElasticsearchVersions" in res: 693 ret["result"] = True 694 ret["response"] = res["CompatibleElasticsearchVersions"] 695 except (ParamValidationError, ClientError) as exp: 696 ret.update({"error": __utils__["boto3.get_error"](exp)["message"]}) 697 return ret 698 699 700@depends("botocore", version="1.10.77") 701def get_upgrade_history(domain_name, region=None, keyid=None, key=None, profile=None): 702 """ 703 Retrieves the complete history of the last 10 upgrades that were performed on the domain. 704 705 :param str domain_name: The name of an Elasticsearch domain. Domain names are 706 unique across the domains owned by an account within an AWS region. Domain 707 names start with a letter or number and can contain the following characters: 708 a-z (lowercase), 0-9, and - (hyphen). 709 710 :rtype: dict 711 :return: Dictionary with key 'result' and as value a boolean denoting success or failure. 712 Upon success, also contains a key 'reponse' with a list of upgrade histories. 713 Upon failure, also contains a key 'error' with the error message as value. 714 715 .. versionadded:: 3001 716 717 """ 718 ret = {"result": False} 719 try: 720 conn = _get_conn(region=region, keyid=keyid, key=key, profile=profile) 721 boto_params = {"DomainName": domain_name} 722 res = [] 723 for page in conn.get_paginator("get_upgrade_history").paginate(**boto_params): 724 res.extend(page["UpgradeHistories"]) 725 if res: 726 ret["result"] = True 727 ret["response"] = res 728 except (ParamValidationError, ClientError) as exp: 729 ret.update({"error": __utils__["boto3.get_error"](exp)["message"]}) 730 return ret 731 732 733@depends("botocore", version="1.10.77") 734def get_upgrade_status(domain_name, region=None, keyid=None, key=None, profile=None): 735 """ 736 Retrieves the latest status of the last upgrade or upgrade eligibility check 737 that was performed on the domain. 738 739 :param str domain_name: The name of an Elasticsearch domain. Domain names are 740 unique across the domains owned by an account within an AWS region. Domain 741 names start with a letter or number and can contain the following characters: 742 a-z (lowercase), 0-9, and - (hyphen). 743 744 :rtype: dict 745 :return: Dictionary with key 'result' and as value a boolean denoting success or failure. 746 Upon success, also contains a key 'reponse' with upgrade status information. 747 Upon failure, also contains a key 'error' with the error message as value. 748 749 .. versionadded:: 3001 750 751 """ 752 ret = {"result": False} 753 boto_params = {"DomainName": domain_name} 754 try: 755 conn = _get_conn(region=region, keyid=keyid, key=key, profile=profile) 756 res = conn.get_upgrade_status(**boto_params) 757 ret["result"] = True 758 ret["response"] = res 759 del res["ResponseMetadata"] 760 except (ParamValidationError, ClientError) as exp: 761 ret.update({"error": __utils__["boto3.get_error"](exp)["message"]}) 762 return ret 763 764 765def list_domain_names(region=None, keyid=None, key=None, profile=None): 766 """ 767 Returns the name of all Elasticsearch domains owned by the current user's account. 768 769 :rtype: dict 770 :return: Dictionary with key 'result' and as value a boolean denoting success or failure. 771 Upon success, also contains a key 'reponse' with a list of domain names. 772 Upon failure, also contains a key 'error' with the error message as value. 773 774 .. versionadded:: 3001 775 776 """ 777 ret = {"result": False} 778 try: 779 conn = _get_conn(region=region, keyid=keyid, key=key, profile=profile) 780 res = conn.list_domain_names() 781 if res and "DomainNames" in res: 782 ret["result"] = True 783 ret["response"] = [item["DomainName"] for item in res["DomainNames"]] 784 except (ParamValidationError, ClientError) as exp: 785 ret.update({"error": __utils__["boto3.get_error"](exp)["message"]}) 786 return ret 787 788 789@depends("botocore", version="1.5.18") 790def list_elasticsearch_instance_types( 791 elasticsearch_version, 792 domain_name=None, 793 region=None, 794 keyid=None, 795 key=None, 796 profile=None, 797): 798 """ 799 List all Elasticsearch instance types that are supported for given ElasticsearchVersion. 800 801 :param str elasticsearch_version: Version of Elasticsearch for which list of 802 supported elasticsearch instance types are needed. 803 :param str domain_name: DomainName represents the name of the Domain that we 804 are trying to modify. This should be present only if we are querying for 805 list of available Elasticsearch instance types when modifying existing domain. 806 807 :rtype: dict 808 :return: Dictionary with key 'result' and as value a boolean denoting success or failure. 809 Upon success, also contains a key 'reponse' with a list of Elasticsearch instance types. 810 Upon failure, also contains a key 'error' with the error message as value. 811 812 .. versionadded:: 3001 813 814 """ 815 ret = {"result": False} 816 try: 817 conn = _get_conn(region=region, keyid=keyid, key=key, profile=profile) 818 boto_params = salt.utils.data.filter_falsey( 819 { 820 "ElasticsearchVersion": str(elasticsearch_version), 821 "DomainName": domain_name, 822 } 823 ) 824 res = [] 825 for page in conn.get_paginator("list_elasticsearch_instance_types").paginate( 826 **boto_params 827 ): 828 res.extend(page["ElasticsearchInstanceTypes"]) 829 if res: 830 ret["result"] = True 831 ret["response"] = res 832 except (ParamValidationError, ClientError) as exp: 833 ret.update({"error": __utils__["boto3.get_error"](exp)["message"]}) 834 return ret 835 836 837@depends("botocore", version="1.5.18") 838def list_elasticsearch_versions(region=None, keyid=None, key=None, profile=None): 839 """ 840 List all supported Elasticsearch versions. 841 842 :rtype: dict 843 :return: Dictionary with key 'result' and as value a boolean denoting success or failure. 844 Upon success, also contains a key 'reponse' with a list of Elasticsearch versions. 845 Upon failure, also contains a key 'error' with the error message as value. 846 847 .. versionadded:: 3001 848 849 """ 850 ret = {"result": False} 851 try: 852 conn = _get_conn(region=region, keyid=keyid, key=key, profile=profile) 853 res = [] 854 for page in conn.get_paginator("list_elasticsearch_versions").paginate(): 855 res.extend(page["ElasticsearchVersions"]) 856 if res: 857 ret["result"] = True 858 ret["response"] = res 859 except (ParamValidationError, ClientError) as exp: 860 ret.update({"error": __utils__["boto3.get_error"](exp)["message"]}) 861 return ret 862 863 864def list_tags( 865 domain_name=None, arn=None, region=None, key=None, keyid=None, profile=None 866): 867 """ 868 Returns all tags for the given Elasticsearch domain. 869 870 :rtype: dict 871 :return: Dictionary with key 'result' and as value a boolean denoting success or failure. 872 Upon success, also contains a key 'reponse' with a dict of tags. 873 Upon failure, also contains a key 'error' with the error message as value. 874 875 .. versionadded:: 3001 876 877 """ 878 if not any((arn, domain_name)): 879 raise SaltInvocationError( 880 "At least one of domain_name or arn must be specified." 881 ) 882 ret = {"result": False} 883 if arn is None: 884 res = describe_elasticsearch_domain( 885 domain_name=domain_name, 886 region=region, 887 key=key, 888 keyid=keyid, 889 profile=profile, 890 ) 891 if "error" in res: 892 ret.update(res) 893 elif not res["result"]: 894 ret.update( 895 { 896 "error": 'The domain with name "{}" does not exist.'.format( 897 domain_name 898 ) 899 } 900 ) 901 else: 902 arn = res["response"].get("ARN") 903 if arn: 904 try: 905 conn = _get_conn(region=region, key=key, keyid=keyid, profile=profile) 906 res = conn.list_tags(ARN=arn) 907 ret["result"] = True 908 ret["response"] = { 909 item["Key"]: item["Value"] for item in res.get("TagList", []) 910 } 911 except (ParamValidationError, ClientError) as exp: 912 ret.update({"error": __utils__["boto3.get_error"](exp)["message"]}) 913 return ret 914 915 916@depends("botocore", version="1.10.15") 917def purchase_reserved_elasticsearch_instance_offering( 918 reserved_elasticsearch_instance_offering_id, 919 reservation_name, 920 instance_count=None, 921 region=None, 922 keyid=None, 923 key=None, 924 profile=None, 925): 926 """ 927 Allows you to purchase reserved Elasticsearch instances. 928 929 :param str reserved_elasticsearch_instance_offering_id: The ID of the reserved 930 Elasticsearch instance offering to purchase. 931 :param str reservation_name: A customer-specified identifier to track this reservation. 932 :param int instance_count: The number of Elasticsearch instances to reserve. 933 934 :rtype: dict 935 :return: Dictionary with key 'result' and as value a boolean denoting success or failure. 936 Upon success, also contains a key 'reponse' with purchase information. 937 Upon failure, also contains a key 'error' with the error message as value. 938 939 .. versionadded:: 3001 940 941 """ 942 ret = {"result": False} 943 boto_params = salt.utils.data.filter_falsey( 944 { 945 "ReservedElasticsearchInstanceOfferingId": reserved_elasticsearch_instance_offering_id, 946 "ReservationName": reservation_name, 947 "InstanceCount": instance_count, 948 } 949 ) 950 try: 951 conn = _get_conn(region=region, keyid=keyid, key=key, profile=profile) 952 res = conn.purchase_reserved_elasticsearch_instance_offering(**boto_params) 953 if res: 954 ret["result"] = True 955 ret["response"] = res 956 except (ParamValidationError, ClientError) as exp: 957 ret.update({"error": __utils__["boto3.get_error"](exp)["message"]}) 958 return ret 959 960 961def remove_tags( 962 tag_keys, 963 domain_name=None, 964 arn=None, 965 region=None, 966 key=None, 967 keyid=None, 968 profile=None, 969): 970 """ 971 Removes the specified set of tags from the specified Elasticsearch domain. 972 973 :param list tag_keys: List with tag keys you want to remove from the Elasticsearch domain. 974 :param str domain_name: The name of the Elasticsearch domain you want to remove tags from. 975 :param str arn: The ARN of the Elasticsearch domain you want to remove tags from. 976 Specifying this overrides ``domain_name``. 977 978 :rtype: dict 979 :return: Dictionary with key 'result' and as value a boolean denoting success or failure. 980 Upon failure, also contains a key 'error' with the error message as value. 981 982 .. versionadded:: 3001 983 984 CLI Example: 985 986 .. code-block:: bash 987 988 salt myminion boto3_elasticsearch.remove_tags '["foo", "bar"]' domain_name=my_domain 989 """ 990 if not any((arn, domain_name)): 991 raise SaltInvocationError( 992 "At least one of domain_name or arn must be specified." 993 ) 994 ret = {"result": False} 995 if arn is None: 996 res = describe_elasticsearch_domain( 997 domain_name=domain_name, 998 region=region, 999 key=key, 1000 keyid=keyid, 1001 profile=profile, 1002 ) 1003 if "error" in res: 1004 ret.update(res) 1005 elif not res["result"]: 1006 ret.update( 1007 { 1008 "error": 'The domain with name "{}" does not exist.'.format( 1009 domain_name 1010 ) 1011 } 1012 ) 1013 else: 1014 arn = res["response"].get("ARN") 1015 if arn: 1016 try: 1017 conn = _get_conn(region=region, key=key, keyid=keyid, profile=profile) 1018 conn.remove_tags(ARN=arn, TagKeys=tag_keys) 1019 ret["result"] = True 1020 except (ParamValidationError, ClientError) as exp: 1021 ret.update({"error": __utils__["boto3.get_error"](exp)["message"]}) 1022 return ret 1023 1024 1025@depends("botocore", version="1.12.21") 1026def start_elasticsearch_service_software_update( 1027 domain_name, region=None, keyid=None, key=None, profile=None 1028): 1029 """ 1030 Schedules a service software update for an Amazon ES domain. 1031 1032 :param str domain_name: The name of the domain that you want to update to the 1033 latest service software. 1034 1035 :rtype: dict 1036 :return: Dictionary with key 'result' and as value a boolean denoting success or failure. 1037 Upon success, also contains a key 'reponse' with service software information. 1038 Upon failure, also contains a key 'error' with the error message as value. 1039 1040 .. versionadded:: 3001 1041 1042 """ 1043 ret = {"result": False} 1044 boto_params = {"DomainName": domain_name} 1045 try: 1046 conn = _get_conn(region=region, keyid=keyid, key=key, profile=profile) 1047 res = conn.start_elasticsearch_service_software_update(**boto_params) 1048 if res and "ServiceSoftwareOptions" in res: 1049 ret["result"] = True 1050 ret["response"] = res["ServiceSoftwareOptions"] 1051 except (ParamValidationError, ClientError) as exp: 1052 ret.update({"error": __utils__["boto3.get_error"](exp)["message"]}) 1053 return ret 1054 1055 1056def update_elasticsearch_domain_config( 1057 domain_name, 1058 elasticsearch_cluster_config=None, 1059 ebs_options=None, 1060 vpc_options=None, 1061 access_policies=None, 1062 snapshot_options=None, 1063 cognito_options=None, 1064 advanced_options=None, 1065 log_publishing_options=None, 1066 blocking=False, 1067 region=None, 1068 key=None, 1069 keyid=None, 1070 profile=None, 1071): 1072 """ 1073 Modifies the cluster configuration of the specified Elasticsearch domain, 1074 for example setting the instance type and the number of instances. 1075 1076 :param str domain_name: The name of the Elasticsearch domain that you are creating. 1077 Domain names are unique across the domains owned by an account within an 1078 AWS region. Domain names must start with a letter or number and can contain 1079 the following characters: a-z (lowercase), 0-9, and - (hyphen). 1080 :param dict elasticsearch_cluster_config: Dictionary specifying the configuration 1081 options for an Elasticsearch domain. Keys (case sensitive) in here are: 1082 1083 - InstanceType (str): The instance type for an Elasticsearch cluster. 1084 - InstanceCount (int): The instance type for an Elasticsearch cluster. 1085 - DedicatedMasterEnabled (bool): Indicate whether a dedicated master 1086 node is enabled. 1087 - ZoneAwarenessEnabled (bool): Indicate whether zone awareness is enabled. 1088 - ZoneAwarenessConfig (dict): Specifies the zone awareness configuration 1089 for a domain when zone awareness is enabled. 1090 Keys (case sensitive) in here are: 1091 1092 - AvailabilityZoneCount (int): An integer value to indicate the 1093 number of availability zones for a domain when zone awareness is 1094 enabled. This should be equal to number of subnets if VPC endpoints 1095 is enabled. 1096 1097 - DedicatedMasterType (str): The instance type for a dedicated master node. 1098 - DedicatedMasterCount (int): Total number of dedicated master nodes, 1099 active and on standby, for the cluster. 1100 :param dict ebs_options: Dict specifying the options to enable or disable and 1101 specifying the type and size of EBS storage volumes. 1102 Keys (case sensitive) in here are: 1103 1104 - EBSEnabled (bool): Specifies whether EBS-based storage is enabled. 1105 - VolumeType (str): Specifies the volume type for EBS-based storage. 1106 - VolumeSize (int): Integer to specify the size of an EBS volume. 1107 - Iops (int): Specifies the IOPD for a Provisioned IOPS EBS volume (SSD). 1108 :param dict snapshot_options: Dict specifying the snapshot options. 1109 Keys (case sensitive) in here are: 1110 1111 - AutomatedSnapshotStartHour (int): Specifies the time, in UTC format, 1112 when the service takes a daily automated snapshot of the specified 1113 Elasticsearch domain. Default value is 0 hours. 1114 :param dict vpc_options: Dict with the options to specify the subnets and security 1115 groups for the VPC endpoint. 1116 Keys (case sensitive) in here are: 1117 1118 - SubnetIds (list): The list of subnets for the VPC endpoint. 1119 - SecurityGroupIds (list): The list of security groups for the VPC endpoint. 1120 :param dict cognito_options: Dict with options to specify the cognito user and 1121 identity pools for Kibana authentication. 1122 Keys (case sensitive) in here are: 1123 1124 - Enabled (bool): Specifies the option to enable Cognito for Kibana authentication. 1125 - UserPoolId (str): Specifies the Cognito user pool ID for Kibana authentication. 1126 - IdentityPoolId (str): Specifies the Cognito identity pool ID for Kibana authentication. 1127 - RoleArn (str): Specifies the role ARN that provides Elasticsearch permissions 1128 for accessing Cognito resources. 1129 :param dict advanced_options: Dict with option to allow references to indices 1130 in an HTTP request body. Must be False when configuring access to individual 1131 sub-resources. By default, the value is True. 1132 See http://docs.aws.amazon.com/elasticsearch-service/latest/developerguide\ 1133 /es-createupdatedomains.html#es-createdomain-configure-advanced-options 1134 for more information. 1135 :param str/dict access_policies: Dict or JSON string with the IAM access policy. 1136 :param dict log_publishing_options: Dict with options for various type of logs. 1137 The keys denote the type of log file and can be one of the following: 1138 1139 INDEX_SLOW_LOGS, SEARCH_SLOW_LOGS, ES_APPLICATION_LOGS. 1140 1141 The value assigned to each key is a dict with the following case sensitive keys: 1142 1143 - CloudWatchLogsLogGroupArn (str): The ARN of the Cloudwatch log 1144 group to which the log needs to be published. 1145 - Enabled (bool): Specifies whether given log publishing option 1146 is enabled or not. 1147 :param bool blocking: Whether or not to wait (block) until the Elasticsearch 1148 domain has been updated. 1149 1150 :rtype: dict 1151 :return: Dictionary with key 'result' and as value a boolean denoting success or failure. 1152 Upon success, also contains a key 'reponse' with the domain configuration. 1153 Upon failure, also contains a key 'error' with the error message as value. 1154 1155 .. versionadded:: 3001 1156 1157 CLI Example: 1158 1159 .. code-block:: bash 1160 1161 salt myminion boto3_elasticsearch.update_elasticsearch_domain_config mydomain \\ 1162 elasticsearch_cluster_config='{\\ 1163 "InstanceType": "t2.micro.elasticsearch", \\ 1164 "InstanceCount": 1, \\ 1165 "DedicatedMasterEnabled": false, 1166 "ZoneAwarenessEnabled": false}' \\ 1167 ebs_options='{\\ 1168 "EBSEnabled": true, \\ 1169 "VolumeType": "gp2", \\ 1170 "VolumeSize": 10, \\ 1171 "Iops": 0}' \\ 1172 access_policies='{"Version": "2012-10-17", "Statement": [{\\ 1173 "Effect": "Allow", "Principal": {"AWS": "*"}, "Action": "es:*", \\ 1174 "Resource": "arn:aws:es:us-east-1:111111111111:domain/mydomain/*", \\ 1175 "Condition": {"IpAddress": {"aws:SourceIp": ["127.0.0.1"]}}}]}' \\ 1176 snapshot_options='{"AutomatedSnapshotStartHour": 0}' \\ 1177 advanced_options='{"rest.action.multi.allow_explicit_index": "true"}' 1178 """ 1179 ret = {"result": False} 1180 boto_kwargs = salt.utils.data.filter_falsey( 1181 { 1182 "DomainName": domain_name, 1183 "ElasticsearchClusterConfig": elasticsearch_cluster_config, 1184 "EBSOptions": ebs_options, 1185 "SnapshotOptions": snapshot_options, 1186 "VPCOptions": vpc_options, 1187 "CognitoOptions": cognito_options, 1188 "AdvancedOptions": advanced_options, 1189 "AccessPolicies": ( 1190 salt.utils.json.dumps(access_policies) 1191 if isinstance(access_policies, dict) 1192 else access_policies 1193 ), 1194 "LogPublishingOptions": log_publishing_options, 1195 } 1196 ) 1197 try: 1198 conn = _get_conn(region=region, keyid=keyid, key=key, profile=profile) 1199 res = conn.update_elasticsearch_domain_config(**boto_kwargs) 1200 if not res or "DomainConfig" not in res: 1201 log.warning("Domain was not updated") 1202 else: 1203 ret["result"] = True 1204 ret["response"] = res["DomainConfig"] 1205 if blocking: 1206 conn.get_waiter("ESDomainAvailable").wait(DomainName=domain_name) 1207 except (ParamValidationError, ClientError, WaiterError) as exp: 1208 ret.update({"error": __utils__["boto3.get_error"](exp)["message"]}) 1209 return ret 1210 1211 1212@depends("botocore", version="1.10.77") 1213def upgrade_elasticsearch_domain( 1214 domain_name, 1215 target_version, 1216 perform_check_only=None, 1217 blocking=False, 1218 region=None, 1219 keyid=None, 1220 key=None, 1221 profile=None, 1222): 1223 """ 1224 Allows you to either upgrade your domain or perform an Upgrade eligibility 1225 check to a compatible Elasticsearch version. 1226 1227 :param str domain_name: The name of an Elasticsearch domain. Domain names are 1228 unique across the domains owned by an account within an AWS region. Domain 1229 names start with a letter or number and can contain the following characters: 1230 a-z (lowercase), 0-9, and - (hyphen). 1231 :param str target_version: The version of Elasticsearch that you intend to 1232 upgrade the domain to. 1233 :param bool perform_check_only: This flag, when set to True, indicates that 1234 an Upgrade Eligibility Check needs to be performed. This will not actually 1235 perform the Upgrade. 1236 :param bool blocking: Whether or not to wait (block) until the Elasticsearch 1237 domain has been upgraded. 1238 1239 :rtype: dict 1240 :return: Dictionary with key 'result' and as value a boolean denoting success or failure. 1241 Upon success, also contains a key 'reponse' with the domain configuration. 1242 Upon failure, also contains a key 'error' with the error message as value. 1243 1244 .. versionadded:: 3001 1245 1246 CLI Example: 1247 1248 .. code-block:: bash 1249 1250 salt myminion boto3_elasticsearch.upgrade_elasticsearch_domain mydomain \\ 1251 target_version='6.7' \\ 1252 perform_check_only=True 1253 """ 1254 ret = {"result": False} 1255 boto_params = salt.utils.data.filter_falsey( 1256 { 1257 "DomainName": domain_name, 1258 "TargetVersion": str(target_version), 1259 "PerformCheckOnly": perform_check_only, 1260 } 1261 ) 1262 try: 1263 conn = _get_conn(region=region, keyid=keyid, key=key, profile=profile) 1264 res = conn.upgrade_elasticsearch_domain(**boto_params) 1265 if res: 1266 ret["result"] = True 1267 ret["response"] = res 1268 if blocking: 1269 conn.get_waiter("ESUpgradeFinished").wait(DomainName=domain_name) 1270 except (ParamValidationError, ClientError, WaiterError) as exp: 1271 ret.update({"error": __utils__["boto3.get_error"](exp)["message"]}) 1272 return ret 1273 1274 1275def exists(domain_name, region=None, key=None, keyid=None, profile=None): 1276 """ 1277 Given a domain name, check to see if the given domain exists. 1278 1279 :param str domain_name: The name of the domain to check. 1280 1281 :rtype: dict 1282 :return: Dictionary with key 'result' and as value a boolean denoting success or failure. 1283 Upon failure, also contains a key 'error' with the error message as value. 1284 1285 .. versionadded:: 3001 1286 1287 """ 1288 ret = {"result": False} 1289 try: 1290 conn = _get_conn(region=region, key=key, keyid=keyid, profile=profile) 1291 conn.describe_elasticsearch_domain(DomainName=domain_name) 1292 ret["result"] = True 1293 except (ParamValidationError, ClientError) as exp: 1294 if exp.response.get("Error", {}).get("Code") != "ResourceNotFoundException": 1295 ret.update({"error": __utils__["boto3.get_error"](exp)["message"]}) 1296 return ret 1297 1298 1299def wait_for_upgrade(domain_name, region=None, keyid=None, key=None, profile=None): 1300 """ 1301 Block until an upgrade-in-progress for domain ``name`` is finished. 1302 1303 :param str name: The name of the domain to wait for. 1304 1305 :rtype dict: 1306 :return: Dictionary with key 'result' and as value a boolean denoting success or failure. 1307 Upon failure, also contains a key 'error' with the error message as value. 1308 1309 .. versionadded:: 3001 1310 1311 """ 1312 ret = {"result": False} 1313 try: 1314 conn = _get_conn(region=region, keyid=keyid, key=key, profile=profile) 1315 conn.get_waiter("ESUpgradeFinished").wait(DomainName=domain_name) 1316 ret["result"] = True 1317 except (ParamValidationError, ClientError, WaiterError) as exp: 1318 ret.update({"error": __utils__["boto3.get_error"](exp)["message"]}) 1319 return ret 1320 1321 1322@depends("botocore", version="1.10.77") 1323def check_upgrade_eligibility( 1324 domain_name, elasticsearch_version, region=None, keyid=None, key=None, profile=None 1325): 1326 """ 1327 Helper function to determine in one call if an Elasticsearch domain can be 1328 upgraded to the specified Elasticsearch version. 1329 1330 This assumes that the Elasticsearch domain is at rest at the moment this function 1331 is called. I.e. The domain is not in the process of : 1332 1333 - being created. 1334 - being updated. 1335 - another upgrade running, or a check thereof. 1336 - being deleted. 1337 1338 Behind the scenes, this does 3 things: 1339 1340 - Check if ``elasticsearch_version`` is among the compatible elasticsearch versions. 1341 - Perform a check if the Elasticsearch domain is eligible for the upgrade. 1342 - Check the result of the check and return the result as a boolean. 1343 1344 :param str name: The Elasticsearch domain name to check. 1345 :param str elasticsearch_version: The Elasticsearch version to upgrade to. 1346 1347 :rtype: dict 1348 :return: Dictionary with key 'result' and as value a boolean denoting success or failure. 1349 Upon success, also contains a key 'reponse' with boolean result of the check. 1350 Upon failure, also contains a key 'error' with the error message as value. 1351 1352 .. versionadded:: 3001 1353 1354 CLI Example: 1355 1356 .. code-block:: bash 1357 1358 salt myminion boto3_elasticsearch.check_upgrade_eligibility mydomain '6.7' 1359 """ 1360 ret = {"result": False} 1361 # Check if the desired version is in the list of compatible versions 1362 res = get_compatible_elasticsearch_versions( 1363 domain_name, region=region, keyid=keyid, key=key, profile=profile 1364 ) 1365 if "error" in res: 1366 return res 1367 compatible_versions = res["response"][0]["TargetVersions"] 1368 if str(elasticsearch_version) not in compatible_versions: 1369 ret["result"] = True 1370 ret["response"] = False 1371 ret["error"] = 'Desired version "{}" not in compatible versions: {}.'.format( 1372 elasticsearch_version, compatible_versions 1373 ) 1374 return ret 1375 # Check if the domain is eligible to upgrade to the desired version 1376 res = upgrade_elasticsearch_domain( 1377 domain_name, 1378 elasticsearch_version, 1379 perform_check_only=True, 1380 blocking=True, 1381 region=region, 1382 keyid=keyid, 1383 key=key, 1384 profile=profile, 1385 ) 1386 if "error" in res: 1387 return res 1388 res = wait_for_upgrade( 1389 domain_name, region=region, keyid=keyid, key=key, profile=profile 1390 ) 1391 if "error" in res: 1392 return res 1393 res = get_upgrade_status( 1394 domain_name, region=region, keyid=keyid, key=key, profile=profile 1395 ) 1396 ret["result"] = True 1397 ret["response"] = ( 1398 res["response"]["UpgradeStep"] == "PRE_UPGRADE_CHECK" 1399 and res["response"]["StepStatus"] == "SUCCEEDED" 1400 ) 1401 return ret 1402