Skip to content
This repository has been archived by the owner on May 10, 2024. It is now read-only.

Commit

Permalink
Merge pull request #1920 from tmacam/AddEMRAddTagSupport
Browse files Browse the repository at this point in the history
Add AddTags support for EMR connections. Fixes #1920.
  • Loading branch information
danielgtaylor committed Dec 17, 2013
2 parents d0bd451 + aaea98e commit 8e4c595
Show file tree
Hide file tree
Showing 2 changed files with 109 additions and 0 deletions.
32 changes: 32 additions & 0 deletions boto/emr/connection.py
Expand Up @@ -267,6 +267,26 @@ def list_steps(self, cluster_id, step_states=None, marker=None):

self.get_object('ListSteps', params, StepSummaryList)

def add_tags(self, resource_id, tags):
"""
Create new metadata tags for the specified resource ids.
:type resource_ids: str
:param resource_ids: The cluster id
:type tags: dict
:param tags: A dictionary containing the name/value pairs.
If you want to create only a tag name, the
value for that tag should be the empty string
(e.g. '') or None.
"""
assert isinstance(resource_id, basestring)
params = {
'ResourceId': resource_id,
}
params.update(self._build_tag_list(tags))
return self.get_status('AddTags', params, verb='POST')

def terminate_jobflow(self, jobflow_id):
"""
Terminate an Elastic MapReduce job flow
Expand Down Expand Up @@ -623,6 +643,18 @@ def _build_step_list(self, steps):
params['Steps.member.%s.%s' % (i+1, key)] = value
return params

def _build_tag_list(self, tags):
assert isinstance(tags, dict)

params = {}
for i, key_value in enumerate(sorted(tags.iteritems()), start=1):
key, value = key_value
current_prefix = 'Tags.member.%s' % i
params['%s.Key' % current_prefix] = key
if value:
params['%s.Value' % current_prefix] = value
return params

def _build_instance_common_args(self, ec2_keyname, availability_zone,
keep_alive, hadoop_version):
"""
Expand Down
77 changes: 77 additions & 0 deletions tests/unit/emr/test_connection.py
Expand Up @@ -291,3 +291,80 @@ def test_add_jobflow_steps(self):
self.assertTrue(isinstance(response, JobFlowStepList))
self.assertEqual(response.stepids[0].value, 'Foo')
self.assertEqual(response.stepids[1].value, 'Bar')


class TestBuildTagList(AWSMockServiceTestCase):
connection_class = EmrConnection

def test_key_without_value_encoding(self):
input_dict = {
'KeyWithNoValue': '',
'AnotherKeyWithNoValue': None
}
res = self.service_connection._build_tag_list(input_dict)
# Keys are outputted in ascending key order.
expected = {
'Tags.member.1.Key': 'AnotherKeyWithNoValue',
'Tags.member.2.Key': 'KeyWithNoValue'
}
self.assertEqual(expected, res)

def test_key_full_key_value_encoding(self):
input_dict = {
'FirstKey': 'One',
'SecondKey': 'Two'
}
res = self.service_connection._build_tag_list(input_dict)
# Keys are outputted in ascending key order.
expected = {
'Tags.member.1.Key': 'FirstKey',
'Tags.member.1.Value': 'One',
'Tags.member.2.Key': 'SecondKey',
'Tags.member.2.Value': 'Two'
}
self.assertEqual(expected, res)


class TestAddTag(AWSMockServiceTestCase):
connection_class = EmrConnection

def default_body(self):
return """<AddTagsResponse
xmlns="http://elasticmapreduce.amazonaws.com/doc/2009-03-31">
<AddTagsResult/>
<ResponseMetadata>
<RequestId>88888888-8888-8888-8888-888888888888</RequestId>
</ResponseMetadata>
</AddTagsResponse>
"""

def test_add_mix_of_tags_with_without_values(self):
input_tags = {
'FirstKey': 'One',
'SecondKey': 'Two',
'ZzzNoValue': ''
}
self.set_http_response(200)

with self.assertRaises(TypeError):
self.service_connection.add_tags()

with self.assertRaises(TypeError):
self.service_connection.add_tags('j-123')

with self.assertRaises(AssertionError):
self.service_connection.add_tags('j-123', [])

response = self.service_connection.add_tags('j-123', input_tags)

self.assertTrue(response)
self.assert_request_parameters({
'Action': 'AddTags',
'ResourceId': 'j-123',
'Tags.member.1.Key': 'FirstKey',
'Tags.member.1.Value': 'One',
'Tags.member.2.Key': 'SecondKey',
'Tags.member.2.Value': 'Two',
'Tags.member.3.Key': 'ZzzNoValue',
'Version': '2009-03-31'
})

0 comments on commit 8e4c595

Please sign in to comment.