def default(self, index=1): from subiquity.ui.views.refresh import RefreshView if self.updated: raise Skip() show = False if index == 1: if self.check_state == CheckState.AVAILABLE: show = True self.offered_first_time = True elif index == 2: if not self.offered_first_time: if self.check_state in [ CheckState.AVAILABLE, CheckState.CHECKING ]: show = True else: raise AssertionError("unexpected index {}".format(index)) if show: self.view = RefreshView(self) self.ui.set_body(self.view) if 'update' in self.answers: if self.answers['update']: self.view.update() else: self.done() else: raise Skip()
def make_ui(self, index=1): if self.app.updated: raise Skip() show = False if index == 1: if self.status.availability == RefreshCheckState.AVAILABLE: show = True self.offered_first_time = True elif index == 2: if not self.offered_first_time: if self.status.availability in [ RefreshCheckState.UNKNOWN, RefreshCheckState.AVAILABLE ]: show = True else: raise AssertionError("unexpected index {}".format(index)) if show: return RefreshView(self) else: raise Skip()
def start_ui(self, index=1): from subiquity.ui.views.refresh import RefreshView if self.app.updated: raise Skip() show = False if index == 1: if self.check_state == CheckState.AVAILABLE: show = True self.offered_first_time = True elif index == 2: if not self.offered_first_time: if self.check_state in [ CheckState.UNKNOWN, CheckState.AVAILABLE ]: show = True else: raise AssertionError("unexpected index {}".format(index)) if show: self.ui.set_body(RefreshView(self)) else: raise Skip()
class RefreshController(BaseController): signals = [ ('snapd-network-change', 'snapd_network_changed'), ] def __init__(self, common): super().__init__(common) self.snap_name = os.environ.get("SNAP_NAME", "subiquity") self.check_state = CheckState.NOT_STARTED self.switch_state = SwitchState.NOT_STARTED self.network_state = "down" self.current_snap_version = "unknown" self.new_snap_version = "" self.view = None self.offered_first_time = False self.answers = self.all_answers.get("Refresh", {}) def start(self): self.switch_state = SwitchState.SWITCHING self.run_in_bg(self._bg_get_snap_details, self._got_snap_details) def _bg_get_snap_details(self): return self.snapd_connection.get( 'v2/snaps/{snap_name}'.format(snap_name=self.snap_name)) def _got_snap_details(self, fut): try: response = fut.result() response.raise_for_status() except requests.exceptions.RequestException: log.exception("_got_snap_details") else: r = response.json() self.current_snap_version = r['result']['version'] log.debug("current version of snap is: %r", self.current_snap_version) channel = self.get_refresh_channel() self.run_in_bg(lambda: self._bg_switch_snap(channel), self._snap_switched) def get_refresh_channel(self): """Return the channel we should refresh subiquity to.""" if 'channel' in self.answers: return self.answers['channel'] with open('/proc/cmdline') as fp: cmdline = fp.read() prefix = "subiquity-channel=" for arg in cmdline.split(): if arg.startswith(prefix): log.debug("found cmdline arg %s", arg) return arg[len(prefix):] info_file = '/cdrom/.disk/info' try: fp = open(info_file) except FileNotFoundError: if self.opts.dry_run: info = ('Ubuntu-Server 18.04.2 LTS "Bionic Beaver" - ' 'Release amd64 (20190214.3)') else: log.debug("failed to find .disk/info file") return else: with fp: info = fp.read() release = info.split()[1] return 'stable/ubuntu-' + release def _bg_switch_snap(self, channel): log.debug("switching %s to %s", self.snap_name, channel) try: response = self.snapd_connection.post( 'v2/snaps/{}'.format(self.snap_name), { 'action': 'switch', 'channel': channel }) response.raise_for_status() except requests.exceptions.RequestException: log.exception("switching") return change = response.json()["change"] while True: try: response = self.snapd_connection.get( 'v2/changes/{}'.format(change)) response.raise_for_status() except requests.exceptions.RequestException: log.exception("checking switch") return if response.json()["result"]["status"] == "Done": return True time.sleep(0.1) def _snap_switched(self, fut): log.debug("snap switching completed") try: success = fut.result() except Exception: log.exception("_snap_switched") return if not success: return self.switch_state = SwitchState.SWITCHED self._maybe_check_for_update() def snapd_network_changed(self): self.network_state = "up" self._maybe_check_for_update() def _maybe_check_for_update(self): # If we have not yet switched to the right channel, wait. if self.switch_state != SwitchState.SWITCHED: return # If the network is not yet up, wait. if self.network_state == "down": return # If we restarted into this version, don't check for a new version. if self.updated: return # If we got an answer, don't check again. if self.check_state.is_definite(): return self.check_state = CheckState.CHECKING self.run_in_bg(self._bg_check_for_update, self._check_result) def _bg_check_for_update(self): return self.snapd_connection.get('v2/find', select='refresh') def _check_result(self, fut): # If we managed to send concurrent requests and one has # already provided an answer, just forget all about the other # one! if self.check_state.is_definite(): return try: response = fut.result() response.raise_for_status() except requests.exceptions.RequestException as e: log.exception("checking for update") self.check_error = e self.check_state = CheckState.FAILED else: result = response.json() log.debug("_check_result %s", result) for snap in result["result"]: if snap["name"] == self.snap_name: self.check_state = CheckState.AVAILABLE self.new_snap_version = snap["version"] log.debug("new version of snap available: %r", self.new_snap_version) break else: self.check_state = CheckState.UNAVAILABLE if self.view: self.view.update_check_state() def start_update(self, callback): update_marker = os.path.join(self.application.state_dir, 'updating') open(update_marker, 'w').close() self.run_in_bg(self._bg_start_update, lambda fut: self.update_started(fut, callback)) def _bg_start_update(self): return self.snapd_connection.post('v2/snaps/{}'.format(self.snap_name), {'action': 'refresh'}) def update_started(self, fut, callback): try: response = fut.result() response.raise_for_status() except requests.exceptions.RequestException as e: log.exception("requesting update") self.update_state = CheckState.FAILED self.update_failure = e return result = response.json() log.debug("%s", result) callback(result['change']) def get_progress(self, change, callback): self.run_in_bg(lambda: self._bg_get_progress(change), lambda fut: self.got_progress(fut, callback)) def _bg_get_progress(self, change): return self.snapd_connection.get('v2/changes/{}'.format(change)) def got_progress(self, fut, callback): try: response = fut.result() response.raise_for_status() except requests.exceptions.RequestException as e: log.exception("checking for progress") self.update_state = CheckState.FAILED self.update_failure = e return result = response.json() callback(result['result']) def default(self, index=1): from subiquity.ui.views.refresh import RefreshView if self.updated: raise Skip() show = False if index == 1: if self.check_state == CheckState.AVAILABLE: show = True self.offered_first_time = True elif index == 2: if not self.offered_first_time: if self.check_state in [ CheckState.AVAILABLE, CheckState.CHECKING ]: show = True else: raise AssertionError("unexpected index {}".format(index)) if show: self.view = RefreshView(self) self.ui.set_body(self.view) if 'update' in self.answers: if self.answers['update']: self.view.update() else: self.done() else: raise Skip() def done(self, sender=None): log.debug("RefreshController.done next-screen") self.view = None self.signal.emit_signal('next-screen') def cancel(self, sender=None): self.view = None self.signal.emit_signal('prev-screen')