nova/nova/virt/xenapi/volumeops.py

224 lines
8.8 KiB
Python

# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright (c) 2010 Citrix Systems, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
"""
Management class for Storage-related functions (attach, detach, etc).
"""
from nova import exception
from nova.openstack.common import log as logging
from nova.virt.xenapi import vm_utils
from nova.virt.xenapi import volume_utils
LOG = logging.getLogger(__name__)
class VolumeOps(object):
"""
Management class for Volume-related tasks
"""
def __init__(self, session):
self._session = session
def create_volume_for_sm(self, volume, sr_uuid):
LOG.debug("Creating volume for Storage Manager")
sm_vol_rec = {}
try:
sr_ref = self._session.call_xenapi("SR.get_by_uuid", sr_uuid)
except self._session.XenAPI.Failure, exc:
LOG.exception(exc)
raise volume_utils.StorageError(_('Unable to get SR using uuid'))
#Create VDI
label = 'vol-' + volume['id']
desc = 'xensm volume for ' + volume['id']
# size presented to xenapi is in bytes, while euca api is in GB
vdi_size = volume['size'] * 1024 * 1024 * 1024
vdi_ref = vm_utils.create_vdi(self._session, sr_ref,
None, label, desc,
vdi_size, False)
vdi_rec = self._session.call_xenapi("VDI.get_record", vdi_ref)
sm_vol_rec['vdi_uuid'] = vdi_rec['uuid']
return sm_vol_rec
def delete_volume_for_sm(self, vdi_uuid):
vdi_ref = self._session.call_xenapi("VDI.get_by_uuid", vdi_uuid)
if vdi_ref is None:
raise exception.NovaException(_('Could not find VDI ref'))
vm_utils.destroy_vdi(self._session, vdi_ref)
def create_sr(self, label, params):
LOG.debug(_("Creating SR %s") % label)
sr_ref = volume_utils.create_sr(self._session, label, params)
if sr_ref is None:
raise exception.NovaException(_('Could not create SR'))
sr_rec = self._session.call_xenapi("SR.get_record", sr_ref)
if sr_rec is None:
raise exception.NovaException(_('Could not retrieve SR record'))
return sr_rec['uuid']
# Checks if sr has already been introduced to this host
def introduce_sr(self, sr_uuid, label, params):
LOG.debug(_("Introducing SR %s") % label)
sr_ref = volume_utils.find_sr_by_uuid(self._session, sr_uuid)
if sr_ref:
LOG.debug(_('SR found in xapi database. No need to introduce'))
return sr_ref
sr_ref = volume_utils.introduce_sr(self._session, sr_uuid, label,
params)
if sr_ref is None:
raise exception.NovaException(_('Could not introduce SR'))
return sr_ref
def is_sr_on_host(self, sr_uuid):
LOG.debug(_('Checking for SR %s') % sr_uuid)
sr_ref = volume_utils.find_sr_by_uuid(self._session, sr_uuid)
if sr_ref:
return True
return False
# Checks if sr has been introduced
def forget_sr(self, sr_uuid):
sr_ref = volume_utils.find_sr_by_uuid(self._session, sr_uuid)
if sr_ref is None:
LOG.INFO(_('SR %s not found in the xapi database') % sr_uuid)
return
try:
volume_utils.forget_sr(self._session, sr_uuid)
except volume_utils.StorageError, exc:
LOG.exception(exc)
raise exception.NovaException(_('Could not forget SR'))
def attach_volume(self, connection_info, instance_name, mountpoint,
hotplug=True):
"""Attach volume storage to VM instance."""
vm_ref = vm_utils.vm_ref_or_raise(self._session, instance_name)
# NOTE: No Resource Pool concept so far
LOG.debug(_("Attach_volume: %(connection_info)s, %(instance_name)s,"
" %(mountpoint)s") % locals())
driver_type = connection_info['driver_volume_type']
if driver_type not in ['iscsi', 'xensm']:
raise exception.VolumeDriverNotFound(driver_type=driver_type)
connection_data = connection_info['data']
dev_number = volume_utils.get_device_number(mountpoint)
self.connect_volume(connection_data, dev_number, instance_name,
vm_ref, hotplug=hotplug)
LOG.info(_('Mountpoint %(mountpoint)s attached to'
' instance %(instance_name)s') % locals())
def connect_volume(self, connection_data, dev_number, instance_name,
vm_ref, hotplug=True):
description = 'Disk-for:%s' % instance_name
uuid, label, sr_params = volume_utils.parse_sr_info(connection_data,
description)
# Introduce SR
try:
sr_ref = self.introduce_sr(uuid, label, sr_params)
LOG.debug(_('Introduced %(label)s as %(sr_ref)s.') % locals())
except self._session.XenAPI.Failure, exc:
LOG.exception(exc)
raise volume_utils.StorageError(
_('Unable to introduce Storage Repository'))
vdi_uuid = None
target_lun = None
if 'vdi_uuid' in connection_data:
vdi_uuid = connection_data['vdi_uuid']
elif 'target_lun' in connection_data:
target_lun = connection_data['target_lun']
else:
vdi_uuid = None
# Introduce VDI and attach VBD to VM
try:
vdi_ref = volume_utils.introduce_vdi(self._session, sr_ref,
vdi_uuid, target_lun)
except volume_utils.StorageError, exc:
LOG.exception(exc)
self.forget_sr(uuid)
raise Exception(_('Unable to create VDI on SR %(sr_ref)s for'
' instance %(instance_name)s') % locals())
try:
vbd_ref = vm_utils.create_vbd(self._session, vm_ref, vdi_ref,
dev_number, bootable=False,
osvol=True)
except self._session.XenAPI.Failure, exc:
LOG.exception(exc)
self.forget_sr(uuid)
raise Exception(_('Unable to use SR %(sr_ref)s for'
' instance %(instance_name)s') % locals())
if hotplug:
try:
self._session.call_xenapi("VBD.plug", vbd_ref)
except self._session.XenAPI.Failure, exc:
LOG.exception(exc)
self.forget_sr(uuid)
raise Exception(_('Unable to attach volume to instance %s')
% instance_name)
def detach_volume(self, connection_info, instance_name, mountpoint):
"""Detach volume storage to VM instance."""
vm_ref = vm_utils.vm_ref_or_raise(self._session, instance_name)
# Detach VBD from VM
LOG.debug(_("Detach_volume: %(instance_name)s, %(mountpoint)s")
% locals())
device_number = volume_utils.mountpoint_to_number(mountpoint)
try:
vbd_ref = vm_utils.find_vbd_by_number(self._session, vm_ref,
device_number)
except volume_utils.StorageError, exc:
LOG.exception(exc)
raise Exception(_('Unable to locate volume %s') % mountpoint)
try:
vm_rec = self._session.call_xenapi("VM.get_record", vm_ref)
sr_ref = volume_utils.find_sr_from_vbd(self._session, vbd_ref)
if vm_rec['power_state'] != 'Halted':
vm_utils.unplug_vbd(self._session, vbd_ref)
except volume_utils.StorageError, exc:
LOG.exception(exc)
raise Exception(_('Unable to detach volume %s') % mountpoint)
try:
vm_utils.destroy_vbd(self._session, vbd_ref)
except volume_utils.StorageError, exc:
LOG.exception(exc)
raise Exception(_('Unable to destroy vbd %s') % mountpoint)
# Forget SR only if no other volumes on this host are using it
try:
volume_utils.purge_sr(self._session, sr_ref)
except volume_utils.StorageError, exc:
LOG.exception(exc)
raise Exception(_('Error purging SR %s') % sr_ref)
LOG.info(_('Mountpoint %(mountpoint)s detached from'
' instance %(instance_name)s') % locals())