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") DISK_PROBE_FAIL = _("Disk probe failure")
INSTALL_FAIL = _("Install failure") INSTALL_FAIL = _("Install failure")
UI = _("Installer crash") UI = _("Installer crash")
NETWORK_FAIL = _("Network error")
UNKNOWN = _("Unknown error") UNKNOWN = _("Unknown error")

View File

@ -14,11 +14,16 @@
# 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 asyncio
import logging
from subiquitycore.async_helpers import schedule_task from subiquitycore.async_helpers import schedule_task
from subiquitycore.controllers.network import NetworkController from subiquitycore.controllers.network import NetworkController
from subiquity.controller import SubiquityController from subiquity.controller import SubiquityController
from subiquity.controllers.error import ErrorReportKind
log = logging.getLogger("subiquity.controllers.network")
class NetworkController(NetworkController, SubiquityController): 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): def load_autoinstall_data(self, data):
self.ai_data = data self.ai_data = data
@ -74,6 +83,20 @@ class NetworkController(NetworkController, SubiquityController):
return r return r
return super().render_config() 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): def done(self):
self.configured() self.configured()
super().done() super().done()

View File

@ -350,14 +350,14 @@ class Subiquity(Application):
else: else:
super().unhandled_input(key) super().unhandled_input(key)
def debug_shell(self): def debug_shell(self, after_hook=None):
def _before(): def _before():
os.system("clear") os.system("clear")
print(DEBUG_SHELL_INTRO) print(DEBUG_SHELL_INTRO)
self.run_command_in_foreground( 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): def note_file_for_apport(self, key, path):
self._apport_files.append((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: _(""" ErrorReportKind.INSTALL_FAIL: _("""
Sorry, there was a problem completing the installation. Sorry, there was a problem completing the installation.
"""),
ErrorReportKind.NETWORK_FAIL: _("""
Sorry, there was a problem applying the network configuration.
"""), """),
ErrorReportKind.UI: _(""" ErrorReportKind.UI: _("""
Sorry, the installer has restarted because of an error. 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 You may be able to fix the issue by switching to a shell and
reconfiguring the system's block devices manually. reconfiguring the system's block devices manually.
"""), ['debug_shell', 'continue']), """), ['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: (_(""" ErrorReportKind.INSTALL_FAIL: (_("""
Do you want to try starting the installation again? Do you want to try starting the installation again?
"""), ['restart', 'close']), """), ['restart', 'close']),
@ -241,7 +248,6 @@ class ErrorReportStretchy(Stretchy):
def debug_shell(self, sender): def debug_shell(self, sender):
self.parent.remove_overlay() self.parent.remove_overlay()
self.app.debug_shell()
def restart(self, sender): def restart(self, sender):
self.app.restart() self.app.restart()

View File

@ -149,13 +149,16 @@ class NetworkController(BaseController):
os.makedirs(netplan_dir) os.makedirs(netplan_dir)
with open(netplan_path, 'w') as fp: with open(netplan_path, 'w') as fp:
fp.write(default_netplan) fp.write(default_netplan)
self.model.parse_netplan_configs(self.root) self.parse_netplan_configs()
self._watching = False self._watching = False
self.network_event_receiver = SubiquityNetworkEventReceiver(self.model) self.network_event_receiver = SubiquityNetworkEventReceiver(self.model)
self.network_event_receiver.add_default_route_watcher( self.network_event_receiver.add_default_route_watcher(
self.route_watcher) self.route_watcher)
def parse_netplan_configs(self):
self.model.parse_netplan_configs(self.root)
def route_watcher(self, routes): def route_watcher(self, routes):
if routes: if routes:
self.signal.emit_signal('network-change') self.signal.emit_signal('network-change')
@ -349,7 +352,7 @@ class NetworkController(BaseController):
self.model.stringify_config(config), self.model.stringify_config(config),
omode="w") omode="w")
self.model.parse_netplan_configs(self.root) self.parse_netplan_configs()
async def _apply_config(self, silent): async def _apply_config(self, silent):
with self.context.child( with self.context.child(
@ -383,6 +386,7 @@ class NetworkController(BaseController):
if not silent and self.view: if not silent and self.view:
self.view.show_apply_spinner() self.view.show_apply_spinner()
try:
def error(stage): def error(stage):
if not silent and self.view: if not silent and self.view:
self.view.show_network_error(stage) self.view.show_network_error(stage)
@ -391,8 +395,9 @@ class NetworkController(BaseController):
delay = 1/self.app.scale_factor delay = 1/self.app.scale_factor
await arun_command(['sleep', str(delay)]) await arun_command(['sleep', str(delay)])
if os.path.exists('/lib/netplan/generate'): if os.path.exists('/lib/netplan/generate'):
# If netplan appears to be installed, run generate to at # If netplan appears to be installed, run generate to
# least test that what we wrote is acceptable to netplan. # at least test that what we wrote is acceptable to
# netplan.
await arun_command( await arun_command(
['netplan', 'generate', '--root', self.root], ['netplan', 'generate', '--root', self.root],
check=True) check=True)
@ -432,7 +437,7 @@ class NetworkController(BaseController):
await arun_command( await arun_command(
['systemctl', 'start', 'systemd-networkd.socket'], ['systemctl', 'start', 'systemd-networkd.socket'],
check=False) check=False)
finally:
if not silent and self.view: if not silent and self.view:
self.view.hide_apply_spinner() self.view.hide_apply_spinner()