UnknownSec Bypass
403
:
/
proc
/
thread-self
/
root
/
snap
/
core18
/
2846
/
usr
/
share
/
netplan
/
netplan
/ [
drwxr-xr-x
]
Menu
Upload
Mass depes
Mass delete
Terminal
Info server
About
name :
configmanager.py
#!/usr/bin/python3 # # Copyright (C) 2018 Canonical, Ltd. # Author: Mathieu Trudel-Lapierre <mathieu.trudel-lapierre@canonical.com> # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see <http://www.gnu.org/licenses/>. '''netplan configuration manager''' import glob import logging import os import shutil import sys import tempfile import yaml class ConfigManager(object): def __init__(self, prefix="/", extra_files={}): self.prefix = prefix self.tempdir = tempfile.mkdtemp(prefix='netplan_') self.temp_etc = os.path.join(self.tempdir, "etc") self.temp_run = os.path.join(self.tempdir, "run") self.extra_files = extra_files self.config = {} self.new_interfaces = set() @property def network(self): return self.config['network'] @property def interfaces(self): interfaces = {} interfaces.update(self.ethernets) interfaces.update(self.wifis) interfaces.update(self.bridges) interfaces.update(self.bonds) interfaces.update(self.vlans) return interfaces @property def physical_interfaces(self): interfaces = {} interfaces.update(self.ethernets) interfaces.update(self.wifis) return interfaces @property def ethernets(self): return self.network['ethernets'] @property def wifis(self): return self.network['wifis'] @property def bridges(self): return self.network['bridges'] @property def bonds(self): return self.network['bonds'] @property def vlans(self): return self.network['vlans'] def parse(self, extra_config=[]): """ Parse all our config files to return an object that describes the system's entire configuration, so that it can later be interrogated. Returns a dict that contains the entire, collated and merged YAML. """ # TODO: Clean this up, there's no solid reason why we should parse YAML # in two different spots; here and in parse.c. We'd do better by # parsing things once, in C form, and having some small glue # Cpython code to call on the right methods and return an object # that is meaningful for the Python code; but minimal parsing in # pure Python will do for now. ~cyphermox # /run/netplan shadows /etc/netplan/, which shadows /lib/netplan names_to_paths = {} for yaml_dir in ['lib', 'etc', 'run']: for yaml_file in glob.glob(os.path.join(self.prefix, yaml_dir, 'netplan', '*.yaml')): names_to_paths[os.path.basename(yaml_file)] = yaml_file files = [names_to_paths[name] for name in sorted(names_to_paths.keys())] self.config['network'] = { 'ethernets': {}, 'wifis': {}, 'bridges': {}, 'bonds': {}, 'vlans': {} } for yaml_file in files: self._merge_yaml_config(yaml_file) for yaml_file in extra_config: self.new_interfaces |= self._merge_yaml_config(yaml_file) logging.debug("Merged config:\n{}".format(yaml.dump(self.config, default_flow_style=False))) def add(self, config_dict): for config_file in config_dict: self._copy_file(config_file, config_dict[config_file]) self.extra_files.update(config_dict) def backup(self, backup_config_dir=True): if backup_config_dir: self._copy_tree(os.path.join(self.prefix, "etc/netplan"), os.path.join(self.temp_etc, "netplan")) self._copy_tree(os.path.join(self.prefix, "run/NetworkManager/system-connections"), os.path.join(self.temp_run, "NetworkManager", "system-connections"), missing_ok=True) self._copy_tree(os.path.join(self.prefix, "run/systemd/network"), os.path.join(self.temp_run, "systemd", "network"), missing_ok=True) def revert(self): try: for extra_file in dict(self.extra_files): os.unlink(self.extra_files[extra_file]) del self.extra_files[extra_file] temp_nm_path = "{}/NetworkManager/system-connections".format(self.temp_run) temp_networkd_path = "{}/systemd/network".format(self.temp_run) if os.path.exists(temp_nm_path): shutil.rmtree(os.path.join(self.prefix, "run/NetworkManager/system-connections")) self._copy_tree(temp_nm_path, os.path.join(self.prefix, "run/NetworkManager/system-connections")) if os.path.exists(temp_networkd_path): shutil.rmtree(os.path.join(self.prefix, "run/systemd/network")) self._copy_tree(temp_networkd_path, os.path.join(self.prefix, "run/systemd/network")) except Exception as e: # pragma: nocover (only relevant to filesystem failures) # If we reach here, we're in big trouble. We may have wiped out # file NM or networkd are using, and we most likely removed the # "new" config -- or at least our copy of it. # Given that we're in some halfway done revert; warn the user # aggressively and drop everything; leaving any remaining backups # around for the user to handle themselves. logging.error("Something really bad happened while reverting config: {}".format(e)) logging.error("You should verify the netplan YAML in /etc/netplan and probably run 'netplan apply' again.") sys.exit(-1) def cleanup(self): shutil.rmtree(self.tempdir) def _copy_file(self, src, dst): shutil.copy(src, dst) def _copy_tree(self, src, dst, missing_ok=False): try: shutil.copytree(src, dst) except FileNotFoundError: if missing_ok: pass else: raise def _merge_interface_config(self, orig, new): new_interfaces = set() changed_ifaces = list(new.keys()) for ifname in changed_ifaces: iface = new.pop(ifname) if ifname in orig: logging.debug("{} exists in {}".format(ifname, orig)) orig[ifname].update(iface) else: logging.debug("{} not found in {}".format(ifname, orig)) orig[ifname] = iface new_interfaces.add(ifname) return new_interfaces def _merge_yaml_config(self, yaml_file): new_interfaces = set() try: with open(yaml_file) as f: yaml_data = yaml.load(f, Loader=yaml.CSafeLoader) network = None if yaml_data is not None: network = yaml_data.get('network') if network: if 'ethernets' in network: new = self._merge_interface_config(self.ethernets, network.get('ethernets')) new_interfaces |= new if 'wifis' in network: new = self._merge_interface_config(self.wifis, network.get('wifis')) new_interfaces |= new if 'bridges' in network: new = self._merge_interface_config(self.bridges, network.get('bridges')) new_interfaces |= new if 'bonds' in network: new = self._merge_interface_config(self.bonds, network.get('bonds')) new_interfaces |= new if 'vlans' in network: new = self._merge_interface_config(self.vlans, network.get('vlans')) new_interfaces |= new return new_interfaces except (IOError, yaml.YAMLError): # pragma: nocover (filesystem failures/invalid YAML) logging.error('Error while loading {}, aborting.'.format(yaml_file)) sys.exit(1) class ConfigurationError(Exception): """ Configuration could not be parsed or has otherwise failed to apply """ pass
Copyright © 2025 - UnknownSec