Add elasticbeanstalk Tags handling
This commit is contained in:
parent
9bfbd8e008
commit
7f387b0bb9
@ -5,3 +5,9 @@ class InvalidParameterValueError(RESTError):
|
|||||||
def __init__(self, message):
|
def __init__(self, message):
|
||||||
super(InvalidParameterValueError, self).__init__(
|
super(InvalidParameterValueError, self).__init__(
|
||||||
"InvalidParameterValue", message)
|
"InvalidParameterValue", message)
|
||||||
|
|
||||||
|
|
||||||
|
class ResourceNotFoundException(RESTError):
|
||||||
|
def __init__(self, message):
|
||||||
|
super(ResourceNotFoundException, self).__init__(
|
||||||
|
"ResourceNotFoundException", message)
|
||||||
|
@ -7,32 +7,70 @@ from .exceptions import InvalidParameterValueError
|
|||||||
|
|
||||||
|
|
||||||
class FakeEnvironment(BaseModel):
|
class FakeEnvironment(BaseModel):
|
||||||
def __init__(self, application, environment_name):
|
def __init__(
|
||||||
self.environment_name = environment_name
|
self,
|
||||||
|
application,
|
||||||
|
environment_name,
|
||||||
|
tags,
|
||||||
|
):
|
||||||
self.application = weakref.proxy(application) # weakref to break circular dependencies
|
self.application = weakref.proxy(application) # weakref to break circular dependencies
|
||||||
|
self.environment_name = environment_name
|
||||||
|
self.tags = tags
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def application_name(self):
|
def application_name(self):
|
||||||
return self.application.application_name
|
return self.application.application_name
|
||||||
|
|
||||||
|
@property
|
||||||
|
def environment_arn(self):
|
||||||
|
return 'arn:aws:elasticbeanstalk:{region}:{account_id}:' \
|
||||||
|
'environment/{application_name}/{environment_name}'.format(
|
||||||
|
region=self.region,
|
||||||
|
account_id='123456789012',
|
||||||
|
application_name=self.application_name,
|
||||||
|
environment_name=self.environment_name,
|
||||||
|
)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def platform_arn(self):
|
||||||
|
return 'TODO' # TODO
|
||||||
|
|
||||||
|
@property
|
||||||
|
def solution_stack_name(self):
|
||||||
|
return 'TODO' # TODO
|
||||||
|
|
||||||
|
@property
|
||||||
|
def region(self):
|
||||||
|
return self.application.region
|
||||||
|
|
||||||
|
|
||||||
class FakeApplication(BaseModel):
|
class FakeApplication(BaseModel):
|
||||||
def __init__(self, application_name):
|
def __init__(self, backend, application_name):
|
||||||
|
self.backend = weakref.proxy(backend) # weakref to break cycles
|
||||||
self.application_name = application_name
|
self.application_name = application_name
|
||||||
self.environments = dict()
|
self.environments = dict()
|
||||||
|
|
||||||
def create_environment(self, environment_name):
|
def create_environment(
|
||||||
|
self,
|
||||||
|
environment_name,
|
||||||
|
tags,
|
||||||
|
):
|
||||||
if environment_name in self.environments:
|
if environment_name in self.environments:
|
||||||
raise InvalidParameterValueError
|
raise InvalidParameterValueError
|
||||||
|
|
||||||
env = FakeEnvironment(
|
env = FakeEnvironment(
|
||||||
application=self,
|
application=self,
|
||||||
environment_name=environment_name,
|
environment_name=environment_name,
|
||||||
|
tags=tags,
|
||||||
)
|
)
|
||||||
self.environments[environment_name] = env
|
self.environments[environment_name] = env
|
||||||
|
|
||||||
return env
|
return env
|
||||||
|
|
||||||
|
@property
|
||||||
|
def region(self):
|
||||||
|
return self.backend.region
|
||||||
|
|
||||||
|
|
||||||
class EBBackend(BaseBackend):
|
class EBBackend(BaseBackend):
|
||||||
def __init__(self, region):
|
def __init__(self, region):
|
||||||
@ -52,6 +90,7 @@ class EBBackend(BaseBackend):
|
|||||||
"Application {} already exists.".format(application_name)
|
"Application {} already exists.".format(application_name)
|
||||||
)
|
)
|
||||||
new_app = FakeApplication(
|
new_app = FakeApplication(
|
||||||
|
backend=self,
|
||||||
application_name=application_name,
|
application_name=application_name,
|
||||||
)
|
)
|
||||||
self.applications[application_name] = new_app
|
self.applications[application_name] = new_app
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
from moto.core.responses import BaseResponse
|
from moto.core.responses import BaseResponse
|
||||||
|
from moto.core.utils import tags_from_query_string
|
||||||
from .models import eb_backends, EBBackend
|
from .models import eb_backends, EBBackend
|
||||||
from .exceptions import InvalidParameterValueError
|
from .exceptions import InvalidParameterValueError, ResourceNotFoundException
|
||||||
|
|
||||||
|
|
||||||
class EBResponse(BaseResponse):
|
class EBResponse(BaseResponse):
|
||||||
@ -38,7 +39,11 @@ class EBResponse(BaseResponse):
|
|||||||
"No Application named \'{}\' found.".format(application_name)
|
"No Application named \'{}\' found.".format(application_name)
|
||||||
)
|
)
|
||||||
|
|
||||||
env = app.create_environment(environment_name=environment_name)
|
tags = tags_from_query_string(self.querystring, prefix="Tags.member")
|
||||||
|
env = app.create_environment(
|
||||||
|
environment_name=environment_name,
|
||||||
|
tags=tags,
|
||||||
|
)
|
||||||
|
|
||||||
template = self.response_template(EB_CREATE_ENVIRONMENT)
|
template = self.response_template(EB_CREATE_ENVIRONMENT)
|
||||||
return template.render(
|
return template.render(
|
||||||
@ -62,6 +67,48 @@ class EBResponse(BaseResponse):
|
|||||||
def list_available_solution_stacks():
|
def list_available_solution_stacks():
|
||||||
return EB_LIST_AVAILABLE_SOLUTION_STACKS
|
return EB_LIST_AVAILABLE_SOLUTION_STACKS
|
||||||
|
|
||||||
|
def _find_environment_by_arn(self, arn):
|
||||||
|
for app in self.backend.applications.keys():
|
||||||
|
for env in self.backend.applications[app].environments.values():
|
||||||
|
if env.environment_arn == arn:
|
||||||
|
return env
|
||||||
|
raise KeyError()
|
||||||
|
|
||||||
|
def update_tags_for_resource(self):
|
||||||
|
resource_arn = self._get_param('ResourceArn')
|
||||||
|
try:
|
||||||
|
res = self._find_environment_by_arn(resource_arn)
|
||||||
|
except KeyError:
|
||||||
|
raise ResourceNotFoundException(
|
||||||
|
"Resource not found for ARN \'{}\'.".format(resource_arn)
|
||||||
|
)
|
||||||
|
|
||||||
|
tags_to_add = tags_from_query_string(self.querystring, prefix="TagsToAdd.member")
|
||||||
|
for key, value in tags_to_add.items():
|
||||||
|
res.tags[key] = value
|
||||||
|
|
||||||
|
tags_to_remove = self._get_multi_param('TagsToRemove.member')
|
||||||
|
for key in tags_to_remove:
|
||||||
|
del res.tags[key]
|
||||||
|
|
||||||
|
return EB_UPDATE_TAGS_FOR_RESOURCE
|
||||||
|
|
||||||
|
def list_tags_for_resource(self):
|
||||||
|
resource_arn = self._get_param('ResourceArn')
|
||||||
|
try:
|
||||||
|
res = self._find_environment_by_arn(resource_arn)
|
||||||
|
except KeyError:
|
||||||
|
raise ResourceNotFoundException(
|
||||||
|
"Resource not found for ARN \'{}\'.".format(resource_arn)
|
||||||
|
)
|
||||||
|
tags = res.tags
|
||||||
|
|
||||||
|
template = self.response_template(EB_LIST_TAGS_FOR_RESOURCE)
|
||||||
|
return template.render(
|
||||||
|
tags=tags,
|
||||||
|
arn=resource_arn,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
EB_CREATE_APPLICATION = """
|
EB_CREATE_APPLICATION = """
|
||||||
<CreateApplicationResponse xmlns="http://elasticbeanstalk.amazonaws.com/docs/2010-12-01/">
|
<CreateApplicationResponse xmlns="http://elasticbeanstalk.amazonaws.com/docs/2010-12-01/">
|
||||||
@ -136,11 +183,11 @@ EB_CREATE_ENVIRONMENT = """
|
|||||||
<CreateEnvironmentResult>
|
<CreateEnvironmentResult>
|
||||||
<SolutionStackName>{{ environment.solution_stack_name }}</SolutionStackName>
|
<SolutionStackName>{{ environment.solution_stack_name }}</SolutionStackName>
|
||||||
<Health>Grey</Health>
|
<Health>Grey</Health>
|
||||||
<EnvironmentArn>arn:aws:elasticbeanstalk:{{ region }}:111122223333:environment/{{ environment.application_name }}/{{ environment.environment_name }}</EnvironmentArn>
|
<EnvironmentArn>{{ environment.environment_arn }}</EnvironmentArn>
|
||||||
<DateUpdated>2019-09-04T09:41:24.222Z</DateUpdated>
|
<DateUpdated>2019-09-04T09:41:24.222Z</DateUpdated>
|
||||||
<DateCreated>2019-09-04T09:41:24.222Z</DateCreated>
|
<DateCreated>2019-09-04T09:41:24.222Z</DateCreated>
|
||||||
<EnvironmentId>{{ environment_id }}</EnvironmentId>
|
<EnvironmentId>{{ environment_id }}</EnvironmentId>
|
||||||
<PlatformArn>arn:aws:elasticbeanstalk:{{ region }}::platform/{{ environment.platform_arn }}</PlatformArn>
|
<PlatformArn>{{ environment.platform_arn }}</PlatformArn>
|
||||||
<Tier>
|
<Tier>
|
||||||
<Name>WebServer</Name>
|
<Name>WebServer</Name>
|
||||||
<Type>Standard</Type>
|
<Type>Standard</Type>
|
||||||
@ -165,7 +212,7 @@ EB_DESCRIBE_ENVIRONMENTS = """
|
|||||||
<member>
|
<member>
|
||||||
<SolutionStackName>{{ env.solution_stack_name }}</SolutionStackName>
|
<SolutionStackName>{{ env.solution_stack_name }}</SolutionStackName>
|
||||||
<Health>Grey</Health>
|
<Health>Grey</Health>
|
||||||
<EnvironmentArn>arn:aws:elasticbeanstalk:{{ region }}:123456789012:environment/{{ env.application_name }}/{{ env.environment_name }}</EnvironmentArn>
|
<EnvironmentArn>{{ env.environment_arn }}</EnvironmentArn>
|
||||||
<MinCapacityEnabled>false</MinCapacityEnabled>
|
<MinCapacityEnabled>false</MinCapacityEnabled>
|
||||||
<DateUpdated>2019-08-30T09:35:10.913Z</DateUpdated>
|
<DateUpdated>2019-08-30T09:35:10.913Z</DateUpdated>
|
||||||
<AbortableOperationInProgress>false</AbortableOperationInProgress>
|
<AbortableOperationInProgress>false</AbortableOperationInProgress>
|
||||||
@ -173,7 +220,7 @@ EB_DESCRIBE_ENVIRONMENTS = """
|
|||||||
<DateCreated>2019-08-22T07:02:47.332Z</DateCreated>
|
<DateCreated>2019-08-22T07:02:47.332Z</DateCreated>
|
||||||
<EnvironmentId>{{ env.environment_id }}</EnvironmentId>
|
<EnvironmentId>{{ env.environment_id }}</EnvironmentId>
|
||||||
<VersionLabel>1</VersionLabel>
|
<VersionLabel>1</VersionLabel>
|
||||||
<PlatformArn>arn:aws:elasticbeanstalk:{{ region }}::platform/{{ env.platform_arn }}</PlatformArn>
|
<PlatformArn>{{ env.platform_arn }}</PlatformArn>
|
||||||
<Tier>
|
<Tier>
|
||||||
<Name>WebServer</Name>
|
<Name>WebServer</Name>
|
||||||
<Type>Standard</Type>
|
<Type>Standard</Type>
|
||||||
@ -1347,3 +1394,32 @@ EB_LIST_AVAILABLE_SOLUTION_STACKS = """
|
|||||||
</ResponseMetadata>
|
</ResponseMetadata>
|
||||||
</ListAvailableSolutionStacksResponse>
|
</ListAvailableSolutionStacksResponse>
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
EB_UPDATE_TAGS_FOR_RESOURCE = """
|
||||||
|
<UpdateTagsForResourceResponse xmlns="http://elasticbeanstalk.amazonaws.com/docs/2010-12-01/">
|
||||||
|
<ResponseMetadata>
|
||||||
|
<RequestId>f355d788-e67e-440f-b915-99e35254ffee</RequestId>
|
||||||
|
</ResponseMetadata>
|
||||||
|
</UpdateTagsForResourceResponse>
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
EB_LIST_TAGS_FOR_RESOURCE = """
|
||||||
|
<ListTagsForResourceResponse xmlns="http://elasticbeanstalk.amazonaws.com/docs/2010-12-01/">
|
||||||
|
<ListTagsForResourceResult>
|
||||||
|
<ResourceTags>
|
||||||
|
{% for key, value in tags.items() %}
|
||||||
|
<member>
|
||||||
|
<Key>{{ key }}</Key>
|
||||||
|
<Value>{{ value }}</Value>
|
||||||
|
</member>
|
||||||
|
{% endfor %}
|
||||||
|
</ResourceTags>
|
||||||
|
<ResourceArn>{{ arn }}</ResourceArn>
|
||||||
|
</ListTagsForResourceResult>
|
||||||
|
<ResponseMetadata>
|
||||||
|
<RequestId>178e410f-3b57-456f-a64c-a3b6a16da9ab</RequestId>
|
||||||
|
</ResponseMetadata>
|
||||||
|
</ListTagsForResourceResponse>
|
||||||
|
"""
|
||||||
|
@ -72,6 +72,78 @@ def test_describe_environments():
|
|||||||
envs[0]['EnvironmentName'].should.equal('myenv')
|
envs[0]['EnvironmentName'].should.equal('myenv')
|
||||||
|
|
||||||
|
|
||||||
|
def tags_dict_to_list(tag_dict):
|
||||||
|
tag_list = []
|
||||||
|
for key, value in tag_dict.items():
|
||||||
|
tag_list.append({'Key': key, 'Value': value})
|
||||||
|
return tag_list
|
||||||
|
|
||||||
|
|
||||||
|
def tags_list_to_dict(tag_list):
|
||||||
|
tag_dict = {}
|
||||||
|
for tag in tag_list:
|
||||||
|
tag_dict[tag['Key']] = tag['Value']
|
||||||
|
return tag_dict
|
||||||
|
|
||||||
|
|
||||||
|
@mock_eb
|
||||||
|
def test_create_environment_tags():
|
||||||
|
conn = boto3.client('elasticbeanstalk', region_name='us-east-1')
|
||||||
|
conn.create_application(
|
||||||
|
ApplicationName="myapp",
|
||||||
|
)
|
||||||
|
env_tags = {'initial key': 'initial value'}
|
||||||
|
env = conn.create_environment(
|
||||||
|
ApplicationName="myapp",
|
||||||
|
EnvironmentName="myenv",
|
||||||
|
Tags=tags_dict_to_list(env_tags),
|
||||||
|
)
|
||||||
|
|
||||||
|
tags = conn.list_tags_for_resource(
|
||||||
|
ResourceArn=env['EnvironmentArn'],
|
||||||
|
)
|
||||||
|
tags['ResourceArn'].should.equal(env['EnvironmentArn'])
|
||||||
|
tags_list_to_dict(tags['ResourceTags']).should.equal(env_tags)
|
||||||
|
|
||||||
|
|
||||||
|
@mock_eb
|
||||||
|
def test_update_tags():
|
||||||
|
conn = boto3.client('elasticbeanstalk', region_name='us-east-1')
|
||||||
|
conn.create_application(
|
||||||
|
ApplicationName="myapp",
|
||||||
|
)
|
||||||
|
env_tags = {
|
||||||
|
'initial key': 'initial value',
|
||||||
|
'to remove': 'delete me',
|
||||||
|
'to update': 'original',
|
||||||
|
}
|
||||||
|
env = conn.create_environment(
|
||||||
|
ApplicationName="myapp",
|
||||||
|
EnvironmentName="myenv",
|
||||||
|
Tags=tags_dict_to_list(env_tags),
|
||||||
|
)
|
||||||
|
|
||||||
|
extra_env_tags = {
|
||||||
|
'to update': 'new',
|
||||||
|
'extra key': 'extra value',
|
||||||
|
}
|
||||||
|
conn.update_tags_for_resource(
|
||||||
|
ResourceArn=env['EnvironmentArn'],
|
||||||
|
TagsToAdd=tags_dict_to_list(extra_env_tags),
|
||||||
|
TagsToRemove=['to remove'],
|
||||||
|
)
|
||||||
|
|
||||||
|
total_env_tags = env_tags.copy()
|
||||||
|
total_env_tags.update(extra_env_tags)
|
||||||
|
del total_env_tags['to remove']
|
||||||
|
|
||||||
|
tags = conn.list_tags_for_resource(
|
||||||
|
ResourceArn=env['EnvironmentArn'],
|
||||||
|
)
|
||||||
|
tags['ResourceArn'].should.equal(env['EnvironmentArn'])
|
||||||
|
tags_list_to_dict(tags['ResourceTags']).should.equal(total_env_tags)
|
||||||
|
|
||||||
|
|
||||||
@mock_eb
|
@mock_eb
|
||||||
def test_list_available_solution_stacks():
|
def test_list_available_solution_stacks():
|
||||||
conn = boto3.client('elasticbeanstalk', region_name='us-east-1')
|
conn = boto3.client('elasticbeanstalk', region_name='us-east-1')
|
||||||
|
Loading…
Reference in New Issue
Block a user