move reboot controller (the last one!) to new world
This commit is contained in:
parent
4367f8f97c
commit
303c0d75d6
|
@ -40,9 +40,6 @@ subiquity/common/tests/__init__.py
|
||||||
subiquity/common/tests/test_filesystem.py
|
subiquity/common/tests/test_filesystem.py
|
||||||
subiquity/common/tests/test_keyboard.py
|
subiquity/common/tests/test_keyboard.py
|
||||||
subiquity/common/types.py
|
subiquity/common/types.py
|
||||||
subiquity/controller.py
|
|
||||||
subiquity/controllers/__init__.py
|
|
||||||
subiquity/controllers/reboot.py
|
|
||||||
subiquitycore/async_helpers.py
|
subiquitycore/async_helpers.py
|
||||||
subiquitycore/contextlib38.py
|
subiquitycore/contextlib38.py
|
||||||
subiquitycore/context.py
|
subiquitycore/context.py
|
||||||
|
@ -129,6 +126,7 @@ subiquity/server/controllers/mirror.py
|
||||||
subiquity/server/controllers/network.py
|
subiquity/server/controllers/network.py
|
||||||
subiquity/server/controllers/package.py
|
subiquity/server/controllers/package.py
|
||||||
subiquity/server/controllers/proxy.py
|
subiquity/server/controllers/proxy.py
|
||||||
|
subiquity/server/controllers/reboot.py
|
||||||
subiquity/server/controllers/refresh.py
|
subiquity/server/controllers/refresh.py
|
||||||
subiquity/server/controllers/reporting.py
|
subiquity/server/controllers/reporting.py
|
||||||
subiquity/server/controllers/snaplist.py
|
subiquity/server/controllers/snaplist.py
|
||||||
|
|
|
@ -186,6 +186,9 @@ class API:
|
||||||
class status:
|
class status:
|
||||||
def GET(cur: Optional[InstallState] = None) -> InstallStatus: ...
|
def GET(cur: Optional[InstallState] = None) -> InstallStatus: ...
|
||||||
|
|
||||||
|
class reboot:
|
||||||
|
def POST(): ...
|
||||||
|
|
||||||
|
|
||||||
class LinkAction(enum.Enum):
|
class LinkAction(enum.Enum):
|
||||||
NEW = enum.auto()
|
NEW = enum.auto()
|
||||||
|
|
|
@ -1,138 +0,0 @@
|
||||||
# Copyright 2019 Canonical, Ltd.
|
|
||||||
#
|
|
||||||
# This program is free software: you can redistribute it and/or modify
|
|
||||||
# it under the terms of the GNU Affero General Public License as
|
|
||||||
# published by the Free Software Foundation, either version 3 of the
|
|
||||||
# License, or (at your option) any later version.
|
|
||||||
#
|
|
||||||
# This program is distributed in the hope that it will be useful,
|
|
||||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
# GNU Affero General Public License for more details.
|
|
||||||
#
|
|
||||||
# You should have received a copy of the GNU Affero General Public License
|
|
||||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
import json
|
|
||||||
import logging
|
|
||||||
import os
|
|
||||||
|
|
||||||
import jsonschema
|
|
||||||
|
|
||||||
from subiquitycore.context import with_context
|
|
||||||
from subiquitycore.controller import (
|
|
||||||
BaseController,
|
|
||||||
)
|
|
||||||
from subiquitycore.tuicontroller import (
|
|
||||||
RepeatedController,
|
|
||||||
TuiController,
|
|
||||||
)
|
|
||||||
|
|
||||||
log = logging.getLogger("subiquity.controller")
|
|
||||||
|
|
||||||
|
|
||||||
class Confirm(Exception):
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
class SubiquityController(BaseController):
|
|
||||||
|
|
||||||
autoinstall_key = None
|
|
||||||
autoinstall_schema = None
|
|
||||||
autoinstall_default = None
|
|
||||||
|
|
||||||
def __init__(self, app):
|
|
||||||
super().__init__(app)
|
|
||||||
self.autoinstall_applied = False
|
|
||||||
self.context.set('controller', self)
|
|
||||||
|
|
||||||
def interactive(self):
|
|
||||||
return False
|
|
||||||
|
|
||||||
def setup_autoinstall(self):
|
|
||||||
if self.app.autoinstall_config:
|
|
||||||
with self.context.child("load_autoinstall_data"):
|
|
||||||
ai_data = self.app.autoinstall_config.get(
|
|
||||||
self.autoinstall_key,
|
|
||||||
self.autoinstall_default)
|
|
||||||
if ai_data is not None and self.autoinstall_schema is not None:
|
|
||||||
jsonschema.validate(ai_data, self.autoinstall_schema)
|
|
||||||
self.load_autoinstall_data(ai_data)
|
|
||||||
|
|
||||||
def load_autoinstall_data(self, data):
|
|
||||||
"""Load autoinstall data.
|
|
||||||
|
|
||||||
This is called if there is an autoinstall happening. This
|
|
||||||
controller may not have any data, and this controller may still
|
|
||||||
be interactive.
|
|
||||||
"""
|
|
||||||
pass
|
|
||||||
|
|
||||||
@with_context()
|
|
||||||
async def apply_autoinstall_config(self, context):
|
|
||||||
"""Apply autoinstall configuration.
|
|
||||||
|
|
||||||
This is only called for a non-interactive controller. It should
|
|
||||||
block until the configuration has been applied. (self.configured()
|
|
||||||
is called after this is done).
|
|
||||||
"""
|
|
||||||
pass
|
|
||||||
|
|
||||||
def configured(self):
|
|
||||||
"""Let the world know that this controller's model is now configured.
|
|
||||||
"""
|
|
||||||
with open(self.app.state_path('states', self.name), 'w') as fp:
|
|
||||||
json.dump(self.serialize(), fp)
|
|
||||||
if self.model_name is not None:
|
|
||||||
self.app.base_model.configured(self.model_name)
|
|
||||||
|
|
||||||
def load_state(self):
|
|
||||||
state_path = self.app.state_path('states', self.name)
|
|
||||||
if not os.path.exists(state_path):
|
|
||||||
return
|
|
||||||
with open(state_path) as fp:
|
|
||||||
self.deserialize(json.load(fp))
|
|
||||||
|
|
||||||
def deserialize(self, state):
|
|
||||||
pass
|
|
||||||
|
|
||||||
def make_autoinstall(self):
|
|
||||||
return {}
|
|
||||||
|
|
||||||
|
|
||||||
class SubiquityTuiController(SubiquityController, TuiController):
|
|
||||||
|
|
||||||
def interactive(self):
|
|
||||||
if not self.app.autoinstall_config:
|
|
||||||
return True
|
|
||||||
i_sections = self.app.autoinstall_config.get(
|
|
||||||
'interactive-sections', [])
|
|
||||||
return '*' in i_sections or self.autoinstall_key in i_sections
|
|
||||||
|
|
||||||
|
|
||||||
class RepeatedController(RepeatedController):
|
|
||||||
|
|
||||||
autoinstall_key = None
|
|
||||||
autoinstall_schema = None
|
|
||||||
|
|
||||||
def __init__(self, orig, index):
|
|
||||||
super().__init__(orig, index)
|
|
||||||
self.autoinstall_applied = False
|
|
||||||
|
|
||||||
def setup_autoinstall(self):
|
|
||||||
pass
|
|
||||||
|
|
||||||
async def apply_autoinstall_config(self):
|
|
||||||
await self.orig.apply_autoinstall_config(index=self.index)
|
|
||||||
|
|
||||||
def configured(self):
|
|
||||||
self.orig.configured()
|
|
||||||
|
|
||||||
def interactive(self):
|
|
||||||
return self.orig.interactive()
|
|
||||||
|
|
||||||
def make_autoinstall(self):
|
|
||||||
return {}
|
|
||||||
|
|
||||||
def load_state(self):
|
|
||||||
pass
|
|
|
@ -1,20 +0,0 @@
|
||||||
# Copyright 2020 Canonical, Ltd.
|
|
||||||
#
|
|
||||||
# This program is free software: you can redistribute it and/or modify
|
|
||||||
# it under the terms of the GNU Affero General Public License as
|
|
||||||
# published by the Free Software Foundation, either version 3 of the
|
|
||||||
# License, or (at your option) any later version.
|
|
||||||
#
|
|
||||||
# This program is distributed in the hope that it will be useful,
|
|
||||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
# GNU Affero General Public License for more details.
|
|
||||||
#
|
|
||||||
# You should have received a copy of the GNU Affero General Public License
|
|
||||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
from .reboot import RebootController
|
|
||||||
|
|
||||||
__all__ = [
|
|
||||||
'RebootController',
|
|
||||||
]
|
|
|
@ -24,6 +24,7 @@ from .mirror import MirrorController
|
||||||
from .network import NetworkController
|
from .network import NetworkController
|
||||||
from .package import PackageController
|
from .package import PackageController
|
||||||
from .proxy import ProxyController
|
from .proxy import ProxyController
|
||||||
|
from .reboot import RebootController
|
||||||
from .refresh import RefreshController
|
from .refresh import RefreshController
|
||||||
from .reporting import ReportingController
|
from .reporting import ReportingController
|
||||||
from .snaplist import SnapListController
|
from .snaplist import SnapListController
|
||||||
|
@ -45,6 +46,7 @@ __all__ = [
|
||||||
'NetworkController',
|
'NetworkController',
|
||||||
'PackageController',
|
'PackageController',
|
||||||
'ProxyController',
|
'ProxyController',
|
||||||
|
'RebootController',
|
||||||
'RefreshController',
|
'RefreshController',
|
||||||
'ReportingController',
|
'ReportingController',
|
||||||
'SnapListController',
|
'SnapListController',
|
||||||
|
|
|
@ -13,28 +13,49 @@
|
||||||
# You should have received a copy of the GNU Affero General Public License
|
# You should have received a copy of the GNU Affero General Public License
|
||||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
import asyncio
|
||||||
import logging
|
import logging
|
||||||
import os
|
import os
|
||||||
import platform
|
import platform
|
||||||
import subprocess
|
import subprocess
|
||||||
|
|
||||||
from subiquitycore.async_helpers import schedule_task
|
|
||||||
from subiquitycore.context import with_context
|
from subiquitycore.context import with_context
|
||||||
from subiquitycore.utils import arun_command, run_command
|
from subiquitycore.utils import arun_command, run_command
|
||||||
|
|
||||||
from subiquity.controller import SubiquityTuiController
|
from subiquity.common.apidef import API
|
||||||
|
from subiquity.server.controller import SubiquityController
|
||||||
|
from subiquity.server.controllers.install import InstallState
|
||||||
|
|
||||||
log = logging.getLogger("subiquity.controllers.restart")
|
log = logging.getLogger("subiquity.controllers.restart")
|
||||||
|
|
||||||
|
|
||||||
class RebootController(SubiquityTuiController):
|
class RebootController(SubiquityController):
|
||||||
|
|
||||||
|
endpoint = API.reboot
|
||||||
|
|
||||||
def __init__(self, app):
|
def __init__(self, app):
|
||||||
super().__init__(app)
|
super().__init__(app)
|
||||||
self.context.set('hidden', True)
|
self.user_reboot_event = asyncio.Event()
|
||||||
|
self.rebooting_event = asyncio.Event()
|
||||||
|
|
||||||
def interactive(self):
|
async def POST(self):
|
||||||
return self.app.interactive()
|
self.app.controllers.Install.stop_uu()
|
||||||
|
self.user_reboot_event.set()
|
||||||
|
await self.rebooting_event.wait()
|
||||||
|
|
||||||
|
def start(self):
|
||||||
|
self.app.aio_loop.create_task(self._run())
|
||||||
|
|
||||||
|
async def _run(self):
|
||||||
|
Install = self.app.controllers.Install
|
||||||
|
await Install.install_task
|
||||||
|
await self.app.controllers.Late.run_event.wait()
|
||||||
|
await self.copy_logs_to_target()
|
||||||
|
if self.app.interactive():
|
||||||
|
await self.user_reboot_event.wait()
|
||||||
|
self.reboot()
|
||||||
|
elif Install.install_state == InstallState.DONE:
|
||||||
|
self.reboot()
|
||||||
|
|
||||||
@with_context()
|
@with_context()
|
||||||
async def copy_logs_to_target(self, context):
|
async def copy_logs_to_target(self, context):
|
||||||
|
@ -56,27 +77,12 @@ class RebootController(SubiquityTuiController):
|
||||||
except Exception:
|
except Exception:
|
||||||
log.exception("saving journal failed")
|
log.exception("saving journal failed")
|
||||||
|
|
||||||
def reboot(self):
|
@with_context()
|
||||||
|
def reboot(self, context):
|
||||||
|
self.rebooting_event.set()
|
||||||
if self.opts.dry_run:
|
if self.opts.dry_run:
|
||||||
self.app.exit()
|
self.app.exit()
|
||||||
else:
|
else:
|
||||||
if platform.machine() == 's390x':
|
if platform.machine() == 's390x':
|
||||||
run_command(["chreipl", "/target/boot"])
|
run_command(["chreipl", "/target/boot"])
|
||||||
run_command(["/sbin/reboot"])
|
run_command(["/sbin/reboot"])
|
||||||
|
|
||||||
@with_context()
|
|
||||||
async def apply_autoinstall_config(self, context):
|
|
||||||
await self.copy_logs_to_target(context=context)
|
|
||||||
self.reboot()
|
|
||||||
|
|
||||||
async def _run(self):
|
|
||||||
await self.copy_logs_to_target()
|
|
||||||
await self.app.controllers.InstallProgress.reboot_clicked.wait()
|
|
||||||
self.reboot()
|
|
||||||
|
|
||||||
def make_ui(self):
|
|
||||||
schedule_task(self._run())
|
|
||||||
return self.ui.body
|
|
||||||
|
|
||||||
def cancel(self):
|
|
||||||
pass
|
|
|
@ -131,6 +131,7 @@ class SubiquityServer(Application):
|
||||||
"SnapList",
|
"SnapList",
|
||||||
"Install",
|
"Install",
|
||||||
"Late",
|
"Late",
|
||||||
|
"Reboot",
|
||||||
]
|
]
|
||||||
|
|
||||||
def make_model(self):
|
def make_model(self):
|
||||||
|
|
|
@ -36,8 +36,6 @@ class SubiquityUI(SubiquityCoreUI):
|
||||||
return super().keypress(size, key)
|
return super().keypress(size, key)
|
||||||
|
|
||||||
def set_body(self, widget):
|
def set_body(self, widget):
|
||||||
if widget is self.body:
|
|
||||||
return
|
|
||||||
super().set_body(widget)
|
super().set_body(widget)
|
||||||
if isinstance(widget, BaseView):
|
if isinstance(widget, BaseView):
|
||||||
for overlay in self.app.global_overlays:
|
for overlay in self.app.global_overlays:
|
||||||
|
|
Loading…
Reference in New Issue