Merge pull request #686 from mwhudson/no-netplan-crash

if netplan apply fails show an error rather than crashing the ui
This commit is contained in:
Dimitri John Ledkov 2020-04-07 09:11:25 +01:00 committed by GitHub
commit 95c20226fd
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 88 additions and 53 deletions

View File

@ -55,6 +55,7 @@ class ErrorReportKind(enum.Enum):
DISK_PROBE_FAIL = _("Disk probe failure")
INSTALL_FAIL = _("Install failure")
UI = _("Installer crash")
NETWORK_FAIL = _("Network error")
UNKNOWN = _("Unknown error")

View File

@ -14,11 +14,16 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import asyncio
import logging
from subiquitycore.async_helpers import schedule_task
from subiquitycore.controllers.network import NetworkController
from subiquity.controller import SubiquityController
from subiquity.controllers.error import ErrorReportKind
log = logging.getLogger("subiquity.controllers.network")
class NetworkController(NetworkController, SubiquityController):
@ -42,6 +47,10 @@ class NetworkController(NetworkController, SubiquityController):
},
}
def __init__(self, app):
super().__init__(app)
app.note_file_for_apport("NetplanConfig", self.netplan_path)
def load_autoinstall_data(self, data):
self.ai_data = data
@ -74,6 +83,20 @@ class NetworkController(NetworkController, SubiquityController):
return r
return super().render_config()
async def _apply_config(self, silent):
try:
await super()._apply_config(silent)
except asyncio.CancelledError:
# asyncio.CancelledError is a subclass of Exception in
# Python 3.6 (sadface)
raise
except Exception:
log.exception("_apply_config failed")
self.model.has_network = False
self.app.make_apport_report(
ErrorReportKind.NETWORK_FAIL, "applying network",
interrupt=True)
def done(self):
self.configured()
super().done()

View File

@ -350,14 +350,14 @@ class Subiquity(Application):
else:
super().unhandled_input(key)
def debug_shell(self):
def debug_shell(self, after_hook=None):
def _before():
os.system("clear")
print(DEBUG_SHELL_INTRO)
self.run_command_in_foreground(
["bash"], before_hook=_before, cwd='/')
["bash"], before_hook=_before, after_hook=after_hook, cwd='/')
def note_file_for_apport(self, key, path):
self._apport_files.append((key, path))

View File

@ -69,6 +69,9 @@ Sorry, there was a problem examining the storage devices on this system.
"""),
ErrorReportKind.INSTALL_FAIL: _("""
Sorry, there was a problem completing the installation.
"""),
ErrorReportKind.NETWORK_FAIL: _("""
Sorry, there was a problem applying the network configuration.
"""),
ErrorReportKind.UI: _("""
Sorry, the installer has restarted because of an error.
@ -106,6 +109,10 @@ devices manually.
You may be able to fix the issue by switching to a shell and
reconfiguring the system's block devices manually.
"""), ['debug_shell', 'continue']),
ErrorReportKind.NETWORK_FAIL: (_("""
You can continue with the installation but it will be assumed the network
is not functional.
"""), ['continue']),
ErrorReportKind.INSTALL_FAIL: (_("""
Do you want to try starting the installation again?
"""), ['restart', 'close']),
@ -241,7 +248,6 @@ class ErrorReportStretchy(Stretchy):
def debug_shell(self, sender):
self.parent.remove_overlay()
self.app.debug_shell()
def restart(self, sender):
self.app.restart()

View File

@ -149,13 +149,16 @@ class NetworkController(BaseController):
os.makedirs(netplan_dir)
with open(netplan_path, 'w') as fp:
fp.write(default_netplan)
self.model.parse_netplan_configs(self.root)
self.parse_netplan_configs()
self._watching = False
self.network_event_receiver = SubiquityNetworkEventReceiver(self.model)
self.network_event_receiver.add_default_route_watcher(
self.route_watcher)
def parse_netplan_configs(self):
self.model.parse_netplan_configs(self.root)
def route_watcher(self, routes):
if routes:
self.signal.emit_signal('network-change')
@ -349,7 +352,7 @@ class NetworkController(BaseController):
self.model.stringify_config(config),
omode="w")
self.model.parse_netplan_configs(self.root)
self.parse_netplan_configs()
async def _apply_config(self, silent):
with self.context.child(
@ -383,58 +386,60 @@ class NetworkController(BaseController):
if not silent and self.view:
self.view.show_apply_spinner()
def error(stage):
if not silent and self.view:
self.view.show_network_error(stage)
try:
def error(stage):
if not silent and self.view:
self.view.show_network_error(stage)
if self.opts.dry_run:
delay = 1/self.app.scale_factor
await arun_command(['sleep', str(delay)])
if os.path.exists('/lib/netplan/generate'):
# If netplan appears to be installed, run generate to at
# least test that what we wrote is acceptable to netplan.
await arun_command(
['netplan', 'generate', '--root', self.root],
check=True)
else:
if devs_to_down or devs_to_delete:
if self.opts.dry_run:
delay = 1/self.app.scale_factor
await arun_command(['sleep', str(delay)])
if os.path.exists('/lib/netplan/generate'):
# If netplan appears to be installed, run generate to
# at least test that what we wrote is acceptable to
# netplan.
await arun_command(
['netplan', 'generate', '--root', self.root],
check=True)
else:
if devs_to_down or devs_to_delete:
try:
await arun_command(
['systemctl', 'mask', '--runtime',
'systemd-networkd.service',
'systemd-networkd.socket'],
check=True)
await arun_command(
['systemctl', 'stop',
'systemd-networkd.service',
'systemd-networkd.socket'],
check=True)
except subprocess.CalledProcessError:
error("stop-networkd")
raise
if devs_to_down:
await self._down_devs(devs_to_down)
if devs_to_delete:
await self._delete_devs(devs_to_delete)
if devs_to_down or devs_to_delete:
await arun_command(
['systemctl', 'unmask', '--runtime',
'systemd-networkd.service',
'systemd-networkd.socket'],
check=True)
try:
await arun_command(
['systemctl', 'mask', '--runtime',
'systemd-networkd.service',
'systemd-networkd.socket'],
check=True)
await arun_command(
['systemctl', 'stop',
'systemd-networkd.service',
'systemd-networkd.socket'],
check=True)
await arun_command(['netplan', 'apply'], check=True)
except subprocess.CalledProcessError:
error("stop-networkd")
error("apply")
raise
if devs_to_down:
await self._down_devs(devs_to_down)
if devs_to_delete:
await self._delete_devs(devs_to_delete)
if devs_to_down or devs_to_delete:
await arun_command(
['systemctl', 'unmask', '--runtime',
'systemd-networkd.service',
'systemd-networkd.socket'],
check=True)
try:
await arun_command(['netplan', 'apply'], check=True)
except subprocess.CalledProcessError:
error("apply")
raise
if devs_to_down or devs_to_delete:
# It's probably running already, but just in case.
await arun_command(
['systemctl', 'start', 'systemd-networkd.socket'],
check=False)
if not silent and self.view:
self.view.hide_apply_spinner()
if devs_to_down or devs_to_delete:
# It's probably running already, but just in case.
await arun_command(
['systemctl', 'start', 'systemd-networkd.socket'],
check=False)
finally:
if not silent and self.view:
self.view.hide_apply_spinner()
if self.answers.get('accept-default', False):
self.done()