Merge pull request #1417 from mwhudson/install-step-refactor
refactor CurtinInstallStep a bit
This commit is contained in:
commit
60d6746a41
|
@ -438,12 +438,6 @@ class SubiquityModel:
|
||||||
|
|
||||||
def render(self):
|
def render(self):
|
||||||
config = {
|
config = {
|
||||||
'curthooks_commands': {
|
|
||||||
'001-mount-cdrom': [
|
|
||||||
'mount', '--bind', '/cdrom', '/target/cdrom',
|
|
||||||
],
|
|
||||||
},
|
|
||||||
|
|
||||||
'grub': {
|
'grub': {
|
||||||
'terminal': 'unmodified',
|
'terminal': 'unmodified',
|
||||||
'probe_additional_os': True
|
'probe_additional_os': True
|
||||||
|
|
|
@ -278,6 +278,11 @@ class AptConfigurer:
|
||||||
|
|
||||||
await self.cleanup()
|
await self.cleanup()
|
||||||
|
|
||||||
|
async def setup_target(self):
|
||||||
|
# Call this after the rootfs has been extracted to the real target
|
||||||
|
# system but before any configuration is applied to it.
|
||||||
|
await self.mount('/cdrom', '/target/cdrom', options='bind')
|
||||||
|
|
||||||
|
|
||||||
class DryRunAptConfigurer(AptConfigurer):
|
class DryRunAptConfigurer(AptConfigurer):
|
||||||
|
|
||||||
|
|
|
@ -19,7 +19,6 @@ import os
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
import re
|
import re
|
||||||
import shutil
|
import shutil
|
||||||
import subprocess
|
|
||||||
import tempfile
|
import tempfile
|
||||||
from typing import Any, Callable, Dict, List
|
from typing import Any, Callable, Dict, List
|
||||||
|
|
||||||
|
@ -75,14 +74,41 @@ class TracebackExtractor:
|
||||||
|
|
||||||
@attr.s(auto_attribs=True)
|
@attr.s(auto_attribs=True)
|
||||||
class CurtinInstallStep:
|
class CurtinInstallStep:
|
||||||
""" Represents the parameters of a single step (i.e., invocation of curtin
|
"""Represents the parameters of a single invocation of curtin install."""
|
||||||
install). """
|
controller: "InstallController"
|
||||||
name: str
|
name: str
|
||||||
stages: List[str]
|
stages: List[str]
|
||||||
config_file: Path
|
config_file: Path
|
||||||
log_file: Path
|
log_file: Path
|
||||||
error_file: Path
|
error_file: Path
|
||||||
acquire_config: Callable[["CurtinInstallStep", Path], Dict[str, Any]]
|
resume_data_file: Path
|
||||||
|
source: str
|
||||||
|
acquire_config: Callable[["CurtinInstallStep"], Dict[str, Any]]
|
||||||
|
|
||||||
|
@with_context(
|
||||||
|
description="executing curtin install {self.name} step")
|
||||||
|
async def run(self, context):
|
||||||
|
""" Run a curtin install step. """
|
||||||
|
|
||||||
|
self.controller.app.note_file_for_apport(
|
||||||
|
f"Curtin{self.name}Config", str(self.config_file))
|
||||||
|
|
||||||
|
self.controller.write_config(
|
||||||
|
config_file=self.config_file,
|
||||||
|
config=self.acquire_config(self)
|
||||||
|
)
|
||||||
|
|
||||||
|
# Make sure the log directory exists.
|
||||||
|
self.log_file.parent.mkdir(parents=True, exist_ok=True)
|
||||||
|
|
||||||
|
# Add a marker to identify the step in the log file.
|
||||||
|
with open(str(self.log_file), mode="a") as fh:
|
||||||
|
fh.write(f"\n---- [[ subiquity step {self.name} ]] ----\n")
|
||||||
|
|
||||||
|
await run_curtin_command(
|
||||||
|
self.controller.app, context, "install", self.source,
|
||||||
|
"--set", f'json:stages={json.dumps(self.stages)}',
|
||||||
|
config=str(self.config_file), private_mounts=False)
|
||||||
|
|
||||||
|
|
||||||
class InstallController(SubiquityController):
|
class InstallController(SubiquityController):
|
||||||
|
@ -120,19 +146,19 @@ class InstallController(SubiquityController):
|
||||||
config_file.parent.mkdir(parents=True, exist_ok=True)
|
config_file.parent.mkdir(parents=True, exist_ok=True)
|
||||||
generate_config_yaml(str(config_file), config)
|
generate_config_yaml(str(config_file), config)
|
||||||
|
|
||||||
def acquire_generic_config(self, step: CurtinInstallStep,
|
def acquire_generic_config(self,
|
||||||
resume_data_file: Path) -> Dict[str, Any]:
|
step: CurtinInstallStep) -> Dict[str, Any]:
|
||||||
""" Return a dictionary object to be used as the configuration of a
|
""" Return a dictionary object to be used as the configuration of a
|
||||||
generic curtin install step. """
|
generic curtin install step. """
|
||||||
config = self.model.render()
|
config = self.model.render()
|
||||||
config["install"]["log_file"] = str(step.log_file)
|
config["install"]["log_file"] = str(step.log_file)
|
||||||
config["install"]["log_file_append"] = True
|
config["install"]["log_file_append"] = True
|
||||||
config["install"]["error_tarfile"] = str(step.error_file)
|
config["install"]["error_tarfile"] = str(step.error_file)
|
||||||
config["install"]["resume_data"] = str(resume_data_file)
|
config["install"]["resume_data"] = str(step.resume_data_file)
|
||||||
return config
|
return config
|
||||||
|
|
||||||
def acquire_initial_config(self, step: CurtinInstallStep,
|
def acquire_initial_config(self,
|
||||||
resume_data_file: Path) -> Dict[str, Any]:
|
step: CurtinInstallStep) -> Dict[str, Any]:
|
||||||
""" Return a dictionary object to be used as the configuration of the
|
""" Return a dictionary object to be used as the configuration of the
|
||||||
initial curtin install step. """
|
initial curtin install step. """
|
||||||
return {
|
return {
|
||||||
|
@ -144,7 +170,7 @@ class InstallController(SubiquityController):
|
||||||
"log_file": str(step.log_file),
|
"log_file": str(step.log_file),
|
||||||
"log_file_append": True,
|
"log_file_append": True,
|
||||||
"error_tarfile": str(step.error_file),
|
"error_tarfile": str(step.error_file),
|
||||||
"resume_data": str(resume_data_file),
|
"resume_data": str(step.resume_data_file),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -162,34 +188,9 @@ class InstallController(SubiquityController):
|
||||||
configurer = await mirror.wait_config()
|
configurer = await mirror.wait_config()
|
||||||
return await configurer.configure_for_install(context)
|
return await configurer.configure_for_install(context)
|
||||||
|
|
||||||
@with_context(
|
async def setup_target(self, context):
|
||||||
description="executing curtin install {step.name} step")
|
mirror = self.app.controllers.Mirror
|
||||||
async def run_curtin_install_step(
|
await mirror.apt_configurer.setup_target()
|
||||||
self, *, context, step: CurtinInstallStep, resume_data_file: Path,
|
|
||||||
source) -> subprocess.CompletedProcess:
|
|
||||||
""" Run a curtin install step. """
|
|
||||||
|
|
||||||
self.app.note_file_for_apport(
|
|
||||||
f"Curtin{step.name}Config", str(step.config_file))
|
|
||||||
|
|
||||||
self.write_config(
|
|
||||||
config_file=step.config_file,
|
|
||||||
config=step.acquire_config(step, resume_data_file)
|
|
||||||
)
|
|
||||||
|
|
||||||
# Make sure the log directory exists.
|
|
||||||
step.log_file.parent.mkdir(parents=True, exist_ok=True)
|
|
||||||
|
|
||||||
# Add a marker to identify the step in the log file.
|
|
||||||
with open(str(step.log_file), mode="a") as fh:
|
|
||||||
fh.write(f"\n---- [[ subiquity step {step.name} ]] ----\n")
|
|
||||||
|
|
||||||
return await run_curtin_command(
|
|
||||||
self.app, context,
|
|
||||||
"install", source,
|
|
||||||
"--set", f'json:stages={json.dumps(step.stages)}',
|
|
||||||
config=str(step.config_file),
|
|
||||||
private_mounts=False)
|
|
||||||
|
|
||||||
@with_context(
|
@with_context(
|
||||||
description="installing system", level="INFO", childlevel="DEBUG")
|
description="installing system", level="INFO", childlevel="DEBUG")
|
||||||
|
@ -210,45 +211,42 @@ class InstallController(SubiquityController):
|
||||||
|
|
||||||
resume_data_file = Path(tempfile.mkdtemp()) / "resume-data.json"
|
resume_data_file = Path(tempfile.mkdtemp()) / "resume-data.json"
|
||||||
|
|
||||||
await self.run_curtin_install_step(step=CurtinInstallStep(
|
def make_curtin_step(name, stages, acquire_config):
|
||||||
name="initial",
|
return CurtinInstallStep(
|
||||||
stages=[],
|
controller=self,
|
||||||
config_file=config_dir / "subiquity-initial.conf",
|
name=name,
|
||||||
|
stages=stages,
|
||||||
|
config_file=config_dir / f"subiquity-{name}.conf",
|
||||||
log_file=install_log_file,
|
log_file=install_log_file,
|
||||||
error_file=error_file,
|
error_file=error_file,
|
||||||
acquire_config=self.acquire_initial_config,
|
resume_data_file=resume_data_file,
|
||||||
), resume_data_file=resume_data_file,
|
source=source,
|
||||||
context=context, source=source)
|
acquire_config=acquire_config,
|
||||||
|
)
|
||||||
|
|
||||||
generic_steps = [
|
generic_steps = [
|
||||||
CurtinInstallStep(
|
make_curtin_step(
|
||||||
name="partitioning",
|
"initial",
|
||||||
stages=["partitioning"],
|
stages=[],
|
||||||
config_file=config_dir / "subiquity-partitioning.conf",
|
acquire_config=self.acquire_initial_config
|
||||||
log_file=install_log_file,
|
).run,
|
||||||
error_file=error_file,
|
make_curtin_step(
|
||||||
|
name="partitioning", stages=["partitioning"],
|
||||||
acquire_config=self.acquire_generic_config,
|
acquire_config=self.acquire_generic_config,
|
||||||
), CurtinInstallStep(
|
).run,
|
||||||
name="extract",
|
make_curtin_step(
|
||||||
stages=["extract"],
|
name="extract", stages=["extract"],
|
||||||
config_file=config_dir / "subiquity-extract.conf",
|
|
||||||
log_file=install_log_file,
|
|
||||||
error_file=error_file,
|
|
||||||
acquire_config=self.acquire_generic_config,
|
acquire_config=self.acquire_generic_config,
|
||||||
), CurtinInstallStep(
|
).run,
|
||||||
name="curthooks",
|
self.setup_target,
|
||||||
stages=["curthooks"],
|
make_curtin_step(
|
||||||
config_file=config_dir / "subiquity-curthooks.conf",
|
name="curthooks", stages=["curthooks"],
|
||||||
log_file=install_log_file,
|
|
||||||
error_file=error_file,
|
|
||||||
acquire_config=self.acquire_generic_config,
|
acquire_config=self.acquire_generic_config,
|
||||||
),
|
).run,
|
||||||
]
|
]
|
||||||
|
|
||||||
for step in generic_steps:
|
for step in generic_steps:
|
||||||
await self.run_curtin_install_step(
|
await step(context=context)
|
||||||
step=step, resume_data_file=resume_data_file,
|
|
||||||
context=context, source=source)
|
|
||||||
|
|
||||||
@with_context()
|
@with_context()
|
||||||
async def install(self, *, context):
|
async def install(self, *, context):
|
||||||
|
|
|
@ -38,19 +38,19 @@ class TestWriteConfig(unittest.IsolatedAsyncioTestCase):
|
||||||
@patch("subiquity.server.controllers.install.run_curtin_command")
|
@patch("subiquity.server.controllers.install.run_curtin_command")
|
||||||
async def test_run_curtin_install_step(self, run_cmd):
|
async def test_run_curtin_install_step(self, run_cmd):
|
||||||
step = CurtinInstallStep(
|
step = CurtinInstallStep(
|
||||||
name="MyStep",
|
controller=self.controller,
|
||||||
stages=["partitioning", "extract"],
|
name="MyStep",
|
||||||
config_file=Path("/config.yaml"),
|
stages=["partitioning", "extract"],
|
||||||
log_file=Path("/logfile.log"),
|
config_file=Path("/config.yaml"),
|
||||||
error_file=Path("/error.tar"),
|
log_file=Path("/logfile.log"),
|
||||||
acquire_config=self.controller.acquire_initial_config)
|
error_file=Path("/error.tar"),
|
||||||
|
resume_data_file=Path("/resume-data.json"),
|
||||||
|
source="/source",
|
||||||
|
acquire_config=self.controller.acquire_initial_config)
|
||||||
|
|
||||||
with patch("subiquity.server.controllers.install.open",
|
with patch("subiquity.server.controllers.install.open",
|
||||||
mock_open()) as m_open:
|
mock_open()) as m_open:
|
||||||
await self.controller.run_curtin_install_step(
|
await step.run(context=step.controller.context)
|
||||||
step=step,
|
|
||||||
resume_data_file=Path("/resume-data.json"),
|
|
||||||
source="/source")
|
|
||||||
|
|
||||||
m_open.assert_called_once_with("/logfile.log", mode="a")
|
m_open.assert_called_once_with("/logfile.log", mode="a")
|
||||||
|
|
||||||
|
@ -64,15 +64,17 @@ class TestWriteConfig(unittest.IsolatedAsyncioTestCase):
|
||||||
|
|
||||||
def test_acquire_initial_config(self):
|
def test_acquire_initial_config(self):
|
||||||
step = CurtinInstallStep(
|
step = CurtinInstallStep(
|
||||||
name="initial",
|
controller=self.controller,
|
||||||
stages=["initial"],
|
name="initial",
|
||||||
config_file=Path("/config-initial.yaml"),
|
stages=["initial"],
|
||||||
log_file=Path("/logfile-initial.log"),
|
config_file=Path("/config-initial.yaml"),
|
||||||
error_file=Path("/error-initial.tar"),
|
log_file=Path("/logfile-initial.log"),
|
||||||
acquire_config=self.controller.acquire_initial_config)
|
error_file=Path("/error-initial.tar"),
|
||||||
|
resume_data_file=Path("/resume-data.json"),
|
||||||
|
source="/source",
|
||||||
|
acquire_config=self.controller.acquire_initial_config)
|
||||||
|
|
||||||
config = self.controller.acquire_initial_config(
|
config = self.controller.acquire_initial_config(step=step)
|
||||||
step=step, resume_data_file=Path("/resume-data.json"))
|
|
||||||
|
|
||||||
self.assertDictEqual(config, {
|
self.assertDictEqual(config, {
|
||||||
"install": {
|
"install": {
|
||||||
|
@ -89,17 +91,19 @@ class TestWriteConfig(unittest.IsolatedAsyncioTestCase):
|
||||||
|
|
||||||
def test_acquire_generic_config(self):
|
def test_acquire_generic_config(self):
|
||||||
step = CurtinInstallStep(
|
step = CurtinInstallStep(
|
||||||
name="partitioning",
|
controller=self.controller,
|
||||||
stages=["partitioning"],
|
name="partitioning",
|
||||||
config_file=Path("/config-partitioning.yaml"),
|
stages=["partitioning"],
|
||||||
log_file=Path("/logfile-partitioning.log"),
|
config_file=Path("/config-partitioning.yaml"),
|
||||||
error_file=Path("/error-partitioning.tar"),
|
log_file=Path("/logfile-partitioning.log"),
|
||||||
acquire_config=self.controller.acquire_initial_config)
|
error_file=Path("/error-partitioning.tar"),
|
||||||
|
resume_data_file=Path("/resume-data.json"),
|
||||||
|
source="/source",
|
||||||
|
acquire_config=self.controller.acquire_initial_config)
|
||||||
|
|
||||||
with patch.object(self.controller.model, "render",
|
with patch.object(self.controller.model, "render",
|
||||||
return_value={"install": {}}):
|
return_value={"install": {}}):
|
||||||
config = self.controller.acquire_generic_config(
|
config = self.controller.acquire_generic_config(step=step)
|
||||||
step=step, resume_data_file=Path("/resume-data.json"))
|
|
||||||
|
|
||||||
self.assertEqual(config["install"]["log_file"],
|
self.assertEqual(config["install"]["log_file"],
|
||||||
"/logfile-partitioning.log")
|
"/logfile-partitioning.log")
|
||||||
|
|
Loading…
Reference in New Issue