예제 #1
0
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"))
예제 #4
0
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 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
예제 #6
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
예제 #7
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
예제 #8
0
	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
예제 #9
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
예제 #10
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)
예제 #11
0
	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"))
예제 #12
0
 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
예제 #13
0
	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
예제 #14
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
예제 #15
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)
예제 #16
0
	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
예제 #18
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"))
예제 #19
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
예제 #20
0
 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")
예제 #21
0
 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
예제 #23
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
예제 #24
0
 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
예제 #25
0
 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
예제 #26
0
 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):
		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
예제 #28
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
예제 #29
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
예제 #30
0
	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
예제 #32
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
예제 #33
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
예제 #34
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
예제 #35
0
파일: __init__.py 프로젝트: succesor/omv
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)
예제 #36
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)
예제 #37
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):
         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
예제 #39
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
예제 #40
0
 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
예제 #41
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):
		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
예제 #44
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
예제 #45
0
 def test_getenv_fail(self):
     self.assertRaises(
         TypeError,
         lambda: openmediavault.getenv("OMV_ABC", 1.5, type="list"),
     )
예제 #46
0
 def test_getenv_float(self):
     value = openmediavault.getenv("OMV_ABC", 1.5, type="float")
     self.assertEqual(isinstance(value, float), True)
예제 #47
0
 def test_getenv_int(self):
     value = openmediavault.getenv("OMV_ENGINED_SO_SNDTIMEO", type="int")
     self.assertEqual(isinstance(value, int), True)
예제 #48
0
 def test_getenv_str(self):
     value = openmediavault.getenv("OMV_MOUNT_DIR")
     self.assertEqual(isinstance(value, str), True)
	def test_getenv_int(self):
		value = openmediavault.getenv("OMV_ENGINED_SO_SNDTIMEO", type="int")
		self.assertEqual(isinstance(value, int), 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_float(self):
		value = openmediavault.getenv("OMV_ABC", 1.5, type="float")
		self.assertEqual(isinstance(value, float), True)
	def test_getenv_bool(self):
		value = openmediavault.getenv("OMV_DEBUG_SCRIPT", type="bool")
		self.assertEqual(isinstance(value, bool), True)
	def test_getenv_str(self):
		value = openmediavault.getenv("OMV_MOUNT_DIR")
		self.assertEqual(isinstance(value, str), True)