Files
nova/nova/privsep/libvirt.py
Stephen Finucane 3a390c2c82 libvirt: Drop support for Xen
This hasn't been validated upstream and there doesn't appear to be
anyone using it. It's time to drop support for this. This is mostly test
and documentation damage, though there is some other cleanup going on,
like the removal of the essentially noop 'pick_disk_driver_name' helper.

Change-Id: I73305e82da5d8da548961b801a8e75fb0e8c4cf1
Signed-off-by: Stephen Finucane <stephenfin@redhat.com>
2021-01-22 10:06:40 +00:00

250 lines
8.6 KiB
Python

# Copyright 2016 Red Hat, Inc
# Copyright 2017 Rackspace Australia
#
# 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.
"""
libvirt specific routines.
"""
import binascii
import os
import stat
from oslo_concurrency import processutils
from oslo_log import log as logging
from oslo_utils import units
from oslo_utils import uuidutils
import nova.privsep
LOG = logging.getLogger(__name__)
@nova.privsep.sys_admin_pctxt.entrypoint
def dmcrypt_create_volume(target, device, cipher, key_size, key):
"""Sets up a dmcrypt mapping
:param target: device mapper logical device name
:param device: underlying block device
:param cipher: encryption cipher string digestible by cryptsetup
:param key_size: encryption key size
:param key: encoded encryption key bytestring
"""
cmd = ('cryptsetup',
'create',
target,
device,
'--cipher=' + cipher,
'--key-size=' + str(key_size),
'--key-file=-')
key = binascii.hexlify(key).decode('utf-8')
processutils.execute(*cmd, process_input=key)
@nova.privsep.sys_admin_pctxt.entrypoint
def dmcrypt_delete_volume(target):
"""Deletes a dmcrypt mapping
:param target: name of the mapped logical device
"""
processutils.execute('cryptsetup', 'remove', target)
@nova.privsep.sys_admin_pctxt.entrypoint
def ploop_init(size, disk_format, fs_type, disk_path):
"""Initialize ploop disk, make it readable for non-root user
:param disk_format: data allocation format (raw or expanded)
:param fs_type: filesystem (ext4, ext3, none)
:param disk_path: ploop image file
"""
processutils.execute('ploop', 'init', '-s', size, '-f', disk_format, '-t',
fs_type, disk_path, check_exit_code=True)
# Add read access for all users, because "ploop init" creates
# disk with rw rights only for root. OpenStack user should have access
# to the disk to request info via "qemu-img info"
# TODO(mikal): this is a faithful rendition of the pre-privsep code from
# the libvirt driver, but it seems undesirable to me. It would be good to
# create the loop file with the right owner or group such that we don't
# need to have it world readable. I don't have access to a system to test
# this on however.
st = os.stat(disk_path)
os.chmod(disk_path, st.st_mode | stat.S_IROTH)
@nova.privsep.sys_admin_pctxt.entrypoint
def ploop_resize(disk_path, size):
"""Resize ploop disk
:param disk_path: ploop image file
:param size: new size (in bytes)
"""
processutils.execute('prl_disk_tool', 'resize',
'--size', '%dM' % (size // units.Mi),
'--resize_partition',
'--hdd', disk_path,
check_exit_code=True)
@nova.privsep.sys_admin_pctxt.entrypoint
def ploop_restore_descriptor(image_dir, base_delta, fmt):
"""Restore ploop disk descriptor XML
:param image_dir: path to where descriptor XML is created
:param base_delta: ploop image file containing the data
:param fmt: ploop data allocation format (raw or expanded)
"""
processutils.execute('ploop', 'restore-descriptor', '-f', fmt,
image_dir, base_delta,
check_exit_code=True)
@nova.privsep.sys_admin_pctxt.entrypoint
def plug_infiniband_vif(vnic_mac, device_id, fabric, net_model, pci_slot):
processutils.execute('ebrctl', 'add-port', vnic_mac, device_id,
fabric, net_model, pci_slot)
@nova.privsep.sys_admin_pctxt.entrypoint
def unplug_infiniband_vif(fabric, vnic_mac):
processutils.execute('ebrctl', 'del-port', fabric, vnic_mac)
@nova.privsep.sys_admin_pctxt.entrypoint
def plug_midonet_vif(port_id, dev):
processutils.execute('mm-ctl', '--bind-port', port_id, dev)
@nova.privsep.sys_admin_pctxt.entrypoint
def unplug_midonet_vif(port_id):
processutils.execute('mm-ctl', '--unbind-port', port_id)
@nova.privsep.sys_admin_pctxt.entrypoint
def plug_plumgrid_vif(dev, iface_id, vif_address, net_id, tenant_id):
processutils.execute('ifc_ctl', 'gateway', 'add_port', dev)
processutils.execute('ifc_ctl', 'gateway', 'ifup', dev,
'access_vm', iface_id, vif_address,
'pgtag2=%s' % net_id, 'pgtag1=%s' % tenant_id)
@nova.privsep.sys_admin_pctxt.entrypoint
def unplug_plumgrid_vif(dev):
processutils.execute('ifc_ctl', 'gateway', 'ifdown', dev)
processutils.execute('ifc_ctl', 'gateway', 'del_port', dev)
@nova.privsep.sys_admin_pctxt.entrypoint
def readpty(path):
# TODO(mikal): I'm not a huge fan that we don't enforce a valid pty path
# here, but I haven't come up with a great way of doing that.
# NOTE(mikal): I am deliberately not catching the ImportError
# exception here... Some platforms (I'm looking at you Windows)
# don't have a fcntl and we may as well let them know that
# with an ImportError, not that they should be calling this at all.
import fcntl
try:
with open(path, 'r') as f:
current_flags = fcntl.fcntl(f.fileno(), fcntl.F_GETFL)
fcntl.fcntl(f.fileno(), fcntl.F_SETFL,
current_flags | os.O_NONBLOCK)
return f.read()
except Exception as exc:
# NOTE(mikal): dear internet, I see you looking at me with your
# judging eyes. There's a story behind why we do this. You see, the
# previous implementation did this:
#
# out, err = utils.execute('dd',
# 'if=%s' % pty,
# 'iflag=nonblock',
# run_as_root=True,
# check_exit_code=False)
# return out
#
# So, it never checked stderr or the return code of the process it
# ran to read the pty. Doing something better than that has turned
# out to be unexpectedly hard because there are a surprisingly large
# variety of errors which appear to be thrown when doing this read.
#
# Therefore for now we log the errors, but keep on rolling. Volunteers
# to help clean this up are welcome and will receive free beverages.
LOG.info(
'Ignored error while reading from instance console pty: %s', exc
)
return ''
@nova.privsep.sys_admin_pctxt.entrypoint
def create_mdev(physical_device, mdev_type, uuid=None):
"""Instantiate a mediated device."""
if uuid is None:
uuid = uuidutils.generate_uuid()
fpath = '/sys/class/mdev_bus/{0}/mdev_supported_types/{1}/create'
fpath = fpath.format(physical_device, mdev_type)
with open(fpath, 'w') as f:
f.write(uuid)
return uuid
@nova.privsep.sys_admin_pctxt.entrypoint
def systemd_run_qb_mount(qb_vol, mnt_base, cfg_file=None):
"""Mount QB volume in separate CGROUP"""
# Note(kaisers): Details on why we run without --user at bug #1756823
sysdr_cmd = ['systemd-run', '--scope', 'mount.quobyte', '--disable-xattrs',
qb_vol, mnt_base]
if cfg_file:
sysdr_cmd.extend(['-c', cfg_file])
return processutils.execute(*sysdr_cmd)
# NOTE(kaisers): this method is deliberately not wrapped in a privsep entry.
def unprivileged_qb_mount(qb_vol, mnt_base, cfg_file=None):
"""Mount QB volume"""
mnt_cmd = ['mount.quobyte', '--disable-xattrs', qb_vol, mnt_base]
if cfg_file:
mnt_cmd.extend(['-c', cfg_file])
return processutils.execute(*mnt_cmd)
@nova.privsep.sys_admin_pctxt.entrypoint
def umount(mnt_base):
"""Unmount volume"""
unprivileged_umount(mnt_base)
# NOTE(kaisers): this method is deliberately not wrapped in a privsep entry.
def unprivileged_umount(mnt_base):
"""Unmount volume"""
umnt_cmd = ['umount', mnt_base]
return processutils.execute(*umnt_cmd)
@nova.privsep.sys_admin_pctxt.entrypoint
def get_pmem_namespaces():
ndctl_cmd = ['ndctl', 'list', '-X']
nss_info = processutils.execute(*ndctl_cmd)[0]
return nss_info
@nova.privsep.sys_admin_pctxt.entrypoint
def cleanup_vpmem(devpath):
daxio_cmd = ['daxio', '-z', '-o', '%s' % devpath]
processutils.execute(*daxio_cmd)