implement the bulk of subiquity-configure-apt in the server process
This uses a kind of crazy approach where the hook script we get curtin to run makes an API call to the server process to do the actual configuration. I can't work out if this is genius or insane or both but anyway it is only a step on to the way to doing the apt configuration before we start curtin so it won't be around for long.
This commit is contained in:
parent
71b1261731
commit
b951216920
|
@ -1,67 +1,3 @@
|
||||||
#!/bin/bash -eux
|
#!/bin/bash -eux
|
||||||
|
|
||||||
# Configure apt so that installs from the pool on the cdrom are preferred
|
curl --fail --unix-socket /run/subiquity/socket --data '' a/install/configure_apt
|
||||||
# during installation but not in the installed system.
|
|
||||||
#
|
|
||||||
# This has a few steps.
|
|
||||||
#
|
|
||||||
# 1. As the remaining steps mean that any changes to apt configuration are do
|
|
||||||
# not persist into the installed system, we get curtin to configure apt a
|
|
||||||
# bit earlier than it would by default.
|
|
||||||
#
|
|
||||||
# 2. Bind-mount the cdrom into the installed system as /run/cdrom
|
|
||||||
#
|
|
||||||
# 3. Set up an overlay over /target/etc/apt. This means that any changes we
|
|
||||||
# make will not persist into the installed system and we do not have to
|
|
||||||
# worry about cleaning up after ourselves.
|
|
||||||
#
|
|
||||||
# 4. Configure apt in /target to look at the pool on the cdrom. This has two
|
|
||||||
# subcases:
|
|
||||||
#
|
|
||||||
# a. if we expect the network to be working, this basically means
|
|
||||||
# prepending "deb file:///run/cdrom $(lsb_release -sc) main restricted"
|
|
||||||
# to the sources.list file.
|
|
||||||
#
|
|
||||||
# b. if the network is not expected to be working, we replace the
|
|
||||||
# sources.list with a file just referencing the cdrom.
|
|
||||||
#
|
|
||||||
# 5. If the network is not expected to be working, we also set up an overlay
|
|
||||||
# over /target/var/lib/apt/lists (if the network is working, we'll run "apt
|
|
||||||
# update" after the /target/etc/apt overlay has been cleared).
|
|
||||||
|
|
||||||
if [ -z "$TARGET_MOUNT_POINT" ]; then
|
|
||||||
# Nothing good can happen from running this script without
|
|
||||||
# TARGET_MOUNT_POINT set.
|
|
||||||
exit 1;
|
|
||||||
fi
|
|
||||||
|
|
||||||
PY=$1
|
|
||||||
HAS_NETWORK=$2
|
|
||||||
|
|
||||||
$PY -m curtin apt-config
|
|
||||||
|
|
||||||
setup_overlay () {
|
|
||||||
local dir=$1
|
|
||||||
local t=$(mktemp -d)
|
|
||||||
mkdir $t/work $t/upper
|
|
||||||
mount -t overlay overlay -o lowerdir=$dir,workdir=$t/work,upperdir=$t/upper $dir
|
|
||||||
}
|
|
||||||
|
|
||||||
setup_overlay $TARGET_MOUNT_POINT/etc/apt
|
|
||||||
|
|
||||||
mkdir -p "$TARGET_MOUNT_POINT/cdrom"
|
|
||||||
mount --bind /cdrom "$TARGET_MOUNT_POINT/cdrom"
|
|
||||||
|
|
||||||
if [ $HAS_NETWORK = 'true' ]; then
|
|
||||||
mv "$TARGET_MOUNT_POINT/etc/apt/sources.list" "$TARGET_MOUNT_POINT/etc/apt/sources.list.d/original.list"
|
|
||||||
else
|
|
||||||
# Do not use the configured proxy during the install if one was configured.
|
|
||||||
rm -f $TARGET_MOUNT_POINT/etc/apt/apt.conf.d/90curtin-aptproxy
|
|
||||||
setup_overlay $TARGET_MOUNT_POINT/var/lib/apt/lists
|
|
||||||
fi
|
|
||||||
|
|
||||||
cat > "$TARGET_MOUNT_POINT/etc/apt/sources.list" <<EOF
|
|
||||||
deb [check-date=no] file:///cdrom $(chroot $TARGET_MOUNT_POINT lsb_release -sc) main restricted
|
|
||||||
EOF
|
|
||||||
|
|
||||||
$PY -m curtin in-target -- apt-get update
|
|
||||||
|
|
|
@ -294,6 +294,11 @@ class API:
|
||||||
def GET() -> TimeZoneInfo: ...
|
def GET() -> TimeZoneInfo: ...
|
||||||
def POST(tz: str): ...
|
def POST(tz: str): ...
|
||||||
|
|
||||||
|
class install:
|
||||||
|
class configure_apt:
|
||||||
|
def POST():
|
||||||
|
"Not for client use."
|
||||||
|
|
||||||
class shutdown:
|
class shutdown:
|
||||||
def POST(mode: ShutdownMode, immediate: bool = False): ...
|
def POST(mode: ShutdownMode, immediate: bool = False): ...
|
||||||
|
|
||||||
|
|
|
@ -18,7 +18,6 @@ from collections import OrderedDict
|
||||||
import functools
|
import functools
|
||||||
import logging
|
import logging
|
||||||
import os
|
import os
|
||||||
import sys
|
|
||||||
import uuid
|
import uuid
|
||||||
import yaml
|
import yaml
|
||||||
|
|
||||||
|
@ -338,7 +337,6 @@ class SubiquityModel:
|
||||||
'curthooks_commands': {
|
'curthooks_commands': {
|
||||||
'001-configure-apt': [
|
'001-configure-apt': [
|
||||||
resource_path('bin/subiquity-configure-apt'),
|
resource_path('bin/subiquity-configure-apt'),
|
||||||
sys.executable, str(self.network.has_network).lower(),
|
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
|
@ -18,6 +18,7 @@ import logging
|
||||||
import os
|
import os
|
||||||
import re
|
import re
|
||||||
import shutil
|
import shutil
|
||||||
|
import tempfile
|
||||||
|
|
||||||
from curtin.commands.install import (
|
from curtin.commands.install import (
|
||||||
ERROR_TARFILE,
|
ERROR_TARFILE,
|
||||||
|
@ -31,7 +32,9 @@ from subiquitycore.async_helpers import (
|
||||||
run_in_thread,
|
run_in_thread,
|
||||||
)
|
)
|
||||||
from subiquitycore.context import with_context
|
from subiquitycore.context import with_context
|
||||||
|
from subiquitycore.lsb_release import lsb_release
|
||||||
|
|
||||||
|
from subiquity.common.apidef import API
|
||||||
from subiquity.common.errorreport import ErrorReportKind
|
from subiquity.common.errorreport import ErrorReportKind
|
||||||
from subiquity.common.types import (
|
from subiquity.common.types import (
|
||||||
ApplicationState,
|
ApplicationState,
|
||||||
|
@ -47,7 +50,6 @@ from subiquity.server.controller import (
|
||||||
SubiquityController,
|
SubiquityController,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
log = logging.getLogger("subiquity.server.controllers.install")
|
log = logging.getLogger("subiquity.server.controllers.install")
|
||||||
|
|
||||||
|
|
||||||
|
@ -72,6 +74,8 @@ class TracebackExtractor:
|
||||||
|
|
||||||
class InstallController(SubiquityController):
|
class InstallController(SubiquityController):
|
||||||
|
|
||||||
|
endpoint = API.install
|
||||||
|
|
||||||
def __init__(self, app):
|
def __init__(self, app):
|
||||||
super().__init__(app)
|
super().__init__(app)
|
||||||
self.model = app.base_model
|
self.model = app.base_model
|
||||||
|
@ -80,6 +84,9 @@ class InstallController(SubiquityController):
|
||||||
self.unattended_upgrades_ctx = None
|
self.unattended_upgrades_ctx = None
|
||||||
self.tb_extractor = TracebackExtractor()
|
self.tb_extractor = TracebackExtractor()
|
||||||
|
|
||||||
|
def interactive(self):
|
||||||
|
return True
|
||||||
|
|
||||||
def stop_uu(self):
|
def stop_uu(self):
|
||||||
if self.app.state == ApplicationState.UU_RUNNING:
|
if self.app.state == ApplicationState.UU_RUNNING:
|
||||||
self.app.update_state(ApplicationState.UU_CANCELLING)
|
self.app.update_state(ApplicationState.UU_CANCELLING)
|
||||||
|
@ -147,14 +154,14 @@ class InstallController(SubiquityController):
|
||||||
|
|
||||||
self.app.update_state(ApplicationState.RUNNING)
|
self.app.update_state(ApplicationState.RUNNING)
|
||||||
|
|
||||||
config_location = self.write_config()
|
self.config_location = self.write_config()
|
||||||
|
|
||||||
if os.path.exists(self.model.target):
|
if os.path.exists(self.model.target):
|
||||||
await self.unmount_target(
|
await self.unmount_target(
|
||||||
context=context, target=self.model.target)
|
context=context, target=self.model.target)
|
||||||
|
|
||||||
await self.curtin_install(
|
await self.curtin_install(
|
||||||
context=context, config_location=config_location)
|
context=context, config_location=self.config_location)
|
||||||
|
|
||||||
self.app.update_state(ApplicationState.POST_WAIT)
|
self.app.update_state(ApplicationState.POST_WAIT)
|
||||||
|
|
||||||
|
@ -257,6 +264,88 @@ class InstallController(SubiquityController):
|
||||||
self.unattended_upgrades_cmd is not None:
|
self.unattended_upgrades_cmd is not None:
|
||||||
self.unattended_upgrades_cmd.proc.terminate()
|
self.unattended_upgrades_cmd.proc.terminate()
|
||||||
|
|
||||||
|
async def configure_apt_POST(self, context):
|
||||||
|
# Configure apt so that installs from the pool on the cdrom are
|
||||||
|
# preferred during installation but not in the installed system.
|
||||||
|
#
|
||||||
|
# This has a few steps.
|
||||||
|
#
|
||||||
|
# 1. As the remaining steps mean that any changes to apt configuration
|
||||||
|
# are do not persist into the installed system, we get curtin to
|
||||||
|
# configure apt a bit earlier than it would by default.
|
||||||
|
#
|
||||||
|
# 2. Bind-mount the cdrom into the installed system as /cdrom.
|
||||||
|
#
|
||||||
|
# 3. Set up an overlay over /target/etc/apt. This means that any
|
||||||
|
# changes we make will not persist into the installed system and we
|
||||||
|
# do not have to worry about cleaning up after ourselves.
|
||||||
|
#
|
||||||
|
# 4. Configure apt in /target to look at the pool on the cdrom. This
|
||||||
|
# has two subcases:
|
||||||
|
#
|
||||||
|
# a. if we expect the network to be working, this basically means
|
||||||
|
# prepending
|
||||||
|
# "deb file:///run/cdrom $(lsb_release -sc) main restricted"
|
||||||
|
# to the sources.list file.
|
||||||
|
#
|
||||||
|
# b. if the network is not expected to be working, we replace the
|
||||||
|
# sources.list with a file just referencing the cdrom.
|
||||||
|
#
|
||||||
|
# 5. If the network is not expected to be working, we also set up an
|
||||||
|
# overlay over /target/var/lib/apt/lists (if the network is working,
|
||||||
|
# we'll run "apt update" after the /target/etc/apt overlay has been
|
||||||
|
# cleared).
|
||||||
|
|
||||||
|
async def mount(device, mountpoint, options=None, type=None):
|
||||||
|
opts = []
|
||||||
|
if options is not None:
|
||||||
|
opts.extend(['-o', options])
|
||||||
|
if type is not None:
|
||||||
|
opts.extend(['-t', type])
|
||||||
|
await self.app.command_runner.run(
|
||||||
|
['mount'] + opts + [device, mountpoint])
|
||||||
|
|
||||||
|
async def unmount(mountpoint):
|
||||||
|
await self.app.command_runner.run(['umount', mountpoint])
|
||||||
|
|
||||||
|
async def setup_overlay(dir):
|
||||||
|
tdir = tempfile.mkdtemp()
|
||||||
|
w = f'{tdir}/work'
|
||||||
|
u = f'{tdir}/upper'
|
||||||
|
for d in w, u:
|
||||||
|
os.mkdir(d)
|
||||||
|
await mount(
|
||||||
|
'overlay', dir, type='overlay',
|
||||||
|
options=f'lowerdir={dir},upperdir={u},workdir={w}')
|
||||||
|
|
||||||
|
await run_curtin_command(
|
||||||
|
self.app, context, 'apt-config', '-t', self.tpath(),
|
||||||
|
config=self.config_location)
|
||||||
|
|
||||||
|
await setup_overlay(self.tpath('etc/apt'))
|
||||||
|
|
||||||
|
os.mkdir(self.tpath('cdrom'))
|
||||||
|
await mount('/cdrom', self.tpath('cdrom'), options='bind')
|
||||||
|
|
||||||
|
if self.model.network.has_network:
|
||||||
|
os.rename(
|
||||||
|
self.tpath('etc/apt/sources.list'),
|
||||||
|
self.tpath('etc/apt/sources.list.d/original.list'))
|
||||||
|
else:
|
||||||
|
os.unlink(self.tpath('etc/apt/apt.conf.d/90curtin-aptproxy'))
|
||||||
|
await setup_overlay(self.tpath('var/lib/apt/lists'))
|
||||||
|
|
||||||
|
codename = lsb_release()['codename']
|
||||||
|
|
||||||
|
write_file(
|
||||||
|
self.tpath('etc/apt/sources.list'),
|
||||||
|
f'deb [check-date=no] file:///cdrom {codename} main restricted\n',
|
||||||
|
)
|
||||||
|
|
||||||
|
await run_curtin_command(
|
||||||
|
self.app, context, "in-target", "-t", self.tpath(),
|
||||||
|
"--", "apt-get", "update")
|
||||||
|
|
||||||
|
|
||||||
uu_apt_conf = b"""\
|
uu_apt_conf = b"""\
|
||||||
# Config for the unattended-upgrades run to avoid failing on battery power or
|
# Config for the unattended-upgrades run to avoid failing on battery power or
|
||||||
|
|
Loading…
Reference in New Issue