40
36
parser = argparse.ArgumentParser(description="Unity8 inside LXC")
41
37
parser.add_argument(
42
"--rebuild-all", action="store_true",
43
help=("Wipe and replace the container rootfs and configuration."))
45
"--rebuild-config", action="store_true",
46
help=("Wipe and regenerate the container configuration."))
48
"--rebuild-rootfs", action="store_true",
38
"--rebuild", action="store_true",
49
39
help=("Wipe and replace the container rootfs."))
50
40
parser.add_argument(
51
"--redownload", action="store_true",
52
help=("Re-download the ISO image instead of using the local version."))
54
41
"--test", type=int, metavar="SECONDS", default=None,
55
42
help=("Test mode, argument is time in seconds for the session."))
56
43
parser.add_argument(
68
55
container = lxc.Container(CONTAINER_NAME)
69
56
container_path = "%s/%s" % (lxc.default_config_path, CONTAINER_NAME)
70
57
rootfs_path = "%s/rootfs" % container_path
71
iso_filename = "%s/ubuntu-next.iso" % container_path
72
iso_path = "%s/iso" % container_path
73
squashfs_path = "%s/squashfs" % container_path
75
(distro, version, codename) = platform.linux_distribution()
77
if not os.path.exists(iso_filename):
78
args.redownload = True
81
generate_config = True
82
60
generate_rootfs = True
84
63
def start_container(wait_for_network=True):
85
64
if not container.running:
86
65
print("Starting the container")
92
71
print("Not able to connect to the network.")
75
def get_latest_lxc_image(arch):
76
cmd = ['/usr/share/lxc/templates/lxc-download', '-d', 'ubuntu', '-a', arch, '-l']
78
proc = subprocess.Popen(cmd, stdout=subprocess.PIPE)
79
output = proc.communicate()[0]
81
lxc_output = output.split(b'\n')
83
for line in lxc_output:
84
if line.decode().startswith('ubuntu'):
87
release = last_line.decode().split('\t')
95
92
# Destroy a container entirely
96
93
if args.destroy and container.defined:
101
98
# Deal with existing containers
102
99
if container.defined:
103
generate_config = False
104
100
generate_rootfs = False
106
102
if not args.test and container.running:
107
103
print("Stopping the existing container.")
111
args.rebuild_config = True
112
args.rebuild_rootfs = True
114
if args.rebuild_config:
115
generate_config = True
116
container.clear_config()
118
if args.rebuild_rootfs:
107
print("Deleting current unity8-lxc container...")
119
108
generate_rootfs = True
120
if os.path.exists(rootfs_path):
121
shutil.rmtree(rootfs_path)
111
container = lxc.Container(CONTAINER_NAME)
123
if not generate_config and not generate_rootfs and not args.test and not args.update_lxc:
113
if not generate_rootfs and not args.test and not args.update_lxc:
124
114
parser.error("The container already exists.")
128
# Setup the container config
129
## Load the default LXC config keys
130
container.load_config("/usr/share/lxc/config/ubuntu.common.conf")
132
## Setup the network ##
133
container.append_config_item("lxc.network.type", "veth")
134
container.append_config_item("lxc.network.link", "lxcbr0")
135
container.append_config_item("lxc.network.hwaddr", "00:16:3e:xx:xx:xx")
138
container.set_config_item("lxc.arch", "x86_64")
141
container.set_config_item("lxc.rootfs", rootfs_path)
144
container.set_config_item("lxc.utsname", CONTAINER_NAME)
148
container.append_config_item("lxc.cgroup.devices.allow", "c 4:* rwm")
151
container.append_config_item("lxc.cgroup.devices.allow", "c 13:* rwm")
152
container.append_config_item("lxc.mount.entry",
153
"/dev/input dev/input none bind,create=dir")
156
container.append_config_item("lxc.cgroup.devices.allow", "c 226:* rwm")
157
container.append_config_item("lxc.mount.entry",
158
"/dev/dri dev/dri none bind,create=dir")
161
container.append_config_item("lxc.cgroup.devices.allow", "c 116:* rwm")
162
container.append_config_item("lxc.mount.entry",
163
"/dev/snd dev/snd none bind,create=dir")
165
## Enable cgmanager access
166
container.set_config_item("lxc.mount.auto", "cgroup:mixed proc:mixed sys:mixed")
168
## Allow nested containers
169
container.set_config_item("lxc.aa_profile", "lxc-container-default-with-nesting")
171
## Disable the lxc autodev
172
container.append_config_item("lxc.autodev", "0")
174
# Setup the /home bind-mount
175
container.append_config_item("lxc.mount.entry", "/home home none bind")
177
# Setup the /etc/shadow bind-mount
178
container.append_config_item("lxc.mount.entry",
179
"/etc/shadow etc/shadow none bind")
181
# Setup the local time and timezone
182
container.append_config_item("lxc.mount.entry",
183
"/etc/localtime etc/localtime none bind")
184
container.append_config_item("lxc.mount.entry",
185
"/etc/timezone etc/timezone none bind")
188
container.append_config_item("lxc.mount.entry",
189
"/run/udev var/lib/host-udev none bind,ro,create=dir")
192
container.append_config_item("lxc.mount.entry",
193
"/run/systemd var/lib/host-systemd none bind,ro,create=dir")
195
## Dump it all to disk
196
container.save_config()
199
116
if generate_rootfs:
200
117
# Setup the container rootfs
209
126
architecture = dpkg.stdout.read().strip()
212
current_release = UbuntuDistroInfo().devel()
213
except DistroDataOutdated:
214
current_release = UbuntuDistroInfo().stable()
216
## Download the ISO image
218
iso_url = ISO_URL.replace("ARCH", architecture)
219
iso_url = iso_url.replace("RELEASE", current_release)
221
### Use zsync to fetch the ISO
222
cmd = "cd %s && zsync -i %s -o %s %s" % (container_path, iso_filename, iso_filename, iso_url)
225
### Remove the ISO backup since it's not needed
226
if os.path.exists(iso_filename+".zs-old"):
227
os.remove(iso_filename+".zs-old")
229
if not os.path.exists(iso_filename):
230
parser.error("No Unity 8 Desktop Next ISO exists!")
233
if not os.path.exists(iso_path):
235
subprocess.call(["mount", "-o", "loop,ro", iso_filename, iso_path])
237
if not os.path.exists(squashfs_path):
238
os.mkdir(squashfs_path)
239
subprocess.call(["mount", "-o", "loop,ro",
240
os.path.join(iso_path, "casper", "filesystem.squashfs"),
244
print("Unpacking the ISO image...")
245
subprocess.call(["rsync", "-aA", "--hard-links", "--numeric-ids",
246
"%s/" % squashfs_path, "%s/" % rootfs_path])
249
subprocess.call(["umount", squashfs_path])
250
os.rmdir(squashfs_path)
252
subprocess.call(["umount", iso_path])
128
print("Determining latest LXC image release...")
129
current_release = get_latest_lxc_image(architecture)
131
print("Creating the new unity8-lxc container...")
132
container.create("download", 0,
134
"release": current_release,
135
"arch": architecture})
256
138
print("Configuring the Unity8 LXC...")
270
152
ff02::2 ip6-allrouters
273
### Disable some upstart jobs
155
# Generate the package install policy override
156
with open(os.path.join(rootfs_path, 'usr', 'sbin', 'policy-rc.d'), 'w+') as fd:
157
fd.write("""#!/bin/sh
168
os.chmod(os.path.join(rootfs_path, 'usr', 'sbin', 'policy-rc.d'), 0o755)
172
# Remove the default ubuntu user in the container
173
container.attach_wait(lxc.attach_run_command,
174
["userdel", "-r", "ubuntu"])
176
# Copy the ubuntu-desktop-next metapackage to the rootfs
177
lxc_archive = os.path.join(rootfs_path, 'tmp', 'ubuntu-desktop-next.deb')
178
glob_name = "ubuntu-desktop-next_*_%s.deb" % architecture
179
metapackage = glob.glob(os.path.join('/', 'usr', 'share', 'unity8-lxc', glob_name))
180
shutil.copy(metapackage[0], lxc_archive)
182
container.attach_wait(lxc.attach_run_command,
183
["apt-get", "update"])
185
container.attach_wait(lxc.attach_run_command,
186
["dpkg", "-i", os.path.join('/', 'tmp', 'ubuntu-desktop-next.deb')])
187
container.attach_wait(lxc.attach_run_command,
188
["apt-get", "install", "-f", "-y"])
190
container.attach_wait(lxc.attach_run_command,
191
["systemctl", "disable", "lightdm.service"])
194
# Disable some upstart jobs
274
195
for job in glob.glob("%s/etc/init/*.conf" % rootfs_path):
275
196
if os.path.basename(job).rsplit(".conf", 1)[0] in SKIP_JOB:
276
197
with open("%s.override" % job.rsplit(".conf", 1)[0], "w+") as fd:
277
198
fd.write("manual")
279
### Create any missing devices
281
tty_path = os.path.join(rootfs_path, "dev", "tty%s" % i)
282
if not os.path.exists(tty_path):
283
os.mknod(tty_path, 0o620 | stat.S_IFCHR, device=os.makedev(4, i))
284
os.chown(tty_path, 0, 5)
286
### Generate /run/udev
287
with open(os.path.join(rootfs_path, "etc", "init", "udev-db.conf"), "w+") as fd:
288
fd.write("""start on starting udev
291
cp -R /var/lib/host-udev /run/udev
295
### Switch back to upstart instead of systemd
296
with open(os.path.join(rootfs_path, "etc", "X11", "default-display-manager"), "w+") as fd:
299
os.chdir(container_path)
301
files = glob.glob("%s/upstart-sysv_*.deb" % container_path)
306
upstart_file = files[0]
308
if args.redownload or not os.path.exists(upstart_file):
309
if os.path.exists(upstart_file):
310
os.remove(upstart_file)
312
rmadison_cmd = "rmadison -s %s upstart-sysv | cut -d '|' -f 2 | tr -d '[[:space:]]'" % current_release
313
upstart_sysv_ver = subprocess.getoutput(rmadison_cmd)
314
upstart_file = "upstart-sysv_%s_%s.deb" % (upstart_sysv_ver, architecture)
316
dget_url = "http://archive.ubuntu.com/ubuntu/pool/main/u/upstart/%s" % upstart_file
317
subprocess.call(["dget", dget_url])
319
if args.rebuild_rootfs:
320
rootfs_archive_path = os.path.join(rootfs_path, "var", "cache", "apt", "archives")
321
shutil.copy(upstart_file, rootfs_archive_path)
323
start_container(False)
325
print("Switching to upstart...")
326
container.attach_wait(lxc.attach_run_command,
327
["apt-get", "install", "upstart-sysv", "-y", "--no-download"])
200
with open(os.path.join(container_path, 'config'), 'a') as fd:
201
fd.write("lxc.include = " + os.path.join('/', 'usr', 'share', 'unity8-lxc', 'unity8-lxc.conf'))
332
205
# Start a test session