nova-lxd/nova/virt/lxd/storage.py

137 lines
5.7 KiB
Python

# Copyright 2016 Canonical Ltd
# All Rights Reserved.
#
# 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.
import os
from oslo_config import cfg
from oslo_utils import fileutils
from nova import exception
from nova import utils
from nova.virt import driver
from nova.virt.lxd import common
CONF = cfg.CONF
def attach_ephemeral(client, block_device_info, lxd_config, instance):
"""Attach ephemeral storage to an instance."""
ephemeral_storage = driver.block_device_info_get_ephemerals(
block_device_info)
if ephemeral_storage:
storage_driver = lxd_config['environment']['storage']
container = client.containers.get(instance.name)
container_id_map = container.config[
'volatile.last_state.idmap'].split(',')
storage_id = container_id_map[2].split(':')[1]
instance_attrs = common.InstanceAttributes(instance)
for ephemeral in ephemeral_storage:
storage_dir = os.path.join(
instance_attrs.storage_path, ephemeral['virtual_name'])
if storage_driver == 'zfs':
# NOTE(ajkavanagh) - BUG/1782329 - this is temporary until
# storage pools is implemented. LXD 3 removed the
# storage.zfs_pool_name key from the config. So, if it fails,
# we need to grab the configured storage pool and use that as
# the name instead.
try:
zfs_pool = lxd_config['config']['storage.zfs_pool_name']
except KeyError:
zfs_pool = CONF.lxd.pool
utils.execute(
'zfs', 'create',
'-o', 'mountpoint=%s' % storage_dir,
'-o', 'quota=%sG' % instance.ephemeral_gb,
'%s/%s-ephemeral' % (zfs_pool, instance.name),
run_as_root=True)
elif storage_driver == 'btrfs':
# We re-use the same btrfs subvolumes that LXD uses,
# so the ephemeral storage path is updated in the profile
# before the container starts.
storage_dir = os.path.join(
instance_attrs.container_path, ephemeral['virtual_name'])
profile = client.profiles.get(instance.name)
storage_name = ephemeral['virtual_name']
profile.devices[storage_name]['source'] = storage_dir
profile.save()
utils.execute(
'btrfs', 'subvolume', 'create', storage_dir,
run_as_root=True)
utils.execute(
'btrfs', 'qgroup', 'limit',
'%sg' % instance.ephemeral_gb, storage_dir,
run_as_root=True)
elif storage_driver == 'lvm':
fileutils.ensure_tree(storage_dir)
lvm_pool = lxd_config['config']['storage.lvm_vg_name']
lvm_volume = '%s-%s' % (instance.name,
ephemeral['virtual_name'])
lvm_path = '/dev/%s/%s' % (lvm_pool, lvm_volume)
cmd = (
'lvcreate', '-L', '%sG' % instance.ephemeral_gb,
'-n', lvm_volume, lvm_pool)
utils.execute(*cmd, run_as_root=True, attempts=3)
utils.execute('mkfs', '-t', 'ext4',
lvm_path, run_as_root=True)
cmd = ('mount', '-t', 'ext4', lvm_path, storage_dir)
utils.execute(*cmd, run_as_root=True)
else:
reason = _("Unsupport LXD storage detected. Supported"
" storage drivers are zfs and btrfs.")
raise exception.NovaException(reason)
utils.execute(
'chown', storage_id,
storage_dir, run_as_root=True)
def detach_ephemeral(client, block_device_info, lxd_config, instance):
"""Detach ephemeral device from the instance."""
ephemeral_storage = driver.block_device_info_get_ephemerals(
block_device_info)
if ephemeral_storage:
storage_driver = lxd_config['environment']['storage']
for ephemeral in ephemeral_storage:
if storage_driver == 'zfs':
# NOTE(ajkavanagh) - BUG/1782329 - this is temporary until
# storage pools is implemented. LXD 3 removed the
# storage.zfs_pool_name key from the config. So, if it fails,
# we need to grab the configured storage pool and use that as
# the name instead.
try:
zfs_pool = lxd_config['config']['storage.zfs_pool_name']
except KeyError:
zfs_pool = CONF.lxd.pool
utils.execute(
'zfs', 'destroy',
'%s/%s-ephemeral' % (zfs_pool, instance.name),
run_as_root=True)
if storage_driver == 'lvm':
lvm_pool = lxd_config['config']['storage.lvm_vg_name']
lvm_path = '/dev/%s/%s-%s' % (
lvm_pool, instance.name, ephemeral['virtual_name'])
utils.execute('umount', lvm_path, run_as_root=True)
utils.execute('lvremove', '-f', lvm_path, run_as_root=True)