2019-08-14 21:11:05 +00:00
|
|
|
import six
|
|
|
|
import uuid
|
|
|
|
from moto.core.responses import BaseResponse
|
|
|
|
from moto.ec2.models import OWNER_ID
|
|
|
|
from moto.ec2.exceptions import FilterNotImplementedError
|
|
|
|
from moto.ec2.utils import filters_from_querystring
|
|
|
|
|
|
|
|
from xml.etree import ElementTree
|
|
|
|
from xml.dom import minidom
|
|
|
|
|
|
|
|
|
|
|
|
def xml_root(name):
|
|
|
|
root = ElementTree.Element(name, {
|
|
|
|
"xmlns": "http://ec2.amazonaws.com/doc/2016-11-15/"
|
|
|
|
})
|
|
|
|
request_id = str(uuid.uuid4()) + "example"
|
|
|
|
ElementTree.SubElement(root, "requestId").text = request_id
|
|
|
|
|
|
|
|
return root
|
|
|
|
|
2019-08-14 21:19:30 +00:00
|
|
|
|
2019-08-14 21:11:05 +00:00
|
|
|
def xml_serialize(tree, key, value):
|
|
|
|
if key:
|
|
|
|
name = key[0].lower() + key[1:]
|
|
|
|
if isinstance(value, list):
|
|
|
|
if name[-1] == 's':
|
|
|
|
name = name[:-1]
|
|
|
|
|
|
|
|
name = name + 'Set'
|
|
|
|
|
|
|
|
node = ElementTree.SubElement(tree, name)
|
|
|
|
else:
|
|
|
|
node = tree
|
|
|
|
|
2019-08-14 22:32:59 +00:00
|
|
|
if isinstance(value, (str, int, float, six.text_type)):
|
2019-08-14 21:11:05 +00:00
|
|
|
node.text = str(value)
|
|
|
|
elif isinstance(value, bool):
|
|
|
|
node.text = str(value).lower()
|
|
|
|
elif isinstance(value, dict):
|
|
|
|
for dictkey, dictvalue in six.iteritems(value):
|
|
|
|
xml_serialize(node, dictkey, dictvalue)
|
|
|
|
elif isinstance(value, list):
|
|
|
|
for item in value:
|
|
|
|
xml_serialize(node, 'item', item)
|
|
|
|
|
2019-08-14 21:19:30 +00:00
|
|
|
|
2019-08-14 21:11:05 +00:00
|
|
|
def pretty_xml(tree):
|
|
|
|
rough = ElementTree.tostring(tree, 'utf-8')
|
|
|
|
parsed = minidom.parseString(rough)
|
|
|
|
return parsed.toprettyxml(indent=' ')
|
|
|
|
|
2019-08-14 21:19:30 +00:00
|
|
|
|
2019-08-14 21:11:05 +00:00
|
|
|
def parse_object(raw_data):
|
|
|
|
out_data = {}
|
|
|
|
for key, value in six.iteritems(raw_data):
|
|
|
|
key_fix_splits = key.split("_")
|
2019-08-14 21:19:30 +00:00
|
|
|
key_len = len(key_fix_splits)
|
2019-08-14 21:11:05 +00:00
|
|
|
|
|
|
|
new_key = ""
|
2019-08-14 21:19:30 +00:00
|
|
|
for i in range(0, key_len):
|
2019-08-14 21:11:05 +00:00
|
|
|
new_key += key_fix_splits[i][0].upper() + key_fix_splits[i][1:]
|
|
|
|
|
|
|
|
data = out_data
|
|
|
|
splits = new_key.split(".")
|
|
|
|
for split in splits[:-1]:
|
|
|
|
if split not in data:
|
|
|
|
data[split] = {}
|
|
|
|
data = data[split]
|
|
|
|
|
|
|
|
data[splits[-1]] = value
|
|
|
|
|
|
|
|
out_data = parse_lists(out_data)
|
|
|
|
return out_data
|
|
|
|
|
2019-08-14 21:19:30 +00:00
|
|
|
|
2019-08-14 21:11:05 +00:00
|
|
|
def parse_lists(data):
|
|
|
|
for key, value in six.iteritems(data):
|
|
|
|
if isinstance(value, dict):
|
|
|
|
keys = data[key].keys()
|
|
|
|
is_list = all(map(lambda k: k.isnumeric(), keys))
|
|
|
|
|
|
|
|
if is_list:
|
|
|
|
new_value = []
|
|
|
|
keys = sorted(list(keys))
|
|
|
|
for k in keys:
|
|
|
|
lvalue = value[k]
|
|
|
|
if isinstance(lvalue, dict):
|
|
|
|
lvalue = parse_lists(lvalue)
|
|
|
|
new_value.append(lvalue)
|
|
|
|
data[key] = new_value
|
|
|
|
return data
|
|
|
|
|
2019-08-14 21:19:30 +00:00
|
|
|
|
2019-08-14 21:11:05 +00:00
|
|
|
class LaunchTemplates(BaseResponse):
|
|
|
|
def create_launch_template(self):
|
|
|
|
name = self._get_param('LaunchTemplateName')
|
|
|
|
version_description = self._get_param('VersionDescription')
|
|
|
|
tag_spec = self._get_param('TagSpecifications')
|
|
|
|
|
|
|
|
raw_template_data = self._get_dict_param('LaunchTemplateData.')
|
|
|
|
parsed_template_data = parse_object(raw_template_data)
|
|
|
|
|
|
|
|
if tag_spec:
|
|
|
|
if 'TagSpecifications' not in parsed_template_data:
|
|
|
|
parsed_template_data['TagSpecifications'] = []
|
|
|
|
parsed_template_data['TagSpecifications'].extend(tag_spec)
|
|
|
|
|
|
|
|
if self.is_not_dryrun('CreateLaunchTemplate'):
|
|
|
|
template = self.ec2_backend.create_launch_template(name, version_description, parsed_template_data)
|
|
|
|
version = template.default_version()
|
|
|
|
|
|
|
|
tree = xml_root("CreateLaunchTemplateResponse")
|
|
|
|
xml_serialize(tree, "launchTemplate", {
|
|
|
|
"createTime": version.create_time,
|
|
|
|
"createdBy": "arn:aws:iam::{OWNER_ID}:root".format(OWNER_ID=OWNER_ID),
|
|
|
|
"defaultVersionNumber": template.default_version_number,
|
|
|
|
"latestVersionNumber": version.number,
|
|
|
|
"launchTemplateId": template.id,
|
|
|
|
"launchTemplateName": template.name
|
|
|
|
})
|
|
|
|
|
|
|
|
return pretty_xml(tree)
|
|
|
|
|
|
|
|
def create_launch_template_version(self):
|
|
|
|
name = self._get_param('LaunchTemplateName')
|
|
|
|
tmpl_id = self._get_param('LaunchTemplateId')
|
|
|
|
if name:
|
|
|
|
template = self.ec2_backend.get_launch_template_by_name(name)
|
|
|
|
if tmpl_id:
|
|
|
|
template = self.ec2_backend.get_launch_template_by_id(tmpl_id)
|
|
|
|
|
|
|
|
version_description = self._get_param('VersionDescription')
|
|
|
|
|
|
|
|
raw_template_data = self._get_dict_param('LaunchTemplateData.')
|
|
|
|
template_data = parse_object(raw_template_data)
|
|
|
|
|
|
|
|
if self.is_not_dryrun('CreateLaunchTemplate'):
|
|
|
|
version = template.create_version(template_data, version_description)
|
|
|
|
|
|
|
|
tree = xml_root("CreateLaunchTemplateVersionResponse")
|
|
|
|
xml_serialize(tree, "launchTemplateVersion", {
|
|
|
|
"createTime": version.create_time,
|
|
|
|
"createdBy": "arn:aws:iam::{OWNER_ID}:root".format(OWNER_ID=OWNER_ID),
|
|
|
|
"defaultVersion": template.is_default(version),
|
|
|
|
"launchTemplateData": version.data,
|
|
|
|
"launchTemplateId": template.id,
|
|
|
|
"launchTemplateName": template.name,
|
|
|
|
"versionDescription": version.description,
|
|
|
|
"versionNumber": version.number,
|
|
|
|
})
|
|
|
|
return pretty_xml(tree)
|
|
|
|
|
|
|
|
# def delete_launch_template(self):
|
|
|
|
# pass
|
|
|
|
|
|
|
|
# def delete_launch_template_versions(self):
|
|
|
|
# pass
|
|
|
|
|
|
|
|
def describe_launch_template_versions(self):
|
|
|
|
name = self._get_param('LaunchTemplateName')
|
|
|
|
template_id = self._get_param('LaunchTemplateId')
|
|
|
|
if name:
|
|
|
|
template = self.ec2_backend.get_launch_template_by_name(name)
|
|
|
|
if template_id:
|
|
|
|
template = self.ec2_backend.get_launch_template_by_id(template_id)
|
|
|
|
|
|
|
|
max_results = self._get_int_param("MaxResults", 15)
|
|
|
|
versions = self._get_multi_param("Versions")
|
|
|
|
min_version = self._get_int_param("MinVersion")
|
|
|
|
max_version = self._get_int_param("MaxVersion")
|
|
|
|
|
|
|
|
filters = filters_from_querystring(self.querystring)
|
|
|
|
if filters:
|
|
|
|
raise FilterNotImplementedError("all filters", "DescribeLaunchTemplateVersions")
|
|
|
|
|
|
|
|
if self.is_not_dryrun('DescribeLaunchTemplateVersions'):
|
|
|
|
tree = ElementTree.Element("DescribeLaunchTemplateVersionsResponse", {
|
|
|
|
"xmlns": "http://ec2.amazonaws.com/doc/2016-11-15/",
|
|
|
|
})
|
|
|
|
request_id = ElementTree.SubElement(tree, "requestId")
|
|
|
|
request_id.text = "65cadec1-b364-4354-8ca8-4176dexample"
|
|
|
|
|
|
|
|
versions_node = ElementTree.SubElement(tree, "launchTemplateVersionSet")
|
|
|
|
|
|
|
|
ret_versions = []
|
|
|
|
if versions:
|
|
|
|
for v in versions:
|
|
|
|
ret_versions.append(template.get_version(int(v)))
|
|
|
|
elif min_version:
|
|
|
|
if max_version:
|
|
|
|
vMax = max_version
|
|
|
|
else:
|
|
|
|
vMax = min_version + max_results
|
|
|
|
|
2019-08-14 21:19:30 +00:00
|
|
|
vMin = min_version - 1
|
|
|
|
vMax = vMax - 1
|
|
|
|
ret_versions = template.versions[vMin:vMax]
|
2019-08-14 21:11:05 +00:00
|
|
|
elif max_version:
|
2019-08-14 21:19:30 +00:00
|
|
|
vMax = max_version - 1
|
|
|
|
ret_versions = template.versions[:vMax]
|
2019-08-14 21:11:05 +00:00
|
|
|
else:
|
|
|
|
ret_versions = template.versions
|
|
|
|
|
|
|
|
ret_versions = ret_versions[:max_results]
|
|
|
|
|
|
|
|
for version in ret_versions:
|
|
|
|
xml_serialize(versions_node, "item", {
|
|
|
|
"createTime": version.create_time,
|
|
|
|
"createdBy": "arn:aws:iam::{OWNER_ID}:root".format(OWNER_ID=OWNER_ID),
|
|
|
|
"defaultVersion": True,
|
|
|
|
"launchTemplateData": version.data,
|
|
|
|
"launchTemplateId": template.id,
|
|
|
|
"launchTemplateName": template.name,
|
|
|
|
"versionDescription": version.description,
|
|
|
|
"versionNumber": version.number,
|
|
|
|
})
|
|
|
|
|
|
|
|
return pretty_xml(tree)
|
|
|
|
|
|
|
|
def describe_launch_templates(self):
|
|
|
|
max_results = self._get_int_param("MaxResults", 15)
|
|
|
|
template_names = self._get_multi_param("LaunchTemplateName")
|
|
|
|
template_ids = self._get_multi_param("LaunchTemplateId")
|
|
|
|
filters = filters_from_querystring(self.querystring)
|
|
|
|
|
|
|
|
if self.is_not_dryrun("DescribeLaunchTemplates"):
|
|
|
|
tree = ElementTree.Element("DescribeLaunchTemplatesResponse")
|
|
|
|
templates_node = ElementTree.SubElement(tree, "launchTemplates")
|
|
|
|
|
|
|
|
templates = self.ec2_backend.get_launch_templates(template_names=template_names, template_ids=template_ids, filters=filters)
|
|
|
|
|
|
|
|
templates = templates[:max_results]
|
|
|
|
|
|
|
|
for template in templates:
|
|
|
|
xml_serialize(templates_node, "item", {
|
|
|
|
"createTime": template.create_time,
|
|
|
|
"createdBy": "arn:aws:iam::{OWNER_ID}:root".format(OWNER_ID=OWNER_ID),
|
|
|
|
"defaultVersionNumber": template.default_version_number,
|
|
|
|
"latestVersionNumber": template.latest_version_number,
|
|
|
|
"launchTemplateId": template.id,
|
|
|
|
"launchTemplateName": template.name,
|
|
|
|
})
|
|
|
|
|
|
|
|
return pretty_xml(tree)
|
|
|
|
|
|
|
|
# def modify_launch_template(self):
|
|
|
|
# pass
|