def network_finish(self, config): log.debug("network config: \n%s", yaml.dump(sanitize_config(config), default_flow_style=False)) netplan_path = self.netplan_path while True: try: tmppath = '%s.%s' % (netplan_path, random.randrange(0, 1000)) fd = os.open(tmppath, os.O_WRONLY | os.O_EXCL | os.O_CREAT, 0o0600) except FileExistsError: continue else: break w = os.fdopen(fd, 'w') with w: w.write("# This is the network config written by '{}'\n".format( self.opts.project)) w.write(yaml.dump(config)) os.rename(tmppath, netplan_path) self.model.parse_netplan_configs(self.root) if self.opts.dry_run: tasks = [ ('one', BackgroundProcess(['sleep', '0.1'])), ('two', PythonSleep(0.1)), ('three', BackgroundProcess(['sleep', '0.1'])), ] 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. tasks.append(('generate', BackgroundProcess( ['netplan', 'generate', '--root', self.root]))) if not self.tried_once: tasks.append( ('timeout', WaitForDefaultRouteTask(3, self.network_event_receiver))) tasks.append(('fail', BackgroundProcess(['false']))) self.tried_once = True else: tasks = [ ('generate', BackgroundProcess(['/lib/netplan/generate'])), ('apply', BackgroundProcess(['netplan', 'apply'])), ('timeout', WaitForDefaultRouteTask(30, self.network_event_receiver)), ] def cancel(): self.cs.cancel() self.task_error('canceled') self.acw = ApplyingConfigWidget(len(tasks), cancel) self.ui.frame.body.show_overlay(self.acw, min_width=60) self.cs = TaskSequence(self.run_in_bg, tasks, self) self.cs.run()
def network_finish(self, config): log.debug("network config: \n%s", yaml.dump(config, default_flow_style=False)) if self.opts.dry_run: if hasattr(self, 'tried_once'): tasks = [ ('one', BackgroundProcess(['sleep', '0.1'])), ('two', PythonSleep(0.1)), ('three', BackgroundProcess(['sleep', '0.1'])), ] else: self.tried_once = True tasks = [ ('timeout', WaitForDefaultRouteTask(30)), ('one', BackgroundProcess(['sleep', '0.1'])), ('two', BackgroundProcess(['sleep', '0.1'])), ('three', BackgroundProcess(['false'])), ('four', BackgroundProcess(['sleep', '0.1'])), ] else: with open('/etc/netplan/00-snapd-config.yaml', 'w') as w: w.write( "# This is the network config written by 'console-conf'\n") w.write(yaml.dump(config)) tasks = [ ('generate', BackgroundProcess(['/lib/netplan/generate'])), ('apply', BackgroundProcess(['netplan', 'apply'])), ('timeout', WaitForDefaultRouteTask(30)), ] def cancel(): self.cs.cancel() self.task_error('canceled') self.acw = ApplyingConfigWidget(len(tasks), cancel) self.ui.frame.body.show_overlay(self.acw) self.cs = TaskSequence(self.loop, tasks, self) self.cs.run()
def network_finish(self, config): log.debug("network config: \n%s", yaml.dump(sanitize_config(config), default_flow_style=False)) for p in netplan.configs_in_root(self.root, masked=True): if p == self.netplan_path: continue os.rename(p, p + ".dist-" + self.opts.project) write_file(self.netplan_path, '\n'.join(( ("# This is the network config written by '%s'" % self.opts.project), yaml.dump(config))), omode="w") self.model.parse_netplan_configs(self.root) if self.opts.dry_run: tasks = [ ('one', BackgroundProcess(['sleep', '0.1'])), ('two', PythonSleep(0.1)), ('three', BackgroundProcess(['sleep', '0.1'])), ] 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. tasks.append(('generate', BackgroundProcess(['netplan', 'generate', '--root', self.root]))) if not self.tried_once: tasks.append( ('timeout', WaitForDefaultRouteTask(3, self.network_event_receiver)) ) tasks.append(('fail', BackgroundProcess(['false']))) self.tried_once = True else: devs_to_down = [] for dev in self.model.get_all_netdevs(): devcfg = self.model.config.config_for_device(dev._net_info) if dev._configuration != devcfg: devs_to_down.append(dev) tasks = [] if devs_to_down: tasks.extend([ ('stop-networkd', BackgroundProcess(['systemctl', 'stop', 'systemd-networkd.service'])), ('down', DownNetworkDevices(self.observer.rtlistener, devs_to_down)), ]) tasks.extend([ ('apply', BackgroundProcess(['netplan', 'apply'])), ('timeout', WaitForDefaultRouteTask(30, self.network_event_receiver)), ]) def cancel(): self.cs.cancel() self.task_error('canceled') self.acw = ApplyingConfigWidget(len(tasks), cancel) self.ui.frame.body.show_overlay(self.acw, min_width=60) self.cs = TaskSequence(self.run_in_bg, tasks, self) self.cs.run()
class NetworkController(BaseController, TaskWatcher): signals = [ ('menu:network:main:set-default-v4-route', 'set_default_v4_route'), ('menu:network:main:set-default-v6-route', 'set_default_v6_route'), ] root = "/" def __init__(self, common): super().__init__(common) self.model = self.base_model.network self.answers = self.all_answers.get("Network", {}) if self.opts.dry_run: self.root = os.path.abspath(".subiquity") self.tried_once = False netplan_path = self.netplan_path netplan_dir = os.path.dirname(netplan_path) if os.path.exists(netplan_dir): import shutil shutil.rmtree(netplan_dir) os.makedirs(netplan_dir) with open(netplan_path, 'w') as fp: fp.write(default_netplan) self.model.parse_netplan_configs(self.root) self.network_event_receiver = SubiquityNetworkEventReceiver(self.model) self.observer, fds = ( self.prober.probe_network(self.network_event_receiver)) for fd in fds: self.loop.watch_file(fd, partial(self._data_ready, fd)) def _data_ready(self, fd): cp = run_command(['udevadm', 'settle', '-t', '0']) if cp.returncode != 0: log.debug("waiting 0.1 to let udev event queue settle") self.loop.set_alarm_in(0.1, lambda loop, ud: self._data_ready(fd)) return self.observer.data_ready(fd) v = self.ui.frame.body if hasattr(v, 'refresh_model_inputs'): v.refresh_model_inputs() def start_scan(self, dev): self.observer.trigger_scan(dev.ifindex) def cancel(self): self.signal.emit_signal('prev-screen') def default(self): self.ui.set_body(NetworkView(self.model, self)) if self.answers.get('accept-default', False): self.network_finish(self.model.render()) @property def netplan_path(self): if self.opts.project == "subiquity": netplan_config_file_name = '00-installer-config.yaml' else: netplan_config_file_name = '00-snapd-config.yaml' return os.path.join(self.root, 'etc/netplan', netplan_config_file_name) def network_finish(self, config): log.debug("network config: \n%s", yaml.dump(sanitize_config(config), default_flow_style=False)) for p in netplan.configs_in_root(self.root, masked=True): if p == self.netplan_path: continue os.rename(p, p + ".dist-" + self.opts.project) write_file(self.netplan_path, '\n'.join(( ("# This is the network config written by '%s'" % self.opts.project), yaml.dump(config))), omode="w") self.model.parse_netplan_configs(self.root) if self.opts.dry_run: tasks = [ ('one', BackgroundProcess(['sleep', '0.1'])), ('two', PythonSleep(0.1)), ('three', BackgroundProcess(['sleep', '0.1'])), ] 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. tasks.append(('generate', BackgroundProcess(['netplan', 'generate', '--root', self.root]))) if not self.tried_once: tasks.append( ('timeout', WaitForDefaultRouteTask(3, self.network_event_receiver)) ) tasks.append(('fail', BackgroundProcess(['false']))) self.tried_once = True else: devs_to_down = [] for dev in self.model.get_all_netdevs(): devcfg = self.model.config.config_for_device(dev._net_info) if dev._configuration != devcfg: devs_to_down.append(dev) tasks = [] if devs_to_down: tasks.extend([ ('stop-networkd', BackgroundProcess(['systemctl', 'stop', 'systemd-networkd.service'])), ('down', DownNetworkDevices(self.observer.rtlistener, devs_to_down)), ]) tasks.extend([ ('apply', BackgroundProcess(['netplan', 'apply'])), ('timeout', WaitForDefaultRouteTask(30, self.network_event_receiver)), ]) def cancel(): self.cs.cancel() self.task_error('canceled') self.acw = ApplyingConfigWidget(len(tasks), cancel) self.ui.frame.body.show_overlay(self.acw, min_width=60) self.cs = TaskSequence(self.run_in_bg, tasks, self) self.cs.run() def task_complete(self, stage): self.acw.advance() def task_error(self, stage, info=None): self.ui.frame.body.remove_overlay() self.ui.frame.body.show_network_error(stage, info) if self.answers.get('accept-default', False): self.network_finish(self.model.render()) def tasks_finished(self): self.signal.emit_signal('network-config-written', self.netplan_path) self.signal.emit_signal('next-screen') def set_default_v4_route(self): self.ui.set_header("Default route") self.ui.set_body( NetworkSetDefaultRouteView(self.model, socket.AF_INET, self)) def set_default_v6_route(self): self.ui.set_header("Default route") self.ui.set_body( NetworkSetDefaultRouteView(self.model, socket.AF_INET6, self)) def bond_interfaces(self): self.ui.set_body(NetworkBondInterfacesView(self.model, self)) def network_configure_interface(self, iface): self.ui.set_header(_("Network interface {}").format(iface)) self.ui.set_footer("") self.ui.set_body( NetworkConfigureInterfaceView(self.model, self, iface)) def network_configure_ipv4_interface(self, iface): self.ui.set_header(_( "Network interface {} manual IPv4 configuration").format(iface)) self.ui.set_footer("") self.ui.set_body( NetworkConfigureIPv4InterfaceView(self.model, self, iface)) def network_configure_wlan_interface(self, iface): self.ui.set_header(_( "Network interface {} WIFI configuration").format(iface)) self.ui.set_footer("") self.ui.set_body(NetworkConfigureWLANView(self.model, self, iface)) def network_configure_ipv6_interface(self, iface): self.ui.set_header(_( "Network interface {} manual IPv6 configuration").format(iface)) self.ui.set_footer("") self.ui.set_body( NetworkConfigureIPv6InterfaceView(self.model, self, iface))
class NetworkController(BaseController, TaskWatcher): root = "/" def __init__(self, common): super().__init__(common) self.model = self.base_model.network self.answers = self.all_answers.get("Network", {}) if self.opts.dry_run: self.root = os.path.abspath(".subiquity") self.tried_once = False netplan_path = self.netplan_path netplan_dir = os.path.dirname(netplan_path) if os.path.exists(netplan_dir): import shutil shutil.rmtree(netplan_dir) os.makedirs(netplan_dir) with open(netplan_path, 'w') as fp: fp.write(default_netplan) self.model.parse_netplan_configs(self.root) self.network_event_receiver = SubiquityNetworkEventReceiver(self.model) self._observer_handles = [] self.observer, self._observer_fds = ( self.prober.probe_network(self.network_event_receiver)) self.start_watching() self._done_by_action = False def stop_watching(self): for handle in self._observer_handles: self.loop.remove_watch_file(handle) self._observer_handles = [] def start_watching(self): if self._observer_handles: return self._observer_handles = [ self.loop.watch_file(fd, partial(self._data_ready, fd)) for fd in self._observer_fds] def _data_ready(self, fd): cp = run_command(['udevadm', 'settle', '-t', '0']) if cp.returncode != 0: log.debug("waiting 0.1 to let udev event queue settle") self.stop_watching() self.loop.set_alarm_in(0.1, lambda loop, ud: self.start_watching()) return self.observer.data_ready(fd) v = self.ui.frame.body if hasattr(v, 'refresh_model_inputs'): v.refresh_model_inputs() def start_scan(self, dev): self.observer.trigger_scan(dev.ifindex) def cancel(self): self.signal.emit_signal('prev-screen') def _action_get(self, id): dev_spec = id[0].split() dev = None if dev_spec[0] == "interface": if dev_spec[1] == "index": dev = self.model.get_all_netdevs()[int(dev_spec[2])] elif dev_spec[1] == "name": dev = self.model.get_netdev_by_name(dev_spec[2]) if dev is None: raise Exception("could not resolve {}".format(id)) if len(id) > 1: part, index = id[1].split() if part == "part": return dev.partitions()[int(index)] else: return dev raise Exception("could not resolve {}".format(id)) def _action_clean_devices(self, devices): return [self._action_get(device) for device in devices] def _answers_action(self, action): from subiquitycore.ui.stretchy import StretchyOverlay log.debug("_answers_action %r", action) if 'obj' in action: obj = self._action_get(action['obj']) meth = getattr( self.ui.frame.body, "_action_{}".format(action['action'])) meth(obj) yield body = self.ui.frame.body._w if not isinstance(body, StretchyOverlay): return for k, v in action.items(): if not k.endswith('data'): continue form_name = "form" submit_key = "submit" if '-' in k: prefix = k.split('-')[0] form_name = prefix + "_form" submit_key = prefix + "-submit" yield from self._enter_form_data( getattr(body.stretchy, form_name), v, action.get(submit_key, True)) elif action['action'] == 'create-bond': self.ui.frame.body._create_bond() yield body = self.ui.frame.body._w yield from self._enter_form_data( body.stretchy.form, action['data'], action.get("submit", True)) elif action['action'] == 'done': self._done_by_action = True self.ui.frame.body.done() else: raise Exception("could not process action {}".format(action)) def default(self): view = NetworkView(self.model, self) self.network_event_receiver.view = view self.ui.set_body(view) if self.answers.get('accept-default', False): self.network_finish(self.model.render()) elif self.answers.get('actions', False): self._run_iterator(self._run_actions(self.answers['actions'])) @property def netplan_path(self): if self.opts.project == "subiquity": netplan_config_file_name = '00-installer-config.yaml' else: netplan_config_file_name = '00-snapd-config.yaml' return os.path.join(self.root, 'etc/netplan', netplan_config_file_name) def add_vlan(self, device, vlan): return self.model.new_vlan(device, vlan) def add_or_update_bond(self, existing, result): mode = result['mode'] params = { 'mode': mode, } if mode in BondParameters.supports_xmit_hash_policy: params['transmit-hash-policy'] = result['xmit_hash_policy'] if mode in BondParameters.supports_lacp_rate: params['lacp-rate'] = result['lacp_rate'] for device in result['devices']: device.config = {} interfaces = [d.name for d in result['devices']] if existing is None: return self.model.new_bond(result['name'], interfaces, params) else: existing.config['interfaces'] = interfaces existing.config['parameters'] = params existing.name = result['name'] return existing def network_finish(self, config): log.debug("network config: \n%s", yaml.dump(sanitize_config(config), default_flow_style=False)) for p in netplan.configs_in_root(self.root, masked=True): if p == self.netplan_path: continue os.rename(p, p + ".dist-" + self.opts.project) write_file(self.netplan_path, '\n'.join(( ("# This is the network config written by '%s'" % self.opts.project), yaml.dump(config, default_flow_style=False))), omode="w") self.model.parse_netplan_configs(self.root) if self.opts.dry_run: delay = 0.1/self.scale_factor tasks = [ ('one', BackgroundProcess(['sleep', str(delay)])), ('two', PythonSleep(delay)), ('three', BackgroundProcess(['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. tasks.append(('generate', BackgroundProcess(['netplan', 'generate', '--root', self.root]))) if not self.tried_once: tasks.append( ('timeout', WaitForDefaultRouteTask(3, self.network_event_receiver)) ) tasks.append(('fail', BackgroundProcess(['false']))) self.tried_once = True else: devs_to_delete = [] devs_to_down = [] for dev in self.model.get_all_netdevs(include_deleted=True): if dev.info is None: continue devcfg = self.model.config.config_for_device(dev.info) if dev.is_virtual: devs_to_delete.append(dev) elif dev.config != devcfg: devs_to_down.append(dev) tasks = [] if devs_to_down or devs_to_delete: tasks.extend([ ('stop-networkd', BackgroundProcess(['systemctl', 'stop', 'systemd-networkd.service'])), ('down', DownNetworkDevices(self.observer.rtlistener, devs_to_down, devs_to_delete)), ]) tasks.extend([ ('apply', BackgroundProcess(['netplan', 'apply'])), ('timeout', WaitForDefaultRouteTask(30, self.network_event_receiver)), ]) def cancel(): self.cs.cancel() self.task_error('canceled') self.acw = ApplyingConfigWidget(len(tasks), cancel) self.ui.frame.body.show_overlay(self.acw, min_width=60) self.cs = TaskSequence(self.run_in_bg, tasks, self) self.cs.run() def task_complete(self, stage): self.acw.advance() def task_error(self, stage, info=None): self.ui.frame.body.remove_overlay() self.ui.frame.body.show_network_error(stage, info) if self.answers.get('accept-default', False) or self._done_by_action: self.network_finish(self.model.render()) def tasks_finished(self): self.signal.emit_signal('network-config-written', self.netplan_path) self.loop.set_alarm_in( 0.0, lambda loop, ud: self.signal.emit_signal('next-screen'))
class NetworkController(BaseController): signals = [ ('menu:network:main:start', 'start'), ('network:finish', 'network_finish'), ('menu:network:main:configure-interface', 'network_configure_interface'), ('menu:network:main:configure-ipv4-interface', 'network_configure_ipv4_interface'), ('menu:network:main:configure-wlan-interface', 'network_configure_wlan_interface'), ('menu:network:main:set-default-v4-route', 'set_default_v4_route'), ('menu:network:main:set-default-v6-route', 'set_default_v6_route'), ] def __init__(self, common): super().__init__(common) self.model = NetworkModel(self.prober, self.opts) def default(self): self.model.reset() log.info("probing for network devices") self.model.probe_network() self.signal.emit_signal('menu:network:main:start') def start(self): title = "Network connections" excerpt = ("Configure at least the main interface this server will " "use to receive updates.") footer = ("Additional networking info here") self.ui.set_header(title, excerpt) self.ui.set_footer(footer, 20) self.ui.set_body(NetworkView(self.model, self.signal)) def network_finish(self, config): log.debug("network config: \n%s", yaml.dump(config, default_flow_style=False)) if self.opts.dry_run: if hasattr(self, 'tried_once'): tasks = [ ('one', BackgroundProcess(['sleep', '0.1'])), ('two', PythonSleep(0.1)), ('three', BackgroundProcess(['sleep', '0.1'])), ] else: self.tried_once = True tasks = [ ('timeout', WaitForDefaultRouteTask(30)), ('one', BackgroundProcess(['sleep', '0.1'])), ('two', BackgroundProcess(['sleep', '0.1'])), ('three', BackgroundProcess(['false'])), ('four', BackgroundProcess(['sleep', '0.1'])), ] else: with open('/etc/netplan/00-snapd-config.yaml', 'w') as w: w.write( "# This is the network config written by 'console-conf'\n") w.write(yaml.dump(config)) tasks = [ ('generate', BackgroundProcess(['/lib/netplan/generate'])), ('apply', BackgroundProcess(['netplan', 'apply'])), ('timeout', WaitForDefaultRouteTask(30)), ] def cancel(): self.cs.cancel() self.task_error('canceled') self.acw = ApplyingConfigWidget(len(tasks), cancel) self.ui.frame.body.show_overlay(self.acw) self.cs = TaskSequence(self.loop, tasks, self) self.cs.run() def task_complete(self, stage): self.acw.advance() def task_error(self, stage): self.ui.frame.body.remove_overlay(self.acw) self.ui.frame.body.show_network_error(stage) def tasks_finished(self): self.signal.emit_signal('next-screen') def set_default_v4_route(self): self.ui.set_header("Default route") self.ui.set_body( NetworkSetDefaultRouteView(self.model, netifaces.AF_INET, self.signal)) def set_default_v6_route(self): self.ui.set_header("Default route") self.ui.set_body( NetworkSetDefaultRouteView(self.model, netifaces.AF_INET6, self.signal)) def bond_interfaces(self): self.ui.set_header("Bond interfaces") self.ui.set_body(NetworkBondInterfacesView(self.model, self.signal)) def network_configure_interface(self, iface): self.ui.set_header("Network interface {}".format(iface)) self.ui.set_body( NetworkConfigureInterfaceView(self.model, self.signal, iface)) def network_configure_ipv4_interface(self, iface): self.model.prev_signal = ('Back to configure interface menu', 'network:configure-interface-menu', 'network_configure_interface') self.ui.set_header("Network interface {} manual IPv4 " "configuration".format(iface)) self.ui.set_body( NetworkConfigureIPv4InterfaceView(self.model, self.signal, iface)) def network_configure_wlan_interface(self, iface): self.model.prev_signal = ('Back to configure interface menu', 'network:configure-interface-menu', 'network_configure_interface') self.ui.set_header("Network interface {} manual IPv4 " "configuration".format(iface)) self.ui.set_body( NetworkConfigureWLANView(self.model, self.signal, iface)) def network_configure_ipv6_interface(self, iface): self.model.prev_signal = ('Back to configure interface menu', 'network:configure-interface-menu', 'network_configure_interface') self.ui.set_body(DummyView(self.signal)) def install_network_driver(self): self.ui.set_body(DummyView(self.signal))
class NetworkController(BaseController, TaskWatcher): signals = [ ('menu:network:main:set-default-v4-route', 'set_default_v4_route'), ('menu:network:main:set-default-v6-route', 'set_default_v6_route'), ] root = "/" def __init__(self, common): super().__init__(common) self.model = self.base_model.network self.answers = self.all_answers.get("Network", {}) if self.opts.dry_run: self.root = os.path.abspath(".subiquity") self.tried_once = False netplan_path = self.netplan_path netplan_dir = os.path.dirname(netplan_path) if os.path.exists(netplan_dir): import shutil shutil.rmtree(netplan_dir) os.makedirs(netplan_dir) with open(netplan_path, 'w') as fp: fp.write(default_netplan) self.model.parse_netplan_configs(self.root) self.network_event_receiver = SubiquityNetworkEventReceiver(self.model) self._observer_handles = [] self.observer, self._observer_fds = (self.prober.probe_network( self.network_event_receiver)) self.start_watching() def stop_watching(self): for handle in self._observer_handles: self.loop.remove_watch_file(handle) self._observer_handles = [] def start_watching(self): if self._observer_handles: return self._observer_handles = [ self.loop.watch_file(fd, partial(self._data_ready, fd)) for fd in self._observer_fds ] def _data_ready(self, fd): cp = run_command(['udevadm', 'settle', '-t', '0']) if cp.returncode != 0: log.debug("waiting 0.1 to let udev event queue settle") self.stop_watching() self.loop.set_alarm_in(0.1, lambda loop, ud: self.start_watching()) return self.observer.data_ready(fd) v = self.ui.frame.body if hasattr(v, 'refresh_model_inputs'): v.refresh_model_inputs() def start_scan(self, dev): self.observer.trigger_scan(dev.ifindex) def cancel(self): self.signal.emit_signal('prev-screen') def default(self): view = NetworkView(self.model, self) self.network_event_receiver.view = view self.ui.set_body(view) if self.answers.get('accept-default', False): self.network_finish(self.model.render()) @property def netplan_path(self): if self.opts.project == "subiquity": netplan_config_file_name = '00-installer-config.yaml' else: netplan_config_file_name = '00-snapd-config.yaml' return os.path.join(self.root, 'etc/netplan', netplan_config_file_name) def add_vlan(self, device, vlan): cmd = [ 'ip', 'link', 'add', 'name', '%s.%s' % (device.name, vlan), 'link', device.name, 'type', 'vlan', 'id', str(vlan) ] try: run_command(cmd, check=True) except subprocess.CalledProcessError: self.ui.frame.body.show_network_error('add-vlan') def add_bond(self, params): cmd = [ 'ip', 'link', 'add', 'name', '%(name)s' % params, 'type', 'bond', 'mode', '%(mode)s' % params ] if params['mode'] in ['balance-xor', '802.3ad', 'balance-tlb']: cmd += ['xmit_hash_policy', '%(xmit_hash_policy)s' % params] if params['mode'] == '802.3ad': cmd += ['lacp_rate', '%(lacp_rate)s' % params] try: run_command(cmd, check=True) except subprocess.CalledProcessError: self.ui.frame.body.show_network_error('add-bond') def rm_virtual_interface(self, device): cmd = ['ip', 'link', 'delete', 'dev', device.name] try: run_command(cmd, check=True) except subprocess.CalledProcessError: self.ui.frame.body.show_network_error('rm-dev') def add_master(self, device, master_dev=None, master_name=None): # Drop ip configs for ip in [4, 6]: device.remove_ip_networks_for_version(ip) device.set_dhcp_for_version(ip, False) down_cmd = ['ip', 'link', 'set', 'dev', device.name, 'down'] cmd = ['ip', 'link', 'set', 'dev', device.name] if master_dev: master_name = master_dev.name if master_name: cmd += ['master', master_name] else: cmd += ['nomaster'] try: # Down the interface, and set new master run_command(down_cmd, check=True) run_command(cmd, check=True) except subprocess.CalledProcessError: self.ui.frame.body.show_network_error('add-master') def network_finish(self, config): log.debug("network config: \n%s", yaml.dump(sanitize_config(config), default_flow_style=False)) for p in netplan.configs_in_root(self.root, masked=True): if p == self.netplan_path: continue os.rename(p, p + ".dist-" + self.opts.project) write_file(self.netplan_path, '\n'.join((("# This is the network config written by '%s'" % self.opts.project), yaml.dump(config, default_flow_style=False))), omode="w") self.model.parse_netplan_configs(self.root) if self.opts.dry_run: tasks = [ ('one', BackgroundProcess(['sleep', '0.1'])), ('two', PythonSleep(0.1)), ('three', BackgroundProcess(['sleep', '0.1'])), ] 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. tasks.append(('generate', BackgroundProcess( ['netplan', 'generate', '--root', self.root]))) if not self.tried_once: tasks.append( ('timeout', WaitForDefaultRouteTask(3, self.network_event_receiver))) tasks.append(('fail', BackgroundProcess(['false']))) self.tried_once = True else: devs_to_down = [] for dev in self.model.get_all_netdevs(): devcfg = self.model.config.config_for_device(dev._net_info) if dev._configuration != devcfg: devs_to_down.append(dev) tasks = [] if devs_to_down: tasks.extend([ ('stop-networkd', BackgroundProcess( ['systemctl', 'stop', 'systemd-networkd.service'])), ('down', DownNetworkDevices(self.observer.rtlistener, devs_to_down)), ]) tasks.extend([ ('apply', BackgroundProcess(['netplan', 'apply'])), ('timeout', WaitForDefaultRouteTask(30, self.network_event_receiver)), ]) def cancel(): self.cs.cancel() self.task_error('canceled') self.acw = ApplyingConfigWidget(len(tasks), cancel) self.ui.frame.body.show_overlay(self.acw, min_width=60) self.cs = TaskSequence(self.run_in_bg, tasks, self) self.cs.run() def task_complete(self, stage): self.acw.advance() def task_error(self, stage, info=None): self.ui.frame.body.remove_overlay() self.ui.frame.body.show_network_error(stage, info) if self.answers.get('accept-default', False): self.network_finish(self.model.render()) def tasks_finished(self): self.signal.emit_signal('network-config-written', self.netplan_path) self.signal.emit_signal('next-screen') def set_default_v4_route(self): self.ui.set_header("Default route") self.ui.set_body( NetworkSetDefaultRouteView(self.model, socket.AF_INET, self)) def set_default_v6_route(self): self.ui.set_header("Default route") self.ui.set_body( NetworkSetDefaultRouteView(self.model, socket.AF_INET6, self))
class NetworkController(BaseController): signals = [ ('menu:network:main:set-default-v4-route', 'set_default_v4_route'), ('menu:network:main:set-default-v6-route', 'set_default_v6_route'), ] root = "/" def __init__(self, common): super().__init__(common) self.model = self.base_model.network self.answers = self.all_answers.get("Network", {}) if self.opts.dry_run: self.root = os.path.abspath(".subiquity") self.tried_once = False netplan_path = self.netplan_path netplan_dir = os.path.dirname(netplan_path) if os.path.exists(netplan_dir): import shutil shutil.rmtree(netplan_dir) os.makedirs(netplan_dir) with open(netplan_path, 'w') as fp: fp.write(default_netplan) self.model.parse_netplan_configs(self.root) self.network_event_receiver = SubiquityNetworkEventReceiver(self.model) self.observer, fds = self.prober.probe_network( self.network_event_receiver) for fd in fds: self.loop.watch_file(fd, partial(self._data_ready, fd)) def _data_ready(self, fd): code = subprocess.call(['udevadm', 'settle', '-t', '0']) if code != 0: log.debug("waiting 0.1 to let udev event queue settle") self.loop.set_alarm_in(0.1, lambda loop, ud: self._data_ready(fd)) return self.observer.data_ready(fd) v = self.ui.frame.body if hasattr(v, 'refresh_model_inputs'): v.refresh_model_inputs() def start_scan(self, dev): self.observer.trigger_scan(dev.ifindex) def cancel(self): self.signal.emit_signal('prev-screen') def default(self): title = _("Network connections") excerpt = _( "Configure at least one interface this server can use to talk to " "other machines, and which preferably provides sufficient access for " "updates.") footer = _( "Select an interface to configure it or select Done to continue") self.ui.set_header(title, excerpt) self.ui.set_footer(footer) self.ui.set_body(NetworkView(self.model, self)) if self.answers.get('accept-default', False): self.network_finish(self.model.render()) @property def netplan_path(self): if self.opts.project == "subiquity": netplan_config_file_name = '00-installer-config.yaml' else: netplan_config_file_name = '00-snapd-config.yaml' return os.path.join(self.root, 'etc/netplan', netplan_config_file_name) def network_finish(self, config): log.debug("network config: \n%s", yaml.dump(sanitize_config(config), default_flow_style=False)) netplan_path = self.netplan_path while True: try: tmppath = '%s.%s' % (netplan_path, random.randrange(0, 1000)) fd = os.open(tmppath, os.O_WRONLY | os.O_EXCL | os.O_CREAT, 0o0600) except FileExistsError: continue else: break w = os.fdopen(fd, 'w') with w: w.write("# This is the network config written by '{}'\n".format( self.opts.project)) w.write(yaml.dump(config)) os.rename(tmppath, netplan_path) self.model.parse_netplan_configs(self.root) if self.opts.dry_run: tasks = [ ('one', BackgroundProcess(['sleep', '0.1'])), ('two', PythonSleep(0.1)), ('three', BackgroundProcess(['sleep', '0.1'])), ] 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. tasks.append(('generate', BackgroundProcess( ['netplan', 'generate', '--root', self.root]))) if not self.tried_once: tasks.append( ('timeout', WaitForDefaultRouteTask(3, self.network_event_receiver))) tasks.append(('fail', BackgroundProcess(['false']))) self.tried_once = True else: tasks = [ ('generate', BackgroundProcess(['/lib/netplan/generate'])), ('apply', BackgroundProcess(['netplan', 'apply'])), ('timeout', WaitForDefaultRouteTask(30, self.network_event_receiver)), ] def cancel(): self.cs.cancel() self.task_error('canceled') self.acw = ApplyingConfigWidget(len(tasks), cancel) self.ui.frame.body.show_overlay(self.acw, min_width=60) self.cs = TaskSequence(self.run_in_bg, tasks, self) self.cs.run() def task_complete(self, stage): self.acw.advance() def task_error(self, stage, info=None): self.ui.frame.body.remove_overlay() self.ui.frame.body.show_network_error(stage, info) if self.answers.get('accept-default', False): self.network_finish(self.model.render()) def tasks_finished(self): self.signal.emit_signal('network-config-written', self.netplan_path) self.loop.set_alarm_in( 0.0, lambda loop, ud: self.signal.emit_signal('next-screen')) def set_default_v4_route(self): self.ui.set_header("Default route") self.ui.set_body( NetworkSetDefaultRouteView(self.model, socket.AF_INET, self)) def set_default_v6_route(self): self.ui.set_header("Default route") self.ui.set_body( NetworkSetDefaultRouteView(self.model, socket.AF_INET6, self)) def bond_interfaces(self): self.ui.set_header("Bond interfaces") self.ui.set_body(NetworkBondInterfacesView(self.model, self)) def network_configure_interface(self, iface): self.ui.set_header("Network interface {}".format(iface)) self.ui.set_footer("") self.ui.set_body(NetworkConfigureInterfaceView(self.model, self, iface)) def network_configure_ipv4_interface(self, iface): self.ui.set_header("Network interface {} manual IPv4 " "configuration".format(iface)) self.ui.set_footer("") self.ui.set_body( NetworkConfigureIPv4InterfaceView(self.model, self, iface)) def network_configure_wlan_interface(self, iface): self.ui.set_header("Network interface {} WIFI " "configuration".format(iface)) self.ui.set_footer("") self.ui.set_body(NetworkConfigureWLANView(self.model, self, iface)) def network_configure_ipv6_interface(self, iface): self.ui.set_header("Network interface {} manual IPv6 " "configuration".format(iface)) self.ui.set_footer("") self.ui.set_body( NetworkConfigureIPv6InterfaceView(self.model, self, iface)) def install_network_driver(self): self.ui.set_body(DummyView(self))