logger = logging.getLogger(__name__)
-from heat.common import exception
from heat.common import heat_keystoneclient as hkc
from novaclient import client as novaclient
try:
return self._cinder
- def attach_volume_to_instance(self, server_id, volume_id, device_id):
- logger.warn('Attaching InstanceId %s VolumeId %s Device %s' %
- (server_id, volume_id, device_id))
-
- va = self.nova().volumes.create_server_volume(
- server_id=server_id,
- volume_id=volume_id,
- device=device_id)
-
- vol = self.cinder().volumes.get(va.id)
- while vol.status == 'available' or vol.status == 'attaching':
- eventlet.sleep(1)
- vol.get()
- if vol.status == 'in-use':
- return va.id
- else:
- raise exception.Error(vol.status)
-
def detach_volume_from_instance(self, server_id, volume_id):
logger.info('VolumeAttachment un-attaching %s %s' %
(server_id, volume_id))
from heat.engine import clients
from heat.engine import resource
+from heat.engine import scheduler
+from heat.engine.resources import volume
+
from heat.common import exception
from heat.engine.resources.network_interface import NetworkInterface
def attach_volumes(self):
if not self.properties['Volumes']:
return
- server_id = self.resource_id
for vol in self.properties['Volumes']:
if 'DeviceId' in vol:
dev = vol['DeviceId']
else:
dev = vol['Device']
- self.stack.clients.attach_volume_to_instance(server_id,
- vol['VolumeId'],
- dev)
+ attach_task = volume.VolumeAttachTask(self.stack,
+ self.resource_id,
+ vol['VolumeId'],
+ vol['Device'])
+ scheduler.TaskRunner(attach_task)()
def detach_volumes(self):
server_id = self.resource_id
return self._delete()
+class VolumeAttachTask(object):
+ """A task for attaching a volume to a Nova server."""
+
+ def __init__(self, stack, server_id, volume_id, device):
+ """
+ Initialise with the stack (for obtaining the clients), ID of the
+ server and volume, and the device name on the server.
+ """
+ self.clients = stack.clients
+ self.server_id = server_id
+ self.volume_id = volume_id
+ self.device = device
+ self.attachment_id = None
+
+ def __str__(self):
+ """Return a human-readable string description of the task."""
+ return 'Attaching Volume %s to Instance %s as %s' % (self.volume_id,
+ self.server_id,
+ self.device)
+
+ def __repr__(self):
+ """Return a brief string description of the task."""
+ return '%s(%s -> %s [%s])' % (type(self).__name__,
+ self.volume_id,
+ self.server_id,
+ self.device)
+
+ def __call__(self):
+ """Return a co-routine which runs the task."""
+ logger.debug(str(self))
+
+ va = self.clients.nova().volumes.create_server_volume(
+ server_id=self.server_id,
+ volume_id=self.volume_id,
+ device=self.device)
+ self.attachment_id = va.id
+ yield
+
+ vol = self.clients.cinder().volumes.get(self.volume_id)
+ while vol.status == 'available' or vol.status == 'attaching':
+ logger.debug('%s - volume status: %s' % (str(self), vol.status))
+ yield
+ vol.get()
+
+ if vol.status != 'in-use':
+ raise exception.Error(vol.status)
+
+ logger.info('%s - complete' % str(self))
+
+
class VolumeAttachment(resource.Resource):
properties_schema = {'InstanceId': {'Type': 'String',
'Required': True},
server_id = self.properties[self._instance_property]
volume_id = self.properties[self._volume_property]
dev = self.properties[self._device_property]
- inst = self.stack.clients.attach_volume_to_instance(server_id,
- volume_id,
- dev)
- self.resource_id_set(inst)
+ attach_task = VolumeAttachTask(self.stack, server_id, volume_id, dev)
+ scheduler.TaskRunner(attach_task)()
+ self.resource_id_set(attach_task.attachment_id)
def handle_update(self, json_snippet):
return self.UPDATE_REPLACE
import eventlet
+import mox
import json
from testtools import skipIf
# create script
clients.OpenStackClients.nova().MultipleTimes().AndReturn(self.fc)
- eventlet.sleep(1).MultipleTimes().AndReturn(None)
+ scheduler.TaskRunner._sleep(mox.IsA(int)).AndReturn(None)
self.fc.volumes.create_server_volume(
device=u'/dev/vdc',
server_id=u'WikiDatabase',
# create script
clients.OpenStackClients.nova().MultipleTimes().AndReturn(self.fc)
- eventlet.sleep(1).MultipleTimes().AndReturn(None)
+ scheduler.TaskRunner._sleep(mox.IsA(int)).AndReturn(None)
self.fc.volumes.create_server_volume(
device=u'/dev/vdc',
server_id=u'WikiDatabase',
self.fc.volumes.delete_server_volume('WikiDatabase',
'vol-123').AndReturn(None)
self.cinder_fc.volumes.get('vol-123').AndReturn(fva)
+ eventlet.sleep(mox.IsA(int)).AndReturn(None)
self.m.ReplayAll()
# create script
clients.OpenStackClients.nova().MultipleTimes().AndReturn(self.fc)
- eventlet.sleep(1).MultipleTimes().AndReturn(None)
+ scheduler.TaskRunner._sleep(mox.IsA(int)).AndReturn(None)
self.fc.volumes.create_server_volume(
device=u'/dev/vdc',
server_id=u'WikiDatabase',
self.fc.volumes.delete_server_volume('WikiDatabase',
'vol-123').AndReturn(None)
self.cinder_fc.volumes.get('vol-123').AndReturn(fva)
+ eventlet.sleep(mox.IsA(int)).AndReturn(None)
self.m.ReplayAll()