def _clean_default(target=None): # clean out any known default files and derived files in target # LP: #1675576 tpath = subp.target_path(target, "etc/netplan/00-snapd-config.yaml") if not os.path.isfile(tpath): return content = util.load_file(tpath, decode=False) if content != KNOWN_SNAPD_CONFIG: return derived = [ subp.target_path(target, f) for f in ( "run/systemd/network/10-netplan-all-en.network", "run/systemd/network/10-netplan-all-eth.network", "run/systemd/generator/netplan.stamp", ) ] existing = [f for f in derived if os.path.isfile(f)] LOG.debug( "removing known config '%s' and derived existing files: %s", tpath, existing, ) for f in [tpath] + existing: os.unlink(f)
def test_bunch_of_slashes_in_path(self): self.assertEqual( "/target/my/path/", subp.target_path("/target/", "//my/path/") ) self.assertEqual( "/target/my/path/", subp.target_path("/target/", "///my/path/") )
def render_network_state(self, network_state, templates=None, target=None): fpeni = subp.target_path(target, self.eni_path) util.ensure_dir(os.path.dirname(fpeni)) header = self.eni_header if self.eni_header else "" util.write_file(fpeni, header + self._render_interfaces(network_state)) if self.netrules_path: netrules = subp.target_path(target, self.netrules_path) util.ensure_dir(os.path.dirname(netrules)) util.write_file(netrules, self._render_persistent_net(network_state))
def available(target=None) -> bool: """Return true if network manager can be used on this system.""" config_present = os.path.isfile( subp.target_path(target, path=NM_CFG_FILE) ) nmcli_present = subp.which("nmcli", target=target) return config_present and bool(nmcli_present)
def clean_cloud_init(target): """clean out any local cloud-init config""" flist = glob.glob( subp.target_path(target, "/etc/cloud/cloud.cfg.d/*dpkg*")) LOG.debug("cleaning cloud-init config from: %s", flist) for dpkg_cfg in flist: os.unlink(dpkg_cfg)
def _resolve_conf(self, settings): nameservers = settings.dns_nameservers searchdomains = settings.dns_searchdomains for interface in settings.iter_interfaces(): for subnet in interface.get("subnets", []): if "dns_nameservers" in subnet: nameservers.extend(subnet["dns_nameservers"]) if "dns_search" in subnet: searchdomains.extend(subnet["dns_search"]) # Try to read the /etc/resolv.conf or just start from scratch if that # fails. try: resolvconf = ResolvConf( util.load_file( subp.target_path(self.target, self.resolv_conf_fn) ) ) resolvconf.parse() except IOError: util.logexc( LOG, "Failed to parse %s, use new empty file", subp.target_path(self.target, self.resolv_conf_fn), ) resolvconf = ResolvConf("") resolvconf.parse() # Add some nameservers for server in set(nameservers): try: resolvconf.add_nameserver(server) except ValueError: util.logexc(LOG, "Failed to add nameserver %s", server) # And add any searchdomains. for domain in set(searchdomains): try: resolvconf.add_search_domain(domain) except ValueError: util.logexc(LOG, "Failed to add search domain %s", domain) util.write_file( subp.target_path(self.target, self.resolv_conf_fn), str(resolvconf), 0o644, )
def render_network_state( self, network_state: NetworkState, templates=None, target=None ): if not templates: templates = self.templates file_mode = 0o644 base_sysconf_dir = subp.target_path(target, self.sysconf_dir) for path, data in self._render_sysconfig( base_sysconf_dir, network_state, self.flavor, templates=templates ).items(): util.write_file(path, data, file_mode) if self.dns_path: dns_path = subp.target_path(target, self.dns_path) resolv_content = self._render_dns( network_state, existing_dns_path=dns_path ) if resolv_content: util.write_file(dns_path, resolv_content, file_mode) if self.networkmanager_conf_path: nm_conf_path = subp.target_path( target, self.networkmanager_conf_path ) nm_conf_content = self._render_networkmanager_conf( network_state, templates ) if nm_conf_content: util.write_file(nm_conf_path, nm_conf_content, file_mode) if self.netrules_path: netrules_content = self._render_persistent_net(network_state) netrules_path = subp.target_path(target, self.netrules_path) util.write_file(netrules_path, netrules_content, file_mode) sysconfig_path = subp.target_path(target, templates.get("control")) # Distros configuring /etc/sysconfig/network as a file e.g. Centos if sysconfig_path.endswith("network"): util.ensure_dir(os.path.dirname(sysconfig_path)) netcfg = [_make_header(), "NETWORKING=yes"] if network_state.use_ipv6: netcfg.append("NETWORKING_IPV6=yes") netcfg.append("IPV6_AUTOCONF=no") util.write_file( sysconfig_path, "\n".join(netcfg) + "\n", file_mode )
def render_network_state(self, network_state, templates=None, target=None): network_dir = self.network_conf_dir if target: network_dir = subp.target_path(target) + network_dir util.ensure_dir(network_dir) ret_dict = self._render_content(network_state) for k, v in ret_dict.items(): self.create_network_file(k, v, network_dir)
def render_network_state(self, network_state, templates=None, target=None): fp_nwkd = self.network_conf_dir if target: fp_nwkd = subp.target_path(target) + fp_nwkd util.ensure_dir(os.path.dirname(fp_nwkd)) ret_dict = self._render_content(network_state) for k, v in ret_dict.items(): self.create_network_file(k, v, fp_nwkd)
def available(target=None): expected = ["ifquery", "ifup", "ifdown"] search = ["/sbin", "/usr/sbin"] for p in expected: if not subp.which(p, search=search, target=target): return False eni = subp.target_path(target, "etc/network/interfaces") if not os.path.isfile(eni): return False return True
def add_apt_sources(srcdict, cloud, target=None, template_params=None, aa_repo_match=None): """ add entries in /etc/apt/sources.list.d for each abbreviated sources.list entry in 'srcdict'. When rendering template, also include the values in dictionary searchList """ if template_params is None: template_params = {} if aa_repo_match is None: raise ValueError('did not get a valid repo matcher') if not isinstance(srcdict, dict): raise TypeError('unknown apt format: %s' % (srcdict)) for filename in srcdict: ent = srcdict[filename] LOG.debug("adding source/key '%s'", ent) if 'filename' not in ent: ent['filename'] = filename add_apt_key(ent, target) if 'source' not in ent: continue source = ent['source'] source = templater.render_string(source, template_params) if not ent['filename'].startswith("/"): ent['filename'] = os.path.join("/etc/apt/sources.list.d/", ent['filename']) if not ent['filename'].endswith(".list"): ent['filename'] += ".list" if aa_repo_match(source): try: subp.subp(["add-apt-repository", source], target=target) except subp.ProcessExecutionError: LOG.exception("add-apt-repository failed.") raise continue sourcefn = subp.target_path(target, ent['filename']) try: contents = "%s\n" % (source) util.write_file(sourcefn, contents, omode="a") except IOError as detail: LOG.exception("failed write to file %s: %s", sourcefn, detail) raise update_packages(cloud) return
def available(target=None): expected = ['ifquery', 'ifup', 'ifdown'] search = ['/sbin', '/usr/sbin'] for p in expected: if not subp.which(p, search=search, target=target): return False eni = subp.target_path(target, 'etc/network/interfaces') if not os.path.isfile(eni): return False return True
def _render_network( entries, target="/", conf_dir="etc/netctl", resolv_conf="etc/resolv.conf", enable_func=None, ): """Render the translate_network format into netctl files in target. Paths will be rendered under target. """ devs = [] nameservers = [] resolv_conf = subp.target_path(target, resolv_conf) conf_dir = subp.target_path(target, conf_dir) for (dev, info) in entries.items(): if dev == "lo": # no configuration should be rendered for 'lo' continue devs.append(dev) net_fn = os.path.join(conf_dir, dev) net_cfg = { "Connection": "ethernet", "Interface": dev, "IP": info.get("bootproto"), "Address": "%s/%s" % (info.get("address"), info.get("netmask")), "Gateway": info.get("gateway"), "DNS": info.get("dns-nameservers", []), } util.write_file(net_fn, convert_netctl(net_cfg)) if enable_func and info.get("auto"): enable_func(dev) if "dns-nameservers" in info: nameservers.extend(info["dns-nameservers"]) if nameservers: util.write_file(resolv_conf, convert_resolv_conf(nameservers)) return devs
def available_sysconfig(target=None): expected = ['ifup', 'ifdown'] search = ['/sbin', '/usr/sbin'] for p in expected: if not subp.which(p, search=search, target=target): return False expected_paths = [ 'etc/sysconfig/network-scripts/network-functions', 'etc/sysconfig/config'] for p in expected_paths: if os.path.isfile(subp.target_path(target, p)): return True return False
def write_config(self): for device_name, v in self.interface_configurations.items(): if_file = 'etc/hostname.{}'.format(device_name) fn = subp.target_path(self.target, if_file) if device_name in self.dhcp_interfaces(): content = 'dhcp\n' elif isinstance(v, dict): try: content = "inet {address} {netmask}\n".format( address=v['address'], netmask=v['netmask']) except KeyError: LOG.error("Invalid static configuration for %s", device_name) util.write_file(fn, content)
def _render_network(entries, target="/", conf_dir="etc/netctl", resolv_conf="etc/resolv.conf", enable_func=None): """Render the translate_network format into netctl files in target. Paths will be rendered under target. """ devs = [] nameservers = [] resolv_conf = subp.target_path(target, resolv_conf) conf_dir = subp.target_path(target, conf_dir) for (dev, info) in entries.items(): if dev == 'lo': # no configuration should be rendered for 'lo' continue devs.append(dev) net_fn = os.path.join(conf_dir, dev) net_cfg = { 'Connection': 'ethernet', 'Interface': dev, 'IP': info.get('bootproto'), 'Address': "%s/%s" % (info.get('address'), info.get('netmask')), 'Gateway': info.get('gateway'), 'DNS': info.get('dns-nameservers', []), } util.write_file(net_fn, convert_netctl(net_cfg)) if enable_func and info.get('auto'): enable_func(dev) if 'dns-nameservers' in info: nameservers.extend(info['dns-nameservers']) if nameservers: util.write_file(resolv_conf, convert_resolv_conf(nameservers)) return devs
def available(target=None): # TODO: Move `uses_systemd` to a more appropriate location # It is imported here to avoid circular import from cloudinit.distros import uses_systemd config_present = os.path.isfile(subp.target_path(target, path=NM_CFG_FILE)) nmcli_present = subp.which("nmcli", target=target) service_active = True if uses_systemd(): try: subp.subp(["systemctl", "is-enabled", "NetworkManager.service"]) except subp.ProcessExecutionError: service_active = False return config_present and bool(nmcli_present) and service_active
def available_sysconfig(target=None): expected = ["ifup", "ifdown"] search = ["/sbin", "/usr/sbin"] for p in expected: if not subp.which(p, search=search, target=target): return False expected_paths = [ "etc/sysconfig/network-scripts/network-functions", "etc/sysconfig/config", ] for p in expected_paths: if os.path.isfile(subp.target_path(target, p)): return True return False
def available(target=None): if not util.system_info()["variant"] in KNOWN_DISTROS: return False expected = ["ifup", "ifdown"] search = ["/sbin", "/usr/sbin"] for p in expected: if not subp.which(p, search=search, target=target): return False expected_paths = [ "etc/sysconfig/network-scripts/network-functions", "etc/sysconfig/config", ] for p in expected_paths: if os.path.isfile(subp.target_path(target, p)): return True return False
def write_config(self): for device_name, v in self.interface_configurations.items(): if_file = "etc/hostname.{}".format(device_name) fn = subp.target_path(self.target, if_file) if device_name in self.dhcp_interfaces(): content = "dhcp\n" elif isinstance(v, dict): try: content = "inet {address} {netmask}".format( address=v["address"], netmask=v["netmask"]) except KeyError: LOG.error("Invalid static configuration for %s", device_name) mtu = v.get("mtu") if mtu: content += " mtu %d" % mtu content += "\n" util.write_file(fn, content)
def render_network_state(self, network_state, templates=None, target=None): # check network state for version # if v2, then extract network_state.config # else render_v2_from_state fpnplan = os.path.join(subp.target_path(target), self.netplan_path) util.ensure_dir(os.path.dirname(fpnplan)) header = self.netplan_header if self.netplan_header else "" # render from state content = self._render_content(network_state) if not header.endswith("\n"): header += "\n" util.write_file(fpnplan, header + content) if self.clean_default: _clean_default(target=target) self._netplan_generate(run=self._postcmds) self._net_setup_link(run=self._postcmds)
def rename_apt_lists(new_mirrors, target, arch): """rename_apt_lists - rename apt lists to preserve old cache data""" default_mirrors = get_default_mirrors(arch) pre = subp.target_path(target, APT_LISTS) for (name, omirror) in default_mirrors.items(): nmirror = new_mirrors.get(name) if not nmirror: continue oprefix = pre + os.path.sep + mirrorurl_to_apt_fileprefix(omirror) nprefix = pre + os.path.sep + mirrorurl_to_apt_fileprefix(nmirror) if oprefix == nprefix: continue olen = len(oprefix) for filename in glob.glob("%s_*" % oprefix): newname = "%s%s" % (nprefix, filename[olen:]) LOG.debug("Renaming apt list %s to %s", filename, newname) try: os.rename(filename, newname) except OSError: # since this is a best effort task, warn with but don't fail LOG.warning("Failed to rename apt list:", exc_info=True)
def available_nm(target=None): if not os.path.isfile(subp.target_path(target, path=NM_CFG_FILE)): return False return True
def set_rc_config_value(self, key, value): fn = subp.target_path(self.target, self.rc_conf_fn) bsd_utils.set_rc_config_value(key, value, fn=fn)
def set_route(self, network, netmask, gateway): if network == "0.0.0.0": if_file = "etc/mygate" fn = subp.target_path(self.target, if_file) content = gateway + "\n" util.write_file(fn, content)
def available(target=None) -> bool: config_present = os.path.isfile( subp.target_path(target, path=NM_CFG_FILE)) nmcli_present = subp.which('nmcli', target=target) return config_present and bool(nmcli_present)
def set_route(self, network, netmask, gateway): if network == '0.0.0.0': if_file = 'etc/mygate' fn = subp.target_path(self.target, if_file) content = gateway + '\n' util.write_file(fn, content)
def add_apt_sources(srcdict, cloud, target=None, template_params=None, aa_repo_match=None): """ install keys and repo source .list files defined in 'sources' for each 'source' entry in the config: 1. expand template variables and write source .list file in /etc/apt/sources.list.d/ 2. install defined keys 3. update packages via distro-specific method (i.e. apt-key update) @param srcdict: a dict containing elements required @param cloud: cloud instance object Example srcdict value: { 'rio-grande-repo': { 'source': 'deb [signed-by=$KEY_FILE] $MIRROR $RELEASE main', 'keyid': 'B59D 5F15 97A5 04B7 E230 6DCA 0620 BBCF 0368 3F77', 'keyserver': 'pgp.mit.edu' } } Note: Deb822 format is not supported """ if template_params is None: template_params = {} if aa_repo_match is None: raise ValueError("did not get a valid repo matcher") if not isinstance(srcdict, dict): raise TypeError("unknown apt format: %s" % (srcdict)) for filename in srcdict: ent = srcdict[filename] LOG.debug("adding source/key '%s'", ent) if "filename" not in ent: ent["filename"] = filename if "source" in ent and "$KEY_FILE" in ent["source"]: key_file = add_apt_key(ent, target, hardened=True) template_params["KEY_FILE"] = key_file else: key_file = add_apt_key(ent, target) if "source" not in ent: continue source = ent["source"] source = templater.render_string(source, template_params) if not ent["filename"].startswith("/"): ent["filename"] = os.path.join("/etc/apt/sources.list.d/", ent["filename"]) if not ent["filename"].endswith(".list"): ent["filename"] += ".list" if aa_repo_match(source): try: subp.subp( ["add-apt-repository", "--no-update", source], target=target, ) except subp.ProcessExecutionError: LOG.exception("add-apt-repository failed.") raise continue sourcefn = subp.target_path(target, ent["filename"]) try: contents = "%s\n" % (source) util.write_file(sourcefn, contents, omode="a") except IOError as detail: LOG.exception("failed write to file %s: %s", sourcefn, detail) raise update_packages(cloud) return
def conn_filename(con_id, target=None): target_con_dir = subp.target_path(target, NM_RUN_DIR) con_file = f"cloud-init-{con_id}.nmconnection" return f"{target_con_dir}/system-connections/{con_file}"
def available(target=None): target_nm_dir = subp.target_path(target, NM_LIB_DIR) return os.path.exists(target_nm_dir)