Skip to content

Commit

Permalink
adding owner id to amis v2 (#1331)
Browse files Browse the repository at this point in the history
* Adding owner-id/OwnerId to the AMI classes to allow the value to be specified to test filtering images based on owner.

* Added default AMIs and filtering by owner-id

* Fixed some tests

* Fixed more random tests

* Updated MANIFEST

* .
  • Loading branch information
terrycain committed Nov 12, 2017
1 parent 123f369 commit bd8c1e4
Show file tree
Hide file tree
Showing 14 changed files with 758 additions and 110 deletions.
1 change: 1 addition & 0 deletions MANIFEST.in
@@ -1,5 +1,6 @@
include README.md LICENSE AUTHORS.md
include requirements.txt requirements-dev.txt tox.ini
include moto/ec2/resources/instance_types.json
include moto/ec2/resources/amis.json
recursive-include moto/templates *
recursive-include tests *
32 changes: 16 additions & 16 deletions moto/cloudformation/responses.py
Expand Up @@ -19,10 +19,19 @@ def _get_stack_from_s3_url(self, template_url):
template_url_parts = urlparse(template_url)
if "localhost" in template_url:
bucket_name, key_name = template_url_parts.path.lstrip(
"/").split("/")
"/").split("/", 1)
else:
bucket_name = template_url_parts.netloc.split(".")[0]
key_name = template_url_parts.path.lstrip("/")
if template_url_parts.netloc.endswith('amazonaws.com') \
and template_url_parts.netloc.startswith('s3'):
# Handle when S3 url uses amazon url with bucket in path
# Also handles getting region as technically s3 is region'd

# region = template_url.netloc.split('.')[1]
bucket_name, key_name = template_url_parts.path.lstrip(
"/").split("/", 1)
else:
bucket_name = template_url_parts.netloc.split(".")[0]
key_name = template_url_parts.path.lstrip("/")

key = s3_backend.get_key(bucket_name, key_name)
return key.value.decode("utf-8")
Expand Down Expand Up @@ -227,13 +236,13 @@ def list_exports(self):
</CreateStackResponse>
"""

UPDATE_STACK_RESPONSE_TEMPLATE = """<UpdateStackResponse>
UPDATE_STACK_RESPONSE_TEMPLATE = """<UpdateStackResponse xmlns="http://cloudformation.amazonaws.com/doc/2010-05-15/">
<UpdateStackResult>
<StackId>{{ stack.stack_id }}</StackId>
</UpdateStackResult>
<ResponseMetadata>
<RequestId>b9b5b068-3a41-11e5-94eb-example</RequestId>
</ResponseMetadata>
<RequestId>b9b4b068-3a41-11e5-94eb-example</RequestId>
</ResponseMetadata>
</UpdateStackResponse>
"""

Expand Down Expand Up @@ -399,23 +408,14 @@ def list_exports(self):
</GetTemplateResponse>"""


UPDATE_STACK_RESPONSE_TEMPLATE = """<UpdateStackResponse xmlns="http://cloudformation.amazonaws.com/doc/2010-05-15/">
<UpdateStackResult>
<StackId>{{ stack.stack_id }}</StackId>
</UpdateStackResult>
<ResponseMetadata>
<RequestId>b9b4b068-3a41-11e5-94eb-example</RequestId>
</ResponseMetadata>
</UpdateStackResponse>
"""

DELETE_STACK_RESPONSE_TEMPLATE = """<DeleteStackResponse>
<ResponseMetadata>
<RequestId>5ccc7dcd-744c-11e5-be70-example</RequestId>
</ResponseMetadata>
</DeleteStackResponse>
"""


LIST_EXPORTS_RESPONSE = """<ListExportsResponse xmlns="http://cloudformation.amazonaws.com/doc/2010-05-15/">
<ListExportsResult>
<Exports>
Expand Down
103 changes: 69 additions & 34 deletions moto/ec2/models.py
Expand Up @@ -6,6 +6,7 @@
import json
import re
import six
import warnings
from pkg_resources import resource_filename

import boto.ec2
Expand Down Expand Up @@ -45,7 +46,6 @@
InvalidRouteTableIdError,
InvalidRouteError,
InvalidInstanceIdError,
MalformedAMIIdError,
InvalidAMIIdError,
InvalidAMIAttributeItemValueError,
InvalidSnapshotIdError,
Expand Down Expand Up @@ -113,8 +113,12 @@
tag_filter_matches,
)

RES_FILE = resource_filename(__name__, 'resources/instance_types.json')
INSTANCE_TYPES = json.load(open(RES_FILE, 'r'))
INSTANCE_TYPES = json.load(
open(resource_filename(__name__, 'resources/instance_types.json'), 'r')
)
AMIS = json.load(
open(resource_filename(__name__, 'resources/amis.json'), 'r')
)


def utc_date_and_time():
Expand Down Expand Up @@ -384,6 +388,11 @@ def __init__(self, ec2_backend, image_id, user_data, security_groups, **kwargs):

amis = self.ec2_backend.describe_images(filters={'image-id': image_id})
ami = amis[0] if amis else None
if ami is None:
warnings.warn('Could not find AMI with image-id:{0}, '
'in the near future this will '
'cause an error'.format(image_id),
PendingDeprecationWarning)

self.platform = ami.platform if ami else None
self.virtualization_type = ami.virtualization_type if ami else 'paravirtual'
Expand Down Expand Up @@ -1001,17 +1010,31 @@ def describe_tags(self, filters=None):

class Ami(TaggedEC2Resource):
def __init__(self, ec2_backend, ami_id, instance=None, source_ami=None,
name=None, description=None):
name=None, description=None, owner_id=None,

public=False, virtualization_type=None, architecture=None,
state='available', creation_date=None, platform=None,
image_type='machine', image_location=None, hypervisor=None,
root_device_type=None, root_device_name=None, sriov='simple',
region_name='us-east-1a'
):
self.ec2_backend = ec2_backend
self.id = ami_id
self.state = "available"
self.state = state
self.name = name
self.image_type = image_type
self.image_location = image_location
self.owner_id = owner_id
self.description = description
self.virtualization_type = None
self.architecture = None
self.virtualization_type = virtualization_type
self.architecture = architecture
self.kernel_id = None
self.platform = None
self.creation_date = utc_date_and_time()
self.platform = platform
self.hypervisor = hypervisor
self.root_device_name = root_device_name
self.root_device_type = root_device_type
self.sriov = sriov
self.creation_date = utc_date_and_time() if creation_date is None else creation_date

if instance:
self.instance = instance
Expand Down Expand Up @@ -1039,8 +1062,11 @@ def __init__(self, ec2_backend, ami_id, instance=None, source_ami=None,
self.launch_permission_groups = set()
self.launch_permission_users = set()

if public:
self.launch_permission_groups.add('all')

# AWS auto-creates these, we should reflect the same.
volume = self.ec2_backend.create_volume(15, "us-east-1a")
volume = self.ec2_backend.create_volume(15, region_name)
self.ebs_snapshot = self.ec2_backend.create_snapshot(
volume.id, "Auto-created snapshot for AMI %s" % self.id)

Expand All @@ -1067,6 +1093,8 @@ def get_filter_value(self, filter_name):
return self.state
elif filter_name == 'name':
return self.name
elif filter_name == 'owner-id':
return self.owner_id
else:
return super(Ami, self).get_filter_value(
filter_name, 'DescribeImages')
Expand All @@ -1075,14 +1103,22 @@ def get_filter_value(self, filter_name):
class AmiBackend(object):
def __init__(self):
self.amis = {}

self._load_amis()

super(AmiBackend, self).__init__()

def create_image(self, instance_id, name=None, description=None):
def _load_amis(self):
for ami in AMIS:
ami_id = ami['ami_id']
self.amis[ami_id] = Ami(self, **ami)

def create_image(self, instance_id, name=None, description=None, owner_id=None):
# TODO: check that instance exists and pull info from it.
ami_id = random_ami_id()
instance = self.get_instance(instance_id)
ami = Ami(self, ami_id, instance=instance, source_ami=None,
name=name, description=description)
name=name, description=description, owner_id=owner_id)
self.amis[ami_id] = ami
return ami

Expand All @@ -1095,30 +1131,29 @@ def copy_image(self, source_image_id, source_region, name=None, description=None
self.amis[ami_id] = ami
return ami

def describe_images(self, ami_ids=(), filters=None, exec_users=None):
images = []
def describe_images(self, ami_ids=(), filters=None, exec_users=None, owners=None):
images = self.amis.values()

# Limit images by launch permissions
if exec_users:
for ami_id in self.amis:
found = False
tmp_images = []
for ami in images:
for user_id in exec_users:
if user_id in self.amis[ami_id].launch_permission_users:
found = True
if found:
images.append(self.amis[ami_id])
if images == []:
return images
if user_id in ami.launch_permission_users:
tmp_images.append(ami)
images = tmp_images

# Limit by owner ids
if owners:
images = [ami for ami in images if ami.owner_id in owners]

if ami_ids:
images = [ami for ami in images if ami.id in ami_ids]

# Generic filters
if filters:
images = images or self.amis.values()
return generic_filter(filters, images)
else:
for ami_id in ami_ids:
if ami_id in self.amis:
images.append(self.amis[ami_id])
elif not ami_id.startswith("ami-"):
raise MalformedAMIIdError(ami_id)
else:
raise InvalidAMIIdError(ami_id)
return images or self.amis.values()
return images

def deregister_image(self, ami_id):
if ami_id in self.amis:
Expand Down Expand Up @@ -3679,8 +3714,8 @@ def delete_nat_gateway(self, nat_gateway_id):
return self.nat_gateways.pop(nat_gateway_id)


class EC2Backend(BaseBackend, InstanceBackend, TagBackend, AmiBackend,
RegionsAndZonesBackend, SecurityGroupBackend, EBSBackend,
class EC2Backend(BaseBackend, InstanceBackend, TagBackend, EBSBackend,
RegionsAndZonesBackend, SecurityGroupBackend, AmiBackend,
VPCBackend, SubnetBackend, SubnetRouteTableAssociationBackend,
NetworkInterfaceBackend, VPNConnectionBackend,
VPCPeeringConnectionBackend,
Expand Down

0 comments on commit bd8c1e4

Please sign in to comment.