charm-nova-lxd/hooks/lxd_utils.py

197 lines
5.2 KiB
Python

import glob
import pwd
import os
from subprocess import call, check_call
from charmhelpers.core.templating import render
from charmhelpers.core.hookenv import (
log,
config,
ERROR,
)
from charmhelpers.core.host import (
add_group,
add_user_to_group,
mkdir,
mount,
service_stop,
service_start,
)
from charmhelpers.contrib.storage.linux.utils import (
is_block_device,
)
from charmhelpers.contrib.storage.linux.loopback import (
ensure_loopback_device
)
from charmhelpers.contrib.storage.linux.lvm import (
create_lvm_volume_group,
create_lvm_physical_volume,
list_lvm_volume_group,
is_lvm_physical_volume,
)
BASE_PACKAGES = [
'btrfs-tools',
'lvm2',
'thin-provisioning-tools'
]
LXD_PACKAGES = ['lxd', 'lxd-client']
LXD_SOURCE_PACKAGES = [
'lxc',
'lxc-dev',
'mercurial',
'git',
'pkg-config',
'protobuf-compiler',
'golang-goprotobuf-dev',
'build-essential',
'golang',
'xz-utils',
'tar',
'acl',
]
LXD_GIT = 'github.com/lxc/lxd'
DEFAULT_LOOPBACK_SIZE = '10G'
def install_lxd():
'''Install LXD'''
def install_lxd_source(user='ubuntu'):
'''Install LXD from source repositories; installs toolchain first'''
log('Installing LXD from source')
home = pwd.getpwnam(user).pw_dir
GOPATH = os.path.join(home, 'go')
LXD_SRC = os.path.join(GOPATH, 'src', 'github.com/lxc/lxd')
if not os.path.exists(GOPATH):
mkdir(GOPATH)
env = os.environ.copy()
env['GOPATH'] = GOPATH
env['HTTP_PROXY'] = 'http://squid.internal:3128'
env['HTTPS_PROXY'] = 'https://squid.internal:3128'
cmd = 'go get -v %s' % LXD_GIT
log('Installing LXD: %s' % (cmd))
check_call(cmd, env=env, shell=True)
if not os.path.exists(LXD_SRC):
log('Failed to go get %s' % LXD_GIT, level=ERROR)
raise
cwd = os.getcwd()
try:
os.chdir(LXD_SRC)
cmd = 'go get -v -d ./...'
log('Downloading LXD deps: %s' % (cmd))
call(cmd, env=env, shell=True)
# build deps
cmd = 'make'
log('Building LXD deps: %s' % (cmd))
call(cmd, env=env, shell=True)
except Exception:
log("failed to install lxd")
raise
finally:
os.chdir(cwd)
def configure_lxd_source(user='ubuntu'):
'''Add required configuration and files when deploying LXD from source'''
log('Configuring LXD Source')
home = pwd.getpwnam(user).pw_dir
GOPATH = os.path.join(home, 'go')
templates_dir = 'templates'
render('lxd_upstart', '/etc/init/lxd.conf', {},
perms=0o644, templates_dir=templates_dir)
render('lxd_service', '/lib/systemd/system/lxd.service', {},
perms=0o644, templates_dir=templates_dir)
add_group('lxd', system_group=True)
add_user_to_group(user, 'lxd')
service_stop('lxd')
files = glob.glob('%s/bin/*' % GOPATH)
for i in files:
cmd = ['cp', i, '/usr/bin']
check_call(cmd)
service_start('lxd')
def configure_lxd_block():
'''Configure a block device for use by LXD for containers'''
log('Configuring LXD container storage')
if filesystem_mounted('/var/lib/lxd'):
log('/varlib/lxd already configured, skipping')
return
lxd_block_device = config('block-device')
if not lxd_block_device:
log('block device is not provided - skipping')
return
dev = None
if lxd_block_device.startswith('/dev/'):
dev = lxd_block_device
elif lxd_block_device.startswith('/'):
log('Configuring loopback device for use with LXD')
_bd = lxd_block_device.split('|')
if len(_bd) == 2:
dev, size = _bd
else:
dev = lxd_block_device
size = DEFAULT_LOOPBACK_SIZE
dev = ensure_loopback_device(dev, size)
if not dev or not is_block_device(dev):
log('Invalid block device provided: %s' % lxd_block_device)
return
if not os.path.exists('/var/lib/lxd'):
mkdir('/var/lib/lxd')
if config('storage-type') == 'btrfs':
service_stop('lxd')
cmd = ['mkfs.btrfs', '-f', dev]
check_call(cmd)
mount(dev,
'/var/lib/lxd',
options='user_subvol_rm_allowed',
persist=True,
filesystem='btrfs')
service_start('lxd')
elif config('storage-type') == 'lvm':
if (is_lvm_physical_volume(dev) and
list_lvm_volume_group(dev) == 'lxd_vg'):
log('Device already configured for LVM/LXD, skipping')
return
# Enable and startup lvm2-lvmetad to avoid extra output
# in lvm2 commands, which confused lxd.
cmd = ['systemctl', 'enable', 'lvm2-lvmetad']
check_call(cmd)
cmd = ['systemctl', 'start', 'lvm2-lvmetad']
check_call(cmd)
create_lvm_physical_volume(dev)
create_lvm_volume_group('lxd_vg', dev)
cmd = ['lxc', 'config', 'set', 'storage.lvm_vg_name', 'lxd_vg']
check_call(cmd)
def determine_packages():
packages = [] + BASE_PACKAGES
packages = list(set(packages))
if config('use-source'):
packages.extend(LXD_SOURCE_PACKAGES)
else:
packages.extend(LXD_PACKAGES)
return packages
def filesystem_mounted(fs):
return call(['grep', '-wqs', fs, '/proc/mounts']) == 0