~ubuntu-branches/ubuntu/saucy/nova/saucy-proposed

« back to all changes in this revision

Viewing changes to nova/api/ec2/cloud.py

  • Committer: Package Import Robot
  • Author(s): Chuck Short
  • Date: 2012-05-24 13:12:53 UTC
  • mfrom: (1.1.55)
  • Revision ID: package-import@ubuntu.com-20120524131253-ommql08fg1en06ut
Tags: 2012.2~f1-0ubuntu1
* New upstream release.
* Prepare for quantal:
  - Dropped debian/patches/upstream/0006-Use-project_id-in-ec2.cloud._format_image.patch
  - Dropped debian/patches/upstream/0005-Populate-image-properties-with-project_id-again.patch
  - Dropped debian/patches/upstream/0004-Fixed-bug-962840-added-a-test-case.patch
  - Dropped debian/patches/upstream/0003-Allow-unprivileged-RADOS-users-to-access-rbd-volumes.patch
  - Dropped debian/patches/upstream/0002-Stop-libvirt-test-from-deleting-instances-dir.patch
  - Dropped debian/patches/upstream/0001-fix-bug-where-nova-ignores-glance-host-in-imageref.patch 
  - Dropped debian/patches/0001-fix-useexisting-deprecation-warnings.patch
* debian/control: Add python-keystone as a dependency. (LP: #907197)
* debian/patches/kombu_tests_timeout.patch: Refreshed.
* debian/nova.conf, debian/nova-common.postinst: Convert to new ini
  file configuration
* debian/patches/nova-manage_flagfile_location.patch: Refreshed

Show diffs side-by-side

added added

removed removed

Lines of Context:
34
34
from nova import compute
35
35
from nova.compute import instance_types
36
36
from nova.compute import vm_states
37
 
from nova import crypto
38
37
from nova import db
39
38
from nova import exception
40
39
from nova import flags
41
40
from nova.image import s3
42
41
from nova import log as logging
43
42
from nova import network
44
 
from nova.rpc import common as rpc_common
 
43
from nova.openstack.common import importutils
45
44
from nova import quota
46
45
from nova import utils
47
46
from nova import volume
48
47
 
49
48
 
50
49
FLAGS = flags.FLAGS
51
 
flags.DECLARE('dhcp_domain', 'nova.network.manager')
52
50
 
53
51
LOG = logging.getLogger(__name__)
54
52
 
62
60
        raise exception.InvalidInstanceIDMalformed(val)
63
61
 
64
62
 
65
 
def _gen_key(context, user_id, key_name):
66
 
    """Generate a key
67
 
 
68
 
    This is a module level method because it is slow and we need to defer
69
 
    it into a process pool."""
70
 
    # NOTE(vish): generating key pair is slow so check for legal
71
 
    #             creation before creating key_pair
72
 
    try:
73
 
        db.key_pair_get(context, user_id, key_name)
74
 
        raise exception.KeyPairExists(key_name=key_name)
75
 
    except exception.NotFound:
76
 
        pass
77
 
    private_key, public_key, fingerprint = crypto.generate_key_pair()
78
 
    key = {}
79
 
    key['user_id'] = user_id
80
 
    key['name'] = key_name
81
 
    key['public_key'] = public_key
82
 
    key['fingerprint'] = fingerprint
83
 
    db.key_pair_create(context, key)
84
 
    return {'private_key': private_key, 'fingerprint': fingerprint}
85
 
 
86
 
 
87
63
# EC2 API can return the following values as documented in the EC2 API
88
64
# http://docs.amazonwebservices.com/AWSEC2/latest/APIReference/
89
65
#    ApiReference-ItemType-InstanceStateType.html
132
108
    if ebs:
133
109
        ec2_id = ebs.pop('snapshot_id', None)
134
110
        if ec2_id:
135
 
            id = ec2utils.ec2_id_to_id(ec2_id)
 
111
            id = ec2utils.ec2_vol_id_to_uuid(ec2_id)
136
112
            if ec2_id.startswith('snap-'):
137
113
                bdm['snapshot_id'] = id
138
114
            elif ec2_id.startswith('vol-'):
213
189
        self.volume_api = volume.API()
214
190
        self.compute_api = compute.API(network_api=self.network_api,
215
191
                                       volume_api=self.volume_api)
216
 
        self.sgh = utils.import_object(FLAGS.security_group_handler)
 
192
        self.keypair_api = compute.api.KeypairAPI()
 
193
        self.sgh = importutils.import_object(FLAGS.security_group_handler)
217
194
 
218
195
    def __str__(self):
219
196
        return 'CloudController'
311
288
        if snapshot_id:
312
289
            snapshots = []
313
290
            for ec2_id in snapshot_id:
314
 
                internal_id = ec2utils.ec2_id_to_id(ec2_id)
 
291
                internal_id = ec2utils.ec2_snap_id_to_uuid(ec2_id)
315
292
                snapshot = self.volume_api.get_snapshot(
316
293
                    context,
317
294
                    snapshot_id=internal_id)
337
314
        validate_ec2_id(volume_id)
338
315
        LOG.audit(_("Create snapshot of volume %s"), volume_id,
339
316
                  context=context)
340
 
        volume_id = ec2utils.ec2_id_to_id(volume_id)
 
317
        volume_id = ec2utils.ec2_vol_id_to_uuid(volume_id)
341
318
        volume = self.volume_api.get(context, volume_id)
342
319
        snapshot = self.volume_api.create_snapshot(
343
320
                context,
347
324
        return self._format_snapshot(context, snapshot)
348
325
 
349
326
    def delete_snapshot(self, context, snapshot_id, **kwargs):
350
 
        snapshot_id = ec2utils.ec2_id_to_id(snapshot_id)
 
327
        snapshot_id = ec2utils.ec2_snap_id_to_uuid(snapshot_id)
351
328
        snapshot = self.volume_api.get_snapshot(context, snapshot_id)
352
329
        self.volume_api.delete_snapshot(context, snapshot)
353
330
        return True
354
331
 
355
332
    def describe_key_pairs(self, context, key_name=None, **kwargs):
356
 
        key_pairs = db.key_pair_get_all_by_user(context, context.user_id)
 
333
        key_pairs = self.keypair_api.get_key_pairs(context, context.user_id)
357
334
        if not key_name is None:
358
335
            key_pairs = [x for x in key_pairs if x['name'] in key_name]
359
336
 
370
347
        return {'keySet': result}
371
348
 
372
349
    def create_key_pair(self, context, key_name, **kwargs):
373
 
        if not re.match('^[a-zA-Z0-9_\- ]+$', str(key_name)):
374
 
            err = _("Value (%s) for KeyName is invalid."
375
 
                    " Content limited to Alphanumeric character, "
376
 
                    "spaces, dashes, and underscore.") % key_name
377
 
            raise exception.EC2APIError(err)
378
 
 
379
 
        if len(str(key_name)) > 255:
380
 
            err = _("Value (%s) for Keyname is invalid."
381
 
                    " Length exceeds maximum of 255.") % key_name
382
 
            raise exception.EC2APIError(err)
383
 
 
384
350
        LOG.audit(_("Create key pair %s"), key_name, context=context)
385
 
        data = _gen_key(context, context.user_id, key_name)
 
351
 
 
352
        try:
 
353
            keypair = self.keypair_api.create_key_pair(context,
 
354
                                                       context.user_id,
 
355
                                                       key_name)
 
356
        except exception.KeypairLimitExceeded:
 
357
            msg = _("Quota exceeded, too many key pairs.")
 
358
            raise exception.EC2APIError(msg)
 
359
        except exception.InvalidKeypair:
 
360
            msg = _("Keypair data is invalid")
 
361
            raise exception.EC2APIError(msg)
 
362
        except exception.KeyPairExists:
 
363
            msg = _("Key pair '%s' already exists.") % key_name
 
364
            raise exception.KeyPairExists(msg)
386
365
        return {'keyName': key_name,
387
 
                'keyFingerprint': data['fingerprint'],
388
 
                'keyMaterial': data['private_key']}
 
366
                'keyFingerprint': keypair['fingerprint'],
 
367
                'keyMaterial': keypair['private_key']}
389
368
        # TODO(vish): when context is no longer an object, pass it here
390
369
 
391
370
    def import_key_pair(self, context, key_name, public_key_material,
392
371
                        **kwargs):
393
372
        LOG.audit(_("Import key %s"), key_name, context=context)
394
 
        try:
395
 
            db.key_pair_get(context, context.user_id, key_name)
396
 
            raise exception.KeyPairExists(key_name=key_name)
397
 
        except exception.NotFound:
398
 
            pass
 
373
 
399
374
        public_key = base64.b64decode(public_key_material)
400
 
        fingerprint = crypto.generate_fingerprint(public_key)
401
 
        key = {}
402
 
        key['user_id'] = context.user_id
403
 
        key['name'] = key_name
404
 
        key['public_key'] = public_key
405
 
        key['fingerprint'] = fingerprint
406
 
        db.key_pair_create(context, key)
 
375
 
 
376
        try:
 
377
            keypair = self.keypair_api.import_key_pair(context,
 
378
                                                       context.user_id,
 
379
                                                       key_name,
 
380
                                                       public_key)
 
381
        except exception.KeypairLimitExceeded:
 
382
            msg = _("Quota exceeded, too many key pairs.")
 
383
            raise exception.EC2APIError(msg)
 
384
        except exception.InvalidKeypair:
 
385
            msg = _("Keypair data is invalid")
 
386
            raise exception.EC2APIError(msg)
 
387
        except exception.KeyPairExists:
 
388
            msg = _("Key pair '%s' already exists.") % key_name
 
389
            raise exception.EC2APIError(msg)
 
390
 
407
391
        return {'keyName': key_name,
408
 
                'keyFingerprint': fingerprint}
 
392
                'keyFingerprint': keypair['fingerprint']}
409
393
 
410
394
    def delete_key_pair(self, context, key_name, **kwargs):
411
395
        LOG.audit(_("Delete key pair %s"), key_name, context=context)
412
396
        try:
413
 
            db.key_pair_destroy(context, context.user_id, key_name)
 
397
            self.keypair_api.delete_key_pair(context, context.user_id,
 
398
                                             key_name)
414
399
        except exception.NotFound:
415
400
            # aws returns true even if the key doesn't exist
416
401
            pass
854
839
            volumes = []
855
840
            for ec2_id in volume_id:
856
841
                validate_ec2_id(ec2_id)
857
 
                internal_id = ec2utils.ec2_id_to_id(ec2_id)
 
842
                internal_id = ec2utils.ec2_vol_id_to_uuid(ec2_id)
858
843
                volume = self.volume_api.get(context, internal_id)
859
844
                volumes.append(volume)
860
845
        else:
865
850
    def _format_volume(self, context, volume):
866
851
        instance_ec2_id = None
867
852
        instance_data = None
868
 
        if volume.get('instance', None):
869
 
            instance_id = volume['instance']['id']
 
853
 
 
854
        if volume.get('instance_uuid', None):
 
855
            instance_uuid = volume['instance_uuid']
 
856
            instance = db.instance_get_by_uuid(context.elevated(),
 
857
                    instance_uuid)
 
858
 
 
859
            instance_id = instance['id']
870
860
            instance_ec2_id = ec2utils.id_to_ec2_id(instance_id)
871
861
            instance_data = '%s[%s]' % (instance_ec2_id,
872
 
                                        volume['instance']['host'])
 
862
                                        instance['host'])
873
863
        v = {}
874
864
        v['volumeId'] = ec2utils.id_to_ec2_vol_id(volume['id'])
875
865
        v['status'] = volume['status']
902
892
    def create_volume(self, context, **kwargs):
903
893
        size = kwargs.get('size')
904
894
        if kwargs.get('snapshot_id') is not None:
905
 
            snapshot_id = ec2utils.ec2_id_to_id(kwargs['snapshot_id'])
 
895
            snapshot_id = ec2utils.ec2_snap_id_to_uuid(kwargs['snapshot_id'])
906
896
            snapshot = self.volume_api.get_snapshot(context, snapshot_id)
907
897
            LOG.audit(_("Create volume from snapshot %s"), snapshot_id,
908
898
                      context=context)
925
915
 
926
916
    def delete_volume(self, context, volume_id, **kwargs):
927
917
        validate_ec2_id(volume_id)
928
 
        volume_id = ec2utils.ec2_id_to_id(volume_id)
 
918
        volume_id = ec2utils.ec2_vol_id_to_uuid(volume_id)
929
919
 
930
920
        try:
931
921
            volume = self.volume_api.get(context, volume_id)
938
928
    def attach_volume(self, context, volume_id, instance_id, device, **kwargs):
939
929
        validate_ec2_id(instance_id)
940
930
        validate_ec2_id(volume_id)
941
 
        volume_id = ec2utils.ec2_id_to_id(volume_id)
 
931
        volume_id = ec2utils.ec2_vol_id_to_uuid(volume_id)
942
932
        instance_id = ec2utils.ec2_id_to_id(instance_id)
943
933
        instance = self.compute_api.get(context, instance_id)
944
934
        msg = _("Attach volume %(volume_id)s to instance %(instance_id)s"
961
951
 
962
952
    def detach_volume(self, context, volume_id, **kwargs):
963
953
        validate_ec2_id(volume_id)
964
 
        volume_id = ec2utils.ec2_id_to_id(volume_id)
 
954
        volume_id = ec2utils.ec2_vol_id_to_uuid(volume_id)
965
955
        LOG.audit(_("Detach volume %s"), volume_id, context=context)
966
956
        volume = self.volume_api.get(context, volume_id)
967
957
 
1000
990
        def _format_attr_block_device_mapping(instance, result):
1001
991
            tmp = {}
1002
992
            self._format_instance_root_device_name(instance, tmp)
1003
 
            self._format_instance_bdm(context, instance_id,
 
993
            self._format_instance_bdm(context, instance['uuid'],
1004
994
                                      tmp['rootDeviceName'], result)
1005
995
 
1006
996
        def _format_attr_disable_api_termination(instance, result):
1100
1090
            instances_set.append(i)
1101
1091
        return {'instancesSet': instances_set}
1102
1092
 
1103
 
    def _format_instance_bdm(self, context, instance_id, root_device_name,
 
1093
    def _format_instance_bdm(self, context, instance_uuid, root_device_name,
1104
1094
                             result):
1105
1095
        """Format InstanceBlockDeviceMappingResponseItemType"""
1106
1096
        root_device_type = 'instance-store'
1107
1097
        mapping = []
1108
1098
        for bdm in db.block_device_mapping_get_all_by_instance(context,
1109
 
                                                               instance_id):
 
1099
                                                               instance_uuid):
1110
1100
            volume_id = bdm['volume_id']
1111
1101
            if (volume_id is None or bdm['no_device']):
1112
1102
                continue
1222
1212
            i['launchTime'] = instance['created_at']
1223
1213
            i['amiLaunchIndex'] = instance['launch_index']
1224
1214
            self._format_instance_root_device_name(instance, i)
1225
 
            self._format_instance_bdm(context, instance_id,
 
1215
            self._format_instance_bdm(context, instance['uuid'],
1226
1216
                                      i['rootDeviceName'], i)
1227
1217
            host = instance['host']
1228
1218
            services = db.service_get_all_by_host(context.elevated(), host)
1239
1229
 
1240
1230
        return list(reservations.values())
1241
1231
 
1242
 
    def describe_addresses(self, context, **kwargs):
1243
 
        return self.format_addresses(context)
1244
 
 
1245
 
    def format_addresses(self, context):
1246
 
        addresses = []
1247
 
        floaters = self.network_api.get_floating_ips_by_project(context)
1248
 
        for floating_ip_ref in floaters:
1249
 
            if floating_ip_ref['project_id'] is None:
1250
 
                continue
1251
 
            address = floating_ip_ref['address']
1252
 
            ec2_id = None
1253
 
            if floating_ip_ref['fixed_ip_id']:
1254
 
                fixed_id = floating_ip_ref['fixed_ip_id']
1255
 
                fixed = self.network_api.get_fixed_ip(context, fixed_id)
1256
 
                if fixed['instance_id'] is not None:
1257
 
                    ec2_id = ec2utils.id_to_ec2_id(fixed['instance_id'])
1258
 
            address_rv = {'public_ip': address,
1259
 
                          'instance_id': ec2_id}
1260
 
            if context.is_admin:
1261
 
                details = "%s (%s)" % (address_rv['instance_id'],
1262
 
                                       floating_ip_ref['project_id'])
1263
 
                address_rv['instance_id'] = details
1264
 
            addresses.append(address_rv)
 
1232
    def describe_addresses(self, context, public_ip=None, **kwargs):
 
1233
        if public_ip:
 
1234
            floatings = []
 
1235
            for address in public_ip:
 
1236
                floating = self.network_api.get_floating_ip_by_address(context,
 
1237
                                                                       address)
 
1238
                floatings.append(floating)
 
1239
        else:
 
1240
            floatings = self.network_api.get_floating_ips_by_project(context)
 
1241
        addresses = [self._format_address(context, f) for f in floatings]
1265
1242
        return {'addressesSet': addresses}
1266
1243
 
 
1244
    def _format_address(self, context, floating_ip):
 
1245
        ec2_id = None
 
1246
        if floating_ip['fixed_ip_id']:
 
1247
            fixed_id = floating_ip['fixed_ip_id']
 
1248
            fixed = self.network_api.get_fixed_ip(context, fixed_id)
 
1249
            if fixed['instance_id'] is not None:
 
1250
                ec2_id = ec2utils.id_to_ec2_id(fixed['instance_id'])
 
1251
        address = {'public_ip': floating_ip['address'],
 
1252
                   'instance_id': ec2_id}
 
1253
        if context.is_admin:
 
1254
            details = "%s (%s)" % (address['instance_id'],
 
1255
                                   floating_ip['project_id'])
 
1256
            address['instance_id'] = details
 
1257
        return address
 
1258
 
1267
1259
    def allocate_address(self, context, **kwargs):
1268
1260
        LOG.audit(_("Allocate address"), context=context)
1269
 
        try:
1270
 
            public_ip = self.network_api.allocate_floating_ip(context)
1271
 
            return {'publicIp': public_ip}
1272
 
        except rpc_common.RemoteError as ex:
1273
 
            # NOTE(tr3buchet) - why does this block exist?
1274
 
            if ex.exc_type == 'NoMoreFloatingIps':
1275
 
                raise exception.NoMoreFloatingIps()
1276
 
            else:
1277
 
                raise
 
1261
        public_ip = self.network_api.allocate_floating_ip(context)
 
1262
        return {'publicIp': public_ip}
1278
1263
 
1279
1264
    def release_address(self, context, public_ip, **kwargs):
1280
1265
        LOG.audit(_("Release address %s"), public_ip, context=context)
1281
 
        self.network_api.release_floating_ip(context, address=public_ip)
1282
 
        return {'return': "true"}
 
1266
        try:
 
1267
            self.network_api.release_floating_ip(context, address=public_ip)
 
1268
            return {'return': "true"}
 
1269
        except exception.FloatingIpNotFound:
 
1270
            raise exception.EC2APIError(_('Unable to release IP Address.'))
1283
1271
 
1284
1272
    def associate_address(self, context, instance_id, public_ip, **kwargs):
1285
1273
        LOG.audit(_("Associate address %(public_ip)s to"
1286
1274
                " instance %(instance_id)s") % locals(), context=context)
1287
1275
        instance_id = ec2utils.ec2_id_to_id(instance_id)
1288
1276
        instance = self.compute_api.get(context, instance_id)
1289
 
        self.compute_api.associate_floating_ip(context,
1290
 
                                               instance,
1291
 
                                               address=public_ip)
1292
 
        return {'return': "true"}
 
1277
        try:
 
1278
            self.compute_api.associate_floating_ip(context,
 
1279
                                                   instance,
 
1280
                                                   address=public_ip)
 
1281
            return {'return': "true"}
 
1282
        except exception.FloatingIpNotFound:
 
1283
            raise exception.EC2APIError(_('Unable to associate IP Address.'))
1293
1284
 
1294
1285
    def disassociate_address(self, context, public_ip, **kwargs):
1295
1286
        LOG.audit(_("Disassociate address %s"), public_ip, context=context)
1410
1401
        ramdisk_id = image['properties'].get('ramdisk_id')
1411
1402
        if ramdisk_id:
1412
1403
            i['ramdiskId'] = ec2utils.image_ec2_id(ramdisk_id, 'ari')
1413
 
 
1414
 
        if FLAGS.auth_strategy == 'deprecated':
1415
 
            i['imageOwnerId'] = image['properties'].get('project_id')
1416
 
        else:
1417
 
            i['imageOwnerId'] = image.get('owner')
 
1404
        i['imageOwnerId'] = image.get('owner')
1418
1405
 
1419
1406
        img_loc = image['properties'].get('image_location')
1420
1407
        if img_loc:
1614
1601
                # NOTE(yamahata): timeout and error. 1 hour for now for safety.
1615
1602
                #                 Is it too short/long?
1616
1603
                #                 Or is there any better way?
1617
 
                timeout = 1 * 60 * 60 * 60
 
1604
                timeout = 1 * 60 * 60
1618
1605
                if time.time() > start_time + timeout:
1619
1606
                    raise exception.EC2APIError(
1620
1607
                        _('Couldn\'t stop instance with in %d sec') % timeout)