2
# Copyright 2012 Canonical Ltd. This software is licensed under the
3
# GNU Affero General Public License version 3 (see the file LICENSE).
5
"""LXC install subcommand: create a Launchpad environment inside an LXC."""
12
'setup_launchpad_lxc',
23
from shelltoolbox import (
31
from lpsetup.settings import (
43
from lpsetup.subcommands import install
44
from lpsetup.utils import (
53
def create_lxc(user, lxc_name, lxc_arch, lxc_os):
54
"""Create the LXC named `lxc_name` sharing `user` home directory.
56
The container will be used as development environment or as base template
57
for parallel testing using ephemeral instances.
59
# Install necessary deb packages.
60
apt_get_install(*LXC_PACKAGES)
61
# XXX 2012-02-02 gmb bug=925024:
62
# These calls need to be removed once the lxc vs. apparmor bug
63
# is resolved, since having apparmor enabled for lxc is very
65
# Disable the apparmor profiles for lxc so that we don't have
66
# problems installing postgres.
68
'/etc/apparmor.d/usr.bin.lxc-start', '/etc/apparmor.d/disable/')
69
call('apparmor_parser', '-R', '/etc/apparmor.d/usr.bin.lxc-start')
70
# Update resolv file in order to get the ability to ssh into the LXC
71
# container using its name.
72
lxc_gateway_name, lxc_gateway_address = get_lxc_gateway()
73
file_prepend(RESOLV_FILE, 'nameserver {0}\n'.format(lxc_gateway_address))
76
'prepend domain-name-servers {0};\n'.format(lxc_gateway_address))
77
# Container configuration template.
78
content = LXC_OPTIONS.format(interface=lxc_gateway_name)
79
with open(LXC_CONFIG_TEMPLATE, 'w') as f:
86
'-f', LXC_CONFIG_TEMPLATE,
88
'-r {os} -a {arch} -b {user}'.format(
89
os=lxc_os, arch=lxc_arch, user=user),
91
# Set up root ssh key.
92
user_authorized_keys = os.path.expanduser(
93
'~' + user + '/.ssh/authorized_keys')
94
with open(user_authorized_keys, 'a') as f:
95
f.write(open('/root/.ssh/id_rsa.pub').read())
96
dst = get_container_path(lxc_name, '/root/.ssh/')
98
shutil.copy(user_authorized_keys, dst)
101
def start_lxc(lxc_name):
102
"""Start the lxc instance named `lxc_name`."""
103
call('lxc-start', '-n', lxc_name, '-d')
106
def wait_for_lxc(lxc_name, trials=60, sleep_seconds=1):
107
"""Try to ssh as `user` into the LXC container named `lxc_name`."""
108
sshcall = ssh(lxc_name)
113
except subprocess.CalledProcessError:
116
time.sleep(sleep_seconds)
121
def initialize_lxc(lxc_name, lxc_os):
122
"""Initialize LXC container."""
123
base_packages = list(BASE_PACKAGES)
124
if lxc_os == 'lucid':
125
# Install argparse to be able to run this script inside a lucid lxc.
126
base_packages.append('python-argparse')
128
'DEBIAN_FRONTEND=noninteractive '
129
'apt-get install -y ' + ' '.join(base_packages))
132
def setup_launchpad_lxc(
133
user, dependencies_dir, directory, valid_ssh_keys, lxc_name):
134
"""Set up the Launchpad environment inside an LXC."""
135
# Use ssh to call this script from inside the container.
137
'install', '-u', user, '-a', 'setup_apt', 'setup_launchpad',
138
'-d', dependencies_dir, '-c', directory
140
cmd = this_command(directory, args)
144
def stop_lxc(lxc_name):
145
"""Stop the lxc instance named `lxc_name`."""
146
ssh(lxc_name)('poweroff')
147
if not lxc_stopped(lxc_name):
148
subprocess.call(['lxc-stop', '-n', lxc_name])
151
class SubCommand(install.SubCommand):
152
"""Install the Launchpad environment inside an LXC."""
156
'user', 'full_name', 'email', 'lpuser', 'private_key',
157
'public_key', 'valid_ssh_keys', 'dependencies_dir', 'directory'),
159
'user', 'lxc_name', 'lxc_arch', 'lxc_os'),
160
(start_lxc, 'lxc_name'),
161
(wait_for_lxc, 'lxc_name'),
163
'lxc_name', 'lxc_os'),
164
(setup_launchpad_lxc,
165
'user', 'dependencies_dir', 'directory', 'valid_ssh_keys',
167
(stop_lxc, 'lxc_name'),
171
def add_arguments(self, parser):
172
super(SubCommand, self).add_arguments(parser)
174
'-n', '--lxc-name', default=LXC_NAME,
175
help='The LXC container name to setup. '
176
'[DEFAULT={0}]'.format(LXC_NAME))
178
'-A', '--lxc-arch', default=LXC_GUEST_ARCH,
179
help='The LXC container architecture. '
180
'[DEFAULT={0}]'.format(LXC_GUEST_ARCH))
182
'-r', '--lxc-os', default=LXC_GUEST_OS,
183
choices=LXC_GUEST_CHOICES,
184
help='The LXC container distro codename. '
185
'[DEFAULT={0}]'.format(LXC_GUEST_OS))