78
131
state = power_state.NOSTATE
79
132
self.db.instance_set_state(context, instance_id, state)
81
@defer.inlineCallbacks
82
@exception.wrap_exception
83
def refresh_security_group(self, context, security_group_id, **_kwargs):
84
"""This call passes stright through to the virtualization driver."""
85
yield self.driver.refresh_security_group(security_group_id)
87
@defer.inlineCallbacks
134
def get_console_topic(self, context, **_kwargs):
135
"""Retrieves the console host for a project on this host
136
Currently this is just set in the flags for each compute
138
#TODO(mdragon): perhaps make this variable by console_type?
139
return self.db.queue_get_for(context,
143
def get_network_topic(self, context, **_kwargs):
144
"""Retrieves the network host for a project on this host"""
145
# TODO(vish): This method should be memoized. This will make
146
# the call to get_network_host cheaper, so that
147
# it can pas messages instead of checking the db
149
if FLAGS.stub_network:
150
host = FLAGS.network_host
152
host = self.network_manager.get_network_host(context)
153
return self.db.queue_get_for(context,
157
def get_console_pool_info(self, context, console_type):
158
return self.driver.get_console_pool_info(console_type)
160
@exception.wrap_exception
161
def refresh_security_group_rules(self, context,
162
security_group_id, **_kwargs):
163
"""This call passes straight through to the virtualization driver."""
164
return self.driver.refresh_security_group_rules(security_group_id)
166
@exception.wrap_exception
167
def refresh_security_group_members(self, context,
168
security_group_id, **_kwargs):
169
"""This call passes straight through to the virtualization driver."""
170
return self.driver.refresh_security_group_members(security_group_id)
88
172
@exception.wrap_exception
89
173
def run_instance(self, context, instance_id, **_kwargs):
90
174
"""Launch a new instance with specified options."""
91
175
context = context.elevated()
92
176
instance_ref = self.db.instance_get(context, instance_id)
93
177
if instance_ref['name'] in self.driver.list_instances():
94
raise exception.Error("Instance has already been created")
95
logging.debug("instance %s: starting...", instance_id)
96
self.network_manager.setup_compute_network(context, instance_id)
178
raise exception.Error(_("Instance has already been created"))
179
LOG.audit(_("instance %s: starting..."), instance_id,
97
181
self.db.instance_update(context,
99
183
{'host': self.host})
185
self.db.instance_set_state(context,
190
is_vpn = instance_ref['image_id'] == FLAGS.vpn_image_id
191
# NOTE(vish): This could be a cast because we don't do anything
192
# with the address currently, but I'm leaving it as
193
# a call to ensure that network setup completes. We
194
# will eventually also need to save the address here.
195
if not FLAGS.stub_network:
196
address = rpc.call(context,
197
self.get_network_topic(context),
198
{"method": "allocate_fixed_ip",
199
"args": {"instance_id": instance_id,
202
self.network_manager.setup_compute_network(context,
101
205
# TODO(vish) check to make sure the availability zone matches
102
206
self.db.instance_set_state(context,
108
yield self.driver.spawn(instance_ref)
212
self.driver.spawn(instance_ref)
109
213
now = datetime.datetime.utcnow()
110
214
self.db.instance_update(context,
112
216
{'launched_at': now})
113
217
except Exception: # pylint: disable-msg=W0702
114
logging.exception("instance %s: Failed to spawn",
115
instance_ref['name'])
218
LOG.exception(_("instance %s: Failed to spawn"), instance_id,
116
220
self.db.instance_set_state(context,
118
222
power_state.SHUTDOWN)
120
224
self._update_state(context, instance_id)
122
@defer.inlineCallbacks
123
226
@exception.wrap_exception
227
@checks_instance_lock
124
228
def terminate_instance(self, context, instance_id):
125
229
"""Terminate an instance on this machine."""
126
230
context = context.elevated()
127
logging.debug("instance %s: terminating", instance_id)
129
231
instance_ref = self.db.instance_get(context, instance_id)
232
LOG.audit(_("Terminating instance %s"), instance_id, context=context)
234
if not FLAGS.stub_network:
235
address = self.db.instance_get_floating_address(context,
238
LOG.debug(_("Disassociating address %s"), address,
240
# NOTE(vish): Right now we don't really care if the ip is
241
# disassociated. We may need to worry about
242
# checking this later.
244
self.get_network_topic(context),
245
{"method": "disassociate_floating_ip",
246
"args": {"floating_address": address}})
248
address = self.db.instance_get_fixed_address(context,
251
LOG.debug(_("Deallocating address %s"), address,
253
# NOTE(vish): Currently, nothing needs to be done on the
254
# network node until release. If this changes,
255
# we will need to cast here.
256
self.network_manager.deallocate_fixed_ip(context.elevated(),
130
259
volumes = instance_ref.get('volumes', []) or []
131
260
for volume in volumes:
132
261
self.detach_volume(context, instance_id, volume['id'])
133
262
if instance_ref['state'] == power_state.SHUTOFF:
134
263
self.db.instance_destroy(context, instance_id)
135
raise exception.Error('trying to destroy already destroyed'
136
' instance: %s' % instance_id)
137
yield self.driver.destroy(instance_ref)
264
raise exception.Error(_('trying to destroy already destroyed'
265
' instance: %s') % instance_id)
266
self.driver.destroy(instance_ref)
139
268
# TODO(ja): should we keep it in a terminated state for a bit?
140
269
self.db.instance_destroy(context, instance_id)
142
@defer.inlineCallbacks
143
271
@exception.wrap_exception
272
@checks_instance_lock
144
273
def reboot_instance(self, context, instance_id):
145
274
"""Reboot an instance on this server."""
146
275
context = context.elevated()
276
self._update_state(context, instance_id)
147
277
instance_ref = self.db.instance_get(context, instance_id)
148
self._update_state(context, instance_id)
278
LOG.audit(_("Rebooting instance %s"), instance_id, context=context)
150
280
if instance_ref['state'] != power_state.RUNNING:
151
logging.warn('trying to reboot a non-running '
152
'instance: %s (state: %s excepted: %s)',
153
instance_ref['internal_id'],
154
instance_ref['state'],
281
LOG.warn(_('trying to reboot a non-running '
282
'instance: %s (state: %s excepted: %s)'),
284
instance_ref['state'],
157
logging.debug('instance %s: rebooting', instance_ref['name'])
158
288
self.db.instance_set_state(context,
160
290
power_state.NOSTATE,
162
yield self.driver.reboot(instance_ref)
163
self._update_state(context, instance_id)
165
@defer.inlineCallbacks
166
@exception.wrap_exception
292
self.network_manager.setup_compute_network(context, instance_id)
293
self.driver.reboot(instance_ref)
294
self._update_state(context, instance_id)
296
@exception.wrap_exception
297
def snapshot_instance(self, context, instance_id, image_id):
298
"""Snapshot an instance on this server."""
299
context = context.elevated()
300
instance_ref = self.db.instance_get(context, instance_id)
302
#NOTE(sirp): update_state currently only refreshes the state field
303
# if we add is_snapshotting, we will need this refreshed too,
305
self._update_state(context, instance_id)
307
LOG.audit(_('instance %s: snapshotting'), instance_id,
309
if instance_ref['state'] != power_state.RUNNING:
310
LOG.warn(_('trying to snapshot a non-running '
311
'instance: %s (state: %s excepted: %s)'),
312
instance_id, instance_ref['state'], power_state.RUNNING)
314
self.driver.snapshot(instance_ref, image_id)
316
@exception.wrap_exception
317
@checks_instance_lock
318
def set_admin_password(self, context, instance_id, new_pass=None):
319
"""Set the root/admin password for an instance on this server."""
320
context = context.elevated()
321
instance_ref = self.db.instance_get(context, instance_id)
322
if instance_ref['state'] != power_state.RUNNING:
323
logging.warn('trying to reset the password on a non-running '
324
'instance: %s (state: %s expected: %s)',
326
instance_ref['state'],
329
logging.debug('instance %s: setting admin password',
330
instance_ref['name'])
332
# Generate a random password
333
new_pass = self._generate_password(FLAGS.password_length)
335
self.driver.set_admin_password(instance_ref, new_pass)
336
self._update_state(context, instance_id)
338
def _generate_password(self, length=20):
339
"""Generate a random sequence of letters and digits
340
to be used as a password.
342
chrs = string.letters + string.digits
343
return "".join([random.choice(chrs) for i in xrange(length)])
345
@exception.wrap_exception
346
@checks_instance_lock
167
347
def rescue_instance(self, context, instance_id):
168
348
"""Rescue an instance on this server."""
169
349
context = context.elevated()
170
350
instance_ref = self.db.instance_get(context, instance_id)
172
logging.debug('instance %s: rescuing',
173
instance_ref['internal_id'])
351
LOG.audit(_('instance %s: rescuing'), instance_id, context=context)
174
352
self.db.instance_set_state(context,
176
354
power_state.NOSTATE,
178
yield self.driver.rescue(instance_ref)
356
self.network_manager.setup_compute_network(context, instance_id)
357
self.driver.rescue(instance_ref)
179
358
self._update_state(context, instance_id)
181
@defer.inlineCallbacks
182
360
@exception.wrap_exception
361
@checks_instance_lock
183
362
def unrescue_instance(self, context, instance_id):
184
363
"""Rescue an instance on this server."""
185
364
context = context.elevated()
186
365
instance_ref = self.db.instance_get(context, instance_id)
188
logging.debug('instance %s: unrescuing',
189
instance_ref['internal_id'])
366
LOG.audit(_('instance %s: unrescuing'), instance_id, context=context)
190
367
self.db.instance_set_state(context,
192
369
power_state.NOSTATE,
194
yield self.driver.unrescue(instance_ref)
195
self._update_state(context, instance_id)
371
self.driver.unrescue(instance_ref)
372
self._update_state(context, instance_id)
375
def _update_state_callback(self, context, instance_id, result):
376
"""Update instance state when async task completes."""
377
self._update_state(context, instance_id)
379
@exception.wrap_exception
380
@checks_instance_lock
381
def pause_instance(self, context, instance_id):
382
"""Pause an instance on this server."""
383
context = context.elevated()
384
instance_ref = self.db.instance_get(context, instance_id)
385
LOG.audit(_('instance %s: pausing'), instance_id, context=context)
386
self.db.instance_set_state(context,
390
self.driver.pause(instance_ref,
391
lambda result: self._update_state_callback(self,
396
@exception.wrap_exception
397
@checks_instance_lock
398
def unpause_instance(self, context, instance_id):
399
"""Unpause a paused instance on this server."""
400
context = context.elevated()
401
instance_ref = self.db.instance_get(context, instance_id)
402
LOG.audit(_('instance %s: unpausing'), instance_id, context=context)
403
self.db.instance_set_state(context,
407
self.driver.unpause(instance_ref,
408
lambda result: self._update_state_callback(self,
413
@exception.wrap_exception
414
def get_diagnostics(self, context, instance_id):
415
"""Retrieve diagnostics for an instance on this server."""
416
instance_ref = self.db.instance_get(context, instance_id)
418
if instance_ref["state"] == power_state.RUNNING:
419
LOG.audit(_("instance %s: retrieving diagnostics"), instance_id,
421
return self.driver.get_diagnostics(instance_ref)
423
@exception.wrap_exception
424
@checks_instance_lock
425
def suspend_instance(self, context, instance_id):
427
suspend the instance with instance_id
430
context = context.elevated()
431
instance_ref = self.db.instance_get(context, instance_id)
432
LOG.audit(_('instance %s: suspending'), instance_id, context=context)
433
self.db.instance_set_state(context, instance_id,
436
self.driver.suspend(instance_ref,
437
lambda result: self._update_state_callback(self,
442
@exception.wrap_exception
443
@checks_instance_lock
444
def resume_instance(self, context, instance_id):
446
resume the suspended instance with instance_id
449
context = context.elevated()
450
instance_ref = self.db.instance_get(context, instance_id)
451
LOG.audit(_('instance %s: resuming'), instance_id, context=context)
452
self.db.instance_set_state(context, instance_id,
455
self.driver.resume(instance_ref,
456
lambda result: self._update_state_callback(self,
461
@exception.wrap_exception
462
def lock_instance(self, context, instance_id):
464
lock the instance with instance_id
467
context = context.elevated()
468
instance_ref = self.db.instance_get(context, instance_id)
470
LOG.debug(_('instance %s: locking'), instance_id, context=context)
471
self.db.instance_update(context, instance_id, {'locked': True})
473
@exception.wrap_exception
474
def unlock_instance(self, context, instance_id):
476
unlock the instance with instance_id
479
context = context.elevated()
480
instance_ref = self.db.instance_get(context, instance_id)
482
LOG.debug(_('instance %s: unlocking'), instance_id, context=context)
483
self.db.instance_update(context, instance_id, {'locked': False})
485
@exception.wrap_exception
486
def get_lock(self, context, instance_id):
488
return the boolean state of (instance with instance_id)'s lock
491
context = context.elevated()
492
LOG.debug(_('instance %s: getting locked state'), instance_id,
494
instance_ref = self.db.instance_get(context, instance_id)
495
return instance_ref['locked']
197
497
@exception.wrap_exception
198
498
def get_console_output(self, context, instance_id):
199
499
"""Send the console output for an instance."""
200
500
context = context.elevated()
201
logging.debug("instance %s: getting console output", instance_id)
202
501
instance_ref = self.db.instance_get(context, instance_id)
502
LOG.audit(_("Get console output for instance %s"), instance_id,
204
504
return self.driver.get_console_output(instance_ref)
206
@defer.inlineCallbacks
207
506
@exception.wrap_exception
507
def get_ajax_console(self, context, instance_id):
508
"""Return connection information for an ajax console"""
509
context = context.elevated()
510
logging.debug(_("instance %s: getting ajax console"), instance_id)
511
instance_ref = self.db.instance_get(context, instance_id)
513
return self.driver.get_ajax_console(instance_ref)
515
@checks_instance_lock
208
516
def attach_volume(self, context, instance_id, volume_id, mountpoint):
209
517
"""Attach a volume to an instance."""
210
518
context = context.elevated()
211
logging.debug("instance %s: attaching volume %s to %s", instance_id,
212
volume_id, mountpoint)
213
519
instance_ref = self.db.instance_get(context, instance_id)
214
dev_path = yield self.volume_manager.setup_compute_volume(context,
520
LOG.audit(_("instance %s: attaching volume %s to %s"), instance_id,
521
volume_id, mountpoint, context=context)
522
dev_path = self.volume_manager.setup_compute_volume(context,
217
yield self.driver.attach_volume(instance_ref['name'],
525
self.driver.attach_volume(instance_ref['name'],
220
528
self.db.volume_attached(context,