def call(service, method, params=None): address = openmediavault.getenv("OMV_ENGINED_SO_ADDRESS") sndtimeo = openmediavault.getenv("OMV_ENGINED_SO_SNDTIMEO", type="int") rcvtimeo = openmediavault.getenv("OMV_ENGINED_SO_RCVTIMEO", type="int") s = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) s.setsockopt(socket.SOL_SOCKET, socket.SO_SNDTIMEO, struct.pack("ll", sndtimeo, 0)) s.setsockopt(socket.SOL_SOCKET, socket.SO_RCVTIMEO, struct.pack("ll", rcvtimeo, 0)) s.connect(address) request = json.dumps({ "service": service, "method": method, "params": params, "context": { "username": "******", "role": 0x1 } }) request = request + "\0" s.sendall(request.encode()) chunks = [] success = False while not success: chunk = s.recv(4096) if chunk == "": raise RuntimeError("Socket connection broken") if chunk.endswith(b"\0"): chunk = chunk[:-1] success = True chunks.append(chunk.decode()) response = json.loads("".join(chunks)) if response["error"] is not None: raise RpcException(**response["error"]) return response["response"]
def test_set_new_iterable(self): self._use_tmp_config_database() db = openmediavault.config.Database() # Check the current number of configuration objects. objs = db.get("conf.system.notification.notification") self.assertIsInstance(objs, list) self.assertEqual(len(objs), 8) # Create a new configuration object. new_obj = openmediavault.config.Object( "conf.system.notification.notification") new_obj.set_dict({ 'uuid': openmediavault.getenv('OMV_CONFIGOBJECT_NEW_UUID'), 'id': 'test', 'enable': False, }) result_obj = db.set(new_obj) # Validate the returned configuration object. self.assertIsInstance(result_obj, openmediavault.config.Object) self.assertNotEqual( result_obj.get("uuid"), openmediavault.getenv('OMV_CONFIGOBJECT_NEW_UUID'), ) # Check whether the new configuration object was stored. objs = db.get("conf.system.notification.notification") self.assertIsInstance(objs, list) self.assertEqual(len(objs), 9) # Get the configuration object to validate its properties. obj = db.get("conf.system.notification.notification", result_obj.get("uuid")) self.assertIsInstance(obj, openmediavault.config.Object) self.assertEqual(obj.get("id"), "test") self.assertFalse(obj.get("enable"))
def test_set_new_iterable(self): self._use_tmp_config_database() db = openmediavault.config.Database() # Check the current number of configuration objects. objs = db.get("conf.system.notification.notification") self.assertIsInstance(objs, list) self.assertEqual(len(objs), 8) # Create a new configuration object. new_obj = openmediavault.config.Object( "conf.system.notification.notification") new_obj.set_dict({ 'uuid': openmediavault.getenv('OMV_CONFIGOBJECT_NEW_UUID'), 'id': 'test', 'enable': False }) result_obj = db.set(new_obj) # Validate the returned configuration object. self.assertIsInstance(result_obj, openmediavault.config.Object) self.assertNotEqual(result_obj.get("uuid"), openmediavault.getenv('OMV_CONFIGOBJECT_NEW_UUID')) # Check whether the new configuration object was stored. objs = db.get("conf.system.notification.notification") self.assertIsInstance(objs, list) self.assertEqual(len(objs), 9) # Get the configuration object to validate its properties. obj = db.get("conf.system.notification.notification", result_obj.get("uuid")) self.assertIsInstance(obj, openmediavault.config.Object) self.assertEqual(obj.get("id"), "test") self.assertFalse(obj.get("enable"))
def execute(self): d = dialog.Dialog(dialog="dialog") # Determine the first revision file which should look like # '<filename>.<revision>'. pathname = "{}.*".format(omv.getenv("OMV_CONFIG_FILE")) configbaks = natsort.humansorted(glob.glob(pathname)) # Does a auto-generated configuration backup exist? if not configbaks: d.msgbox("No configuration backup found!", backtitle=self.description, height=5, width=34) return 0 # Get the latest configuration backup file. configbak = configbaks.pop() # Only show a diff, if there's a difference. rc = omv.subprocess.call([ "diff", "--brief", omv.getenv("OMV_CONFIG_FILE"), configbak ], stdout=subprocess.PIPE) if rc == 0: d.msgbox("There's no difference between the configuration " \ "files. Nothing to restore.", backtitle=self.description, height=6, width=58) return 0 # Display the differences? code = d.yesno("Do you want to see the differences between the " \ "current configuration and the backup.", backtitle=self.description, height=6, width=46) if code == d.ESC: return 0 if code == d.OK: output = "===================================================================\n" \ "All lines with '-' will be changed to the lines with '+'\n" \ "===================================================================\n" p = omv.subprocess.Popen([ "diff", "--unified=1", omv.getenv("OMV_CONFIG_FILE"), configbak ], stdout=subprocess.PIPE, shell=False) stdout, stderr = p.communicate() output += stdout.decode() d.scrollbox(output, backtitle=self.description, height=18, width=72, clear=True) # Restore configuration backup? code = d.yesno("Do you want to restore the configuration backup? " \ "This will overwrite the actual configuration?", backtitle=self.description, height=6, width=57, defaultno=True) if code != d.OK: return 0 omv.rpc.call("Config", "revertChanges", { "filename": configbak }) print("Configuration backup successfully restored.") return 0
def load_collectd_config(plugin_name, option): """ A simple configuration loader. """ result = [] section_found = False filename = os.path.join( openmediavault.getenv('OMV_COLLECTD_CONFIG_DIR', '/etc/collectd/collectd.conf.d'), '{}.conf'.format(plugin_name)) if os.path.exists(filename): with open(filename, 'r') as fd: for line in fd: line = line.strip() m = re.match(r'^<Plugin\s+{}\s*>$'.format(plugin_name), line, flags=re.IGNORECASE) if m: section_found = True continue if section_found: m = re.match(r'^\s*{}\s*(.+)$'.format(option), line, flags=re.IGNORECASE) if m: result.append(m.group(1).strip('"\'')) continue if re.match(r'^</Plugin>$', line, flags=re.IGNORECASE): break return result
def load_collectd_config(plugin_name, option): """ A simple configuration loader. """ result = [] section_found = False filename = os.path.join( openmediavault.getenv( 'OMV_COLLECTD_CONFIG_DIR', '/etc/collectd/collectd.conf.d' ), '{}.conf'.format(plugin_name) ) if os.path.exists(filename): with open(filename, 'r') as fd: for line in fd: line = line.strip() m = re.match( r'^<Plugin\s+{}\s*>$'.format(plugin_name), line, flags=re.IGNORECASE ) if m: section_found = True continue if section_found: m = re.match( r'^\s*{}\s*(.+)$'.format(option), line, flags=re.IGNORECASE ) if m: result.append(m.group(1).strip('"\'')) continue if re.match(r'^</Plugin>$', line, flags=re.IGNORECASE): break return result
def execute(self): print("Checking all RRD files. Please wait ...") path = omv.getenv("OMV_RRDCACHED_BASEDIR", "/var/lib/rrdcached/db/") rrd_files = glob.glob(os.path.join(path, "localhost", "*", "*.rrd")) invalid = 0 omv.subprocess.check_call([ "monit", "stop", "rrdcached" ]) for rrd_file in rrd_files: ts_last = int(omv.subprocess.check_output([ "rrdtool", "last", rrd_file ]).decode()) dt_now = datetime.datetime.now() if datetime.datetime.utcfromtimestamp(ts_last) > dt_now: invalid += 1 dirname = os.path.basename(os.path.dirname(rrd_file)) basename = os.path.basename(rrd_file) d = dialog.Dialog(dialog="dialog") code = d.yesno("The RRD file '../{}/{}' contains " \ "timestamps in future.\nDo you want to delete " \ "it?".format(dirname, basename), backtitle=self.description, height=7, width=65) if code == d.ESC: return 0 if code == d.OK: os.remove(rrd_file) if invalid == 0: print("All RRD database files are valid.") else: print("{} invalid RRD database files were removed.".format( invalid)) omv.subprocess.call([ "monit", "start", "rrdcached" ]) return 0
def __init__(self): self._dict = {} prod_file = omv.getenv("OMV_PRODUCTINFO_FILE", "/usr/share/openmediavault/productinfo.xml") tree = xml.etree.ElementTree.parse(prod_file) for child in tree.iter(): self._dict[child.tag] = child.text
def copy_placeholder_image(filename): """ Helper function to copy the error graph image. :param filename: The destination filename. """ src = openmediavault.getenv('OMV_RRDGRAPH_ERROR_IMAGE', '/usr/share/openmediavault/icons/rrd_graph_error_64.png'); shutil.copyfile(src, filename)
def rollbackChanges(self): """ Rollback all changes in the configuration database. """ if not self._backup_path: raise RuntimeError("No configuration backup exists") shutil.copy(self._backup_path, openmediavault.getenv( "OMV_CONFIG_FILE"))
def execute(self, *args): rc = 1 # Parse the command line arguments. parser = argparse.ArgumentParser( prog="%s %s" % (os.path.basename(args[0]), args[1]), description=self.description, ) parser.add_argument( "id", type=self.argparse_is_datamodel_id, help="The data model ID, e.g. 'conf.service.ssh'", ) parser.add_argument("version", type=self.argparse_is_version) cmd_args = parser.parse_args(args[2:]) # Get the migrations. migrations = {} migrations_dir = openmediavault.getenv( "OMV_CONFDB_MIGRATIONS_DIR", "/usr/share/openmediavault/confdb/migrations.d", ) # Collect the migrations to be executed. for name in os.listdir(migrations_dir): # Split the script name into its parts: # <DATAMODELID>_<VERSION>.<EXT> parts = re.split(r'_', os.path.splitext(name)[0]) if 2 != len(parts): continue if cmd_args.id != parts[0]: continue if LooseVersion(parts[1]) < LooseVersion(cmd_args.version): continue migrations[parts[1]] = name try: # Create a backup of the configuration database. self.create_backup() # Execute the configuration database migration scripts. for cmd_args.version in sorted(migrations, key=lambda v: LooseVersion(v)): name = "%s_%s" % (cmd_args.id, cmd_args.version) path = os.path.join(migrations_dir, migrations[cmd_args.version]) # Test if the script is executable. if not os.access(path, os.X_OK): raise RuntimeError("The script '%s' is not executable" % path) # Execute the script. print(" Running migration %s" % name) openmediavault.subprocess.check_call([path]) rc = 0 except Exception as e: # Display the exception message. openmediavault.log.error("Failed to apply migrations: %s" % str(e)) # Rollback all changes. self.rollback_changes() finally: # Unlink the configuration database backup. self.unlink_backup() return rc
def execute(self): print("Clear out the local repository of uploaded package " \ "files. Please wait ...") path = omv.getenv("OMV_DPKGARCHIVE_DIR") omv.subprocess.check_call([ "rm", "-fv", "{}/*.deb".format(path) ]) omv.subprocess.check_call("cd {} && apt-ftparchive packages . " \ "> Packages".format(path), shell=True) omv.subprocess.check_call([ "apt-get", "update" ]) return 0
def execute(self): print("Checking all RRD files. Please wait ...") path = openmediavault.getenv( "OMV_RRDCACHED_BASEDIR", "/var/lib/rrdcached/db/" ) rrd_files = glob.glob(os.path.join(path, "localhost", "*", "*.rrd")) invalid = 0 monit_rrdcached = openmediavault.monit.Monit('rrdcached') # Get the performance statistics configuration? db = openmediavault.config.Database() obj = db.get("conf.system.monitoring.perfstats") # Disable rrdcached if performance stats are enabled. if obj.get("enable"): monit_rrdcached.stop() for rrd_file in rrd_files: output = None remove_rrd = False try: output = openmediavault.subprocess.check_output( ["rrdtool", "last", rrd_file], stderr=subprocess.PIPE ) except subprocess.CalledProcessError as e: if 'is not an RRD file' in e.stderr.decode(): invalid += 1 remove_rrd = True else: raise e if output is not None: ts_last = int(output.decode()) dt_now = datetime.datetime.now() if datetime.datetime.utcfromtimestamp(ts_last) > dt_now: invalid += 1 dirname = os.path.basename(os.path.dirname(rrd_file)) basename = os.path.basename(rrd_file) d = dialog.Dialog(dialog="dialog") code = d.yesno( "The RRD file '../{}/{}' contains " "timestamps in future.\nDo you want to delete " "it?".format(dirname, basename), backtitle=self.description, height=7, width=65, ) if code == d.ESC: continue if code == d.OK: remove_rrd = True if remove_rrd: os.remove(rrd_file) if invalid == 0: print("All RRD database files are valid.") else: print("{} invalid RRD database files were removed.".format(invalid)) # Re-enable rrdcached if performance stats are enabled. if obj.get("enable"): monit_rrdcached.start() return 0
def copy_placeholder_image(filename): """ Helper function to copy the error graph image. :param filename: The destination filename. """ src = openmediavault.getenv( 'OMV_RRDGRAPH_ERROR_IMAGE', '/usr/share/openmediavault/icons/rrd_graph_error_64.png') shutil.copyfile(src, filename)
def mkBackup(self): """ Create a backup of the configuration database. :returns: Returns the path of the backup file. """ (fh, self._backup_path) = tempfile.mkstemp(); shutil.copy(openmediavault.getenv("OMV_CONFIG_FILE"), self._backup_path) return self._backup_path
def execute(self): print("Checking all RRD files. Please wait ...") path = openmediavault.getenv( "OMV_RRDCACHED_BASEDIR", "/var/lib/rrdcached/db/" ) rrd_files = glob.glob(os.path.join(path, "localhost", "*", "*.rrd")) invalid = 0 monit_rrdcached = openmediavault.monit.Monit('rrdcached') # Get the performance statistics configuration? db = openmediavault.config.Database() obj = db.get("conf.system.monitoring.perfstats") # Disable rrdcached if performance stats are enabled. if obj.get("enable"): monit_rrdcached.stop() for rrd_file in rrd_files: output = None remove_rrd = False try: output = openmediavault.subprocess.check_output( ["rrdtool", "last", rrd_file], stderr=subprocess.PIPE ) except subprocess.CalledProcessError as e: if 'is not an RRD file' in e.stderr.decode(): invalid += 1 remove_rrd = True else: raise e if output is not None: ts_last = int(output.decode()) dt_now = datetime.datetime.now() if datetime.datetime.utcfromtimestamp(ts_last) > dt_now: invalid += 1 dirname = os.path.basename(os.path.dirname(rrd_file)) basename = os.path.basename(rrd_file) d = dialog.Dialog(dialog="dialog") code = d.yesno("The RRD file '../{}/{}' contains " \ "timestamps in future.\nDo you want to delete " \ "it?".format(dirname, basename), backtitle=self.description, height=7, width=65) if code == d.ESC: continue if code == d.OK: remove_rrd = True if remove_rrd: os.remove(rrd_file) if invalid == 0: print("All RRD database files are valid.") else: print( "{} invalid RRD database files were removed.".format(invalid) ) # Re-enable rrdcached if performance stats are enabled. if obj.get("enable"): monit_rrdcached.start() return 0
def rollbackChanges(self): """ Rollback all changes in the configuration database. """ if self._backup_path is None: raise RuntimeError("No configuration backup exists.") if not self._backup_path: return shutil.copy(self._backup_path, openmediavault.getenv( "OMV_CONFIG_FILE"))
def __init__(self): self._dict = {} prod_file = openmediavault.getenv("OMV_PRODUCTINFO_FILE", "/usr/share/openmediavault/productinfo.xml") tree = xml.etree.ElementTree.parse(prod_file) for child in tree.iter(): # Skip all elements with children. if list(child): continue self._dict[child.tag] = child.text
def is_new(self): """ Check if the configuration object is new. Use this method only if the configuration object has an 'uuid' property. :returns: Returns True if the configuration object is identified as new, otherwise False. """ if not openmediavault.string.is_uuid4(self.id): return False return self.id == openmediavault.getenv("OMV_CONFIGOBJECT_NEW_UUID")
def is_new(self): """ Check if the configuration object is new. Use this method only if the configuration object has an 'uuid' property. :returns: Returns True if the configuration object is identified as new, otherwise False. """ if not openmediavault.stringutils.is_uuid4(self.id): return False return self.id == openmediavault.getenv("OMV_CONFIGOBJECT_NEW_UUID")
def execute(self): print("Clear out the local repository of uploaded package " \ "files. Please wait ...") path = openmediavault.getenv("OMV_DPKGARCHIVE_DIR") openmediavault.subprocess.check_call( [ "rm", "-fv", "%s/*.deb" % path ]) openmediavault.subprocess.check_call( "cd %s && apt-ftparchive packages > Packages" % path, shell=True) openmediavault.subprocess.check_call([ "apt-get", "update" ]) return 0
def __init__(self): self._dict = {} prod_file = openmediavault.getenv( "OMV_PRODUCTINFO_FILE", "/usr/share/openmediavault/productinfo.xml" ) tree = xml.etree.ElementTree.parse(prod_file) for child in tree.iter(): # Skip all elements with children. if list(child): continue self._dict[child.tag] = child.text
def create_backup(self): """ Create a backup of the configuration database. :returns: Returns the path of the backup file, otherwise None. """ config_path = openmediavault.getenv("OMV_CONFIG_FILE") if not os.path.exists(config_path): self._backup_path = False return None (fh, self._backup_path) = tempfile.mkstemp() shutil.copy(config_path, self._backup_path) return self._backup_path
def execute(self, *args): rc = 1 # Parse the command line arguments. parser = argparse.ArgumentParser( prog="%s %s" % (os.path.basename(args[0]), args[1]), description=self.description ) parser.add_argument( "id", type=self.argparse_is_datamodel_id, help="The data model ID, e.g. 'conf.service.ssh'" ) cmd_args = parser.parse_args(args[2:]) # Find the script. create_dir = openmediavault.getenv( "OMV_CONFDB_CREATE_DIR", "/usr/share/openmediavault/confdb/create.d" ) script_name = "" for name in os.listdir(create_dir): # Split the script name into its parts: # <DATAMODELID>.<EXT> if cmd_args.id == os.path.splitext(name)[0]: script_name = name break try: # Create a backup of the configuration database. self.create_backup() # Test if the script exists and is executable. script_path = os.path.join(create_dir, script_name) if not os.path.exists(script_path): raise RuntimeError( "The script '%s' does not exist" % script_name ) if not os.access(script_path, os.X_OK): raise RuntimeError( "The script '%s' is not executable" % script_name ) # Execute the script. openmediavault.subprocess.check_call([script_path]) rc = 0 except Exception as e: # Display the exception message. openmediavault.log.error( "Failed to create the default " "configuration: %s" % str(e) ) # Rollback all changes. self.rollback_changes() finally: # Unlink the configuration database backup. self.unlink_backup() return rc
def execute(self): print("Clear out the local repository of uploaded package " \ "files. Please wait ...") path = openmediavault.getenv("OMV_DPKGARCHIVE_DIR", "/var/cache/openmediavault/archives") for f in glob.glob("{}/*.deb".format(path)): os.remove(f) openmediavault.subprocess.check_call( "cd {} && apt-ftparchive packages . > Packages".format(path), shell=True) openmediavault.subprocess.check_call(["apt-get", "update"]) return 0
def execute(self, *args): # Execute all scripts located in the directory. scripts_dir = openmediavault.getenv( "OMV_CONFDB_POPULATE_DIR", "/usr/share/openmediavault/confdb/populate.d") for script_name in os.listdir(scripts_dir): # Make sure the script is executable. script_path = os.path.join(scripts_dir, script_name) if not os.access(script_path, os.X_OK): raise RuntimeError("The script '%s' is not executable" % script_name) openmediavault.subprocess.check_call([script_path]) return 0
def _load(self, id): """ Load the specified data model from file system. :param id: The data model identifier, e.g. 'conf.service.ftp.share'. :returns: The JSON object of the data model. :raises FileNotFoundError: """ # Load the file content. datamodels_dir = openmediavault.getenv( "OMV_DATAMODELS_DIR", "/usr/share/openmediavault/datamodels") with open(os.path.join(datamodels_dir, "%s.json" % id)) as f: content = f.read() return content
def execute(self, *args): rc = 1 # Parse the command line arguments. parser = argparse.ArgumentParser( prog="%s %s" % (os.path.basename(args[0]), args[1]), description=self.description) parser.add_argument("id", type=self.argparse_is_datamodel_id, help="The data model ID, e.g. 'conf.service.ssh'") parser.add_argument("version", type=self.argparse_is_version) cmd_args = parser.parse_args(args[2:]) # Get the migrations. migrations = {} migrations_dir = openmediavault.getenv("OMV_CONFDB_MIGRATIONS_DIR", "/usr/share/openmediavault/confdb/migrations.d"); # Collect the migrations to be executed. for name in os.listdir(migrations_dir): # Split the script name into its parts: # <DATAMODELID>_<VERSION>.<EXT> parts = re.split(r'_', os.path.splitext(name)[0]) if 2 != len(parts): continue if cmd_args.id != parts[0]: continue if LooseVersion(parts[1]) < LooseVersion(cmd_args.version): continue migrations[parts[1]] = name try: # Create a backup of the configuration database. self.mkBackup() # Execute the configuration database migration scripts. for cmd_args.version in sorted(migrations, key=lambda v: LooseVersion(v)): name = "%s_%s" % (cmd_args.id, cmd_args.version) path = os.path.join(migrations_dir, migrations[cmd_args.version]) # Test if the script is executable. if not os.access(path, os.X_OK): raise RuntimeError("The script '%s' is not " \ "executable" % path) # Execute the script. print(" Running migration %s" % name) openmediavault.subprocess.check_call([ path ]) rc = 0 except Exception as e: # Display the exception message. openmediavault.log.error("Failed to apply migrations: %s" % str(e)) # Rollback all changes. self.rollbackChanges() finally: # Unlink the configuration database backup. self.unlinkBackup() return rc
def execute(self): print("Clear out the local repository of uploaded package " \ "files. Please wait ...") path = openmediavault.getenv( "OMV_DPKGARCHIVE_DIR", "/var/cache/openmediavault/archives" ) for f in glob.glob("{}/*.deb".format(path)): os.remove(f) openmediavault.subprocess.check_call( "cd {} && apt-ftparchive packages . > Packages".format(path), shell=True ) openmediavault.subprocess.check_call(["apt-get", "update"]) return 0
def _load(self, id): """ Load the specified data model from file system. :param id: The data model identifier, e.g. 'conf.service.ftp.share'. :returns: The JSON object of the data model. :raises openmediavault.datamodel.DatamodelNotFoundException: """ # Load the file content. datamodels_dir = openmediavault.getenv("OMV_DATAMODELS_DIR", "/usr/share/openmediavault/datamodels"); datamodel_path = os.path.join(datamodels_dir, "%s.json" % id) if not os.path.exists(datamodel_path): raise DatamodelNotFoundException(id) with open(datamodel_path) as f: content = f.read() return content
def execute(self, *args): datamodel_ids = [] # Load all data models. datamodels_path = openmediavault.getenv("OMV_DATAMODELS_DIR", "/usr/share/openmediavault/datamodels"); for f in glob.glob(os.path.join(datamodels_path, "conf.*.json")): datamodel_id = os.path.splitext(os.path.basename(f))[0] # Note, currently the filename is the data model id, but # this may change someday, so we load the data model and # ask for its identifier to be on the safe side. datamodel = openmediavault.config.Datamodel(datamodel_id) datamodel_ids.append(datamodel.id) # Print the data model identifiers. for datamodel_id in natsort.humansorted(datamodel_ids): print(datamodel_id) return 0
def execute(self, *args): datamodel_ids = [] # Load all data models. datamodels_path = openmediavault.getenv( "OMV_DATAMODELS_DIR", "/usr/share/openmediavault/datamodels") for f in glob.glob(os.path.join(datamodels_path, "conf.*.json")): datamodel_id = os.path.splitext(os.path.basename(f))[0] # Note, currently the filename is the data model id, but # this may change someday, so we load the data model and # ask for its identifier to be on the safe side. datamodel = openmediavault.config.Datamodel(datamodel_id) datamodel_ids.append(datamodel.id) # Print the data model identifiers. for datamodel_id in natsort.humansorted(datamodel_ids): print(datamodel_id) return 0
def make_mount_path(id_): """ Build the mount path from any given string, device file or file system UUID. :param id_: The device file or the file system UUID. :type id_: str :return: Returns the mount path, e.g * /srv/6c5be784-50a8-440c-9d25-aab99b9c6fb1/ * /srv/_dev_disk_by-id_wwn-0x5000cca211cc703c-part1/ :rtype: str """ mount_path = os.path.join(openmediavault.getenv("OMV_MOUNT_DIR", "/srv"), id_.replace('/', '_')) return openmediavault.string.path_prettify(mount_path)
def make_mount_path(id_): """ Build the mount path from any given string, device file or file system UUID. :param id_: The device file or the file system UUID. :type id_: str :return: Returns the mount path, e.g * /srv/6c5be784-50a8-440c-9d25-aab99b9c6fb1/ * /srv/_dev_disk_by-id_wwn-0x5000cca211cc703c-part1/ :rtype: str """ mount_path = os.path.join( openmediavault.getenv("OMV_MOUNT_DIR", "/srv"), id_.replace('/', '_') ) return openmediavault.string.path_prettify(mount_path)
def execute(self, *args): # Execute all scripts located in the directory. scripts_dir = openmediavault.getenv( "OMV_CONFDB_POPULATE_DIR", "/usr/share/openmediavault/confdb/populate.d" ) for script_name in os.listdir(scripts_dir): if script_name in ['README.md']: continue # Make sure the script is executable. script_path = os.path.join(scripts_dir, script_name) if not os.access(script_path, os.X_OK): raise RuntimeError( "The script '%s' is not executable" % script_name ) openmediavault.subprocess.check_call([script_path]) return 0
def execute(self): print("Checking configuration status file. Please wait ...") path = omv.getenv("OMV_ENGINED_DIRTY_MODULES_FILE", "/var/lib/openmediavault/dirtymodules.json") if not os.path.exists(path): print("No configuration changes file found.") return 0 # Try to load the JSON file. If it fails, then remove it because # in this case the file content is no valid JSON string and it # is not possible to restore it. try: with open(path) as json_file: json.load(json_file) print("The configuration status file is valid.") except: print("Removing invalid configuration status file.") os.unlink(json_path) return 0
def property_get_default(self, path): """ Get the default value of the specified property as defined in the data model. :param path: The path of the property, e.g. "aaa.bbb.ccc". :returns: The default value as specified in the data model schema or by the type of the property. """ prop_schema = self.schema.get_by_path(path) if "default" in prop_schema: result = prop_schema['default'] else: if isinstance(prop_schema['type'], list): raise openmediavault.json.SchemaException( "The attribute 'type' must not be an array at '%s'." % path ) type = "any" if "type" in prop_schema: type = prop_schema['type'] if "array" == type: result = [] elif "object" == type: result = {} elif "boolean" == type: result = False elif "integer" == type: result = 0 elif type in ["number", "double", "float"]: result = 0.0 elif "string" == type: result = "" if "format" in prop_schema: if "uuidv4" == prop_schema['format']: if self.is_identifiable and self.idproperty == path: result = openmediavault.getenv( "OMV_CONFIGOBJECT_NEW_UUID" ) # elif type in [ "any", "null", "float" ]: # result = None else: result = None return result
def execute(self, *args): rc = 1 datamodel_id = args[1] version = args[2] migrations = {} migrations_dir = openmediavault.getenv( "OMV_CONFDB_MIGRATIONS_DIR", "/usr/share/openmediavault/confdb/migrations.d") # Collect the migrations to be executed. for name in os.listdir(migrations_dir): # Split the script name into its parts: # <DATAMODELID>_<VERSION>.<EXT> parts = re.split(r'_', os.path.splitext(name)[0]) if 2 != len(parts): continue if datamodel_id != parts[0]: continue if LooseVersion(parts[1]) < LooseVersion(version): continue migrations[parts[1]] = name try: # Create a backup of the configuration database. self.mkBackup() # Execute the configuration database migration scripts. for version in sorted(migrations, key=lambda v: LooseVersion(v)): name = "%s_%s" % (datamodel_id, version) path = os.path.join(migrations_dir, migrations[version]) # Test if the script is executable. if not os.access(path, os.X_OK): raise RuntimeError("The script '%s' is not " \ "executable" % path) # Execute the script. print(" Running migration %s" % name) openmediavault.subprocess.check_call([path]) rc = 0 except Exception as e: # Display the exception message. openmediavault.log.error("Failed to apply migrations: %s" % str(e)) # Rollback all changes. self.rollbackChanges() finally: # Unlink the configuration database backup. self.unlinkBackup() return rc
def execute(self): print("Checking all RRD files. Please wait ...") path = openmediavault.getenv("OMV_RRDCACHED_BASEDIR", "/var/lib/rrdcached/db/") rrd_files = glob.glob(os.path.join(path, "localhost", "*", "*.rrd")) invalid = 0 # Get the performance statistics configuration? db = openmediavault.config.Database() obj = db.get("conf.system.monitoring.perfstats") # Disable rrdcached if performance stats are enabled. if obj.get("enable"): openmediavault.subprocess.check_call( ["monit", "stop", "rrdcached"]) for rrd_file in rrd_files: ts_last = int(openmediavault.subprocess.check_output( [ "rrdtool", "last", rrd_file ]).decode()) dt_now = datetime.datetime.now() if datetime.datetime.utcfromtimestamp(ts_last) > dt_now: invalid += 1 dirname = os.path.basename(os.path.dirname(rrd_file)) basename = os.path.basename(rrd_file) d = dialog.Dialog(dialog="dialog") code = d.yesno("The RRD file '../{}/{}' contains " \ "timestamps in future.\nDo you want to delete " \ "it?".format(dirname, basename), backtitle=self.description, height=7, width=65) if code == d.ESC: return 0 if code == d.OK: os.remove(rrd_file) if invalid == 0: print("All RRD database files are valid.") else: print("{} invalid RRD database files were removed.".format( invalid)) # Re-enable rrdcached if performance stats are enabled. if obj.get("enable"): openmediavault.subprocess.check_call( ["monit", "start", "rrdcached"]) return 0
def execute(self): print("Checking configuration status file. Please wait ...") path = openmediavault.getenv( "OMV_ENGINED_DIRTY_MODULES_FILE", "/var/lib/openmediavault/dirtymodules.json" ) if not os.path.exists(path): print("No configuration changes file found.") return 0 # Try to load the JSON file. If it fails, then remove it because # in this case the file content is no valid JSON string and it # is not possible to restore it. try: with open(path) as json_file: json.load(json_file) print("The configuration status file is valid.") except Exception: print("Removing invalid configuration status file.") os.unlink(json_file) return 0
def execute(self, *args): rc = 1 datamodel_id = args[1] create_dir = openmediavault.getenv( "OMV_CONFDB_CREATE_DIR", "/usr/share/openmediavault/confdb/create.d") script_name = "" for name in os.listdir(create_dir): # Split the script name into its parts: # <DATAMODELID>.<EXT> if datamodel_id == os.path.splitext(name)[0]: script_name = name break try: # Create a backup of the configuration database. self.mkBackup() # Test if the script exists and is executable. script_path = os.path.join(create_dir, script_name) if not os.path.exists(script_path): raise RuntimeError("The script '%s' does not exist" % script_name) if not os.access(script_path, os.X_OK): raise RuntimeError("The script '%s' is not " \ "executable" % script_name) # Execute the script. openmediavault.subprocess.check_call([script_path]) rc = 0 except Exception as e: # Display the exception message. openmediavault.log.error("Failed to create the default " \ "configuration: %s" % str(e)) # Rollback all changes. self.rollbackChanges() finally: # Unlink the configuration database backup. self.unlinkBackup() return rc
def test_getenv_fail(self): self.assertRaises( TypeError, lambda: openmediavault.getenv("OMV_ABC", 1.5, type="list"), )
def test_getenv_float(self): value = openmediavault.getenv("OMV_ABC", 1.5, type="float") self.assertEqual(isinstance(value, float), True)
def test_getenv_int(self): value = openmediavault.getenv("OMV_ENGINED_SO_SNDTIMEO", type="int") self.assertEqual(isinstance(value, int), True)
def test_getenv_str(self): value = openmediavault.getenv("OMV_MOUNT_DIR") self.assertEqual(isinstance(value, str), True)
def execute(self): # Default values. address = "" netmask = "" gateway = "" method = "dhcp" address6 = "" method6 = "manual" netmask6 = 64 gateway6 = "" wol = False dns_nameservers = "" wpa_ssid = None wpa_psk = None rpc_method = "setEthernetIface" rpc_params = {} # Get the network interface device. devices = [] context = pyudev.Context() for device in context.list_devices(subsystem="net"): # Skip unwanted network interface devices. if device.sys_name in ("lo"): continue if device.device_type and device.device_type in ("bond"): continue # Append the network interface name for later use. devices.append(device.sys_name) devices = natsort.humansorted(devices) choices = [] for idx, sys_name in enumerate(devices): device = pyudev.Device.from_name(context, "net", sys_name) for id in [ "ID_MODEL_FROM_DATABASE", "ID_VENDOR_FROM_DATABASE" ]: if not id in device: continue choices.append([ sys_name, openmediavault.string.truncate( device[id], 50) ]) break d = dialog.Dialog(dialog="dialog") (code, tag) = d.menu("Please select a network interface. Note, the " \ "existing network interface configuration will be deleted.", backtitle=self.description, clear=True, height=14, width=70, menu_height=6, choices=choices) if code in (d.CANCEL, d.ESC): return 0 device_name = tag # Use DHCP? code = d.yesno("Do you want to use DHCPv4 for this interface?", backtitle=self.description, height=5, width=49) if code == d.ESC: return 0 if code != d.OK: address = None netmask = None gateway = None method = "static" # Get the static IPv4 address. while not address: (code, address) = d.inputbox( "Please enter the IPv4 address.", backtitle=self.description, clear=True, height=8, width=60, init="") if code != d.OK: return 0 if not address: d.msgbox("The field must not be empty.", backtitle=self.description, height=5, width=32) continue try: ipaddress.ip_address(address) except Exception as e: address = None d.msgbox("Please enter a valid IPv4 address.", backtitle=self.description, height=5, width=38) continue # Get the IPv4 netmask. while not netmask: (code, netmask) = d.inputbox( "Please enter the IPv4 netmask.", backtitle=self.description, clear=True, height=8, width=60, init="") if code != d.OK: return 0 if not netmask: d.msgbox("The field must not be empty.", backtitle=self.description, height=5, width=32) continue try: ipaddress.ip_address(netmask) except: netmask = None d.msgbox("Please enter a valid netmask.", backtitle=self.description, height=5, width=33) continue # Get default IPv4 gateway. while not gateway: (code, gateway) = d.inputbox( "Please enter the default IPv4 gateway.", backtitle=self.description, clear=True, height=8, width=60, init="") if code != d.OK: return 0 try: ipaddress.ip_address(gateway) except: gateway = None d.msgbox("Please enter a valid gateway.", backtitle=self.description, height=5, width=33) continue # Use IPv6? code = d.yesno("Do you want to configure IPv6 for this interface?", backtitle=self.description, height=5, width=53, defaultno=True) if code == d.ESC: return 0 if code == d.OK: # Use stateful address autoconfiguration (DHCPv6)? code = d.yesno("Do you want to enable stateful address " \ "autoconfiguration (DHCPv6)?", backtitle=self.description, height=6, width=42) if code == d.ESC: return 0 if code == d.OK: method6 = "dhcp" else: # Use stateless address autoconfiguration (SLAAC)? code = d.yesno("Do you want to enable stateless address " \ "autoconfiguration (SLAAC)?", backtitle=self.description, height=6, width=42) if code == d.ESC: return 0 if code == d.OK: method6 = "auto" else: method6 = "static" # Get static IPv6 address. address6 = None while not address6: (code, address6) = d.inputbox( "Please enter the IPv6 address.", backtitle=self.description, clear=True, height=8, width=60, init="") if code != d.OK: return 0 if not address6: d.msgbox("The field must not be empty.", backtitle=self.description, height=5, width=32) continue try: ipaddress.ip_address(address6) except: address6 = None d.msgbox("Please enter a valid IPv6 address.", backtitle=self.description, height=5, width=38) continue # Get the prefix length. netmask6 = None while not netmask6: (code, netmask6) = d.inputbox( "Please enter the IPv6 prefix length.", backtitle=self.description, clear=True, height=8, width=64, init="64") if code != d.OK: return 0 if not netmask6: d.msgbox("The field must not be empty.", backtitle=self.description, height=5, width=32) continue if int(netmask6) < 0 or int(netmask6) > 128: netmask6 = None d.msgbox("Please enter a valid netmask.", backtitle=self.description, height=5, width=33) continue # Get default IPv6 gateway. gateway6 = None while not gateway6: (code, gateway6) = d.inputbox( "Please enter the default IPv6 gateway.", backtitle=self.description, clear=True, height=8, width=60, init="") if code != d.OK: return 0 try: ipaddress.ip_address(gateway6) except: gateway6 = None d.msgbox("Please enter a valid gateway.", backtitle=self.description, height=5, width=33) continue # Get the DNS name servers. Note, only one IP address is # supported here. if method == "static" or method6 == "static": while True: (code, dns_nameservers) = d.inputbox( "Please enter the DNS name server. If you don't want " \ "to use any name server, just leave this field blank.", backtitle=self.description, clear=True, height=8, width=60, init="") if code != d.OK: return 0 if not dns_nameservers: break try: ipaddress.ip_address(dns_nameservers) break except: dns_nameservers = "" d.msgbox("Please enter a valid IP address.", backtitle=self.description, height=5, width=30) # Enable WOL? code = d.yesno("Do you want to enable WOL for this interface?", backtitle=self.description, height=5, width=50, defaultno=True) if code == d.ESC: return 0 if code == d.OK: wol = True # Set the default RPC parameters. rpc_params.update({ "uuid": openmediavault.getenv("OMV_CONFIGOBJECT_NEW_UUID"), "devicename": device_name, "method": method, "address": address, "netmask": netmask, "gateway": gateway, "method6": method6, "address6": address6, "netmask6": netmask6, "gateway6": gateway6, "dnsnameservers": dns_nameservers, "dnssearch": "", "mtu": 0, "wol": wol, "options": "", "comment": "", }) # Do we process a wireless network interface? if re.match(r"^wlan[0-9]+$", device_name): rpc_method = "setWirelessIface" # Get the SSID. while not wpa_ssid: (code, wpa_ssid) = d.inputbox( "Please enter the name of the wireless network (SSID).", backtitle=self.description, clear=True, height=8, width=60, init="") if code != d.OK: return 0 if not wpa_ssid: d.msgbox("The field must not be empty.", backtitle=self.description, height=5, width=32) rpc_params["wpassid"] = wpa_ssid # Get the pre-shared key. while not wpa_psk: (code, wpa_psk) = d.inputbox( "Please enter the pre-shared key (PSK).", backtitle=self.description, clear=True, height=8, width=45, init="") if code != d.OK: return 0 if not wpa_psk: d.msgbox("The field must not be empty.", backtitle=self.description, height=5, width=32) rpc_params["wpapsk"] = wpa_psk # Update the interface configuration. print("Configuring network interface. Please wait ...") # Delete all existing network interface configuration objects. interfaces = openmediavault.rpc.call("Network", "enumerateConfiguredDevices") for interface in interfaces: openmediavault.rpc.call("Network", "deleteInterface", { "uuid": interface["uuid"] }) # Insert a new network interface configuration object. openmediavault.rpc.call("Network", rpc_method, rpc_params) openmediavault.rpc.call("Config", "applyChanges", { "modules": [], "force": False }) print("The network interface configuration was successfully changed.") return 0
def test_getenv_fail(self): self.assertRaises(TypeError, lambda: openmediavault.getenv( "OMV_ABC", 1.5, type="list"))
def test_getenv_bool(self): value = openmediavault.getenv("OMV_DEBUG_SCRIPT", type="bool") self.assertEqual(isinstance(value, bool), True)