Merge in master.
This commit is contained in:
commit
3b4ef2cf15
74
CODE_OF_CONDUCT.md
Normal file
74
CODE_OF_CONDUCT.md
Normal file
@ -0,0 +1,74 @@
|
||||
# Contributor Covenant Code of Conduct
|
||||
|
||||
## Our Pledge
|
||||
|
||||
In the interest of fostering an open and welcoming environment, we as
|
||||
contributors and maintainers pledge to making participation in our project and
|
||||
our community a harassment-free experience for everyone, regardless of age, body
|
||||
size, disability, ethnicity, gender identity and expression, level of experience,
|
||||
nationality, personal appearance, race, religion, or sexual identity and
|
||||
orientation.
|
||||
|
||||
## Our Standards
|
||||
|
||||
Examples of behavior that contributes to creating a positive environment
|
||||
include:
|
||||
|
||||
* Using welcoming and inclusive language
|
||||
* Being respectful of differing viewpoints and experiences
|
||||
* Gracefully accepting constructive criticism
|
||||
* Focusing on what is best for the community
|
||||
* Showing empathy towards other community members
|
||||
|
||||
Examples of unacceptable behavior by participants include:
|
||||
|
||||
* The use of sexualized language or imagery and unwelcome sexual attention or
|
||||
advances
|
||||
* Trolling, insulting/derogatory comments, and personal or political attacks
|
||||
* Public or private harassment
|
||||
* Publishing others' private information, such as a physical or electronic
|
||||
address, without explicit permission
|
||||
* Other conduct which could reasonably be considered inappropriate in a
|
||||
professional setting
|
||||
|
||||
## Our Responsibilities
|
||||
|
||||
Project maintainers are responsible for clarifying the standards of acceptable
|
||||
behavior and are expected to take appropriate and fair corrective action in
|
||||
response to any instances of unacceptable behavior.
|
||||
|
||||
Project maintainers have the right and responsibility to remove, edit, or
|
||||
reject comments, commits, code, wiki edits, issues, and other contributions
|
||||
that are not aligned to this Code of Conduct, or to ban temporarily or
|
||||
permanently any contributor for other behaviors that they deem inappropriate,
|
||||
threatening, offensive, or harmful.
|
||||
|
||||
## Scope
|
||||
|
||||
This Code of Conduct applies both within project spaces and in public spaces
|
||||
when an individual is representing the project or its community. Examples of
|
||||
representing a project or community include using an official project e-mail
|
||||
address, posting via an official social media account, or acting as an appointed
|
||||
representative at an online or offline event. Representation of a project may be
|
||||
further defined and clarified by project maintainers.
|
||||
|
||||
## Enforcement
|
||||
|
||||
Instances of abusive, harassing, or otherwise unacceptable behavior may be
|
||||
reported by contacting the project maintainer at spulec@gmail.com. All
|
||||
complaints will be reviewed and investigated and will result in a response that
|
||||
is deemed necessary and appropriate to the circumstances. The project team is
|
||||
obligated to maintain confidentiality with regard to the reporter of an incident.
|
||||
Further details of specific enforcement policies may be posted separately.
|
||||
|
||||
Project maintainers who do not follow or enforce the Code of Conduct in good
|
||||
faith may face temporary or permanent repercussions as determined by other
|
||||
members of the project's leadership.
|
||||
|
||||
## Attribution
|
||||
|
||||
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
|
||||
available at [http://contributor-covenant.org/version/1/4][version]
|
||||
|
||||
[homepage]: http://contributor-covenant.org
|
||||
[version]: http://contributor-covenant.org/version/1/4/
|
4
CONTRIBUTING.md
Normal file
4
CONTRIBUTING.md
Normal file
@ -0,0 +1,4 @@
|
||||
### Contributing code
|
||||
|
||||
If you have improvements to Moto, send us your pull requests! For those
|
||||
just getting started, Github has a [howto](https://help.github.com/articles/using-pull-requests/).
|
33
ISSUE_TEMPLATE.md
Normal file
33
ISSUE_TEMPLATE.md
Normal file
@ -0,0 +1,33 @@
|
||||
## Reporting Bugs
|
||||
|
||||
Please be aware of the following things when filing bug reports:
|
||||
|
||||
1. Avoid raising duplicate issues. *Please* use the GitHub issue search feature
|
||||
to check whether your bug report or feature request has been mentioned in
|
||||
the past.
|
||||
2. When filing bug reports about exceptions or tracebacks, please include the
|
||||
*complete* traceback. Partial tracebacks, or just the exception text, are
|
||||
not helpful.
|
||||
3. Make sure you provide a suitable amount of information to work with. This
|
||||
means you should provide:
|
||||
|
||||
- Guidance on **how to reproduce the issue**. Ideally, this should be a
|
||||
*small* code sample that can be run immediately by the maintainers.
|
||||
Failing that, let us know what you're doing, how often it happens, what
|
||||
environment you're using, etc. Be thorough: it prevents us needing to ask
|
||||
further questions.
|
||||
- Tell us **what you expected to happen**. When we run your example code,
|
||||
what are we expecting to happen? What does "success" look like for your
|
||||
code?
|
||||
- Tell us **what actually happens**. It's not helpful for you to say "it
|
||||
doesn't work" or "it fails". Tell us *how* it fails: do you get an
|
||||
exception? A hang? How was the actual result different from your expected
|
||||
result?
|
||||
- Tell us **what version of Moto you're using**, and
|
||||
**how you installed it**. Tell us whether you're using standalone server
|
||||
mode or the Python mocks. If you are using the Python mocks, include the
|
||||
version of boto/boto3/botocore.
|
||||
|
||||
|
||||
If you do not provide all of these things, it will take us much longer to
|
||||
fix your problem.
|
@ -339,11 +339,14 @@ class RestAPI(object):
|
||||
return status_code, {}, response
|
||||
|
||||
def update_integration_mocks(self, stage_name):
|
||||
stage_url = STAGE_URL.format(api_id=self.id,
|
||||
stage_url_lower = STAGE_URL.format(api_id=self.id.lower(),
|
||||
region_name=self.region_name, stage_name=stage_name)
|
||||
responses.add_callback(responses.GET, stage_url.upper(),
|
||||
stage_url_upper = STAGE_URL.format(api_id=self.id.upper(),
|
||||
region_name=self.region_name, stage_name=stage_name)
|
||||
|
||||
responses.add_callback(responses.GET, stage_url_lower,
|
||||
callback=self.resource_callback)
|
||||
responses.add_callback(responses.GET, stage_url.lower(),
|
||||
responses.add_callback(responses.GET, stage_url_upper,
|
||||
callback=self.resource_callback)
|
||||
|
||||
def create_stage(self, name, deployment_id, variables=None, description='', cacheClusterEnabled=None, cacheClusterSize=None):
|
||||
|
@ -341,6 +341,7 @@ class AutoScalingBackend(BaseBackend):
|
||||
|
||||
max_size = make_int(max_size)
|
||||
min_size = make_int(min_size)
|
||||
desired_capacity = make_int(desired_capacity)
|
||||
default_cooldown = make_int(default_cooldown)
|
||||
if health_check_period is None:
|
||||
health_check_period = 300
|
||||
|
@ -139,6 +139,8 @@ class LambdaFunction(object):
|
||||
print("Exception %s", ex)
|
||||
|
||||
try:
|
||||
original_stdout = sys.stdout
|
||||
original_stderr = sys.stderr
|
||||
codeOut = StringIO()
|
||||
codeErr = StringIO()
|
||||
sys.stdout = codeOut
|
||||
@ -154,8 +156,8 @@ class LambdaFunction(object):
|
||||
finally:
|
||||
codeErr.close()
|
||||
codeOut.close()
|
||||
sys.stdout = sys.__stdout__
|
||||
sys.stderr = sys.__stderr__
|
||||
sys.stdout = original_stdout
|
||||
sys.stderr = original_stderr
|
||||
return self.convert(result)
|
||||
|
||||
def invoke(self, body, request_headers, response_headers):
|
||||
|
@ -1,6 +1,7 @@
|
||||
from __future__ import unicode_literals
|
||||
from datetime import datetime
|
||||
import json
|
||||
import uuid
|
||||
|
||||
import boto.cloudformation
|
||||
from moto.core import BaseBackend
|
||||
@ -81,11 +82,10 @@ class FakeStack(object):
|
||||
def stack_outputs(self):
|
||||
return self.output_map.values()
|
||||
|
||||
def update(self, template, role_arn=None):
|
||||
self._add_stack_event("UPDATE_IN_PROGRESS",
|
||||
resource_status_reason="User Initiated")
|
||||
def update(self, template, role_arn=None, parameters=None):
|
||||
self._add_stack_event("UPDATE_IN_PROGRESS", resource_status_reason="User Initiated")
|
||||
self.template = template
|
||||
self.resource_map.update(json.loads(template))
|
||||
self.resource_map.update(json.loads(template), parameters)
|
||||
self.output_map = self._create_output_map()
|
||||
self._add_stack_event("UPDATE_COMPLETE")
|
||||
self.status = "UPDATE_COMPLETE"
|
||||
@ -111,6 +111,7 @@ class FakeEvent(object):
|
||||
self.resource_status_reason = resource_status_reason
|
||||
self.resource_properties = resource_properties
|
||||
self.timestamp = datetime.utcnow()
|
||||
self.event_id = uuid.uuid4()
|
||||
|
||||
|
||||
class CloudFormationBackend(BaseBackend):
|
||||
@ -163,9 +164,9 @@ class CloudFormationBackend(BaseBackend):
|
||||
if stack.name == name_or_stack_id:
|
||||
return stack
|
||||
|
||||
def update_stack(self, name, template, role_arn=None):
|
||||
def update_stack(self, name, template, role_arn=None, parameters=None):
|
||||
stack = self.get_stack(name)
|
||||
stack.update(template, role_arn)
|
||||
stack.update(template, role_arn, parameters=parameters)
|
||||
return stack
|
||||
|
||||
def list_stack_resources(self, stack_name_or_id):
|
||||
|
@ -143,7 +143,7 @@ def clean_json(resource_json, resources_map):
|
||||
|
||||
if 'Fn::If' in resource_json:
|
||||
condition_name, true_value, false_value = resource_json['Fn::If']
|
||||
if resources_map[condition_name]:
|
||||
if resources_map.lazy_condition_map[condition_name]:
|
||||
return clean_json(true_value, resources_map)
|
||||
else:
|
||||
return clean_json(false_value, resources_map)
|
||||
@ -207,7 +207,7 @@ def parse_resource(logical_id, resource_json, resources_map):
|
||||
|
||||
def parse_and_create_resource(logical_id, resource_json, resources_map, region_name):
|
||||
condition = resource_json.get('Condition')
|
||||
if condition and not resources_map[condition]:
|
||||
if condition and not resources_map.lazy_condition_map[condition]:
|
||||
# If this has a False condition, don't create the resource
|
||||
return None
|
||||
|
||||
@ -359,14 +359,13 @@ class ResourceMap(collections.Mapping):
|
||||
|
||||
def load_conditions(self):
|
||||
conditions = self._template.get('Conditions', {})
|
||||
lazy_condition_map = LazyDict()
|
||||
self.lazy_condition_map = LazyDict()
|
||||
for condition_name, condition in conditions.items():
|
||||
lazy_condition_map[condition_name] = functools.partial(parse_condition,
|
||||
condition, self._parsed_resources, lazy_condition_map)
|
||||
self.lazy_condition_map[condition_name] = functools.partial(parse_condition,
|
||||
condition, self._parsed_resources, self.lazy_condition_map)
|
||||
|
||||
for condition_name in lazy_condition_map:
|
||||
self._parsed_resources[
|
||||
condition_name] = lazy_condition_map[condition_name]
|
||||
for condition_name in self.lazy_condition_map:
|
||||
_ = self.lazy_condition_map[condition_name]
|
||||
|
||||
def create(self):
|
||||
self.load_mapping()
|
||||
@ -383,7 +382,9 @@ class ResourceMap(collections.Mapping):
|
||||
ec2_models.ec2_backends[self._region_name].create_tags(
|
||||
[self[resource].physical_resource_id], self.tags)
|
||||
|
||||
def update(self, template):
|
||||
def update(self, template, parameters=None):
|
||||
if parameters:
|
||||
self.input_parameters = parameters
|
||||
self.load_mapping()
|
||||
self.load_parameters()
|
||||
self.load_conditions()
|
||||
|
@ -147,6 +147,11 @@ class CloudFormationResponse(BaseResponse):
|
||||
stack_name).template
|
||||
else:
|
||||
stack_body = self._get_param('TemplateBody')
|
||||
parameters = dict([
|
||||
(parameter['parameter_key'], parameter['parameter_value'])
|
||||
for parameter
|
||||
in self._get_list_prefix("Parameters.member")
|
||||
])
|
||||
|
||||
stack = self.cloudformation_backend.get_stack(stack_name)
|
||||
if stack.status == 'ROLLBACK_COMPLETE':
|
||||
@ -157,6 +162,7 @@ class CloudFormationResponse(BaseResponse):
|
||||
name=stack_name,
|
||||
template=stack_body,
|
||||
role_arn=role_arn,
|
||||
parameters=parameters
|
||||
)
|
||||
if self.request_json:
|
||||
stack_body = {
|
||||
@ -296,7 +302,7 @@ DESCRIBE_STACK_RESOURCES_RESPONSE = """<DescribeStackResourcesResponse>
|
||||
DESCRIBE_STACK_EVENTS_RESPONSE = """<DescribeStackEventsResponse xmlns="http://cloudformation.amazonaws.com/doc/2010-05-15/">
|
||||
<DescribeStackEventsResult>
|
||||
<StackEvents>
|
||||
{% for event in stack.events %}
|
||||
{% for event in stack.events[::-1] %}
|
||||
<member>
|
||||
<Timestamp>{{ event.timestamp.strftime('%Y-%m-%dT%H:%M:%S.%fZ') }}</Timestamp>
|
||||
<ResourceStatus>{{ event.resource_status }}</ResourceStatus>
|
||||
|
@ -349,8 +349,8 @@ class NetworkInterfaceBackend(object):
|
||||
return generic_filter(filters, enis)
|
||||
|
||||
|
||||
class Instance(BotoInstance, TaggedEC2Resource):
|
||||
|
||||
class Instance(TaggedEC2Resource, BotoInstance):
|
||||
def __init__(self, ec2_backend, image_id, user_data, security_groups, **kwargs):
|
||||
super(Instance, self).__init__()
|
||||
self.ec2_backend = ec2_backend
|
||||
@ -458,7 +458,10 @@ class Instance(BotoInstance, TaggedEC2Resource):
|
||||
key_name=properties.get("KeyName"),
|
||||
private_ip=properties.get('PrivateIpAddress'),
|
||||
)
|
||||
return reservation.instances[0]
|
||||
instance = reservation.instances[0]
|
||||
for tag in properties.get("Tags", []):
|
||||
instance.add_tag(tag["Key"], tag["Value"])
|
||||
return instance
|
||||
|
||||
@property
|
||||
def physical_resource_id(self):
|
||||
@ -2956,7 +2959,7 @@ class ElasticAddress(object):
|
||||
|
||||
@property
|
||||
def physical_resource_id(self):
|
||||
return self.allocation_id if self.allocation_id else self.public_ip
|
||||
return self.public_ip
|
||||
|
||||
def get_cfn_attribute(self, attribute_name):
|
||||
from moto.cloudformation.exceptions import UnformattedGetAttTemplateException
|
||||
|
@ -382,9 +382,11 @@ class EC2ContainerServiceBackend(BaseBackend):
|
||||
if not container_instances:
|
||||
raise Exception(
|
||||
"No instances found in cluster {}".format(cluster_name))
|
||||
active_container_instances = [x for x in container_instances if
|
||||
self.container_instances[cluster_name][x].status == 'ACTIVE']
|
||||
for _ in range(count or 1):
|
||||
container_instance_arn = self.container_instances[cluster_name][
|
||||
container_instances[randint(0, len(container_instances) - 1)]
|
||||
active_container_instances[randint(0, len(active_container_instances) - 1)]
|
||||
].containerInstanceArn
|
||||
task = Task(cluster, task_definition, container_instance_arn,
|
||||
overrides or {}, started_by or '')
|
||||
@ -574,6 +576,25 @@ class EC2ContainerServiceBackend(BaseBackend):
|
||||
|
||||
return container_instance_objects, failures
|
||||
|
||||
def update_container_instances_state(self, cluster_str, list_container_instance_ids, status):
|
||||
cluster_name = cluster_str.split('/')[-1]
|
||||
if cluster_name not in self.clusters:
|
||||
raise Exception("{0} is not a cluster".format(cluster_name))
|
||||
status = status.upper()
|
||||
if status not in ['ACTIVE', 'DRAINING']:
|
||||
raise Exception("An error occurred (InvalidParameterException) when calling the UpdateContainerInstancesState operation: Container instances status should be one of [ACTIVE,DRAINING]")
|
||||
failures = []
|
||||
container_instance_objects = []
|
||||
for container_instance_id in list_container_instance_ids:
|
||||
container_instance = self.container_instances[cluster_name].get(container_instance_id, None)
|
||||
if container_instance is not None:
|
||||
container_instance.status = status
|
||||
container_instance_objects.append(container_instance)
|
||||
else:
|
||||
failures.append(ContainerInstanceFailure('MISSING', container_instance_id))
|
||||
|
||||
return container_instance_objects, failures
|
||||
|
||||
def deregister_container_instance(self, cluster_str, container_instance_str):
|
||||
pass
|
||||
|
||||
|
@ -220,3 +220,13 @@ class EC2ContainerServiceResponse(BaseResponse):
|
||||
'failures': [ci.response_object for ci in failures],
|
||||
'containerInstances': [ci.response_object for ci in container_instances]
|
||||
})
|
||||
|
||||
def update_container_instances_state(self):
|
||||
cluster_str = self._get_param('cluster')
|
||||
list_container_instance_arns = self._get_param('containerInstances')
|
||||
status_str = self._get_param('status')
|
||||
container_instances, failures = self.ecs_backend.update_container_instances_state(cluster_str, list_container_instance_arns, status_str)
|
||||
return json.dumps({
|
||||
'failures': [ci.response_object for ci in failures],
|
||||
'containerInstances': [ci.response_object for ci in container_instances]
|
||||
})
|
||||
|
@ -171,6 +171,7 @@ class Group(object):
|
||||
)
|
||||
|
||||
self.users = []
|
||||
self.policies = {}
|
||||
|
||||
def get_cfn_attribute(self, attribute_name):
|
||||
from moto.cloudformation.exceptions import UnformattedGetAttTemplateException
|
||||
@ -178,6 +179,24 @@ class Group(object):
|
||||
raise NotImplementedError('"Fn::GetAtt" : [ "{0}" , "Arn" ]"')
|
||||
raise UnformattedGetAttTemplateException()
|
||||
|
||||
def get_policy(self, policy_name):
|
||||
try:
|
||||
policy_json = self.policies[policy_name]
|
||||
except KeyError:
|
||||
raise IAMNotFoundException("Policy {0} not found".format(policy_name))
|
||||
|
||||
return {
|
||||
'policy_name': policy_name,
|
||||
'policy_document': policy_json,
|
||||
'group_name': self.name,
|
||||
}
|
||||
|
||||
def put_policy(self, policy_name, policy_json):
|
||||
self.policies[policy_name] = policy_json
|
||||
|
||||
def list_policies(self):
|
||||
return self.policies.keys()
|
||||
|
||||
|
||||
class User(object):
|
||||
|
||||
@ -589,6 +608,18 @@ class IAMBackend(BaseBackend):
|
||||
|
||||
return groups
|
||||
|
||||
def put_group_policy(self, group_name, policy_name, policy_json):
|
||||
group = self.get_group(group_name)
|
||||
group.put_policy(policy_name, policy_json)
|
||||
|
||||
def list_group_policies(self, group_name, marker=None, max_items=None):
|
||||
group = self.get_group(group_name)
|
||||
return group.list_policies()
|
||||
|
||||
def get_group_policy(self, group_name, policy_name):
|
||||
group = self.get_group(group_name)
|
||||
return group.get_policy(policy_name)
|
||||
|
||||
def create_user(self, user_name, path='/'):
|
||||
if user_name in self.users:
|
||||
raise IAMConflictException(
|
||||
|
@ -198,6 +198,32 @@ class IamResponse(BaseResponse):
|
||||
template = self.response_template(LIST_GROUPS_FOR_USER_TEMPLATE)
|
||||
return template.render(groups=groups)
|
||||
|
||||
def put_group_policy(self):
|
||||
group_name = self._get_param('GroupName')
|
||||
policy_name = self._get_param('PolicyName')
|
||||
policy_document = self._get_param('PolicyDocument')
|
||||
iam_backend.put_group_policy(group_name, policy_name, policy_document)
|
||||
template = self.response_template(GENERIC_EMPTY_TEMPLATE)
|
||||
return template.render(name="PutGroupPolicyResponse")
|
||||
|
||||
def list_group_policies(self):
|
||||
group_name = self._get_param('GroupName')
|
||||
marker = self._get_param('Marker')
|
||||
max_items = self._get_param('MaxItems')
|
||||
policies = iam_backend.list_group_policies(group_name,
|
||||
marker=marker, max_items=max_items)
|
||||
template = self.response_template(LIST_GROUP_POLICIES_TEMPLATE)
|
||||
return template.render(name="ListGroupPoliciesResponse",
|
||||
policies=policies,
|
||||
marker=marker)
|
||||
|
||||
def get_group_policy(self):
|
||||
group_name = self._get_param('GroupName')
|
||||
policy_name = self._get_param('PolicyName')
|
||||
policy_result = iam_backend.get_group_policy(group_name, policy_name)
|
||||
template = self.response_template(GET_GROUP_POLICY_TEMPLATE)
|
||||
return template.render(name="GetGroupPolicyResponse", **policy_result)
|
||||
|
||||
def create_user(self):
|
||||
user_name = self._get_param('UserName')
|
||||
path = self._get_param('Path')
|
||||
@ -206,6 +232,7 @@ class IamResponse(BaseResponse):
|
||||
template = self.response_template(USER_TEMPLATE)
|
||||
return template.render(action='Create', user=user)
|
||||
|
||||
|
||||
def get_user(self):
|
||||
user_name = self._get_param('UserName')
|
||||
user = iam_backend.get_user(user_name)
|
||||
@ -590,18 +617,16 @@ LIST_SERVER_CERTIFICATES_TEMPLATE = """<ListServerCertificatesResponse>
|
||||
<ServerCertificateMetadataList>
|
||||
{% for certificate in server_certificates %}
|
||||
<member>
|
||||
<ServerCertificateMetadata>
|
||||
<ServerCertificateName>{{ certificate.cert_name }}</ServerCertificateName>
|
||||
{% if certificate.path %}
|
||||
<Path>{{ certificate.path }}</Path>
|
||||
<Arn>arn:aws:iam::123456789012:server-certificate/{{ certificate.path }}/{{ certificate.cert_name }}</Arn>
|
||||
{% else %}
|
||||
<Arn>arn:aws:iam::123456789012:server-certificate/{{ certificate.cert_name }}</Arn>
|
||||
{% endif %}
|
||||
<UploadDate>2010-05-08T01:02:03.004Z</UploadDate>
|
||||
<ServerCertificateId>ASCACKCEVSQ6C2EXAMPLE</ServerCertificateId>
|
||||
<Expiration>2012-05-08T01:02:03.004Z</Expiration>
|
||||
</ServerCertificateMetadata>
|
||||
<ServerCertificateName>{{ certificate.cert_name }}</ServerCertificateName>
|
||||
{% if certificate.path %}
|
||||
<Path>{{ certificate.path }}</Path>
|
||||
<Arn>arn:aws:iam::123456789012:server-certificate/{{ certificate.path }}/{{ certificate.cert_name }}</Arn>
|
||||
{% else %}
|
||||
<Arn>arn:aws:iam::123456789012:server-certificate/{{ certificate.cert_name }}</Arn>
|
||||
{% endif %}
|
||||
<UploadDate>2010-05-08T01:02:03.004Z</UploadDate>
|
||||
<ServerCertificateId>ASCACKCEVSQ6C2EXAMPLE</ServerCertificateId>
|
||||
<Expiration>2012-05-08T01:02:03.004Z</Expiration>
|
||||
</member>
|
||||
{% endfor %}
|
||||
</ServerCertificateMetadataList>
|
||||
@ -713,6 +738,35 @@ LIST_GROUPS_FOR_USER_TEMPLATE = """<ListGroupsForUserResponse>
|
||||
</ResponseMetadata>
|
||||
</ListGroupsForUserResponse>"""
|
||||
|
||||
LIST_GROUP_POLICIES_TEMPLATE = """<ListGroupPoliciesResponse>
|
||||
<ListGroupPoliciesResult>
|
||||
{% if marker is none %}
|
||||
<IsTruncated>false</IsTruncated>
|
||||
{% else %}
|
||||
<IsTruncated>true</IsTruncated>
|
||||
<Marker>{{ marker }}</Marker>
|
||||
{% endif %}
|
||||
<PolicyNames>
|
||||
{% for policy in policies %}
|
||||
<member>{{ policy }}</member>
|
||||
{% endfor %}
|
||||
</PolicyNames>
|
||||
</ListGroupPoliciesResult>
|
||||
<ResponseMetadata>
|
||||
<RequestId>7a62c49f-347e-4fc4-9331-6e8eEXAMPLE</RequestId>
|
||||
</ResponseMetadata>
|
||||
</ListGroupPoliciesResponse>"""
|
||||
|
||||
GET_GROUP_POLICY_TEMPLATE = """<GetGroupPolicyResponse xmlns="https://iam.amazonaws.com/doc/2010-05-08/">
|
||||
<GetGroupPolicyResult>
|
||||
<PolicyName>{{ policy_name }}</PolicyName>
|
||||
<GroupName>{{ group_name }}</GroupName>
|
||||
<PolicyDocument>{{ policy_document }}</PolicyDocument>
|
||||
</GetGroupPolicyResult>
|
||||
<ResponseMetadata>
|
||||
<RequestId>7e7cd8bc-99ef-11e1-a4c3-27EXAMPLE804</RequestId>
|
||||
</ResponseMetadata>
|
||||
</GetGroupPolicyResponse>"""
|
||||
|
||||
USER_TEMPLATE = """<{{ action }}UserResponse>
|
||||
<{{ action }}UserResult>
|
||||
|
@ -226,8 +226,11 @@ class RecordSetGroup(object):
|
||||
def create_from_cloudformation_json(cls, resource_name, cloudformation_json, region_name):
|
||||
properties = cloudformation_json['Properties']
|
||||
|
||||
zone_name = properties["HostedZoneName"]
|
||||
hosted_zone = route53_backend.get_hosted_zone_by_name(zone_name)
|
||||
zone_name = properties.get("HostedZoneName")
|
||||
if zone_name:
|
||||
hosted_zone = route53_backend.get_hosted_zone_by_name(zone_name)
|
||||
else:
|
||||
hosted_zone = route53_backend.get_hosted_zone(properties["HostedZoneId"])
|
||||
record_sets = properties["RecordSets"]
|
||||
for record_set in record_sets:
|
||||
hosted_zone.add_rrset(record_set)
|
||||
|
@ -90,7 +90,7 @@ class FakeKey(object):
|
||||
@property
|
||||
def response_dict(self):
|
||||
res = {
|
||||
'etag': self.etag,
|
||||
'Etag': self.etag,
|
||||
'last-modified': self.last_modified_RFC1123,
|
||||
'content-length': str(len(self.value)),
|
||||
}
|
||||
|
@ -183,9 +183,8 @@ class Queue(object):
|
||||
self, camelcase_to_underscores(attribute))
|
||||
return result
|
||||
|
||||
@property
|
||||
def url(self):
|
||||
return "http://sqs.{0}.amazonaws.com/123456789012/{1}".format(self.region, self.name)
|
||||
def url(self, request_url):
|
||||
return "{0}://{1}/123456789012/{2}".format(request_url.scheme, request_url.netloc, self.name)
|
||||
|
||||
@property
|
||||
def messages(self):
|
||||
|
@ -1,4 +1,5 @@
|
||||
from __future__ import unicode_literals
|
||||
from six.moves.urllib.parse import urlparse
|
||||
|
||||
from moto.core.responses import BaseResponse
|
||||
from moto.core.utils import camelcase_to_underscores
|
||||
@ -58,26 +59,29 @@ class SQSResponse(BaseResponse):
|
||||
return status_code, headers, body
|
||||
|
||||
def create_queue(self):
|
||||
request_url = urlparse(self.uri)
|
||||
queue_name = self.querystring.get("QueueName")[0]
|
||||
queue = self.sqs_backend.create_queue(queue_name, visibility_timeout=self.attribute.get('VisibilityTimeout'),
|
||||
wait_time_seconds=self.attribute.get('WaitTimeSeconds'))
|
||||
template = self.response_template(CREATE_QUEUE_RESPONSE)
|
||||
return template.render(queue=queue)
|
||||
return template.render(queue=queue, request_url=request_url)
|
||||
|
||||
def get_queue_url(self):
|
||||
request_url = urlparse(self.uri)
|
||||
queue_name = self.querystring.get("QueueName")[0]
|
||||
queue = self.sqs_backend.get_queue(queue_name)
|
||||
if queue:
|
||||
template = self.response_template(GET_QUEUE_URL_RESPONSE)
|
||||
return template.render(queue=queue)
|
||||
return template.render(queue=queue, request_url=request_url)
|
||||
else:
|
||||
return "", dict(status=404)
|
||||
|
||||
def list_queues(self):
|
||||
request_url = urlparse(self.uri)
|
||||
queue_name_prefix = self.querystring.get("QueueNamePrefix", [None])[0]
|
||||
queues = self.sqs_backend.list_queues(queue_name_prefix)
|
||||
template = self.response_template(LIST_QUEUES_RESPONSE)
|
||||
return template.render(queues=queues)
|
||||
return template.render(queues=queues, request_url=request_url)
|
||||
|
||||
def change_message_visibility(self):
|
||||
queue_name = self._get_queue_name()
|
||||
@ -276,7 +280,7 @@ class SQSResponse(BaseResponse):
|
||||
|
||||
CREATE_QUEUE_RESPONSE = """<CreateQueueResponse>
|
||||
<CreateQueueResult>
|
||||
<QueueUrl>{{ queue.url }}</QueueUrl>
|
||||
<QueueUrl>{{ queue.url(request_url) }}</QueueUrl>
|
||||
<VisibilityTimeout>{{ queue.visibility_timeout }}</VisibilityTimeout>
|
||||
</CreateQueueResult>
|
||||
<ResponseMetadata>
|
||||
@ -286,7 +290,7 @@ CREATE_QUEUE_RESPONSE = """<CreateQueueResponse>
|
||||
|
||||
GET_QUEUE_URL_RESPONSE = """<GetQueueUrlResponse>
|
||||
<GetQueueUrlResult>
|
||||
<QueueUrl>{{ queue.url }}</QueueUrl>
|
||||
<QueueUrl>{{ queue.url(request_url) }}</QueueUrl>
|
||||
</GetQueueUrlResult>
|
||||
<ResponseMetadata>
|
||||
<RequestId>470a6f13-2ed9-4181-ad8a-2fdea142988e</RequestId>
|
||||
@ -296,7 +300,7 @@ GET_QUEUE_URL_RESPONSE = """<GetQueueUrlResponse>
|
||||
LIST_QUEUES_RESPONSE = """<ListQueuesResponse>
|
||||
<ListQueuesResult>
|
||||
{% for queue in queues %}
|
||||
<QueueUrl>{{ queue.url }}</QueueUrl>
|
||||
<QueueUrl>{{ queue.url(request_url) }}</QueueUrl>
|
||||
{% endfor %}
|
||||
</ListQueuesResult>
|
||||
<ResponseMetadata>
|
||||
|
@ -5,6 +5,6 @@ sure==1.2.24
|
||||
coverage
|
||||
freezegun
|
||||
flask
|
||||
boto3>=1.3.1
|
||||
boto3>=1.4.4
|
||||
botocore>=1.4.28
|
||||
six
|
||||
|
@ -236,6 +236,10 @@ template = {
|
||||
"Ref": "AWS::StackId"
|
||||
},
|
||||
"Key": "Application"
|
||||
},
|
||||
{
|
||||
"Value": "Bar",
|
||||
"Key": "Foo"
|
||||
}
|
||||
],
|
||||
"SecurityGroupIds": [
|
||||
|
@ -12,7 +12,7 @@ import sure # noqa
|
||||
import tests.backport_assert_raises # noqa
|
||||
from nose.tools import assert_raises
|
||||
|
||||
from moto import mock_cloudformation_deprecated, mock_s3_deprecated
|
||||
from moto import mock_cloudformation_deprecated, mock_s3_deprecated, mock_route53_deprecated
|
||||
from moto.cloudformation import cloudformation_backends
|
||||
|
||||
dummy_template = {
|
||||
@ -69,6 +69,57 @@ def test_create_stack():
|
||||
})
|
||||
|
||||
|
||||
@mock_cloudformation_deprecated
|
||||
@mock_route53_deprecated
|
||||
def test_create_stack_hosted_zone_by_id():
|
||||
conn = boto.connect_cloudformation()
|
||||
dummy_template = {
|
||||
"AWSTemplateFormatVersion": "2010-09-09",
|
||||
"Description": "Stack 1",
|
||||
"Parameters": {
|
||||
},
|
||||
"Resources": {
|
||||
"Bar": {
|
||||
"Type" : "AWS::Route53::HostedZone",
|
||||
"Properties" : {
|
||||
"Name" : "foo.bar.baz",
|
||||
}
|
||||
},
|
||||
},
|
||||
}
|
||||
dummy_template2 = {
|
||||
"AWSTemplateFormatVersion": "2010-09-09",
|
||||
"Description": "Stack 2",
|
||||
"Parameters": {
|
||||
"ZoneId": { "Type": "String" }
|
||||
},
|
||||
"Resources": {
|
||||
"Foo": {
|
||||
"Properties": {
|
||||
"HostedZoneId": {"Ref": "ZoneId"},
|
||||
"RecordSets": []
|
||||
},
|
||||
"Type": "AWS::Route53::RecordSetGroup"
|
||||
}
|
||||
},
|
||||
}
|
||||
conn.create_stack(
|
||||
"test_stack",
|
||||
template_body=json.dumps(dummy_template),
|
||||
parameters={}.items()
|
||||
)
|
||||
r53_conn = boto.connect_route53()
|
||||
zone_id = r53_conn.get_zones()[0].id
|
||||
conn.create_stack(
|
||||
"test_stack",
|
||||
template_body=json.dumps(dummy_template2),
|
||||
parameters={"ZoneId": zone_id}.items()
|
||||
)
|
||||
|
||||
stack = conn.describe_stacks()[0]
|
||||
assert stack.list_resources()
|
||||
|
||||
|
||||
@mock_cloudformation_deprecated
|
||||
def test_creating_stacks_across_regions():
|
||||
west1_conn = boto.cloudformation.connect_to_region("us-west-1")
|
||||
@ -281,6 +332,60 @@ def test_cloudformation_params():
|
||||
param.value.should.equal('testing123')
|
||||
|
||||
|
||||
@mock_cloudformation_deprecated
|
||||
def test_cloudformation_params_conditions_and_resources_are_distinct():
|
||||
dummy_template = {
|
||||
"AWSTemplateFormatVersion": "2010-09-09",
|
||||
"Description": "Stack 1",
|
||||
"Conditions": {
|
||||
"FooEnabled": {
|
||||
"Fn::Equals": [
|
||||
{
|
||||
"Ref": "FooEnabled"
|
||||
},
|
||||
"true"
|
||||
]
|
||||
},
|
||||
"FooDisabled": {
|
||||
"Fn::Not": [
|
||||
{
|
||||
"Fn::Equals": [
|
||||
{
|
||||
"Ref": "FooEnabled"
|
||||
},
|
||||
"true"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"Parameters": {
|
||||
"FooEnabled": {
|
||||
"Type": "String",
|
||||
"AllowedValues": [
|
||||
"true",
|
||||
"false"
|
||||
]
|
||||
}
|
||||
},
|
||||
"Resources": {
|
||||
"Bar": {
|
||||
"Properties": {
|
||||
"CidrBlock": "192.168.0.0/16",
|
||||
},
|
||||
"Condition": "FooDisabled",
|
||||
"Type": "AWS::EC2::VPC"
|
||||
}
|
||||
}
|
||||
}
|
||||
dummy_template_json = json.dumps(dummy_template)
|
||||
cfn = boto.connect_cloudformation()
|
||||
cfn.create_stack('test_stack1', template_body=dummy_template_json, parameters=[('FooEnabled', 'true')])
|
||||
stack = cfn.describe_stacks('test_stack1')[0]
|
||||
resources = stack.list_resources()
|
||||
assert not [resource for resource in resources if resource.logical_resource_id == 'Bar']
|
||||
|
||||
|
||||
@mock_cloudformation_deprecated
|
||||
def test_stack_tags():
|
||||
conn = boto.connect_cloudformation()
|
||||
@ -341,6 +446,42 @@ def test_update_stack():
|
||||
})
|
||||
|
||||
|
||||
@mock_cloudformation_deprecated
|
||||
def test_update_stack_with_parameters():
|
||||
dummy_template = {
|
||||
"AWSTemplateFormatVersion": "2010-09-09",
|
||||
"Description": "Stack",
|
||||
"Resources": {
|
||||
"VPC": {
|
||||
"Properties": {
|
||||
"CidrBlock": {"Ref": "Bar"}
|
||||
},
|
||||
"Type": "AWS::EC2::VPC"
|
||||
}
|
||||
},
|
||||
"Parameters": {
|
||||
"Bar": {
|
||||
"Type": "String"
|
||||
}
|
||||
}
|
||||
}
|
||||
dummy_template_json = json.dumps(dummy_template)
|
||||
conn = boto.connect_cloudformation()
|
||||
conn.create_stack(
|
||||
"test_stack",
|
||||
template_body=dummy_template_json,
|
||||
parameters=[("Bar", "192.168.0.0/16")]
|
||||
)
|
||||
conn.update_stack(
|
||||
"test_stack",
|
||||
template_body=dummy_template_json,
|
||||
parameters=[("Bar", "192.168.0.1/16")]
|
||||
)
|
||||
|
||||
stack = conn.describe_stacks()[0]
|
||||
assert stack.parameters[0].value == "192.168.0.1/16"
|
||||
|
||||
|
||||
@mock_cloudformation_deprecated
|
||||
def test_update_stack_when_rolled_back():
|
||||
conn = boto.connect_cloudformation()
|
||||
@ -374,16 +515,21 @@ def test_describe_stack_events_shows_create_update_and_delete():
|
||||
events[0].resource_type.should.equal("AWS::CloudFormation::Stack")
|
||||
events[-1].resource_type.should.equal("AWS::CloudFormation::Stack")
|
||||
|
||||
# testing ordering of stack events without assuming resource events will
|
||||
# not exist
|
||||
# testing ordering of stack events without assuming resource events will not exist
|
||||
# the AWS API returns events in reverse chronological order
|
||||
stack_events_to_look_for = iter([
|
||||
("CREATE_IN_PROGRESS", "User Initiated"), ("CREATE_COMPLETE", None),
|
||||
("UPDATE_IN_PROGRESS", "User Initiated"), ("UPDATE_COMPLETE", None),
|
||||
("DELETE_IN_PROGRESS", "User Initiated"), ("DELETE_COMPLETE", None)])
|
||||
("DELETE_COMPLETE", None),
|
||||
("DELETE_IN_PROGRESS", "User Initiated"),
|
||||
("UPDATE_COMPLETE", None),
|
||||
("UPDATE_IN_PROGRESS", "User Initiated"),
|
||||
("CREATE_COMPLETE", None),
|
||||
("CREATE_IN_PROGRESS", "User Initiated"),
|
||||
])
|
||||
try:
|
||||
for event in events:
|
||||
event.stack_id.should.equal(stack_id)
|
||||
event.stack_name.should.equal("test_stack")
|
||||
event.event_id.should.match(r"[0-9a-f]{8}-([0-9a-f]{4}-){3}[0-9a-f]{12}")
|
||||
|
||||
if event.resource_type == "AWS::CloudFormation::Stack":
|
||||
event.logical_resource_id.should.equal("test_stack")
|
||||
|
@ -354,16 +354,21 @@ def test_stack_events():
|
||||
events[0].resource_type.should.equal("AWS::CloudFormation::Stack")
|
||||
events[-1].resource_type.should.equal("AWS::CloudFormation::Stack")
|
||||
|
||||
# testing ordering of stack events without assuming resource events will
|
||||
# not exist
|
||||
# testing ordering of stack events without assuming resource events will not exist
|
||||
# the AWS API returns events in reverse chronological order
|
||||
stack_events_to_look_for = iter([
|
||||
("CREATE_IN_PROGRESS", "User Initiated"), ("CREATE_COMPLETE", None),
|
||||
("UPDATE_IN_PROGRESS", "User Initiated"), ("UPDATE_COMPLETE", None),
|
||||
("DELETE_IN_PROGRESS", "User Initiated"), ("DELETE_COMPLETE", None)])
|
||||
("DELETE_COMPLETE", None),
|
||||
("DELETE_IN_PROGRESS", "User Initiated"),
|
||||
("UPDATE_COMPLETE", None),
|
||||
("UPDATE_IN_PROGRESS", "User Initiated"),
|
||||
("CREATE_COMPLETE", None),
|
||||
("CREATE_IN_PROGRESS", "User Initiated"),
|
||||
])
|
||||
try:
|
||||
for event in events:
|
||||
event.stack_id.should.equal(stack.stack_id)
|
||||
event.stack_name.should.equal("test_stack")
|
||||
event.event_id.should.match(r"[0-9a-f]{8}-([0-9a-f]{4}-){3}[0-9a-f]{12}")
|
||||
|
||||
if event.resource_type == "AWS::CloudFormation::Stack":
|
||||
event.logical_resource_id.should.equal("test_stack")
|
||||
|
@ -548,6 +548,7 @@ def test_autoscaling_group_with_elb():
|
||||
"LaunchConfigurationName": {"Ref": "my-launch-config"},
|
||||
"MinSize": "2",
|
||||
"MaxSize": "2",
|
||||
"DesiredCapacity": "2",
|
||||
"LoadBalancerNames": [{"Ref": "my-elb"}]
|
||||
},
|
||||
},
|
||||
@ -631,6 +632,7 @@ def test_autoscaling_group_update():
|
||||
"LaunchConfigurationName": {"Ref": "my-launch-config"},
|
||||
"MinSize": "2",
|
||||
"MaxSize": "2",
|
||||
"DesiredCapacity": "2"
|
||||
},
|
||||
},
|
||||
|
||||
@ -655,6 +657,7 @@ def test_autoscaling_group_update():
|
||||
asg = autoscale_conn.get_all_groups()[0]
|
||||
asg.min_size.should.equal(2)
|
||||
asg.max_size.should.equal(2)
|
||||
asg.desired_capacity.should.equal(2)
|
||||
|
||||
asg_template['Resources']['my-as-group']['Properties']['MaxSize'] = 3
|
||||
asg_template_json = json.dumps(asg_template)
|
||||
@ -665,6 +668,7 @@ def test_autoscaling_group_update():
|
||||
asg = autoscale_conn.get_all_groups()[0]
|
||||
asg.min_size.should.equal(2)
|
||||
asg.max_size.should.equal(3)
|
||||
asg.desired_capacity.should.equal(2)
|
||||
|
||||
|
||||
@mock_ec2_deprecated()
|
||||
@ -693,6 +697,7 @@ def test_vpc_single_instance_in_subnet():
|
||||
ec2_conn = boto.ec2.connect_to_region("us-west-1")
|
||||
reservation = ec2_conn.get_all_instances()[0]
|
||||
instance = reservation.instances[0]
|
||||
instance.tags["Foo"].should.equal("Bar")
|
||||
# Check that the EIP is attached the the EC2 instance
|
||||
eip = ec2_conn.get_all_addresses()[0]
|
||||
eip.domain.should.equal('vpc')
|
||||
@ -714,7 +719,7 @@ def test_vpc_single_instance_in_subnet():
|
||||
|
||||
eip_resource = [
|
||||
resource for resource in resources if resource.resource_type == 'AWS::EC2::EIP'][0]
|
||||
eip_resource.physical_resource_id.should.equal(eip.allocation_id)
|
||||
eip_resource.physical_resource_id.should.equal(eip.public_ip)
|
||||
|
||||
|
||||
@mock_cloudformation()
|
||||
@ -1027,7 +1032,7 @@ def test_vpc_eip():
|
||||
resources = stack.describe_resources()
|
||||
cfn_eip = [
|
||||
resource for resource in resources if resource.resource_type == 'AWS::EC2::EIP'][0]
|
||||
cfn_eip.physical_resource_id.should.equal(eip.allocation_id)
|
||||
cfn_eip.physical_resource_id.should.equal(eip.public_ip)
|
||||
|
||||
|
||||
@mock_ec2_deprecated()
|
||||
|
@ -622,6 +622,58 @@ def test_describe_container_instances():
|
||||
for arn in test_instance_arns:
|
||||
response_arns.should.contain(arn)
|
||||
|
||||
@mock_ec2
|
||||
@mock_ecs
|
||||
def test_update_container_instances_state():
|
||||
ecs_client = boto3.client('ecs', region_name='us-east-1')
|
||||
ec2 = boto3.resource('ec2', region_name='us-east-1')
|
||||
|
||||
test_cluster_name = 'test_ecs_cluster'
|
||||
_ = ecs_client.create_cluster(
|
||||
clusterName=test_cluster_name
|
||||
)
|
||||
|
||||
instance_to_create = 3
|
||||
test_instance_arns = []
|
||||
for i in range(0, instance_to_create):
|
||||
test_instance = ec2.create_instances(
|
||||
ImageId="ami-1234abcd",
|
||||
MinCount=1,
|
||||
MaxCount=1,
|
||||
)[0]
|
||||
|
||||
instance_id_document = json.dumps(
|
||||
ec2_utils.generate_instance_identity_document(test_instance)
|
||||
)
|
||||
|
||||
response = ecs_client.register_container_instance(
|
||||
cluster=test_cluster_name,
|
||||
instanceIdentityDocument=instance_id_document)
|
||||
|
||||
test_instance_arns.append(response['containerInstance']['containerInstanceArn'])
|
||||
|
||||
test_instance_ids = list(map((lambda x: x.split('/')[1]), test_instance_arns))
|
||||
response = ecs_client.update_container_instances_state(cluster=test_cluster_name, containerInstances=test_instance_ids, status='DRAINING')
|
||||
len(response['failures']).should.equal(0)
|
||||
len(response['containerInstances']).should.equal(instance_to_create)
|
||||
response_statuses = [ci['status'] for ci in response['containerInstances']]
|
||||
for status in response_statuses:
|
||||
status.should.equal('DRAINING')
|
||||
response = ecs_client.update_container_instances_state(cluster=test_cluster_name, containerInstances=test_instance_ids, status='DRAINING')
|
||||
len(response['failures']).should.equal(0)
|
||||
len(response['containerInstances']).should.equal(instance_to_create)
|
||||
response_statuses = [ci['status'] for ci in response['containerInstances']]
|
||||
for status in response_statuses:
|
||||
status.should.equal('DRAINING')
|
||||
response = ecs_client.update_container_instances_state(cluster=test_cluster_name, containerInstances=test_instance_ids, status='ACTIVE')
|
||||
len(response['failures']).should.equal(0)
|
||||
len(response['containerInstances']).should.equal(instance_to_create)
|
||||
response_statuses = [ci['status'] for ci in response['containerInstances']]
|
||||
for status in response_statuses:
|
||||
status.should.equal('ACTIVE')
|
||||
ecs_client.update_container_instances_state.when.called_with(cluster=test_cluster_name, containerInstances=test_instance_ids, status='test_status').should.throw(Exception)
|
||||
|
||||
|
||||
|
||||
@mock_ec2
|
||||
@mock_ecs
|
||||
|
@ -1,5 +1,6 @@
|
||||
from __future__ import unicode_literals
|
||||
import boto
|
||||
import boto3
|
||||
import sure # noqa
|
||||
|
||||
from nose.tools import assert_raises
|
||||
@ -72,3 +73,40 @@ def test_get_groups_for_user():
|
||||
groups = conn.get_groups_for_user(
|
||||
'my-user')['list_groups_for_user_response']['list_groups_for_user_result']['groups']
|
||||
groups.should.have.length_of(2)
|
||||
|
||||
|
||||
@mock_iam_deprecated()
|
||||
def test_put_group_policy():
|
||||
conn = boto.connect_iam()
|
||||
conn.create_group('my-group')
|
||||
conn.put_group_policy('my-group', 'my-policy', '{"some": "json"}')
|
||||
|
||||
|
||||
@mock_iam_deprecated()
|
||||
def test_get_group_policy():
|
||||
conn = boto.connect_iam()
|
||||
conn.create_group('my-group')
|
||||
with assert_raises(BotoServerError):
|
||||
conn.get_group_policy('my-group', 'my-policy')
|
||||
|
||||
conn.put_group_policy('my-group', 'my-policy', '{"some": "json"}')
|
||||
policy = conn.get_group_policy('my-group', 'my-policy')
|
||||
|
||||
@mock_iam_deprecated()
|
||||
def test_get_all_group_policies():
|
||||
conn = boto.connect_iam()
|
||||
conn.create_group('my-group')
|
||||
policies = conn.get_all_group_policies('my-group')['list_group_policies_response']['list_group_policies_result']['policy_names']
|
||||
assert policies == []
|
||||
conn.put_group_policy('my-group', 'my-policy', '{"some": "json"}')
|
||||
policies = conn.get_all_group_policies('my-group')['list_group_policies_response']['list_group_policies_result']['policy_names']
|
||||
assert policies == ['my-policy']
|
||||
|
||||
|
||||
@mock_iam()
|
||||
def test_list_group_policies():
|
||||
conn = boto3.client('iam')
|
||||
conn.create_group(GroupName='my-group')
|
||||
policies = conn.list_group_policies(GroupName='my-group')['PolicyNames'].should.be.empty
|
||||
conn.put_group_policy(GroupName='my-group', PolicyName='my-policy', PolicyDocument='{"some": "json"}')
|
||||
policies = conn.list_group_policies(GroupName='my-group')['PolicyNames'].should.equal(['my-policy'])
|
||||
|
@ -77,7 +77,7 @@ def test_create_queues_in_multiple_region():
|
||||
list(west2_conn.list_queues()['QueueUrls']).should.have.length_of(1)
|
||||
|
||||
west1_conn.list_queues()['QueueUrls'][0].should.equal(
|
||||
'http://sqs.us-west-1.amazonaws.com/123456789012/blah')
|
||||
'https://us-west-1.queue.amazonaws.com/123456789012/blah')
|
||||
|
||||
|
||||
@mock_sqs
|
||||
@ -92,7 +92,7 @@ def test_get_queue_with_prefix():
|
||||
queue = conn.list_queues(QueueNamePrefix="test-")['QueueUrls']
|
||||
queue.should.have.length_of(1)
|
||||
queue[0].should.equal(
|
||||
"http://sqs.us-west-1.amazonaws.com/123456789012/test-queue")
|
||||
"https://us-west-1.queue.amazonaws.com/123456789012/test-queue")
|
||||
|
||||
|
||||
@mock_sqs
|
||||
|
Loading…
x
Reference in New Issue
Block a user