Feature: ServiceDiscovery/CloudMap (#4862)
This commit is contained in:
parent
a7e169a545
commit
871591f7f1
@ -4810,6 +4810,38 @@
|
|||||||
- [ ] validate_resource_policy
|
- [ ] validate_resource_policy
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
|
## servicediscovery
|
||||||
|
<details>
|
||||||
|
<summary>61% implemented</summary>
|
||||||
|
|
||||||
|
- [X] create_http_namespace
|
||||||
|
- [X] create_private_dns_namespace
|
||||||
|
- [X] create_public_dns_namespace
|
||||||
|
- [X] create_service
|
||||||
|
- [X] delete_namespace
|
||||||
|
- [X] delete_service
|
||||||
|
- [ ] deregister_instance
|
||||||
|
- [ ] discover_instances
|
||||||
|
- [ ] get_instance
|
||||||
|
- [ ] get_instances_health_status
|
||||||
|
- [X] get_namespace
|
||||||
|
- [X] get_operation
|
||||||
|
- [X] get_service
|
||||||
|
- [ ] list_instances
|
||||||
|
- [X] list_namespaces
|
||||||
|
- [X] list_operations
|
||||||
|
- [X] list_services
|
||||||
|
- [X] list_tags_for_resource
|
||||||
|
- [ ] register_instance
|
||||||
|
- [X] tag_resource
|
||||||
|
- [X] untag_resource
|
||||||
|
- [ ] update_http_namespace
|
||||||
|
- [ ] update_instance_custom_health_status
|
||||||
|
- [ ] update_private_dns_namespace
|
||||||
|
- [ ] update_public_dns_namespace
|
||||||
|
- [X] update_service
|
||||||
|
</details>
|
||||||
|
|
||||||
## ses
|
## ses
|
||||||
<details>
|
<details>
|
||||||
<summary>32% implemented</summary>
|
<summary>32% implemented</summary>
|
||||||
@ -5544,7 +5576,6 @@
|
|||||||
- service-quotas
|
- service-quotas
|
||||||
- servicecatalog
|
- servicecatalog
|
||||||
- servicecatalog-appregistry
|
- servicecatalog-appregistry
|
||||||
- servicediscovery
|
|
||||||
- sesv2
|
- sesv2
|
||||||
- shield
|
- shield
|
||||||
- signer
|
- signer
|
||||||
|
68
docs/docs/services/servicediscovery.rst
Normal file
68
docs/docs/services/servicediscovery.rst
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
.. _implementedservice_servicediscovery:
|
||||||
|
|
||||||
|
.. |start-h3| raw:: html
|
||||||
|
|
||||||
|
<h3>
|
||||||
|
|
||||||
|
.. |end-h3| raw:: html
|
||||||
|
|
||||||
|
</h3>
|
||||||
|
|
||||||
|
================
|
||||||
|
servicediscovery
|
||||||
|
================
|
||||||
|
|
||||||
|
.. autoclass:: moto.servicediscovery.models.ServiceDiscoveryBackend
|
||||||
|
|
||||||
|
|start-h3| Example usage |end-h3|
|
||||||
|
|
||||||
|
.. sourcecode:: python
|
||||||
|
|
||||||
|
@mock_servicediscovery
|
||||||
|
def test_servicediscovery_behaviour:
|
||||||
|
boto3.client("servicediscovery")
|
||||||
|
...
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|start-h3| Implemented features for this service |end-h3|
|
||||||
|
|
||||||
|
- [X] create_http_namespace
|
||||||
|
- [X] create_private_dns_namespace
|
||||||
|
- [X] create_public_dns_namespace
|
||||||
|
- [X] create_service
|
||||||
|
- [X] delete_namespace
|
||||||
|
- [X] delete_service
|
||||||
|
- [ ] deregister_instance
|
||||||
|
- [ ] discover_instances
|
||||||
|
- [ ] get_instance
|
||||||
|
- [ ] get_instances_health_status
|
||||||
|
- [X] get_namespace
|
||||||
|
- [X] get_operation
|
||||||
|
- [X] get_service
|
||||||
|
- [ ] list_instances
|
||||||
|
- [X] list_namespaces
|
||||||
|
|
||||||
|
Pagination or the Filters-parameter is not yet implemented
|
||||||
|
|
||||||
|
|
||||||
|
- [X] list_operations
|
||||||
|
|
||||||
|
Pagination or the Filters-argument is not yet implemented
|
||||||
|
|
||||||
|
|
||||||
|
- [X] list_services
|
||||||
|
|
||||||
|
Pagination or the Filters-argument is not yet implemented
|
||||||
|
|
||||||
|
|
||||||
|
- [X] list_tags_for_resource
|
||||||
|
- [ ] register_instance
|
||||||
|
- [X] tag_resource
|
||||||
|
- [X] untag_resource
|
||||||
|
- [ ] update_http_namespace
|
||||||
|
- [ ] update_instance_custom_health_status
|
||||||
|
- [ ] update_private_dns_namespace
|
||||||
|
- [ ] update_public_dns_namespace
|
||||||
|
- [X] update_service
|
||||||
|
|
@ -130,6 +130,7 @@ mock_sagemaker = lazy_load(".sagemaker", "mock_sagemaker")
|
|||||||
mock_sdb = lazy_load(".sdb", "mock_sdb")
|
mock_sdb = lazy_load(".sdb", "mock_sdb")
|
||||||
mock_secretsmanager = lazy_load(".secretsmanager", "mock_secretsmanager")
|
mock_secretsmanager = lazy_load(".secretsmanager", "mock_secretsmanager")
|
||||||
mock_ses = lazy_load(".ses", "mock_ses")
|
mock_ses = lazy_load(".ses", "mock_ses")
|
||||||
|
mock_servicediscovery = lazy_load(".servicediscovery", "mock_servicediscovery")
|
||||||
mock_sns = lazy_load(".sns", "mock_sns")
|
mock_sns = lazy_load(".sns", "mock_sns")
|
||||||
mock_sqs = lazy_load(".sqs", "mock_sqs")
|
mock_sqs = lazy_load(".sqs", "mock_sqs")
|
||||||
mock_ssm = lazy_load(".ssm", "mock_ssm")
|
mock_ssm = lazy_load(".ssm", "mock_ssm")
|
||||||
|
@ -124,6 +124,10 @@ backend_url_patterns = [
|
|||||||
("sagemaker", re.compile("https?://api.sagemaker\\.(.+)\\.amazonaws.com")),
|
("sagemaker", re.compile("https?://api.sagemaker\\.(.+)\\.amazonaws.com")),
|
||||||
("sdb", re.compile("https?://sdb\\.(.+)\\.amazonaws\\.com")),
|
("sdb", re.compile("https?://sdb\\.(.+)\\.amazonaws\\.com")),
|
||||||
("secretsmanager", re.compile("https?://secretsmanager\\.(.+)\\.amazonaws\\.com")),
|
("secretsmanager", re.compile("https?://secretsmanager\\.(.+)\\.amazonaws\\.com")),
|
||||||
|
(
|
||||||
|
"servicediscovery",
|
||||||
|
re.compile("https?://servicediscovery\\.(.+)\\.amazonaws\\.com"),
|
||||||
|
),
|
||||||
("ses", re.compile("https?://email\\.(.+)\\.amazonaws\\.com")),
|
("ses", re.compile("https?://email\\.(.+)\\.amazonaws\\.com")),
|
||||||
("ses", re.compile("https?://ses\\.(.+)\\.amazonaws\\.com")),
|
("ses", re.compile("https?://ses\\.(.+)\\.amazonaws\\.com")),
|
||||||
("sns", re.compile("https?://sns\\.(.+)\\.amazonaws\\.com")),
|
("sns", re.compile("https?://sns\\.(.+)\\.amazonaws\\.com")),
|
||||||
|
5
moto/servicediscovery/__init__.py
Normal file
5
moto/servicediscovery/__init__.py
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
"""servicediscovery module initialization; sets value for base decorator."""
|
||||||
|
from .models import servicediscovery_backends
|
||||||
|
from ..core.models import base_decorator
|
||||||
|
|
||||||
|
mock_servicediscovery = base_decorator(servicediscovery_backends)
|
22
moto/servicediscovery/exceptions.py
Normal file
22
moto/servicediscovery/exceptions.py
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
"""Exceptions raised by the servicediscovery service."""
|
||||||
|
from moto.core.exceptions import JsonRESTError
|
||||||
|
|
||||||
|
|
||||||
|
class OperationNotFound(JsonRESTError):
|
||||||
|
def __init__(self):
|
||||||
|
super().__init__("OperationNotFound", "")
|
||||||
|
|
||||||
|
|
||||||
|
class NamespaceNotFound(JsonRESTError):
|
||||||
|
def __init__(self, ns_id):
|
||||||
|
super().__init__("NamespaceNotFound", f"{ns_id}")
|
||||||
|
|
||||||
|
|
||||||
|
class ServiceNotFound(JsonRESTError):
|
||||||
|
def __init__(self, ns_id):
|
||||||
|
super().__init__("ServiceNotFound", f"{ns_id}")
|
||||||
|
|
||||||
|
|
||||||
|
class ConflictingDomainExists(JsonRESTError):
|
||||||
|
def __init__(self, vpc_id):
|
||||||
|
super().__init__("ConflictingDomainExists", f"{vpc_id}")
|
330
moto/servicediscovery/models.py
Normal file
330
moto/servicediscovery/models.py
Normal file
@ -0,0 +1,330 @@
|
|||||||
|
import random
|
||||||
|
import string
|
||||||
|
|
||||||
|
from moto.core import ACCOUNT_ID, BaseBackend, BaseModel
|
||||||
|
from moto.core.utils import BackendDict, unix_time
|
||||||
|
from moto.utilities.tagging_service import TaggingService
|
||||||
|
|
||||||
|
from .exceptions import (
|
||||||
|
ConflictingDomainExists,
|
||||||
|
NamespaceNotFound,
|
||||||
|
OperationNotFound,
|
||||||
|
ServiceNotFound,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def random_id(size):
|
||||||
|
return "".join(
|
||||||
|
[random.choice(string.ascii_lowercase + string.digits) for _ in range(size)]
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class Namespace(BaseModel):
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
region,
|
||||||
|
name,
|
||||||
|
ns_type,
|
||||||
|
creator_request_id,
|
||||||
|
description,
|
||||||
|
dns_properties,
|
||||||
|
http_properties,
|
||||||
|
vpc=None,
|
||||||
|
):
|
||||||
|
super().__init__()
|
||||||
|
self.id = f"ns-{random_id(20)}"
|
||||||
|
self.arn = f"arn:aws:servicediscovery:{region}:{ACCOUNT_ID}:namespace/{self.id}"
|
||||||
|
self.name = name
|
||||||
|
self.type = ns_type
|
||||||
|
self.creator_request_id = creator_request_id
|
||||||
|
self.description = description
|
||||||
|
self.dns_properties = dns_properties
|
||||||
|
self.http_properties = http_properties
|
||||||
|
self.vpc = vpc
|
||||||
|
self.created = unix_time()
|
||||||
|
self.updated = unix_time()
|
||||||
|
|
||||||
|
def to_json(self):
|
||||||
|
return {
|
||||||
|
"Arn": self.arn,
|
||||||
|
"Id": self.id,
|
||||||
|
"Name": self.name,
|
||||||
|
"Description": self.description,
|
||||||
|
"Type": self.type,
|
||||||
|
"Properties": {
|
||||||
|
"DnsProperties": self.dns_properties,
|
||||||
|
"HttpProperties": self.http_properties,
|
||||||
|
},
|
||||||
|
"CreateDate": self.created,
|
||||||
|
"UpdateDate": self.updated,
|
||||||
|
"CreatorRequestId": self.creator_request_id,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class Service(BaseModel):
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
region,
|
||||||
|
name,
|
||||||
|
namespace_id,
|
||||||
|
description,
|
||||||
|
creator_request_id,
|
||||||
|
dns_config,
|
||||||
|
health_check_config,
|
||||||
|
health_check_custom_config,
|
||||||
|
service_type,
|
||||||
|
):
|
||||||
|
super().__init__()
|
||||||
|
self.id = f"srv-{random_id(8)}"
|
||||||
|
self.arn = f"arn:aws:servicediscovery:{region}:{ACCOUNT_ID}:service/{self.id}"
|
||||||
|
self.name = name
|
||||||
|
self.namespace_id = namespace_id
|
||||||
|
self.description = description
|
||||||
|
self.creator_request_id = creator_request_id
|
||||||
|
self.dns_config = dns_config
|
||||||
|
self.health_check_config = health_check_config
|
||||||
|
self.health_check_custom_config = health_check_custom_config
|
||||||
|
self.service_type = service_type
|
||||||
|
self.created = unix_time()
|
||||||
|
|
||||||
|
def update(self, details):
|
||||||
|
if "Description" in details:
|
||||||
|
self.description = details["Description"]
|
||||||
|
if "DnsConfig" in details:
|
||||||
|
if self.dns_config is None:
|
||||||
|
self.dns_config = {}
|
||||||
|
self.dns_config["DnsRecords"] = details["DnsConfig"]["DnsRecords"]
|
||||||
|
else:
|
||||||
|
# From the docs:
|
||||||
|
# If you omit any existing DnsRecords or HealthCheckConfig configurations from an UpdateService request,
|
||||||
|
# the configurations are deleted from the service.
|
||||||
|
self.dns_config = None
|
||||||
|
if "HealthCheckConfig" in details:
|
||||||
|
self.health_check_config = details["HealthCheckConfig"]
|
||||||
|
|
||||||
|
def to_json(self):
|
||||||
|
return {
|
||||||
|
"Arn": self.arn,
|
||||||
|
"Id": self.id,
|
||||||
|
"Name": self.name,
|
||||||
|
"NamespaceId": self.namespace_id,
|
||||||
|
"CreateDate": self.created,
|
||||||
|
"Description": self.description,
|
||||||
|
"CreatorRequestId": self.creator_request_id,
|
||||||
|
"DnsConfig": self.dns_config,
|
||||||
|
"HealthCheckConfig": self.health_check_config,
|
||||||
|
"HealthCheckCustomConfig": self.health_check_custom_config,
|
||||||
|
"Type": self.service_type,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class Operation(BaseModel):
|
||||||
|
def __init__(self, operation_type, targets):
|
||||||
|
super().__init__()
|
||||||
|
self.id = f"{random_id(32)}-{random_id(8)}"
|
||||||
|
self.status = "SUCCESS"
|
||||||
|
self.operation_type = operation_type
|
||||||
|
self.created = unix_time()
|
||||||
|
self.updated = unix_time()
|
||||||
|
self.targets = targets
|
||||||
|
|
||||||
|
def to_json(self, short=False):
|
||||||
|
if short:
|
||||||
|
return {"Id": self.id, "Status": self.status}
|
||||||
|
else:
|
||||||
|
return {
|
||||||
|
"Id": self.id,
|
||||||
|
"Status": self.status,
|
||||||
|
"Type": self.operation_type,
|
||||||
|
"CreateDate": self.created,
|
||||||
|
"UpdateDate": self.updated,
|
||||||
|
"Targets": self.targets,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class ServiceDiscoveryBackend(BaseBackend):
|
||||||
|
"""Implementation of ServiceDiscovery APIs."""
|
||||||
|
|
||||||
|
def __init__(self, region_name=None):
|
||||||
|
self.region_name = region_name
|
||||||
|
self.operations = dict()
|
||||||
|
self.namespaces = dict()
|
||||||
|
self.services = dict()
|
||||||
|
self.tagger = TaggingService()
|
||||||
|
|
||||||
|
def reset(self):
|
||||||
|
"""Re-initialize all attributes for this instance."""
|
||||||
|
region_name = self.region_name
|
||||||
|
self.__dict__ = {}
|
||||||
|
self.__init__(region_name)
|
||||||
|
|
||||||
|
def list_namespaces(self):
|
||||||
|
"""
|
||||||
|
Pagination or the Filters-parameter is not yet implemented
|
||||||
|
"""
|
||||||
|
return self.namespaces.values()
|
||||||
|
|
||||||
|
def create_http_namespace(self, name, creator_request_id, description, tags):
|
||||||
|
namespace = Namespace(
|
||||||
|
region=self.region_name,
|
||||||
|
name=name,
|
||||||
|
ns_type="HTTP",
|
||||||
|
creator_request_id=creator_request_id,
|
||||||
|
description=description,
|
||||||
|
dns_properties={"SOA": {}},
|
||||||
|
http_properties={"HttpName": name},
|
||||||
|
)
|
||||||
|
self.namespaces[namespace.id] = namespace
|
||||||
|
if tags:
|
||||||
|
self.tagger.tag_resource(namespace.arn, tags)
|
||||||
|
operation_id = self._create_operation(
|
||||||
|
"CREATE_NAMESPACE", targets={"NAMESPACE": namespace.id}
|
||||||
|
)
|
||||||
|
return operation_id
|
||||||
|
|
||||||
|
def _create_operation(self, op_type, targets):
|
||||||
|
operation = Operation(operation_type=op_type, targets=targets)
|
||||||
|
self.operations[operation.id] = operation
|
||||||
|
operation_id = operation.id
|
||||||
|
return operation_id
|
||||||
|
|
||||||
|
def delete_namespace(self, namespace_id):
|
||||||
|
if namespace_id not in self.namespaces:
|
||||||
|
raise NamespaceNotFound(namespace_id)
|
||||||
|
del self.namespaces[namespace_id]
|
||||||
|
operation_id = self._create_operation(
|
||||||
|
op_type="DELETE_NAMESPACE", targets={"NAMESPACE": namespace_id}
|
||||||
|
)
|
||||||
|
return operation_id
|
||||||
|
|
||||||
|
def get_namespace(self, namespace_id):
|
||||||
|
if namespace_id not in self.namespaces:
|
||||||
|
raise NamespaceNotFound(namespace_id)
|
||||||
|
return self.namespaces[namespace_id]
|
||||||
|
|
||||||
|
def list_operations(self):
|
||||||
|
"""
|
||||||
|
Pagination or the Filters-argument is not yet implemented
|
||||||
|
"""
|
||||||
|
# Operations for namespaces will only be listed as long as namespaces exist
|
||||||
|
self.operations = {
|
||||||
|
op_id: op
|
||||||
|
for op_id, op in self.operations.items()
|
||||||
|
if op.targets.get("NAMESPACE") in self.namespaces
|
||||||
|
}
|
||||||
|
return self.operations.values()
|
||||||
|
|
||||||
|
def get_operation(self, operation_id):
|
||||||
|
if operation_id not in self.operations:
|
||||||
|
raise OperationNotFound()
|
||||||
|
return self.operations[operation_id]
|
||||||
|
|
||||||
|
def tag_resource(self, resource_arn, tags):
|
||||||
|
self.tagger.tag_resource(resource_arn, tags)
|
||||||
|
|
||||||
|
def untag_resource(self, resource_arn, tag_keys):
|
||||||
|
self.tagger.untag_resource_using_names(resource_arn, tag_keys)
|
||||||
|
|
||||||
|
def list_tags_for_resource(self, resource_arn):
|
||||||
|
return self.tagger.list_tags_for_resource(resource_arn)
|
||||||
|
|
||||||
|
def create_private_dns_namespace(
|
||||||
|
self, name, creator_request_id, description, vpc, tags, properties
|
||||||
|
):
|
||||||
|
for namespace in self.namespaces.values():
|
||||||
|
if namespace.vpc == vpc:
|
||||||
|
raise ConflictingDomainExists(vpc)
|
||||||
|
dns_properties = (properties or {}).get("DnsProperties", {})
|
||||||
|
dns_properties["HostedZoneId"] = "hzi"
|
||||||
|
namespace = Namespace(
|
||||||
|
region=self.region_name,
|
||||||
|
name=name,
|
||||||
|
ns_type="DNS_PRIVATE",
|
||||||
|
creator_request_id=creator_request_id,
|
||||||
|
description=description,
|
||||||
|
dns_properties=dns_properties,
|
||||||
|
http_properties={},
|
||||||
|
vpc=vpc,
|
||||||
|
)
|
||||||
|
self.namespaces[namespace.id] = namespace
|
||||||
|
if tags:
|
||||||
|
self.tagger.tag_resource(namespace.arn, tags)
|
||||||
|
operation_id = self._create_operation(
|
||||||
|
"CREATE_NAMESPACE", targets={"NAMESPACE": namespace.id}
|
||||||
|
)
|
||||||
|
return operation_id
|
||||||
|
|
||||||
|
def create_public_dns_namespace(
|
||||||
|
self, name, creator_request_id, description, tags, properties
|
||||||
|
):
|
||||||
|
dns_properties = (properties or {}).get("DnsProperties", {})
|
||||||
|
dns_properties["HostedZoneId"] = "hzi"
|
||||||
|
namespace = Namespace(
|
||||||
|
region=self.region_name,
|
||||||
|
name=name,
|
||||||
|
ns_type="DNS_PUBLIC",
|
||||||
|
creator_request_id=creator_request_id,
|
||||||
|
description=description,
|
||||||
|
dns_properties=dns_properties,
|
||||||
|
http_properties={},
|
||||||
|
)
|
||||||
|
self.namespaces[namespace.id] = namespace
|
||||||
|
if tags:
|
||||||
|
self.tagger.tag_resource(namespace.arn, tags)
|
||||||
|
operation_id = self._create_operation(
|
||||||
|
"CREATE_NAMESPACE", targets={"NAMESPACE": namespace.id}
|
||||||
|
)
|
||||||
|
return operation_id
|
||||||
|
|
||||||
|
def create_service(
|
||||||
|
self,
|
||||||
|
name,
|
||||||
|
namespace_id,
|
||||||
|
creator_request_id,
|
||||||
|
description,
|
||||||
|
dns_config,
|
||||||
|
health_check_config,
|
||||||
|
health_check_custom_config,
|
||||||
|
tags,
|
||||||
|
service_type,
|
||||||
|
):
|
||||||
|
service = Service(
|
||||||
|
region=self.region_name,
|
||||||
|
name=name,
|
||||||
|
namespace_id=namespace_id,
|
||||||
|
description=description,
|
||||||
|
creator_request_id=creator_request_id,
|
||||||
|
dns_config=dns_config,
|
||||||
|
health_check_config=health_check_config,
|
||||||
|
health_check_custom_config=health_check_custom_config,
|
||||||
|
service_type=service_type,
|
||||||
|
)
|
||||||
|
self.services[service.id] = service
|
||||||
|
if tags:
|
||||||
|
self.tagger.tag_resource(service.arn, tags)
|
||||||
|
return service
|
||||||
|
|
||||||
|
def get_service(self, service_id):
|
||||||
|
if service_id not in self.services:
|
||||||
|
raise ServiceNotFound(service_id)
|
||||||
|
return self.services[service_id]
|
||||||
|
|
||||||
|
def delete_service(self, service_id):
|
||||||
|
self.services.pop(service_id, None)
|
||||||
|
|
||||||
|
def list_services(self):
|
||||||
|
"""
|
||||||
|
Pagination or the Filters-argument is not yet implemented
|
||||||
|
"""
|
||||||
|
return self.services.values()
|
||||||
|
|
||||||
|
def update_service(self, service_id, details):
|
||||||
|
service = self.get_service(service_id)
|
||||||
|
service.update(details=details)
|
||||||
|
operation_id = self._create_operation(
|
||||||
|
"UPDATE_SERVICE", targets={"SEVICE": service.id}
|
||||||
|
)
|
||||||
|
return operation_id
|
||||||
|
|
||||||
|
|
||||||
|
servicediscovery_backends = BackendDict(ServiceDiscoveryBackend, "servicediscovery")
|
171
moto/servicediscovery/responses.py
Normal file
171
moto/servicediscovery/responses.py
Normal file
@ -0,0 +1,171 @@
|
|||||||
|
"""Handles incoming servicediscovery requests, invokes methods, returns responses."""
|
||||||
|
import json
|
||||||
|
|
||||||
|
from moto.core.responses import BaseResponse
|
||||||
|
from .models import servicediscovery_backends
|
||||||
|
|
||||||
|
|
||||||
|
class ServiceDiscoveryResponse(BaseResponse):
|
||||||
|
@property
|
||||||
|
def servicediscovery_backend(self):
|
||||||
|
"""Return backend instance specific for this region."""
|
||||||
|
return servicediscovery_backends[self.region]
|
||||||
|
|
||||||
|
def list_namespaces(self):
|
||||||
|
namespaces = self.servicediscovery_backend.list_namespaces()
|
||||||
|
return 200, {}, json.dumps({"Namespaces": [ns.to_json() for ns in namespaces]})
|
||||||
|
|
||||||
|
def create_http_namespace(self):
|
||||||
|
params = json.loads(self.body)
|
||||||
|
name = params.get("Name")
|
||||||
|
creator_request_id = params.get("CreatorRequestId")
|
||||||
|
description = params.get("Description")
|
||||||
|
tags = params.get("Tags")
|
||||||
|
operation_id = self.servicediscovery_backend.create_http_namespace(
|
||||||
|
name=name,
|
||||||
|
creator_request_id=creator_request_id,
|
||||||
|
description=description,
|
||||||
|
tags=tags,
|
||||||
|
)
|
||||||
|
return json.dumps(dict(OperationId=operation_id))
|
||||||
|
|
||||||
|
def delete_namespace(self):
|
||||||
|
params = json.loads(self.body)
|
||||||
|
namespace_id = params.get("Id")
|
||||||
|
operation_id = self.servicediscovery_backend.delete_namespace(
|
||||||
|
namespace_id=namespace_id,
|
||||||
|
)
|
||||||
|
return json.dumps(dict(OperationId=operation_id))
|
||||||
|
|
||||||
|
def list_operations(self):
|
||||||
|
operations = self.servicediscovery_backend.list_operations()
|
||||||
|
return (
|
||||||
|
200,
|
||||||
|
{},
|
||||||
|
json.dumps({"Operations": [o.to_json(short=True) for o in operations]}),
|
||||||
|
)
|
||||||
|
|
||||||
|
def get_operation(self):
|
||||||
|
params = json.loads(self.body)
|
||||||
|
operation_id = params.get("OperationId")
|
||||||
|
operation = self.servicediscovery_backend.get_operation(
|
||||||
|
operation_id=operation_id,
|
||||||
|
)
|
||||||
|
return json.dumps(dict(Operation=operation.to_json()))
|
||||||
|
|
||||||
|
def get_namespace(self):
|
||||||
|
params = json.loads(self.body)
|
||||||
|
namespace_id = params.get("Id")
|
||||||
|
namespace = self.servicediscovery_backend.get_namespace(
|
||||||
|
namespace_id=namespace_id,
|
||||||
|
)
|
||||||
|
return json.dumps(dict(Namespace=namespace.to_json()))
|
||||||
|
|
||||||
|
def tag_resource(self):
|
||||||
|
params = json.loads(self.body)
|
||||||
|
resource_arn = params.get("ResourceARN")
|
||||||
|
tags = params.get("Tags")
|
||||||
|
self.servicediscovery_backend.tag_resource(
|
||||||
|
resource_arn=resource_arn, tags=tags,
|
||||||
|
)
|
||||||
|
return json.dumps(dict())
|
||||||
|
|
||||||
|
def untag_resource(self):
|
||||||
|
params = json.loads(self.body)
|
||||||
|
resource_arn = params.get("ResourceARN")
|
||||||
|
tag_keys = params.get("TagKeys")
|
||||||
|
self.servicediscovery_backend.untag_resource(
|
||||||
|
resource_arn=resource_arn, tag_keys=tag_keys,
|
||||||
|
)
|
||||||
|
return json.dumps(dict())
|
||||||
|
|
||||||
|
def list_tags_for_resource(self):
|
||||||
|
params = json.loads(self.body)
|
||||||
|
resource_arn = params.get("ResourceARN")
|
||||||
|
tags = self.servicediscovery_backend.list_tags_for_resource(
|
||||||
|
resource_arn=resource_arn,
|
||||||
|
)
|
||||||
|
return 200, {}, json.dumps(tags)
|
||||||
|
|
||||||
|
def create_private_dns_namespace(self):
|
||||||
|
params = json.loads(self.body)
|
||||||
|
name = params.get("Name")
|
||||||
|
creator_request_id = params.get("CreatorRequestId")
|
||||||
|
description = params.get("Description")
|
||||||
|
vpc = params.get("Vpc")
|
||||||
|
tags = params.get("Tags")
|
||||||
|
properties = params.get("Properties")
|
||||||
|
operation_id = self.servicediscovery_backend.create_private_dns_namespace(
|
||||||
|
name=name,
|
||||||
|
creator_request_id=creator_request_id,
|
||||||
|
description=description,
|
||||||
|
vpc=vpc,
|
||||||
|
tags=tags,
|
||||||
|
properties=properties,
|
||||||
|
)
|
||||||
|
return json.dumps(dict(OperationId=operation_id))
|
||||||
|
|
||||||
|
def create_public_dns_namespace(self):
|
||||||
|
params = json.loads(self.body)
|
||||||
|
name = params.get("Name")
|
||||||
|
creator_request_id = params.get("CreatorRequestId")
|
||||||
|
description = params.get("Description")
|
||||||
|
tags = params.get("Tags")
|
||||||
|
properties = params.get("Properties")
|
||||||
|
operation_id = self.servicediscovery_backend.create_public_dns_namespace(
|
||||||
|
name=name,
|
||||||
|
creator_request_id=creator_request_id,
|
||||||
|
description=description,
|
||||||
|
tags=tags,
|
||||||
|
properties=properties,
|
||||||
|
)
|
||||||
|
return json.dumps(dict(OperationId=operation_id))
|
||||||
|
|
||||||
|
def create_service(self):
|
||||||
|
params = json.loads(self.body)
|
||||||
|
name = params.get("Name")
|
||||||
|
namespace_id = params.get("NamespaceId")
|
||||||
|
creator_request_id = params.get("CreatorRequestId")
|
||||||
|
description = params.get("Description")
|
||||||
|
dns_config = params.get("DnsConfig")
|
||||||
|
health_check_config = params.get("HealthCheckConfig")
|
||||||
|
health_check_custom_config = params.get("HealthCheckCustomConfig")
|
||||||
|
tags = params.get("Tags")
|
||||||
|
service_type = params.get("Type")
|
||||||
|
service = self.servicediscovery_backend.create_service(
|
||||||
|
name=name,
|
||||||
|
namespace_id=namespace_id,
|
||||||
|
creator_request_id=creator_request_id,
|
||||||
|
description=description,
|
||||||
|
dns_config=dns_config,
|
||||||
|
health_check_config=health_check_config,
|
||||||
|
health_check_custom_config=health_check_custom_config,
|
||||||
|
tags=tags,
|
||||||
|
service_type=service_type,
|
||||||
|
)
|
||||||
|
return json.dumps(dict(Service=service.to_json()))
|
||||||
|
|
||||||
|
def get_service(self):
|
||||||
|
params = json.loads(self.body)
|
||||||
|
service_id = params.get("Id")
|
||||||
|
service = self.servicediscovery_backend.get_service(service_id=service_id)
|
||||||
|
return json.dumps(dict(Service=service.to_json()))
|
||||||
|
|
||||||
|
def delete_service(self):
|
||||||
|
params = json.loads(self.body)
|
||||||
|
service_id = params.get("Id")
|
||||||
|
self.servicediscovery_backend.delete_service(service_id=service_id)
|
||||||
|
return json.dumps(dict())
|
||||||
|
|
||||||
|
def list_services(self):
|
||||||
|
services = self.servicediscovery_backend.list_services()
|
||||||
|
return json.dumps(dict(Services=[s.to_json() for s in services]))
|
||||||
|
|
||||||
|
def update_service(self):
|
||||||
|
params = json.loads(self.body)
|
||||||
|
service_id = params.get("Id")
|
||||||
|
details = params.get("Service")
|
||||||
|
operation_id = self.servicediscovery_backend.update_service(
|
||||||
|
service_id=service_id, details=details,
|
||||||
|
)
|
||||||
|
return json.dumps(dict(OperationId=operation_id))
|
11
moto/servicediscovery/urls.py
Normal file
11
moto/servicediscovery/urls.py
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
"""servicediscovery base URL and path."""
|
||||||
|
from .responses import ServiceDiscoveryResponse
|
||||||
|
|
||||||
|
url_bases = [
|
||||||
|
r"https?://servicediscovery\.(.+)\.amazonaws\.com",
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
url_paths = {
|
||||||
|
"{0}/$": ServiceDiscoveryResponse.dispatch,
|
||||||
|
}
|
@ -85,6 +85,7 @@ TestAccAWSRedshiftServiceAccount
|
|||||||
TestAccAWSRolePolicyAttachment
|
TestAccAWSRolePolicyAttachment
|
||||||
TestAccAWSSNSSMSPreferences
|
TestAccAWSSNSSMSPreferences
|
||||||
TestAccAWSSageMakerPrebuiltECRImage
|
TestAccAWSSageMakerPrebuiltECRImage
|
||||||
|
TestAccAWSServiceDiscovery
|
||||||
TestAccAWSSQSQueuePolicy
|
TestAccAWSSQSQueuePolicy
|
||||||
TestAccAWSSSMDocument
|
TestAccAWSSSMDocument
|
||||||
TestValidateSSMDocumentPermissions
|
TestValidateSSMDocumentPermissions
|
||||||
|
0
tests/test_servicediscovery/__init__.py
Normal file
0
tests/test_servicediscovery/__init__.py
Normal file
15
tests/test_servicediscovery/test_server.py
Normal file
15
tests/test_servicediscovery/test_server.py
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
import json
|
||||||
|
import sure # noqa # pylint: disable=unused-import
|
||||||
|
|
||||||
|
import moto.server as server
|
||||||
|
|
||||||
|
|
||||||
|
def test_servicediscovery_list():
|
||||||
|
backend = server.create_backend_app("servicediscovery")
|
||||||
|
test_client = backend.test_client()
|
||||||
|
|
||||||
|
headers = {"X-Amz-Target": "Route53AutoNaming_v20170314.ListNamespaces"}
|
||||||
|
|
||||||
|
resp = test_client.get("/", headers=headers)
|
||||||
|
resp.status_code.should.equal(200)
|
||||||
|
json.loads(resp.data).should.equal({"Namespaces": []})
|
@ -0,0 +1,233 @@
|
|||||||
|
"""Unit tests for servicediscovery-supported APIs."""
|
||||||
|
import boto3
|
||||||
|
import pytest
|
||||||
|
import sure # noqa # pylint: disable=unused-import
|
||||||
|
|
||||||
|
from botocore.exceptions import ClientError
|
||||||
|
from moto import mock_servicediscovery
|
||||||
|
from moto.core import ACCOUNT_ID
|
||||||
|
|
||||||
|
# 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
|
||||||
|
|
||||||
|
|
||||||
|
@mock_servicediscovery
|
||||||
|
def test_create_http_namespace():
|
||||||
|
client = boto3.client("servicediscovery", region_name="eu-west-1")
|
||||||
|
client.create_http_namespace(Name="mynamespace")
|
||||||
|
|
||||||
|
resp = client.list_namespaces()
|
||||||
|
resp.should.have.key("Namespaces").length_of(1)
|
||||||
|
|
||||||
|
namespace = resp["Namespaces"][0]
|
||||||
|
namespace.should.have.key("Id").match("ns-[a-z0-9]{16}")
|
||||||
|
namespace.should.have.key("Arn").match(
|
||||||
|
f"arn:aws:servicediscovery:eu-west-1:{ACCOUNT_ID}:namespace/{namespace['Id']}"
|
||||||
|
)
|
||||||
|
namespace.should.have.key("Name").equals("mynamespace")
|
||||||
|
namespace.should.have.key("Type").equals("HTTP")
|
||||||
|
namespace.should.have.key("CreateDate")
|
||||||
|
|
||||||
|
namespace.should.have.key("Properties")
|
||||||
|
props = namespace["Properties"]
|
||||||
|
props.should.have.key("DnsProperties").equals({"SOA": {}})
|
||||||
|
props.should.have.key("HttpProperties").equals({"HttpName": "mynamespace"})
|
||||||
|
|
||||||
|
|
||||||
|
@mock_servicediscovery
|
||||||
|
def test_get_http_namespace_minimal():
|
||||||
|
client = boto3.client("servicediscovery", region_name="eu-west-1")
|
||||||
|
client.create_http_namespace(Name="mynamespace")
|
||||||
|
|
||||||
|
ns_id = client.list_namespaces()["Namespaces"][0]["Id"]
|
||||||
|
|
||||||
|
resp = client.get_namespace(Id=ns_id)
|
||||||
|
resp.should.have.key("Namespace")
|
||||||
|
|
||||||
|
namespace = resp["Namespace"]
|
||||||
|
namespace.should.have.key("Id").match(ns_id)
|
||||||
|
namespace.should.have.key("Arn").match(
|
||||||
|
f"arn:aws:servicediscovery:eu-west-1:{ACCOUNT_ID}:namespace/{namespace['Id']}"
|
||||||
|
)
|
||||||
|
namespace.should.have.key("Name").equals("mynamespace")
|
||||||
|
namespace.should.have.key("Type").equals("HTTP")
|
||||||
|
namespace.should.have.key("CreateDate")
|
||||||
|
namespace.should.have.key("CreatorRequestId")
|
||||||
|
|
||||||
|
namespace.should.have.key("Properties")
|
||||||
|
props = namespace["Properties"]
|
||||||
|
props.should.have.key("DnsProperties").equals({"SOA": {}})
|
||||||
|
props.should.have.key("HttpProperties").equals({"HttpName": "mynamespace"})
|
||||||
|
|
||||||
|
namespace.shouldnt.have.key("Description")
|
||||||
|
|
||||||
|
|
||||||
|
@mock_servicediscovery
|
||||||
|
def test_get_http_namespace():
|
||||||
|
client = boto3.client("servicediscovery", region_name="eu-west-1")
|
||||||
|
client.create_http_namespace(
|
||||||
|
Name="mynamespace", CreatorRequestId="crid", Description="mu fancy namespace"
|
||||||
|
)
|
||||||
|
|
||||||
|
ns_id = client.list_namespaces()["Namespaces"][0]["Id"]
|
||||||
|
|
||||||
|
resp = client.get_namespace(Id=ns_id)
|
||||||
|
resp.should.have.key("Namespace")
|
||||||
|
|
||||||
|
namespace = resp["Namespace"]
|
||||||
|
namespace.should.have.key("Id").match(ns_id)
|
||||||
|
namespace.should.have.key("Arn").match(
|
||||||
|
f"arn:aws:servicediscovery:eu-west-1:{ACCOUNT_ID}:namespace/{namespace['Id']}"
|
||||||
|
)
|
||||||
|
namespace.should.have.key("Name").equals("mynamespace")
|
||||||
|
namespace.should.have.key("Type").equals("HTTP")
|
||||||
|
namespace.should.have.key("CreateDate")
|
||||||
|
namespace.should.have.key("CreatorRequestId").equals("crid")
|
||||||
|
namespace.should.have.key("Description").equals("mu fancy namespace")
|
||||||
|
|
||||||
|
namespace.should.have.key("Properties")
|
||||||
|
props = namespace["Properties"]
|
||||||
|
props.should.have.key("DnsProperties").equals({"SOA": {}})
|
||||||
|
props.should.have.key("HttpProperties").equals({"HttpName": "mynamespace"})
|
||||||
|
|
||||||
|
|
||||||
|
@mock_servicediscovery
|
||||||
|
def test_delete_namespace():
|
||||||
|
client = boto3.client("servicediscovery", region_name="eu-west-1")
|
||||||
|
client.create_http_namespace(Name="mynamespace")
|
||||||
|
ns_id = client.list_namespaces()["Namespaces"][0]["Id"]
|
||||||
|
|
||||||
|
resp = client.delete_namespace(Id=ns_id)
|
||||||
|
resp.should.have.key("OperationId")
|
||||||
|
|
||||||
|
# Calling delete again while this is in progress results in an error:
|
||||||
|
# Another operation of type DeleteNamespace and id dlmpkcn33aovnztwdpsdplgtheuhgcap-k6x64euq is in progress
|
||||||
|
# list_operations is empty after successfull deletion - old operations from this namespace should be deleted
|
||||||
|
# list_namespaces is also empty (obvs)
|
||||||
|
|
||||||
|
client.list_namespaces()["Namespaces"].should.equal([])
|
||||||
|
client.list_operations()["Operations"].should.equal([])
|
||||||
|
|
||||||
|
|
||||||
|
@mock_servicediscovery
|
||||||
|
def test_delete_unknown_namespace():
|
||||||
|
client = boto3.client("servicediscovery", region_name="eu-west-1")
|
||||||
|
with pytest.raises(ClientError) as exc:
|
||||||
|
client.delete_namespace(Id="unknown")
|
||||||
|
err = exc.value.response["Error"]
|
||||||
|
err["Code"].should.equal("NamespaceNotFound")
|
||||||
|
err["Message"].should.equal("unknown")
|
||||||
|
|
||||||
|
|
||||||
|
@mock_servicediscovery
|
||||||
|
def test_get_unknown_namespace():
|
||||||
|
client = boto3.client("servicediscovery", region_name="eu-west-1")
|
||||||
|
with pytest.raises(ClientError) as exc:
|
||||||
|
client.get_namespace(Id="unknown")
|
||||||
|
err = exc.value.response["Error"]
|
||||||
|
err["Code"].should.equal("NamespaceNotFound")
|
||||||
|
err["Message"].should.equal("unknown")
|
||||||
|
|
||||||
|
|
||||||
|
@mock_servicediscovery
|
||||||
|
def test_create_private_dns_namespace_minimal():
|
||||||
|
client = boto3.client("servicediscovery", region_name="eu-west-1")
|
||||||
|
client.create_private_dns_namespace(Name="dns_ns", Vpc="vpc_id")
|
||||||
|
|
||||||
|
ns_id = client.list_namespaces()["Namespaces"][0]["Id"]
|
||||||
|
|
||||||
|
resp = client.get_namespace(Id=ns_id)
|
||||||
|
resp.should.have.key("Namespace")
|
||||||
|
|
||||||
|
namespace = resp["Namespace"]
|
||||||
|
namespace.should.have.key("Id").match(ns_id)
|
||||||
|
namespace.should.have.key("Name").equals("dns_ns")
|
||||||
|
namespace.should.have.key("Type").equals("DNS_PRIVATE")
|
||||||
|
|
||||||
|
namespace.should.have.key("Properties")
|
||||||
|
props = namespace["Properties"]
|
||||||
|
props.should.have.key("DnsProperties")
|
||||||
|
props["DnsProperties"].should.have.key("HostedZoneId")
|
||||||
|
props["DnsProperties"].shouldnt.have.key("SOA")
|
||||||
|
|
||||||
|
|
||||||
|
@mock_servicediscovery
|
||||||
|
def test_create_private_dns_namespace():
|
||||||
|
client = boto3.client("servicediscovery", region_name="eu-west-1")
|
||||||
|
client.create_private_dns_namespace(
|
||||||
|
Name="dns_ns",
|
||||||
|
Vpc="vpc_id",
|
||||||
|
Description="my private dns",
|
||||||
|
Properties={"DnsProperties": {"SOA": {"TTL": 123}}},
|
||||||
|
)
|
||||||
|
|
||||||
|
ns_id = client.list_namespaces()["Namespaces"][0]["Id"]
|
||||||
|
|
||||||
|
resp = client.get_namespace(Id=ns_id)
|
||||||
|
resp.should.have.key("Namespace")
|
||||||
|
|
||||||
|
namespace = resp["Namespace"]
|
||||||
|
namespace.should.have.key("Id").match(ns_id)
|
||||||
|
namespace.should.have.key("Name").equals("dns_ns")
|
||||||
|
namespace.should.have.key("Type").equals("DNS_PRIVATE")
|
||||||
|
namespace.should.have.key("Description").equals("my private dns")
|
||||||
|
|
||||||
|
namespace.should.have.key("Properties")
|
||||||
|
props = namespace["Properties"]
|
||||||
|
props.should.have.key("DnsProperties")
|
||||||
|
props["DnsProperties"].should.have.key("HostedZoneId")
|
||||||
|
props["DnsProperties"].should.have.key("SOA").equals({"TTL": 123})
|
||||||
|
|
||||||
|
|
||||||
|
@mock_servicediscovery
|
||||||
|
def test_create_private_dns_namespace_with_duplicate_vpc():
|
||||||
|
client = boto3.client("servicediscovery", region_name="eu-west-1")
|
||||||
|
client.create_private_dns_namespace(Name="dns_ns", Vpc="vpc_id")
|
||||||
|
|
||||||
|
with pytest.raises(ClientError) as exc:
|
||||||
|
client.create_private_dns_namespace(Name="sth else", Vpc="vpc_id")
|
||||||
|
err = exc.value.response["Error"]
|
||||||
|
err["Code"].should.equal("ConflictingDomainExists")
|
||||||
|
|
||||||
|
|
||||||
|
@mock_servicediscovery
|
||||||
|
def test_create_public_dns_namespace_minimal():
|
||||||
|
client = boto3.client("servicediscovery", region_name="us-east-2")
|
||||||
|
client.create_public_dns_namespace(Name="public_dns_ns")
|
||||||
|
|
||||||
|
ns_id = client.list_namespaces()["Namespaces"][0]["Id"]
|
||||||
|
|
||||||
|
resp = client.get_namespace(Id=ns_id)
|
||||||
|
resp.should.have.key("Namespace")
|
||||||
|
|
||||||
|
namespace = resp["Namespace"]
|
||||||
|
namespace.should.have.key("Id").match(ns_id)
|
||||||
|
namespace.should.have.key("Name").equals("public_dns_ns")
|
||||||
|
namespace.should.have.key("Type").equals("DNS_PUBLIC")
|
||||||
|
|
||||||
|
|
||||||
|
@mock_servicediscovery
|
||||||
|
def test_create_public_dns_namespace():
|
||||||
|
client = boto3.client("servicediscovery", region_name="us-east-2")
|
||||||
|
client.create_public_dns_namespace(
|
||||||
|
Name="public_dns_ns",
|
||||||
|
CreatorRequestId="cri",
|
||||||
|
Description="my public dns",
|
||||||
|
Properties={"DnsProperties": {"SOA": {"TTL": 124}}},
|
||||||
|
)
|
||||||
|
|
||||||
|
ns_id = client.list_namespaces()["Namespaces"][0]["Id"]
|
||||||
|
|
||||||
|
resp = client.get_namespace(Id=ns_id)
|
||||||
|
resp.should.have.key("Namespace")
|
||||||
|
|
||||||
|
namespace = resp["Namespace"]
|
||||||
|
namespace.should.have.key("Id").match(ns_id)
|
||||||
|
namespace.should.have.key("Name").equals("public_dns_ns")
|
||||||
|
namespace.should.have.key("Type").equals("DNS_PUBLIC")
|
||||||
|
namespace.should.have.key("Description").equals("my public dns")
|
||||||
|
namespace.should.have.key("CreatorRequestId").equals("cri")
|
||||||
|
|
||||||
|
namespace.should.have.key("Properties").should.have.key("DnsProperties")
|
||||||
|
dns_props = namespace["Properties"]["DnsProperties"]
|
||||||
|
dns_props.should.equal({"HostedZoneId": "hzi", "SOA": {"TTL": 124}})
|
135
tests/test_servicediscovery/test_servicediscovery_operations.py
Normal file
135
tests/test_servicediscovery/test_servicediscovery_operations.py
Normal file
@ -0,0 +1,135 @@
|
|||||||
|
"""Unit tests for servicediscovery-supported APIs."""
|
||||||
|
import boto3
|
||||||
|
import pytest
|
||||||
|
import sure # noqa # pylint: disable=unused-import
|
||||||
|
|
||||||
|
from botocore.exceptions import ClientError
|
||||||
|
from moto import mock_servicediscovery
|
||||||
|
|
||||||
|
# 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
|
||||||
|
|
||||||
|
|
||||||
|
@mock_servicediscovery
|
||||||
|
def test_list_operations_initial():
|
||||||
|
client = boto3.client("servicediscovery", region_name="eu-west-1")
|
||||||
|
resp = client.list_operations()
|
||||||
|
|
||||||
|
resp.should.have.key("Operations").equals([])
|
||||||
|
|
||||||
|
|
||||||
|
@mock_servicediscovery
|
||||||
|
def test_list_operations():
|
||||||
|
client = boto3.client("servicediscovery", region_name="eu-west-2")
|
||||||
|
|
||||||
|
resp = client.create_http_namespace(Name="n/a")
|
||||||
|
resp.should.have.key("OperationId")
|
||||||
|
op_id = resp["OperationId"]
|
||||||
|
|
||||||
|
resp = client.list_operations()
|
||||||
|
resp.should.have.key("Operations").length_of(1)
|
||||||
|
resp["Operations"].should.equal([{"Id": op_id, "Status": "SUCCESS"}])
|
||||||
|
|
||||||
|
|
||||||
|
@mock_servicediscovery
|
||||||
|
def test_get_create_http_namespace_operation():
|
||||||
|
client = boto3.client("servicediscovery", region_name="eu-west-1")
|
||||||
|
resp = client.create_http_namespace(Name="mynamespace")
|
||||||
|
|
||||||
|
resp["OperationId"].should.match("[a-z0-9]{32}-[a-z0-9]{8}")
|
||||||
|
|
||||||
|
operation_id = resp["OperationId"]
|
||||||
|
|
||||||
|
resp = client.get_operation(OperationId=operation_id)
|
||||||
|
|
||||||
|
resp.should.have.key("Operation")
|
||||||
|
operation = resp["Operation"]
|
||||||
|
operation.should.have.key("Id").equals(operation_id)
|
||||||
|
operation.should.have.key("Type").equals("CREATE_NAMESPACE")
|
||||||
|
operation.should.have.key("Status").equals("SUCCESS")
|
||||||
|
operation.should.have.key("CreateDate")
|
||||||
|
operation.should.have.key("UpdateDate")
|
||||||
|
operation.should.have.key("Targets")
|
||||||
|
|
||||||
|
targets = operation["Targets"]
|
||||||
|
targets.should.have.key("NAMESPACE")
|
||||||
|
|
||||||
|
namespaces = client.list_namespaces()["Namespaces"]
|
||||||
|
[ns["Id"] for ns in namespaces].should.contain(targets["NAMESPACE"])
|
||||||
|
|
||||||
|
|
||||||
|
@mock_servicediscovery
|
||||||
|
def test_get_private_dns_namespace_operation():
|
||||||
|
client = boto3.client("servicediscovery", region_name="eu-west-1")
|
||||||
|
resp = client.create_private_dns_namespace(Name="dns_ns", Vpc="vpc_id")
|
||||||
|
|
||||||
|
resp["OperationId"].should.match("[a-z0-9]{32}-[a-z0-9]{8}")
|
||||||
|
|
||||||
|
operation_id = resp["OperationId"]
|
||||||
|
|
||||||
|
resp = client.get_operation(OperationId=operation_id)
|
||||||
|
|
||||||
|
resp.should.have.key("Operation")
|
||||||
|
operation = resp["Operation"]
|
||||||
|
operation.should.have.key("Id").equals(operation_id)
|
||||||
|
operation.should.have.key("Type").equals("CREATE_NAMESPACE")
|
||||||
|
operation.should.have.key("Status").equals("SUCCESS")
|
||||||
|
operation.should.have.key("CreateDate")
|
||||||
|
operation.should.have.key("UpdateDate")
|
||||||
|
operation.should.have.key("Targets")
|
||||||
|
|
||||||
|
|
||||||
|
@mock_servicediscovery
|
||||||
|
def test_get_public_dns_namespace_operation():
|
||||||
|
client = boto3.client("servicediscovery", region_name="eu-west-1")
|
||||||
|
resp = client.create_public_dns_namespace(Name="dns_ns")
|
||||||
|
|
||||||
|
resp["OperationId"].should.match("[a-z0-9]{32}-[a-z0-9]{8}")
|
||||||
|
|
||||||
|
operation_id = resp["OperationId"]
|
||||||
|
|
||||||
|
resp = client.get_operation(OperationId=operation_id)
|
||||||
|
|
||||||
|
resp.should.have.key("Operation")
|
||||||
|
operation = resp["Operation"]
|
||||||
|
operation.should.have.key("Id").equals(operation_id)
|
||||||
|
operation.should.have.key("Type").equals("CREATE_NAMESPACE")
|
||||||
|
operation.should.have.key("Status").equals("SUCCESS")
|
||||||
|
operation.should.have.key("CreateDate")
|
||||||
|
operation.should.have.key("UpdateDate")
|
||||||
|
operation.should.have.key("Targets")
|
||||||
|
|
||||||
|
|
||||||
|
@mock_servicediscovery
|
||||||
|
def test_get_update_service_operation():
|
||||||
|
client = boto3.client("servicediscovery", region_name="eu-west-1")
|
||||||
|
service_id = client.create_service(
|
||||||
|
Name="my service", NamespaceId="ns_id", Description="first desc",
|
||||||
|
)["Service"]["Id"]
|
||||||
|
|
||||||
|
resp = client.update_service(Id=service_id, Service={"Description": "updated desc"})
|
||||||
|
|
||||||
|
resp["OperationId"].should.match("[a-z0-9]{32}-[a-z0-9]{8}")
|
||||||
|
|
||||||
|
operation_id = resp["OperationId"]
|
||||||
|
|
||||||
|
resp = client.get_operation(OperationId=operation_id)
|
||||||
|
|
||||||
|
resp.should.have.key("Operation")
|
||||||
|
operation = resp["Operation"]
|
||||||
|
operation.should.have.key("Id").equals(operation_id)
|
||||||
|
operation.should.have.key("Type").equals("UPDATE_SERVICE")
|
||||||
|
operation.should.have.key("Status").equals("SUCCESS")
|
||||||
|
operation.should.have.key("CreateDate")
|
||||||
|
operation.should.have.key("UpdateDate")
|
||||||
|
operation.should.have.key("Targets")
|
||||||
|
|
||||||
|
|
||||||
|
@mock_servicediscovery
|
||||||
|
def test_get_unknown_operation():
|
||||||
|
client = boto3.client("servicediscovery", region_name="eu-west-1")
|
||||||
|
|
||||||
|
with pytest.raises(ClientError) as exc:
|
||||||
|
client.get_operation(OperationId="unknown")
|
||||||
|
err = exc.value.response["Error"]
|
||||||
|
err["Code"].should.equal("OperationNotFound")
|
208
tests/test_servicediscovery/test_servicediscovery_service.py
Normal file
208
tests/test_servicediscovery/test_servicediscovery_service.py
Normal file
@ -0,0 +1,208 @@
|
|||||||
|
"""Unit tests for servicediscovery-supported APIs."""
|
||||||
|
import boto3
|
||||||
|
import pytest
|
||||||
|
import sure # noqa # pylint: disable=unused-import
|
||||||
|
|
||||||
|
from botocore.exceptions import ClientError
|
||||||
|
from moto import mock_servicediscovery
|
||||||
|
|
||||||
|
# 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
|
||||||
|
|
||||||
|
|
||||||
|
@mock_servicediscovery
|
||||||
|
def test_create_service_minimal():
|
||||||
|
client = boto3.client("servicediscovery", region_name="ap-southeast-1")
|
||||||
|
operation_id = client.create_http_namespace(Name="mynamespace")["OperationId"]
|
||||||
|
namespace_id = client.get_operation(OperationId=operation_id)["Operation"][
|
||||||
|
"Targets"
|
||||||
|
]["NAMESPACE"]
|
||||||
|
|
||||||
|
resp = client.create_service(Name="my service", NamespaceId=namespace_id)
|
||||||
|
|
||||||
|
resp.should.have.key("Service")
|
||||||
|
resp["Service"].should.have.key("Id")
|
||||||
|
resp["Service"].should.have.key("Arn")
|
||||||
|
resp["Service"].should.have.key("Name").equals("my service")
|
||||||
|
resp["Service"].should.have.key("NamespaceId").equals(namespace_id)
|
||||||
|
resp["Service"].should.have.key("CreateDate")
|
||||||
|
|
||||||
|
|
||||||
|
@mock_servicediscovery
|
||||||
|
def test_create_service():
|
||||||
|
client = boto3.client("servicediscovery", region_name="ap-southeast-1")
|
||||||
|
operation_id = client.create_http_namespace(Name="mynamespace")["OperationId"]
|
||||||
|
namespace_id = client.get_operation(OperationId=operation_id)["Operation"][
|
||||||
|
"Targets"
|
||||||
|
]["NAMESPACE"]
|
||||||
|
|
||||||
|
resp = client.create_service(
|
||||||
|
Name="my service",
|
||||||
|
CreatorRequestId="crid",
|
||||||
|
Description="my service",
|
||||||
|
DnsConfig={
|
||||||
|
"NamespaceId": namespace_id,
|
||||||
|
"RoutingPolicy": "WEIGHTED",
|
||||||
|
"DnsRecords": [{"Type": "SRV", "TTL": 0}],
|
||||||
|
},
|
||||||
|
HealthCheckConfig={"Type": "TCP", "ResourcePath": "/sth"},
|
||||||
|
HealthCheckCustomConfig={"FailureThreshold": 125},
|
||||||
|
Type="HTTP",
|
||||||
|
)
|
||||||
|
|
||||||
|
resp.should.have.key("Service")
|
||||||
|
resp["Service"].should.have.key("Id")
|
||||||
|
resp["Service"].should.have.key("Arn")
|
||||||
|
resp["Service"].should.have.key("Name").equals("my service")
|
||||||
|
resp["Service"].shouldnt.have.key("NamespaceId")
|
||||||
|
resp["Service"].should.have.key("Description").equals("my service")
|
||||||
|
resp["Service"].should.have.key("DnsConfig").equals(
|
||||||
|
{
|
||||||
|
"NamespaceId": namespace_id,
|
||||||
|
"RoutingPolicy": "WEIGHTED",
|
||||||
|
"DnsRecords": [{"Type": "SRV", "TTL": 0}],
|
||||||
|
}
|
||||||
|
)
|
||||||
|
resp["Service"].should.have.key("HealthCheckConfig").equals(
|
||||||
|
{"Type": "TCP", "ResourcePath": "/sth"}
|
||||||
|
)
|
||||||
|
resp["Service"].should.have.key("HealthCheckCustomConfig").equals(
|
||||||
|
{"FailureThreshold": 125}
|
||||||
|
)
|
||||||
|
resp["Service"].should.have.key("Type").equals("HTTP")
|
||||||
|
resp["Service"].should.have.key("CreatorRequestId").equals("crid")
|
||||||
|
|
||||||
|
|
||||||
|
@mock_servicediscovery
|
||||||
|
def test_get_service():
|
||||||
|
client = boto3.client("servicediscovery", region_name="ap-southeast-1")
|
||||||
|
|
||||||
|
operation_id = client.create_http_namespace(Name="mynamespace")["OperationId"]
|
||||||
|
namespace_id = client.get_operation(OperationId=operation_id)["Operation"][
|
||||||
|
"Targets"
|
||||||
|
]["NAMESPACE"]
|
||||||
|
|
||||||
|
service_id = client.create_service(Name="my service", NamespaceId=namespace_id)[
|
||||||
|
"Service"
|
||||||
|
]["Id"]
|
||||||
|
|
||||||
|
resp = client.get_service(Id=service_id)
|
||||||
|
|
||||||
|
resp.should.have.key("Service")
|
||||||
|
resp["Service"].should.have.key("Id")
|
||||||
|
resp["Service"].should.have.key("Arn")
|
||||||
|
resp["Service"].should.have.key("Name").equals("my service")
|
||||||
|
resp["Service"].should.have.key("NamespaceId").equals(namespace_id)
|
||||||
|
|
||||||
|
|
||||||
|
@mock_servicediscovery
|
||||||
|
def test_get_unknown_service():
|
||||||
|
client = boto3.client("servicediscovery", region_name="ap-southeast-1")
|
||||||
|
|
||||||
|
with pytest.raises(ClientError) as exc:
|
||||||
|
client.get_service(Id="unknown")
|
||||||
|
err = exc.value.response["Error"]
|
||||||
|
err["Code"].should.equal("ServiceNotFound")
|
||||||
|
err["Message"].should.equal("unknown")
|
||||||
|
|
||||||
|
|
||||||
|
@mock_servicediscovery
|
||||||
|
def test_delete_service():
|
||||||
|
client = boto3.client("servicediscovery", region_name="eu-west-1")
|
||||||
|
|
||||||
|
operation_id = client.create_http_namespace(Name="mynamespace")["OperationId"]
|
||||||
|
namespace_id = client.get_operation(OperationId=operation_id)["Operation"][
|
||||||
|
"Targets"
|
||||||
|
]["NAMESPACE"]
|
||||||
|
service_id = client.create_service(Name="my service", NamespaceId=namespace_id)[
|
||||||
|
"Service"
|
||||||
|
]["Id"]
|
||||||
|
|
||||||
|
client.delete_service(Id=service_id)
|
||||||
|
|
||||||
|
with pytest.raises(ClientError) as exc:
|
||||||
|
client.get_service(Id=service_id)
|
||||||
|
err = exc.value.response["Error"]
|
||||||
|
err["Code"].should.equal("ServiceNotFound")
|
||||||
|
err["Message"].should.equal(service_id)
|
||||||
|
|
||||||
|
|
||||||
|
@mock_servicediscovery
|
||||||
|
def test_update_service_description():
|
||||||
|
client = boto3.client("servicediscovery", region_name="ap-southeast-1")
|
||||||
|
operation_id = client.create_http_namespace(Name="mynamespace")["OperationId"]
|
||||||
|
namespace_id = client.get_operation(OperationId=operation_id)["Operation"][
|
||||||
|
"Targets"
|
||||||
|
]["NAMESPACE"]
|
||||||
|
|
||||||
|
service_id = client.create_service(
|
||||||
|
Name="my service",
|
||||||
|
NamespaceId=namespace_id,
|
||||||
|
Description="first desc",
|
||||||
|
DnsConfig={
|
||||||
|
"NamespaceId": namespace_id,
|
||||||
|
"RoutingPolicy": "WEIGHTED",
|
||||||
|
"DnsRecords": [{"Type": "SRV", "TTL": 0}],
|
||||||
|
},
|
||||||
|
HealthCheckConfig={"Type": "TCP", "ResourcePath": "/sth"},
|
||||||
|
)["Service"]["Id"]
|
||||||
|
|
||||||
|
client.update_service(Id=service_id, Service={"Description": "updated desc"})
|
||||||
|
|
||||||
|
resp = client.get_service(Id=service_id)
|
||||||
|
|
||||||
|
resp.should.have.key("Service")
|
||||||
|
resp["Service"].should.have.key("Id").equals(service_id)
|
||||||
|
resp["Service"].should.have.key("Arn")
|
||||||
|
resp["Service"].should.have.key("Name").equals("my service")
|
||||||
|
resp["Service"].should.have.key("NamespaceId").equals(namespace_id)
|
||||||
|
resp["Service"].should.have.key("Description").equals("updated desc")
|
||||||
|
# From the docs:
|
||||||
|
# If you omit any existing DnsRecords or HealthCheckConfig configurations from an UpdateService request,
|
||||||
|
# the configurations are deleted from the service.
|
||||||
|
resp["Service"].shouldnt.have.key("DnsConfig")
|
||||||
|
resp["Service"].should.have.key("HealthCheckConfig").equals(
|
||||||
|
{"Type": "TCP", "ResourcePath": "/sth"}
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@mock_servicediscovery
|
||||||
|
def test_update_service_others():
|
||||||
|
client = boto3.client("servicediscovery", region_name="ap-southeast-1")
|
||||||
|
operation_id = client.create_http_namespace(Name="mynamespace")["OperationId"]
|
||||||
|
namespace_id = client.get_operation(OperationId=operation_id)["Operation"][
|
||||||
|
"Targets"
|
||||||
|
]["NAMESPACE"]
|
||||||
|
|
||||||
|
service_id = client.create_service(
|
||||||
|
Name="my service",
|
||||||
|
NamespaceId=namespace_id,
|
||||||
|
Description="first desc",
|
||||||
|
DnsConfig={
|
||||||
|
"RoutingPolicy": "WEIGHTED",
|
||||||
|
"DnsRecords": [{"Type": "SRV", "TTL": 0}],
|
||||||
|
},
|
||||||
|
)["Service"]["Id"]
|
||||||
|
|
||||||
|
client.update_service(
|
||||||
|
Id=service_id,
|
||||||
|
Service={
|
||||||
|
"DnsConfig": {"DnsRecords": [{"Type": "SRV", "TTL": 12}]},
|
||||||
|
"HealthCheckConfig": {"Type": "TCP", "ResourcePath": "/sth"},
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
resp = client.get_service(Id=service_id)
|
||||||
|
|
||||||
|
resp.should.have.key("Service")
|
||||||
|
resp["Service"].should.have.key("Id").equals(service_id)
|
||||||
|
resp["Service"].should.have.key("Arn")
|
||||||
|
resp["Service"].should.have.key("Name").equals("my service")
|
||||||
|
resp["Service"].should.have.key("NamespaceId").equals(namespace_id)
|
||||||
|
resp["Service"].should.have.key("Description").equals("first desc")
|
||||||
|
resp["Service"].should.have.key("DnsConfig").equals(
|
||||||
|
{"RoutingPolicy": "WEIGHTED", "DnsRecords": [{"Type": "SRV", "TTL": 12}]}
|
||||||
|
)
|
||||||
|
resp["Service"].should.have.key("HealthCheckConfig").equals(
|
||||||
|
{"Type": "TCP", "ResourcePath": "/sth"}
|
||||||
|
)
|
103
tests/test_servicediscovery/test_servicediscovery_tags.py
Normal file
103
tests/test_servicediscovery/test_servicediscovery_tags.py
Normal file
@ -0,0 +1,103 @@
|
|||||||
|
"""Unit tests for servicediscovery-supported APIs."""
|
||||||
|
import boto3
|
||||||
|
|
||||||
|
import sure # noqa # pylint: disable=unused-import
|
||||||
|
from moto import mock_servicediscovery
|
||||||
|
|
||||||
|
# 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
|
||||||
|
|
||||||
|
|
||||||
|
@mock_servicediscovery
|
||||||
|
def test_create_http_namespace_with_tags():
|
||||||
|
client = boto3.client("servicediscovery", region_name="eu-west-1")
|
||||||
|
client.create_http_namespace(
|
||||||
|
Name="mynamespace", Tags=[{"Key": "key1", "Value": "val1"}]
|
||||||
|
)
|
||||||
|
|
||||||
|
ns_arn = client.list_namespaces()["Namespaces"][0]["Arn"]
|
||||||
|
|
||||||
|
resp = client.list_tags_for_resource(ResourceARN=ns_arn)
|
||||||
|
resp.should.have.key("Tags")
|
||||||
|
|
||||||
|
resp["Tags"].should.equal([{"Key": "key1", "Value": "val1"}])
|
||||||
|
|
||||||
|
|
||||||
|
@mock_servicediscovery
|
||||||
|
def test_create_public_dns_namespace_with_tags():
|
||||||
|
client = boto3.client("servicediscovery", region_name="eu-west-1")
|
||||||
|
client.create_public_dns_namespace(
|
||||||
|
Name="mynamespace", Tags=[{"Key": "key1", "Value": "val1"}]
|
||||||
|
)
|
||||||
|
|
||||||
|
ns_arn = client.list_namespaces()["Namespaces"][0]["Arn"]
|
||||||
|
|
||||||
|
resp = client.list_tags_for_resource(ResourceARN=ns_arn)
|
||||||
|
resp.should.have.key("Tags")
|
||||||
|
|
||||||
|
resp["Tags"].should.equal([{"Key": "key1", "Value": "val1"}])
|
||||||
|
|
||||||
|
|
||||||
|
@mock_servicediscovery
|
||||||
|
def test_create_private_dns_namespace_with_tags():
|
||||||
|
client = boto3.client("servicediscovery", region_name="eu-west-1")
|
||||||
|
client.create_private_dns_namespace(
|
||||||
|
Name="mynamespace", Vpc="vpc", Tags=[{"Key": "key1", "Value": "val1"}]
|
||||||
|
)
|
||||||
|
|
||||||
|
ns_arn = client.list_namespaces()["Namespaces"][0]["Arn"]
|
||||||
|
|
||||||
|
resp = client.list_tags_for_resource(ResourceARN=ns_arn)
|
||||||
|
resp.should.have.key("Tags")
|
||||||
|
|
||||||
|
resp["Tags"].should.equal([{"Key": "key1", "Value": "val1"}])
|
||||||
|
|
||||||
|
|
||||||
|
@mock_servicediscovery
|
||||||
|
def test_create_service_with_tags():
|
||||||
|
client = boto3.client("servicediscovery", region_name="eu-west-1")
|
||||||
|
client.create_service(Name="myservice", Tags=[{"Key": "key1", "Value": "val1"}])
|
||||||
|
|
||||||
|
ns_arn = client.list_services()["Services"][0]["Arn"]
|
||||||
|
|
||||||
|
resp = client.list_tags_for_resource(ResourceARN=ns_arn)
|
||||||
|
resp.should.have.key("Tags")
|
||||||
|
|
||||||
|
resp["Tags"].should.equal([{"Key": "key1", "Value": "val1"}])
|
||||||
|
|
||||||
|
|
||||||
|
@mock_servicediscovery
|
||||||
|
def test_tag_resource():
|
||||||
|
client = boto3.client("servicediscovery", region_name="ap-southeast-1")
|
||||||
|
client.create_http_namespace(
|
||||||
|
Name="mynamespace", Tags=[{"Key": "key1", "Value": "val1"}]
|
||||||
|
)
|
||||||
|
|
||||||
|
ns_arn = client.list_namespaces()["Namespaces"][0]["Arn"]
|
||||||
|
client.tag_resource(ResourceARN=ns_arn, Tags=[{"Key": "key2", "Value": "val2"}])
|
||||||
|
|
||||||
|
resp = client.list_tags_for_resource(ResourceARN=ns_arn)
|
||||||
|
resp.should.have.key("Tags")
|
||||||
|
|
||||||
|
resp["Tags"].should.equal(
|
||||||
|
[{"Key": "key1", "Value": "val1"}, {"Key": "key2", "Value": "val2"}]
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@mock_servicediscovery
|
||||||
|
def test_untag_resource():
|
||||||
|
client = boto3.client("servicediscovery", region_name="us-east-2")
|
||||||
|
client.create_http_namespace(Name="mynamespace")
|
||||||
|
|
||||||
|
ns_arn = client.list_namespaces()["Namespaces"][0]["Arn"]
|
||||||
|
client.tag_resource(
|
||||||
|
ResourceARN=ns_arn,
|
||||||
|
Tags=[{"Key": "key1", "Value": "val1"}, {"Key": "key2", "Value": "val2"}],
|
||||||
|
)
|
||||||
|
|
||||||
|
client.untag_resource(ResourceARN=ns_arn, TagKeys=["key1"])
|
||||||
|
|
||||||
|
resp = client.list_tags_for_resource(ResourceARN=ns_arn)
|
||||||
|
resp.should.have.key("Tags")
|
||||||
|
|
||||||
|
resp["Tags"].should.equal([{"Key": "key2", "Value": "val2"}])
|
Loading…
x
Reference in New Issue
Block a user