Feature: ElasticsearchService (#4703)

This commit is contained in:
Bert Blommers 2021-12-20 11:51:59 -01:00 committed by GitHub
parent cd0f0ee83c
commit 82d18443d3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 687 additions and 1 deletions

View File

@ -2191,6 +2191,52 @@
- [ ] untag_resource
</details>
## es
<details>
<summary>10% implemented</summary>
- [ ] accept_inbound_cross_cluster_search_connection
- [ ] add_tags
- [ ] associate_package
- [ ] cancel_elasticsearch_service_software_update
- [X] create_elasticsearch_domain
- [ ] create_outbound_cross_cluster_search_connection
- [ ] create_package
- [X] delete_elasticsearch_domain
- [ ] delete_elasticsearch_service_role
- [ ] delete_inbound_cross_cluster_search_connection
- [ ] delete_outbound_cross_cluster_search_connection
- [ ] delete_package
- [ ] describe_domain_auto_tunes
- [X] describe_elasticsearch_domain
- [ ] describe_elasticsearch_domain_config
- [ ] describe_elasticsearch_domains
- [ ] describe_elasticsearch_instance_type_limits
- [ ] describe_inbound_cross_cluster_search_connections
- [ ] describe_outbound_cross_cluster_search_connections
- [ ] describe_packages
- [ ] describe_reserved_elasticsearch_instance_offerings
- [ ] describe_reserved_elasticsearch_instances
- [ ] dissociate_package
- [ ] get_compatible_elasticsearch_versions
- [ ] get_package_version_history
- [ ] get_upgrade_history
- [ ] get_upgrade_status
- [X] list_domain_names
- [ ] list_domains_for_package
- [ ] list_elasticsearch_instance_types
- [ ] list_elasticsearch_versions
- [ ] list_packages_for_domain
- [ ] list_tags
- [ ] purchase_reserved_elasticsearch_instance_offering
- [ ] reject_inbound_cross_cluster_search_connection
- [ ] remove_tags
- [ ] start_elasticsearch_service_software_update
- [ ] update_elasticsearch_domain_config
- [ ] update_package
- [ ] upgrade_elasticsearch_domain
</details>
## events
<details>
<summary>78% implemented</summary>
@ -5054,7 +5100,6 @@
- ebs
- ecr-public
- elastic-inference
- es
- evidently
- finspace
- finspace-data

75
docs/docs/services/es.rst Normal file
View File

@ -0,0 +1,75 @@
.. _implementedservice_es:
.. |start-h3| raw:: html
<h3>
.. |end-h3| raw:: html
</h3>
==
es
==
.. autoclass:: moto.es.models.ElasticsearchServiceBackend
|start-h3| Example usage |end-h3|
.. sourcecode:: python
@mock_es
def test_es_behaviour:
boto3.client("es")
...
|start-h3| Implemented features for this service |end-h3|
- [ ] accept_inbound_cross_cluster_search_connection
- [ ] add_tags
- [ ] associate_package
- [ ] cancel_elasticsearch_service_software_update
- [X] create_elasticsearch_domain
- [ ] create_outbound_cross_cluster_search_connection
- [ ] create_package
- [X] delete_elasticsearch_domain
- [ ] delete_elasticsearch_service_role
- [ ] delete_inbound_cross_cluster_search_connection
- [ ] delete_outbound_cross_cluster_search_connection
- [ ] delete_package
- [ ] describe_domain_auto_tunes
- [X] describe_elasticsearch_domain
- [ ] describe_elasticsearch_domain_config
- [ ] describe_elasticsearch_domains
- [ ] describe_elasticsearch_instance_type_limits
- [ ] describe_inbound_cross_cluster_search_connections
- [ ] describe_outbound_cross_cluster_search_connections
- [ ] describe_packages
- [ ] describe_reserved_elasticsearch_instance_offerings
- [ ] describe_reserved_elasticsearch_instances
- [ ] dissociate_package
- [ ] get_compatible_elasticsearch_versions
- [ ] get_package_version_history
- [ ] get_upgrade_history
- [ ] get_upgrade_status
- [X] list_domain_names
The engine-type parameter is not yet supported.
Pagination is not yet implemented.
- [ ] list_domains_for_package
- [ ] list_elasticsearch_instance_types
- [ ] list_elasticsearch_versions
- [ ] list_packages_for_domain
- [ ] list_tags
- [ ] purchase_reserved_elasticsearch_instance_offering
- [ ] reject_inbound_cross_cluster_search_connection
- [ ] remove_tags
- [ ] start_elasticsearch_service_software_update
- [ ] update_elasticsearch_domain_config
- [ ] update_package
- [ ] upgrade_elasticsearch_domain

View File

@ -89,6 +89,7 @@ mock_emr_deprecated = lazy_load(".emr", "mock_emr_deprecated")
mock_emrcontainers = lazy_load(
".emrcontainers", "mock_emrcontainers", boto3_name="emr-containers"
)
mock_es = lazy_load(".es", "mock_es")
mock_events = lazy_load(".events", "mock_events")
mock_firehose = lazy_load(".firehose", "mock_firehose")
mock_forecast = lazy_load(".forecast", "mock_forecast")

View File

@ -61,6 +61,7 @@ backend_url_patterns = [
("emr", re.compile("https?://(.+)\\.elasticmapreduce\\.amazonaws.com")),
("emr", re.compile("https?://elasticmapreduce\\.(.+)\\.amazonaws.com")),
("emr-containers", re.compile("https?://emr-containers\\.(.+)\\.amazonaws\\.com")),
("es", re.compile("https?://es\\.(.+)\\.amazonaws\\.com")),
("events", re.compile("https?://events\\.(.+)\\.amazonaws\\.com")),
("firehose", re.compile("https?://firehose\\.(.+)\\.amazonaws\\.com")),
("forecast", re.compile("https?://forecast\\.(.+)\\.amazonaws\\.com")),

5
moto/es/__init__.py Normal file
View File

@ -0,0 +1,5 @@
"""es module initialization; sets value for base decorator."""
from .models import es_backends
from ..core.models import base_decorator
mock_es = base_decorator(es_backends)

25
moto/es/exceptions.py Normal file
View File

@ -0,0 +1,25 @@
"""Exceptions raised by the ElasticSearch service."""
from moto.core.exceptions import JsonRESTError
class ElasticSearchError(JsonRESTError):
code = 400
class ResourceNotFound(ElasticSearchError):
code = 409
def __init__(self, resource_type, resource_name):
msg = f"{resource_type} not found: {resource_name}"
super().__init__("ResourceNotFoundException", msg)
class InvalidDomainName(ElasticSearchError):
def __init__(self, domain_name):
msg = f"1 validation error detected: Value '{domain_name}' at 'domainName' failed to satisfy constraint: Member must satisfy regular expression pattern: [a-z][a-z0-9\\-]+"
super().__init__("ValidationException", msg)
class DomainNotFound(ResourceNotFound):
def __init__(self, domain_name):
super().__init__("Domain", domain_name)

160
moto/es/models.py Normal file
View File

@ -0,0 +1,160 @@
from boto3 import Session
from moto.core import BaseBackend, BaseModel
from moto.core.utils import get_random_hex
from .exceptions import DomainNotFound
class Domain(BaseModel):
def __init__(
self,
region_name,
domain_name,
es_version,
elasticsearch_cluster_config,
ebs_options,
access_policies,
snapshot_options,
vpc_options,
cognito_options,
encryption_at_rest_options,
node_to_node_encryption_options,
advanced_options,
log_publishing_options,
domain_endpoint_options,
advanced_security_options,
auto_tune_options,
tag_list,
):
self.domain_id = get_random_hex(8)
self.region_name = region_name
self.domain_name = domain_name
self.es_version = es_version
self.elasticsearch_cluster_config = elasticsearch_cluster_config
self.ebs_options = ebs_options
self.access_policies = access_policies
self.snapshot_options = snapshot_options
self.vpc_options = vpc_options
self.cognito_options = cognito_options
self.encryption_at_rest_options = encryption_at_rest_options
self.node_to_node_encryption_options = node_to_node_encryption_options
self.advanced_options = advanced_options
self.log_publishing_options = log_publishing_options
self.domain_endpoint_options = domain_endpoint_options
self.advanced_security_options = advanced_security_options
self.auto_tune_options = auto_tune_options
if self.auto_tune_options:
self.auto_tune_options["State"] = "ENABLED"
@property
def arn(self):
return f"arn:aws:es:{self.region_name}:domain/{self.domain_id}"
def to_json(self):
return {
"DomainId": self.domain_id,
"DomainName": self.domain_name,
"ARN": self.arn,
"Created": True,
"Deleted": False,
"Processing": False,
"UpgradeProcessing": False,
"ElasticsearchVersion": self.es_version,
"ElasticsearchClusterConfig": self.elasticsearch_cluster_config,
"EBSOptions": self.ebs_options,
"AccessPolicies": self.access_policies,
"SnapshotOptions": self.snapshot_options,
"VPCOptions": self.vpc_options,
"CognitoOptions": self.cognito_options,
"EncryptionAtRestOptions": self.encryption_at_rest_options,
"NodeToNodeEncryptionOptions": self.node_to_node_encryption_options,
"AdvancedOptions": self.advanced_options,
"LogPublishingOptions": self.log_publishing_options,
"DomainEndpointOptions": self.domain_endpoint_options,
"AdvancedSecurityOptions": self.advanced_security_options,
"AutoTuneOptions": self.auto_tune_options,
}
class ElasticsearchServiceBackend(BaseBackend):
"""Implementation of ElasticsearchService APIs."""
def __init__(self, region_name=None):
self.region_name = region_name
self.domains = dict()
def reset(self):
"""Re-initialize all attributes for this instance."""
region_name = self.region_name
self.__dict__ = {}
self.__init__(region_name)
def create_elasticsearch_domain(
self,
domain_name,
elasticsearch_version,
elasticsearch_cluster_config,
ebs_options,
access_policies,
snapshot_options,
vpc_options,
cognito_options,
encryption_at_rest_options,
node_to_node_encryption_options,
advanced_options,
log_publishing_options,
domain_endpoint_options,
advanced_security_options,
auto_tune_options,
tag_list,
):
# TODO: Persist/Return other attributes
new_domain = Domain(
region_name=self.region_name,
domain_name=domain_name,
es_version=elasticsearch_version,
elasticsearch_cluster_config=elasticsearch_cluster_config,
ebs_options=ebs_options,
access_policies=access_policies,
snapshot_options=snapshot_options,
vpc_options=vpc_options,
cognito_options=cognito_options,
encryption_at_rest_options=encryption_at_rest_options,
node_to_node_encryption_options=node_to_node_encryption_options,
advanced_options=advanced_options,
log_publishing_options=log_publishing_options,
domain_endpoint_options=domain_endpoint_options,
advanced_security_options=advanced_security_options,
auto_tune_options=auto_tune_options,
tag_list=tag_list,
)
self.domains[domain_name] = new_domain
return new_domain.to_json()
def delete_elasticsearch_domain(self, domain_name):
if domain_name not in self.domains:
raise DomainNotFound(domain_name)
del self.domains[domain_name]
def describe_elasticsearch_domain(self, domain_name):
if domain_name not in self.domains:
raise DomainNotFound(domain_name)
return self.domains[domain_name].to_json()
def list_domain_names(self, engine_type):
"""
The engine-type parameter is not yet supported.
Pagination is not yet implemented.
"""
return [{"DomainName": domain.domain_name} for domain in self.domains.values()]
es_backends = {}
for available_region in Session().get_available_regions("es"):
es_backends[available_region] = ElasticsearchServiceBackend(available_region)
for available_region in Session().get_available_regions(
"es", partition_name="aws-us-gov"
):
es_backends[available_region] = ElasticsearchServiceBackend(available_region)
for available_region in Session().get_available_regions("es", partition_name="aws-cn"):
es_backends[available_region] = ElasticsearchServiceBackend(available_region)

113
moto/es/responses.py Normal file
View File

@ -0,0 +1,113 @@
import json
import re
from functools import wraps
from moto.core.responses import BaseResponse
from .exceptions import ElasticSearchError, InvalidDomainName
from .models import es_backends
def error_handler(f):
@wraps(f)
def _wrapper(*args, **kwargs):
try:
return f(*args, **kwargs)
except ElasticSearchError as e:
return e.code, e.get_headers(), e.get_body()
return _wrapper
class ElasticsearchServiceResponse(BaseResponse):
"""Handler for ElasticsearchService requests and responses."""
@property
def es_backend(self):
"""Return backend instance specific for this region."""
return es_backends[self.region]
@classmethod
@error_handler
def list_domains(cls, request, full_url, headers):
response = ElasticsearchServiceResponse()
response.setup_class(request, full_url, headers)
if request.method == "GET":
return response.list_domain_names()
@classmethod
@error_handler
def domains(cls, request, full_url, headers):
response = ElasticsearchServiceResponse()
response.setup_class(request, full_url, headers)
if request.method == "POST":
return response.create_elasticsearch_domain()
@classmethod
@error_handler
def domain(cls, request, full_url, headers):
response = ElasticsearchServiceResponse()
response.setup_class(request, full_url, headers)
if request.method == "DELETE":
return response.delete_elasticsearch_domain()
if request.method == "GET":
return response.describe_elasticsearch_domain()
def create_elasticsearch_domain(self):
params = json.loads(self.body)
domain_name = params.get("DomainName")
if not re.match(r"^[a-z][a-z0-9\-]+$", domain_name):
raise InvalidDomainName(domain_name)
elasticsearch_version = params.get("ElasticsearchVersion")
elasticsearch_cluster_config = params.get("ElasticsearchClusterConfig")
ebs_options = params.get("EBSOptions")
access_policies = params.get("AccessPolicies")
snapshot_options = params.get("SnapshotOptions")
vpc_options = params.get("VPCOptions")
cognito_options = params.get("CognitoOptions")
encryption_at_rest_options = params.get("EncryptionAtRestOptions")
node_to_node_encryption_options = params.get("NodeToNodeEncryptionOptions")
advanced_options = params.get("AdvancedOptions")
log_publishing_options = params.get("LogPublishingOptions")
domain_endpoint_options = params.get("DomainEndpointOptions")
advanced_security_options = params.get("AdvancedSecurityOptions")
auto_tune_options = params.get("AutoTuneOptions")
tag_list = params.get("TagList")
domain_status = self.es_backend.create_elasticsearch_domain(
domain_name=domain_name,
elasticsearch_version=elasticsearch_version,
elasticsearch_cluster_config=elasticsearch_cluster_config,
ebs_options=ebs_options,
access_policies=access_policies,
snapshot_options=snapshot_options,
vpc_options=vpc_options,
cognito_options=cognito_options,
encryption_at_rest_options=encryption_at_rest_options,
node_to_node_encryption_options=node_to_node_encryption_options,
advanced_options=advanced_options,
log_publishing_options=log_publishing_options,
domain_endpoint_options=domain_endpoint_options,
advanced_security_options=advanced_security_options,
auto_tune_options=auto_tune_options,
tag_list=tag_list,
)
return 200, {}, json.dumps({"DomainStatus": domain_status})
def delete_elasticsearch_domain(self):
domain_name = self.path.split("/")[-1]
self.es_backend.delete_elasticsearch_domain(domain_name=domain_name,)
return 200, {}, json.dumps(dict())
def describe_elasticsearch_domain(self):
domain_name = self.path.split("/")[-1]
if not re.match(r"^[a-z][a-z0-9\-]+$", domain_name):
raise InvalidDomainName(domain_name)
domain_status = self.es_backend.describe_elasticsearch_domain(
domain_name=domain_name,
)
return 200, {}, json.dumps({"DomainStatus": domain_status})
def list_domain_names(self):
params = self._get_params()
engine_type = params.get("EngineType")
domain_names = self.es_backend.list_domain_names(engine_type=engine_type,)
return 200, {}, json.dumps({"DomainNames": domain_names})

12
moto/es/urls.py Normal file
View File

@ -0,0 +1,12 @@
from .responses import ElasticsearchServiceResponse
url_bases = [
r"https?://es\.(.+)\.amazonaws\.com",
]
url_paths = {
"{0}/2015-01-01/domain$": ElasticsearchServiceResponse.list_domains,
"{0}/2015-01-01/es/domain$": ElasticsearchServiceResponse.domains,
"{0}/2015-01-01/es/domain/(?P<domainname>[^/]+)": ElasticsearchServiceResponse.domain,
}

View File

236
tests/test_es/test_es.py Normal file
View File

@ -0,0 +1,236 @@
"""Unit tests for es-supported APIs."""
import boto3
import pytest
import sure # noqa # pylint: disable=unused-import
from botocore.exceptions import ClientError
from moto import mock_es
# See our Development Tips on writing tests for hints on how to write good tests:
# http://docs.getmoto.org/en/latest/docs/contributing/development_tips/tests.html
@pytest.mark.parametrize(
"name", ["getmoto.org", "search-is-$$$", "dev_or_test", "dev/test", "1love", "DEV"]
)
@mock_es
def test_create_domain_invalid_name(name):
client = boto3.client("es", region_name="us-east-2")
with pytest.raises(ClientError) as exc:
client.create_elasticsearch_domain(DomainName=name)
err = exc.value.response["Error"]
err["Message"].should.equal(
f"1 validation error detected: Value '{name}' at 'domainName' failed to satisfy constraint: Member must satisfy regular expression pattern: [a-z][a-z0-9\\-]+"
)
err["Code"].should.equal("ValidationException")
@mock_es
def test_create_elasticsearch_domain_minimal():
client = boto3.client("es", region_name="us-east-2")
resp = client.create_elasticsearch_domain(DomainName="motosearch")
resp.should.have.key("DomainStatus")
domain = resp["DomainStatus"]
domain.should.have.key("DomainName").equals("motosearch")
domain.should.have.key("DomainId")
domain.should.have.key("ARN").equals(
f"arn:aws:es:us-east-2:domain/{domain['DomainId']}"
)
domain.should.have.key("Created").equals(True)
domain.should.have.key("Deleted").equals(False)
domain.should.have.key("Processing").equals(False)
domain.should.have.key("UpgradeProcessing").equals(False)
domain.shouldnt.have.key("ElasticsearchVersion")
@mock_es
def test_create_elasticsearch_domain():
client = boto3.client("es", region_name="us-east-2")
resp = client.create_elasticsearch_domain(
DomainName="motosearch",
ElasticsearchVersion="7.10",
ElasticsearchClusterConfig={
"InstanceType": "m3.large.elasticsearch",
"InstanceCount": 1,
"DedicatedMasterEnabled": True,
"DedicatedMasterType": "m3.large.elasticsearch",
"DedicatedMasterCount": 1,
"ZoneAwarenessEnabled": False,
"WarmEnabled": False,
"ColdStorageOptions": {"Enabled": False},
},
EBSOptions={
"EBSEnabled": True,
"VolumeType": "io2",
"VolumeSize": 10,
"Iops": 1,
},
AccessPolicies="some unvalidated accesspolicy",
SnapshotOptions={"AutomatedSnapshotStartHour": 1,},
VPCOptions={"SubnetIds": ["s1"], "SecurityGroupIds": ["sg1"]},
CognitoOptions={"Enabled": False},
EncryptionAtRestOptions={"Enabled": False},
NodeToNodeEncryptionOptions={"Enabled": False},
AdvancedOptions={"option": "value"},
LogPublishingOptions={"log1": {"Enabled": False}},
DomainEndpointOptions={"EnforceHTTPS": True, "CustomEndpointEnabled": False,},
AdvancedSecurityOptions={"Enabled": False},
AutoTuneOptions={"DesiredState": "ENABLED"},
)
domain = resp["DomainStatus"]
domain.should.have.key("DomainId")
domain.should.have.key("Created").equals(True)
domain.should.have.key("ElasticsearchVersion").equals("7.10")
domain.should.have.key("ElasticsearchClusterConfig")
cluster_config = domain["ElasticsearchClusterConfig"]
cluster_config.should.have.key("ColdStorageOptions").equals({"Enabled": False})
cluster_config.should.have.key("DedicatedMasterCount").equals(1)
cluster_config.should.have.key("DedicatedMasterType").equals(
"m3.large.elasticsearch"
)
cluster_config.should.have.key("WarmEnabled").equals(False)
domain.should.have.key("EBSOptions")
ebs = domain["EBSOptions"]
ebs.should.have.key("EBSEnabled").equals(True)
ebs.should.have.key("Iops").equals(1)
ebs.should.have.key("VolumeSize").equals(10)
ebs.should.have.key("VolumeType").equals("io2")
domain.should.have.key("AccessPolicies").equals("some unvalidated accesspolicy")
domain.should.have.key("SnapshotOptions")
snapshots = domain["SnapshotOptions"]
snapshots.should.have.key("AutomatedSnapshotStartHour").equals(1)
domain.should.have.key("VPCOptions")
vpcs = domain["VPCOptions"]
vpcs.should.have.key("SubnetIds").equals(["s1"])
vpcs.should.have.key("SecurityGroupIds").equals(["sg1"])
domain.should.have.key("CognitoOptions")
cognito = domain["CognitoOptions"]
cognito.should.have.key("Enabled").equals(False)
domain.should.have.key("EncryptionAtRestOptions")
encryption_at_rest = domain["EncryptionAtRestOptions"]
encryption_at_rest.should.have.key("Enabled").equals(False)
domain.should.have.key("NodeToNodeEncryptionOptions")
encryption = domain["NodeToNodeEncryptionOptions"]
encryption.should.have.key("Enabled").equals(False)
domain.should.have.key("AdvancedOptions")
advanced = domain["AdvancedOptions"]
advanced.should.have.key("option").equals("value")
domain.should.have.key("LogPublishingOptions")
advanced = domain["LogPublishingOptions"]
advanced.should.have.key("log1").equals({"Enabled": False})
domain.should.have.key("DomainEndpointOptions")
endpoint = domain["DomainEndpointOptions"]
endpoint.should.have.key("EnforceHTTPS").equals(True)
endpoint.should.have.key("CustomEndpointEnabled").equals(False)
domain.should.have.key("AdvancedSecurityOptions")
advanced_security = domain["AdvancedSecurityOptions"]
advanced_security.should.have.key("Enabled").equals(False)
domain.should.have.key("AutoTuneOptions")
auto_tune = domain["AutoTuneOptions"]
auto_tune.should.have.key("State").equals("ENABLED")
@mock_es
def test_delete_elasticsearch_domain():
client = boto3.client("es", region_name="ap-southeast-1")
client.create_elasticsearch_domain(DomainName="motosearch")
client.delete_elasticsearch_domain(DomainName="motosearch")
client.list_domain_names()["DomainNames"].should.equal([])
@mock_es
def test_missing_delete_elasticsearch_domain():
client = boto3.client("es", region_name="ap-southeast-1")
with pytest.raises(ClientError) as exc:
client.delete_elasticsearch_domain(DomainName="unknown")
meta = exc.value.response["ResponseMetadata"]
meta["HTTPStatusCode"].should.equal(409)
err = exc.value.response["Error"]
err["Code"].should.equal("ResourceNotFoundException")
err["Message"].should.equal("Domain not found: unknown")
@mock_es
def test_describe_invalid_domain():
client = boto3.client("es", region_name="us-east-2")
with pytest.raises(ClientError) as exc:
client.describe_elasticsearch_domain(DomainName="moto.org")
meta = exc.value.response["ResponseMetadata"]
meta["HTTPStatusCode"].should.equal(400)
err = exc.value.response["Error"]
err["Message"].should.equal(
f"1 validation error detected: Value 'moto.org' at 'domainName' failed to satisfy constraint: Member must satisfy regular expression pattern: [a-z][a-z0-9\\-]+"
)
err["Code"].should.equal("ValidationException")
@mock_es
def test_describe_unknown_domain():
client = boto3.client("es", region_name="ap-southeast-1")
with pytest.raises(ClientError) as exc:
client.describe_elasticsearch_domain(DomainName="unknown")
meta = exc.value.response["ResponseMetadata"]
meta["HTTPStatusCode"].should.equal(409)
err = exc.value.response["Error"]
err["Code"].should.equal("ResourceNotFoundException")
err["Message"].should.equal("Domain not found: unknown")
@mock_es
def test_describe_elasticsearch_domain():
client = boto3.client("es", region_name="ap-southeast-1")
client.create_elasticsearch_domain(DomainName="motosearch")
resp = client.describe_elasticsearch_domain(DomainName="motosearch")
resp.should.have.key("DomainStatus")
domain = resp["DomainStatus"]
domain.should.have.key("DomainName").equals("motosearch")
domain.should.have.key("DomainId")
domain.should.have.key("ARN").equals(
f"arn:aws:es:ap-southeast-1:domain/{domain['DomainId']}"
)
domain.should.have.key("Created").equals(True)
domain.should.have.key("Deleted").equals(False)
domain.should.have.key("Processing").equals(False)
domain.should.have.key("UpgradeProcessing").equals(False)
domain.shouldnt.have.key("ElasticsearchVersion")
@mock_es
def test_list_domain_names_initial():
client = boto3.client("es", region_name="eu-west-1")
resp = client.list_domain_names()
resp.should.have.key("DomainNames").equals([])
@mock_es
def test_list_domain_names_with_multiple_domains():
client = boto3.client("es", region_name="eu-west-1")
domain_names = [f"env{i}" for i in range(1, 5)]
for name in domain_names:
client.create_elasticsearch_domain(DomainName=name)
resp = client.list_domain_names()
resp.should.have.key("DomainNames").length_of(4)
for name in domain_names:
resp["DomainNames"].should.contain({"DomainName": name})

View File

@ -0,0 +1,13 @@
import json
import sure # noqa # pylint: disable=unused-import
import moto.server as server
def test_es_list():
backend = server.create_backend_app("es")
test_client = backend.test_client()
resp = test_client.get("/2015-01-01/domain")
resp.status_code.should.equal(200)
json.loads(resp.data).should.equals({"DomainNames": []})