~raxnetworking/nova/bare_bones_melange

« back to all changes in this revision

Viewing changes to nova/compute/api.py

  • Committer: Rajaram Mallya
  • Date: 2011-09-12 10:03:21 UTC
  • mfrom: (1265.2.287 nova)
  • Revision ID: rajarammallya@gmail.com-20110912100321-8zw8575a206dc026
Merged from nova trunk

Show diffs side-by-side

added added

removed removed

Lines of Context:
19
19
 
20
20
"""Handles all requests relating to instances (guest vms)."""
21
21
 
22
 
import eventlet
23
22
import novaclient
24
23
import re
25
24
import time
26
25
 
27
26
from nova import block_device
28
 
from nova import db
29
27
from nova import exception
30
28
from nova import flags
31
29
import nova.image
37
35
from nova import volume
38
36
from nova.compute import instance_types
39
37
from nova.compute import power_state
 
38
from nova.compute import task_states
 
39
from nova.compute import vm_states
40
40
from nova.compute.utils import terminate_volumes
41
41
from nova.scheduler import api as scheduler_api
42
42
from nova.db import base
75
75
 
76
76
 
77
77
def _is_able_to_shutdown(instance, instance_id):
78
 
    states = {'terminating': "Instance %s is already being terminated",
79
 
              'migrating': "Instance %s is being migrated",
80
 
              'stopping': "Instance %s is being stopped"}
81
 
    msg = states.get(instance['state_description'])
82
 
    if msg:
83
 
        LOG.warning(_(msg), instance_id)
 
78
    vm_state = instance["vm_state"]
 
79
    task_state = instance["task_state"]
 
80
 
 
81
    valid_shutdown_states = [
 
82
        vm_states.ACTIVE,
 
83
        vm_states.REBUILDING,
 
84
        vm_states.BUILDING,
 
85
    ]
 
86
 
 
87
    if vm_state not in valid_shutdown_states:
 
88
        LOG.warn(_("Instance %(instance_id)s is not in an 'active' state. It "
 
89
                   "is currently %(vm_state)s. Shutdown aborted.") % locals())
84
90
        return False
85
91
 
86
92
    return True
237
243
        self.ensure_default_security_group(context)
238
244
 
239
245
        if key_data is None and key_name:
240
 
            key_pair = db.key_pair_get(context, context.user_id, key_name)
 
246
            key_pair = self.db.key_pair_get(context, context.user_id, key_name)
241
247
            key_data = key_pair['public_key']
242
248
 
243
249
        if reservation_id is None:
251
257
            'image_ref': image_href,
252
258
            'kernel_id': kernel_id or '',
253
259
            'ramdisk_id': ramdisk_id or '',
 
260
            'power_state': power_state.NOSTATE,
 
261
            'vm_state': vm_states.BUILDING,
254
262
            'config_drive_id': config_drive_id or '',
255
263
            'config_drive': config_drive or '',
256
 
            'state': 0,
257
 
            'state_description': 'scheduling',
258
264
            'user_id': context.user_id,
259
265
            'project_id': context.project_id,
260
266
            'launch_time': time.strftime('%Y-%m-%dT%H:%M:%SZ', time.gmtime()),
377
383
        If you are changing this method, be sure to update both
378
384
        call paths.
379
385
        """
380
 
        instance = dict(launch_index=num, **base_options)
381
 
        instance = self.db.instance_create(context, instance)
382
 
        instance_id = instance['id']
383
 
 
384
386
        elevated = context.elevated()
385
387
        if security_group is None:
386
388
            security_group = ['default']
389
391
 
390
392
        security_groups = []
391
393
        for security_group_name in security_group:
392
 
            group = db.security_group_get_by_name(context,
393
 
                                                  context.project_id,
394
 
                                                  security_group_name)
 
394
            group = self.db.security_group_get_by_name(context,
 
395
                    context.project_id,
 
396
                    security_group_name)
395
397
            security_groups.append(group['id'])
396
398
 
 
399
        instance = dict(launch_index=num, **base_options)
 
400
        instance = self.db.instance_create(context, instance)
 
401
        instance_id = instance['id']
 
402
 
397
403
        for security_group_id in security_groups:
398
404
            self.db.instance_add_security_group(elevated,
399
405
                                                instance_id,
415
421
            updates['display_name'] = "Server %s" % instance_id
416
422
            instance['display_name'] = updates['display_name']
417
423
        updates['hostname'] = self.hostname_factory(instance)
 
424
        updates['vm_state'] = vm_states.BUILDING
 
425
        updates['task_state'] = task_states.SCHEDULING
418
426
 
419
427
        instance = self.update(context, instance_id, **updates)
420
428
        return instance
551
559
    def has_finished_migration(self, context, instance_uuid):
552
560
        """Returns true if an instance has a finished migration."""
553
561
        try:
554
 
            db.migration_get_by_instance_and_status(context, instance_uuid,
555
 
                    'finished')
 
562
            self.db.migration_get_by_instance_and_status(context,
 
563
                                                         instance_uuid,
 
564
                                                         'finished')
556
565
            return True
557
566
        except exception.NotFound:
558
567
            return False
566
575
        :param context: the security context
567
576
        """
568
577
        try:
569
 
            db.security_group_get_by_name(context, context.project_id,
570
 
                                          'default')
 
578
            self.db.security_group_get_by_name(context,
 
579
                                               context.project_id,
 
580
                                               'default')
571
581
        except exception.NotFound:
572
582
            values = {'name': 'default',
573
583
                      'description': 'default',
574
584
                      'user_id': context.user_id,
575
585
                      'project_id': context.project_id}
576
 
            db.security_group_create(context, values)
 
586
            self.db.security_group_create(context, values)
577
587
 
578
588
    def trigger_security_group_rules_refresh(self, context, security_group_id):
579
589
        """Called when a rule is added to or removed from a security_group."""
638
648
        """Called when a rule is added to or removed from a security_group"""
639
649
 
640
650
        hosts = [x['host'] for (x, idx)
641
 
                           in db.service_get_all_compute_sorted(context)]
 
651
                           in self.db.service_get_all_compute_sorted(context)]
642
652
        for host in hosts:
643
653
            rpc.cast(context,
644
654
                     self.db.queue_get_for(context, FLAGS.compute_topic, host),
666
676
 
667
677
    def add_security_group(self, context, instance_id, security_group_name):
668
678
        """Add security group to the instance"""
669
 
        security_group = db.security_group_get_by_name(context,
670
 
                                                       context.project_id,
671
 
                                                       security_group_name)
 
679
        security_group = self.db.security_group_get_by_name(context,
 
680
                context.project_id,
 
681
                security_group_name)
672
682
        # check if the server exists
673
 
        inst = db.instance_get(context, instance_id)
 
683
        inst = self.db.instance_get(context, instance_id)
674
684
        #check if the security group is associated with the server
675
685
        if self._is_security_group_associated_with_server(security_group,
676
686
                                                        instance_id):
682
692
        if inst['state'] != power_state.RUNNING:
683
693
            raise exception.InstanceNotRunning(instance_id=instance_id)
684
694
 
685
 
        db.instance_add_security_group(context.elevated(),
686
 
                                       instance_id,
687
 
                                       security_group['id'])
 
695
        self.db.instance_add_security_group(context.elevated(),
 
696
                                            instance_id,
 
697
                                            security_group['id'])
688
698
        rpc.cast(context,
689
 
             db.queue_get_for(context, FLAGS.compute_topic, inst['host']),
 
699
             self.db.queue_get_for(context, FLAGS.compute_topic, inst['host']),
690
700
             {"method": "refresh_security_group_rules",
691
701
              "args": {"security_group_id": security_group['id']}})
692
702
 
693
703
    def remove_security_group(self, context, instance_id, security_group_name):
694
704
        """Remove the security group associated with the instance"""
695
 
        security_group = db.security_group_get_by_name(context,
696
 
                                                       context.project_id,
697
 
                                                       security_group_name)
 
705
        security_group = self.db.security_group_get_by_name(context,
 
706
                context.project_id,
 
707
                security_group_name)
698
708
        # check if the server exists
699
 
        inst = db.instance_get(context, instance_id)
 
709
        inst = self.db.instance_get(context, instance_id)
700
710
        #check if the security group is associated with the server
701
711
        if not self._is_security_group_associated_with_server(security_group,
702
712
                                                        instance_id):
708
718
        if inst['state'] != power_state.RUNNING:
709
719
            raise exception.InstanceNotRunning(instance_id=instance_id)
710
720
 
711
 
        db.instance_remove_security_group(context.elevated(),
712
 
                                       instance_id,
713
 
                                       security_group['id'])
 
721
        self.db.instance_remove_security_group(context.elevated(),
 
722
                                               instance_id,
 
723
                                               security_group['id'])
714
724
        rpc.cast(context,
715
 
             db.queue_get_for(context, FLAGS.compute_topic, inst['host']),
 
725
             self.db.queue_get_for(context, FLAGS.compute_topic, inst['host']),
716
726
             {"method": "refresh_security_group_rules",
717
727
              "args": {"security_group_id": security_group['id']}})
718
728
 
750
760
            return
751
761
 
752
762
        self.update(context,
753
 
                    instance['id'],
754
 
                    state_description='terminating',
755
 
                    state=0,
756
 
                    terminated_at=utils.utcnow())
 
763
                    instance_id,
 
764
                    task_state=task_states.DELETING)
757
765
 
758
766
        host = instance['host']
759
767
        if host:
773
781
            return
774
782
 
775
783
        self.update(context,
776
 
                    instance['id'],
777
 
                    state_description='stopping',
778
 
                    state=power_state.NOSTATE,
 
784
                    instance_id,
 
785
                    vm_state=vm_states.ACTIVE,
 
786
                    task_state=task_states.STOPPING,
779
787
                    terminated_at=utils.utcnow())
780
788
 
781
789
        host = instance['host']
787
795
        """Start an instance."""
788
796
        LOG.debug(_("Going to try to start %s"), instance_id)
789
797
        instance = self._get_instance(context, instance_id, 'starting')
790
 
        if instance['state_description'] != 'stopped':
791
 
            _state_description = instance['state_description']
 
798
        vm_state = instance["vm_state"]
 
799
 
 
800
        if vm_state != vm_states.STOPPED:
792
801
            LOG.warning(_("Instance %(instance_id)s is not "
793
 
                          "stopped(%(_state_description)s)") % locals())
 
802
                          "stopped. (%(vm_state)s)") % locals())
794
803
            return
795
804
 
 
805
        self.update(context,
 
806
                    instance_id,
 
807
                    vm_state=vm_states.STOPPED,
 
808
                    task_state=task_states.STARTING)
 
809
 
796
810
        # TODO(yamahata): injected_files isn't supported right now.
797
811
        #                 It is used only for osapi. not for ec2 api.
798
812
        #                 availability_zone isn't used by run_instance.
802
816
                  "args": {"topic": FLAGS.compute_topic,
803
817
                           "instance_id": instance_id}})
804
818
 
 
819
    def get_active_by_window(self, context, begin, end=None, project_id=None):
 
820
        """Get instances that were continuously active over a window."""
 
821
        return self.db.instance_get_active_by_window(context, begin, end,
 
822
                                                     project_id)
 
823
 
 
824
    def get_instance_type(self, context, instance_type_id):
 
825
        """Get an instance type by instance type id."""
 
826
        return self.db.instance_type_get(context, instance_type_id)
 
827
 
805
828
    def get(self, context, instance_id):
806
829
        """Get a single instance with the given instance_id."""
807
830
        # NOTE(sirp): id used to be exclusively integer IDs; now we're
854
877
                'image': 'image_ref',
855
878
                'name': 'display_name',
856
879
                'instance_name': 'name',
 
880
                'tenant_id': 'project_id',
857
881
                'recurse_zones': None,
858
882
                'flavor': _remap_flavor_filter,
859
883
                'fixed_ip': _remap_fixed_ip_filter}
1001
1025
        :param extra_properties: dict of extra image properties to include
1002
1026
 
1003
1027
        """
1004
 
        instance = db.api.instance_get(context, instance_id)
 
1028
        instance = self.db.instance_get(context, instance_id)
1005
1029
        properties = {'instance_uuid': instance['uuid'],
1006
1030
                      'user_id': str(context.user_id),
1007
1031
                      'image_state': 'creating',
1018
1042
        return recv_meta
1019
1043
 
1020
1044
    @scheduler_api.reroute_compute("reboot")
1021
 
    def reboot(self, context, instance_id):
 
1045
    def reboot(self, context, instance_id, reboot_type):
1022
1046
        """Reboot the given instance."""
1023
 
        self._cast_compute_message('reboot_instance', context, instance_id)
 
1047
        self.update(context,
 
1048
                    instance_id,
 
1049
                    vm_state=vm_states.ACTIVE,
 
1050
                    task_state=task_states.REBOOTING)
 
1051
        self._cast_compute_message('reboot_instance', context, instance_id,
 
1052
                reboot_type)
1024
1053
 
1025
1054
    @scheduler_api.reroute_compute("rebuild")
1026
1055
    def rebuild(self, context, instance_id, image_href, admin_password,
1027
1056
                name=None, metadata=None, files_to_inject=None):
1028
1057
        """Rebuild the given instance with the provided metadata."""
1029
 
        instance = db.api.instance_get(context, instance_id)
 
1058
        instance = self.db.instance_get(context, instance_id)
 
1059
        name = name or instance["display_name"]
1030
1060
 
1031
 
        if instance["state"] == power_state.BUILDING:
1032
 
            msg = _("Instance already building")
1033
 
            raise exception.BuildInProgress(msg)
 
1061
        if instance["vm_state"] != vm_states.ACTIVE:
 
1062
            msg = _("Instance must be active to rebuild.")
 
1063
            raise exception.RebuildRequiresActiveInstance(msg)
1034
1064
 
1035
1065
        files_to_inject = files_to_inject or []
 
1066
        metadata = metadata or {}
 
1067
 
1036
1068
        self._check_injected_file_quota(context, files_to_inject)
 
1069
        self._check_metadata_properties_quota(context, metadata)
1037
1070
 
1038
 
        values = {"image_ref": image_href}
1039
 
        if metadata is not None:
1040
 
            self._check_metadata_properties_quota(context, metadata)
1041
 
            values['metadata'] = metadata
1042
 
        if name is not None:
1043
 
            values['display_name'] = name
1044
 
        self.db.instance_update(context, instance_id, values)
 
1071
        self.update(context,
 
1072
                    instance_id,
 
1073
                    metadata=metadata,
 
1074
                    display_name=name,
 
1075
                    image_ref=image_href,
 
1076
                    vm_state=vm_states.ACTIVE,
 
1077
                    task_state=task_states.REBUILDING)
1045
1078
 
1046
1079
        rebuild_params = {
1047
1080
            "new_pass": admin_password,
1065
1098
            raise exception.MigrationNotFoundByStatus(instance_id=instance_id,
1066
1099
                                                      status='finished')
1067
1100
 
 
1101
        self.update(context,
 
1102
                    instance_id,
 
1103
                    vm_state=vm_states.ACTIVE,
 
1104
                    task_state=None)
 
1105
 
1068
1106
        params = {'migration_id': migration_ref['id']}
1069
1107
        self._cast_compute_message('revert_resize', context,
1070
1108
                                   instance_ref['uuid'],
1085
1123
        if not migration_ref:
1086
1124
            raise exception.MigrationNotFoundByStatus(instance_id=instance_id,
1087
1125
                                                      status='finished')
 
1126
 
 
1127
        self.update(context,
 
1128
                    instance_id,
 
1129
                    vm_state=vm_states.ACTIVE,
 
1130
                    task_state=None)
 
1131
 
1088
1132
        params = {'migration_id': migration_ref['id']}
1089
1133
        self._cast_compute_message('confirm_resize', context,
1090
1134
                                   instance_ref['uuid'],
1130
1174
        if (current_memory_mb == new_memory_mb) and flavor_id:
1131
1175
            raise exception.CannotResizeToSameSize()
1132
1176
 
 
1177
        self.update(context,
 
1178
                    instance_id,
 
1179
                    vm_state=vm_states.RESIZING,
 
1180
                    task_state=task_states.RESIZE_PREP)
 
1181
 
1133
1182
        instance_ref = self._get_instance(context, instance_id, 'resize')
1134
1183
        self._cast_scheduler_message(context,
1135
1184
                    {"method": "prep_resize",
1163
1212
    @scheduler_api.reroute_compute("pause")
1164
1213
    def pause(self, context, instance_id):
1165
1214
        """Pause the given instance."""
 
1215
        self.update(context,
 
1216
                    instance_id,
 
1217
                    vm_state=vm_states.ACTIVE,
 
1218
                    task_state=task_states.PAUSING)
1166
1219
        self._cast_compute_message('pause_instance', context, instance_id)
1167
1220
 
1168
1221
    @scheduler_api.reroute_compute("unpause")
1169
1222
    def unpause(self, context, instance_id):
1170
1223
        """Unpause the given instance."""
 
1224
        self.update(context,
 
1225
                    instance_id,
 
1226
                    vm_state=vm_states.PAUSED,
 
1227
                    task_state=task_states.UNPAUSING)
1171
1228
        self._cast_compute_message('unpause_instance', context, instance_id)
1172
1229
 
1173
1230
    def _call_compute_message_for_host(self, action, context, host, params):
1200
1257
    @scheduler_api.reroute_compute("suspend")
1201
1258
    def suspend(self, context, instance_id):
1202
1259
        """Suspend the given instance."""
 
1260
        self.update(context,
 
1261
                    instance_id,
 
1262
                    vm_state=vm_states.ACTIVE,
 
1263
                    task_state=task_states.SUSPENDING)
1203
1264
        self._cast_compute_message('suspend_instance', context, instance_id)
1204
1265
 
1205
1266
    @scheduler_api.reroute_compute("resume")
1206
1267
    def resume(self, context, instance_id):
1207
1268
        """Resume the given instance."""
 
1269
        self.update(context,
 
1270
                    instance_id,
 
1271
                    vm_state=vm_states.SUSPENDED,
 
1272
                    task_state=task_states.RESUMING)
1208
1273
        self._cast_compute_message('resume_instance', context, instance_id)
1209
1274
 
1210
1275
    @scheduler_api.reroute_compute("rescue")
1211
1276
    def rescue(self, context, instance_id):
1212
1277
        """Rescue the given instance."""
 
1278
        self.update(context,
 
1279
                    instance_id,
 
1280
                    vm_state=vm_states.ACTIVE,
 
1281
                    task_state=task_states.RESCUING)
1213
1282
        self._cast_compute_message('rescue_instance', context, instance_id)
1214
1283
 
1215
1284
    @scheduler_api.reroute_compute("unrescue")
1216
1285
    def unrescue(self, context, instance_id):
1217
1286
        """Unrescue the given instance."""
 
1287
        self.update(context,
 
1288
                    instance_id,
 
1289
                    vm_state=vm_states.RESCUED,
 
1290
                    task_state=task_states.UNRESCUING)
1218
1291
        self._cast_compute_message('unrescue_instance', context, instance_id)
1219
1292
 
1220
1293
    @scheduler_api.reroute_compute("set_admin_password")