summaryrefslogtreecommitdiffstats
path: root/nova/api
diff options
context:
space:
mode:
authorJenkins <jenkins@review.openstack.org>2013-04-04 20:48:19 +0000
committerGerrit Code Review <review@openstack.org>2013-04-04 20:48:19 +0000
commit7a65d7ed74a634cbb61d0d555438bf011a4046eb (patch)
tree802948a3e5ea67645f5691cf583b31fedd671b1f /nova/api
parentd6715e843c422466452c59a6536cf21d5dee026e (diff)
parent55a04a4bc3228e698bb84a641d50507810ae9a02 (diff)
Merge "Add CRUD methods for tags to the EC2 API."
Diffstat (limited to 'nova/api')
-rw-r--r--nova/api/ec2/cloud.py135
-rw-r--r--nova/api/ec2/ec2utils.py25
2 files changed, 160 insertions, 0 deletions
diff --git a/nova/api/ec2/cloud.py b/nova/api/ec2/cloud.py
index 0d06dde33..3d210404c 100644
--- a/nova/api/ec2/cloud.py
+++ b/nova/api/ec2/cloud.py
@@ -1174,6 +1174,10 @@ class CloudController(object):
i['ipAddress'] = floating_ip or fixed_ip
i['dnsName'] = i['publicDnsName'] or i['privateDnsName']
i['keyName'] = instance['key_name']
+ i['tagSet'] = []
+ for k, v in self.compute_api.get_instance_metadata(
+ context, instance).iteritems():
+ i['tagSet'].append({'key': k, 'value': v})
if context.is_admin:
i['keyName'] = '%s (%s, %s)' % (i['keyName'],
@@ -1677,6 +1681,137 @@ class CloudController(object):
return {'imageId': ec2_id}
+ def create_tags(self, context, **kwargs):
+ """Add tags to a resource
+
+ Returns True on success, error on failure.
+
+ :param context: context under which the method is called
+ """
+ resources = kwargs.get('resource_id', None)
+ tags = kwargs.get('tag', None)
+ if resources is None or tags is None:
+ raise exception.EC2APIError(_('resource_id and tag are required'))
+
+ if not isinstance(resources, (tuple, list, set)):
+ raise exception.EC2APIError(_('Expecting a list of resources'))
+
+ for r in resources:
+ if ec2utils.resource_type_from_id(context, r) != 'instance':
+ raise exception.EC2APIError(_('Only instances implemented'))
+
+ if not isinstance(tags, (tuple, list, set)):
+ raise exception.EC2APIError(_('Expecting a list of tagSets'))
+
+ metadata = {}
+ for tag in tags:
+ if not isinstance(tag, dict):
+ raise exception.EC2APIError(_
+ ('Expecting tagSet to be key/value pairs'))
+
+ key = tag.get('key', None)
+ val = tag.get('value', None)
+
+ if key is None or val is None:
+ raise exception.EC2APIError(_
+ ('Expecting both key and value to be set'))
+
+ metadata[key] = val
+
+ for ec2_id in resources:
+ instance_uuid = ec2utils.ec2_inst_id_to_uuid(context, ec2_id)
+ instance = self.compute_api.get(context, instance_uuid)
+ self.compute_api.update_instance_metadata(context,
+ instance, metadata)
+
+ return True
+
+ def delete_tags(self, context, **kwargs):
+ """Delete tags
+
+ Returns True on success, error on failure.
+
+ :param context: context under which the method is called
+ """
+ resources = kwargs.get('resource_id', None)
+ tags = kwargs.get('tag', None)
+ if resources is None or tags is None:
+ raise exception.EC2APIError(_('resource_id and tag are required'))
+
+ if not isinstance(resources, (tuple, list, set)):
+ raise exception.EC2APIError(_('Expecting a list of resources'))
+
+ for r in resources:
+ if ec2utils.resource_type_from_id(context, r) != 'instance':
+ raise exception.EC2APIError(_('Only instances implemented'))
+
+ if not isinstance(tags, (tuple, list, set)):
+ raise exception.EC2APIError(_('Expecting a list of tagSets'))
+
+ for ec2_id in resources:
+ instance_uuid = ec2utils.ec2_inst_id_to_uuid(context, ec2_id)
+ instance = self.compute_api.get(context, instance_uuid)
+ for tag in tags:
+ if not isinstance(tag, dict):
+ raise exception.EC2APIError(_
+ ('Expecting tagSet to be key/value pairs'))
+
+ key = tag.get('key', None)
+ if key is None:
+ raise exception.EC2APIError(_('Expecting key to be set'))
+
+ self.compute_api.delete_instance_metadata(context,
+ instance, key)
+
+ return True
+
+ def describe_tags(self, context, **kwargs):
+ """List tags
+
+ Returns a dict with a single key 'tagSet' on success, error on failure.
+
+ :param context: context under which the method is called
+ """
+ filters = kwargs.get('filter', None)
+
+ search_filts = []
+ if filters:
+ for filter_block in filters:
+ key_name = filter_block.get('name', None)
+ val = filter_block.get('value', None)
+ if val:
+ if isinstance(val, dict):
+ val = val.values()
+ if not isinstance(val, (tuple, list, set)):
+ val = (val,)
+ if key_name:
+ search_block = {}
+ if key_name == 'resource_id':
+ search_block['resource_id'] = []
+ for res_id in val:
+ search_block['resource_id'].append(
+ ec2utils.ec2_inst_id_to_uuid(context, res_id))
+ elif key_name in ['key', 'value']:
+ search_block[key_name] = val
+ elif key_name == 'resource_type':
+ for res_type in val:
+ if res_type != 'instance':
+ raise exception.EC2APIError(_
+ ('Only instances implemented'))
+ search_block[key_name] = 'instance'
+ if len(search_block.keys()) > 0:
+ search_filts.append(search_block)
+ ts = []
+ for tag in self.compute_api.get_all_instance_metadata(context,
+ search_filts):
+ ts.append({
+ 'resource_id': ec2utils.id_to_ec2_inst_id(tag['instance_id']),
+ 'resource_type': 'instance',
+ 'key': tag['key'],
+ 'value': tag['value']
+ })
+ return {"tagSet": ts}
+
class EC2SecurityGroupExceptions(object):
@staticmethod
diff --git a/nova/api/ec2/ec2utils.py b/nova/api/ec2/ec2utils.py
index 311d0baf1..660c0e8d4 100644
--- a/nova/api/ec2/ec2utils.py
+++ b/nova/api/ec2/ec2utils.py
@@ -72,6 +72,31 @@ def image_type(image_type):
return image_type
+def resource_type_from_id(context, resource_id):
+ """Get resource type by ID
+
+ Returns a string representation of the Amazon resource type, if known.
+ Returns None on failure.
+
+ :param context: context under which the method is called
+ :param resource_id: resource_id to evaluate
+ """
+
+ known_types = {
+ 'i': 'instance',
+ 'r': 'reservation',
+ 'vol': 'volume',
+ 'snap': 'snapshot',
+ 'ami': 'image',
+ 'aki': 'image',
+ 'ari': 'image'
+ }
+
+ type_marker = resource_id.split('-')[0]
+
+ return known_types.get(type_marker)
+
+
@memoize
def id_to_glance_id(context, image_id):
"""Convert an internal (db) id to a glance id."""