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
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'])
83
LOG.warning(_(msg), instance_id)
78
vm_state = instance["vm_state"]
79
task_state = instance["task_state"]
81
valid_shutdown_states = [
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())
237
243
self.ensure_default_security_group(context)
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']
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 '',
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
380
instance = dict(launch_index=num, **base_options)
381
instance = self.db.instance_create(context, instance)
382
instance_id = instance['id']
384
386
elevated = context.elevated()
385
387
if security_group is None:
386
388
security_group = ['default']
390
392
security_groups = []
391
393
for security_group_name in security_group:
392
group = db.security_group_get_by_name(context,
394
group = self.db.security_group_get_by_name(context,
395
397
security_groups.append(group['id'])
399
instance = dict(launch_index=num, **base_options)
400
instance = self.db.instance_create(context, instance)
401
instance_id = instance['id']
397
403
for security_group_id in security_groups:
398
404
self.db.instance_add_security_group(elevated,
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
419
427
instance = self.update(context, instance_id, **updates)
551
559
def has_finished_migration(self, context, instance_uuid):
552
560
"""Returns true if an instance has a finished migration."""
554
db.migration_get_by_instance_and_status(context, instance_uuid,
562
self.db.migration_get_by_instance_and_status(context,
557
566
except exception.NotFound:
566
575
:param context: the security context
569
db.security_group_get_by_name(context, context.project_id,
578
self.db.security_group_get_by_name(context,
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)
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"""
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),
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,
679
security_group = self.db.security_group_get_by_name(context,
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,
682
692
if inst['state'] != power_state.RUNNING:
683
693
raise exception.InstanceNotRunning(instance_id=instance_id)
685
db.instance_add_security_group(context.elevated(),
687
security_group['id'])
695
self.db.instance_add_security_group(context.elevated(),
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']}})
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,
705
security_group = self.db.security_group_get_by_name(context,
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,
708
718
if inst['state'] != power_state.RUNNING:
709
719
raise exception.InstanceNotRunning(instance_id=instance_id)
711
db.instance_remove_security_group(context.elevated(),
713
security_group['id'])
721
self.db.instance_remove_security_group(context.elevated(),
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']}})
775
783
self.update(context,
777
state_description='stopping',
778
state=power_state.NOSTATE,
785
vm_state=vm_states.ACTIVE,
786
task_state=task_states.STOPPING,
779
787
terminated_at=utils.utcnow())
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"]
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())
807
vm_state=vm_states.STOPPED,
808
task_state=task_states.STARTING)
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}})
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,
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)
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
1001
1025
:param extra_properties: dict of extra image properties to include
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
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,
1049
vm_state=vm_states.ACTIVE,
1050
task_state=task_states.REBOOTING)
1051
self._cast_compute_message('reboot_instance', context, instance_id,
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"]
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)
1035
1065
files_to_inject = files_to_inject or []
1066
metadata = metadata or {}
1036
1068
self._check_injected_file_quota(context, files_to_inject)
1069
self._check_metadata_properties_quota(context, metadata)
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,
1075
image_ref=image_href,
1076
vm_state=vm_states.ACTIVE,
1077
task_state=task_states.REBUILDING)
1046
1079
rebuild_params = {
1047
1080
"new_pass": admin_password,
1065
1098
raise exception.MigrationNotFoundByStatus(instance_id=instance_id,
1066
1099
status='finished')
1101
self.update(context,
1103
vm_state=vm_states.ACTIVE,
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')
1127
self.update(context,
1129
vm_state=vm_states.ACTIVE,
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()
1177
self.update(context,
1179
vm_state=vm_states.RESIZING,
1180
task_state=task_states.RESIZE_PREP)
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,
1217
vm_state=vm_states.ACTIVE,
1218
task_state=task_states.PAUSING)
1166
1219
self._cast_compute_message('pause_instance', context, instance_id)
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,
1226
vm_state=vm_states.PAUSED,
1227
task_state=task_states.UNPAUSING)
1171
1228
self._cast_compute_message('unpause_instance', context, instance_id)
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,
1262
vm_state=vm_states.ACTIVE,
1263
task_state=task_states.SUSPENDING)
1203
1264
self._cast_compute_message('suspend_instance', context, instance_id)
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,
1271
vm_state=vm_states.SUSPENDED,
1272
task_state=task_states.RESUMING)
1208
1273
self._cast_compute_message('resume_instance', context, instance_id)
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,
1280
vm_state=vm_states.ACTIVE,
1281
task_state=task_states.RESCUING)
1213
1282
self._cast_compute_message('rescue_instance', context, instance_id)
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,
1289
vm_state=vm_states.RESCUED,
1290
task_state=task_states.UNRESCUING)
1218
1291
self._cast_compute_message('unrescue_instance', context, instance_id)
1220
1293
@scheduler_api.reroute_compute("set_admin_password")