Example #1
0
    def _modules_loaded_(self, **kwargs):
        """
        Called after _load_ is called for all the modules. Get's a list of configuration items all library
        or modules define or use.

        Note: This complies with i18n translations for future use.

        **Hooks called**:

        * _configuration_details_ : Gets various details about a configuration item. Do not implement, not set
          in stone. Might migrate to i18n library.

        **Usage**:

        .. code-block:: python

           def _configuration_details_(self, **kwargs):
               return [{"webinterface": {
                           "enabled": {
                               "description": {
                                   "en": "Enables/disables the web interface.",
                               },
                               "encrypt": True
                           },
                           "port": {
                               "description": {
                                   "en": "Port number for the web interface to listen on."
                               }
                           }
                       },
               }]
        """
        config_details = yield global_invoke_all("_configuration_details_",
                                                 called_by=self)

        for component, details in config_details.items():
            if details is None:
                continue
            for list in details:
                #                logger.warn("For module {component}, adding details: {list}", component=component, list=list)
                self.configs_details = dict_merge(self.configs_details, list)

        for section, options in self.configs.items():
            for option, keys in options.items():
                try:
                    self.configs[section][option][
                        "details"] = self.configs_details[section][option]
                except:
                    pass
Example #2
0
    def set(self, section, option, value, ignore_case=None, **kwargs):
        """
        Set value of configuration option for a given section.  The option length
        **cannot exceed 1000 characters**.  The value cannot exceed 5000 bytes.

        Section and option will be converted to lowercase, rending the set/get function case insenstive.

        **Usage**:

        .. code-block:: python

           gatewayUUID = self._Config.set("section_name"
           , "myoption", "New Value")

        :raises YomboInvalidArgument: When an argument is invalid or illegal.
        :raises KeyError: When the requested section and option are not found.
        :param section: The configuration section to use.
        :type section: string
        :param option: The option (key) to use.
        :type option: string
        :param value: What to return if no result is found, default = None.
        :type value: int or string
        """
        if len(section) > self.MAX_SECTION_LENGTH:
            self._Statistics.increment("lib.configuration.set.invalid_length",
                                       bucket_size=15,
                                       anon=True)
            raise YomboInvalidArgument(
                f"section cannot be more than {self.MAX_OPTION_LENGTH:d} chars"
            )
        if len(option) > self.MAX_OPTION_LENGTH:
            self._Statistics.increment("lib.configuration.set.invalid_length",
                                       bucket_size=15,
                                       anon=True)
            raise YomboInvalidArgument(
                f"option cannot be more than {self.MAX_OPTION_LENGTH:d} chars")

        # Can't set value!
        if section == "yombo":
            self._Statistics.increment(
                "lib.configuration.set.no_setting_yombo",
                bucket_size=15,
                anon=True)
            raise YomboInvalidArgument("Not allowed to set value")

        if isinstance(value, str):
            if len(value) > self.MAX_VALUE_LENGTH:
                self._Statistics.increment(
                    "lib.configuration.set.value_too_long",
                    bucket_size=15,
                    anon=True)
                raise YomboInvalidArgument(
                    f"value cannot be more than {self.MAX_VALUE:d} chars")

        if ignore_case is not True:
            section = section.lower()
            option = option.lower()

        if section not in self.configs:
            self.configs[section] = {}
        if option not in self.configs[section]:
            self.configs[section][option] = {
                "created_at": int(time()),
                "reads": 0,
                "writes": 0,
            }
            self._Statistics.increment("lib.configuration.set.new",
                                       bucket_size=15,
                                       anon=True)
        else:
            # already have a value. If it's the same, we won't set it.
            if self.configs[section][option]["value"] == value:
                self._Statistics.increment(
                    "lib.configuration.set.skipped_same_value",
                    bucket_size=15,
                    anon=True)
                return value
            self._Statistics.increment("lib.configuration.set.update",
                                       bucket_size=15,
                                       anon=True)

        self.configs[section][option] = dict_merge(
            self.configs[section][option], {
                "updated_at": int(time()),
                "value": value,
                "hash": sha224(str(value).encode("utf-8")).hexdigest(),
            })
        self.configs_dirty = True
        if self.loading_yombo_ini is False:
            self.configs[section][option]["writes"] += 1
            yield global_invoke_all(
                "_configuration_set_",
                called_by=self,
                section=section,
                option=option,
                value=value,
            )
        return value
Example #3
0
    def set(self, section, option, value, **kwargs):
        """
        Set value of configuration option for a given section.  The option length
        **cannot exceed 1000 characters**.  The value cannot exceed 5000 bytes.

        Section and option will be converted to lowercase, rending the set/get function case insenstive.

        **Usage**:

        .. code-block:: python

           gatewayUUID = self._Config.set("section_name", "myoption", "New Value")

        :raises InvalidArgumentError: When an argument is invalid or illegal.
        :raises KeyError: When the requested section and option are not found.
        :param section: The configuration section to use.
        :type section: string
        :param option: The option (key) to use.
        :type option: string
        :param value: What to return if no result is found, default = None.
        :type value: int or string
        """
        # print("cfgs set: %s:%s = %s" % (section, option, value))

        if len(section) > self.MAX_SECTION_LENGTH:
            self._Statistics.increment("lib.configuration.set.invalid_length",
                                       bucket_size=15,
                                       anon=True)
            raise InvalidArgumentError("section cannot be more than %d chars" %
                                       self.MAX_OPTION_LENGTH)
        if len(option) > self.MAX_OPTION_LENGTH:
            self._Statistics.increment("lib.configuration.set.invalid_length",
                                       bucket_size=15,
                                       anon=True)
            raise InvalidArgumentError("option cannot be more than %d chars" %
                                       self.MAX_OPTION_LENGTH)

        # Can't set value!
        if section == 'yombo':
            self._Statistics.increment(
                "lib.configuration.set.no_setting_yombo",
                bucket_size=15,
                anon=True)
            raise InvalidArgumentError("Not allowed to set value")

        if isinstance(value, str):
            if len(value) > self.MAX_VALUE_LENGTH:
                self._Statistics.increment(
                    "lib.configuration.set.value_too_long",
                    bucket_size=15,
                    anon=True)
                raise InvalidArgumentError(
                    "value cannot be more than %d chars" % self.MAX_VALUE)

        section = section.lower()
        option = option.lower()

        if section not in self.configs:
            self.configs[section] = {}
        if option not in self.configs[section]:
            self.configs[section][option] = {
                'created_at': int(time()),
                'reads': 0,
                'writes': 0,
            }
            self._Statistics.increment("lib.configuration.set.new",
                                       bucket_size=15,
                                       anon=True)
        else:
            # already have a value. If it's the same, we won't set it.
            if self.configs[section][option]['value'] == value:
                self._Statistics.increment(
                    "lib.configuration.set.skipped_same_value",
                    bucket_size=15,
                    anon=True)
                return
            self._Statistics.increment("lib.configuration.set.update",
                                       bucket_size=15,
                                       anon=True)

        self.configs[section][option] = dict_merge(
            self.configs[section][option], {
                'updated_at': int(time()),
                'value': value,
                'hash': hashlib.sha224(str(value).encode('utf-8')).hexdigest(),
            })
        self.configs_dirty = True
        if self.loading_yombo_ini is False:
            self.configs[section][option]['writes'] += 1
            yield global_invoke_all('_configuration_set_',
                                    called_by=self,
                                    **{
                                        'section': section,
                                        'option': option,
                                        'value': value,
                                        'action': 'set'
                                    })
Example #4
0
    def _init_(self, **kwargs):
        """
        Open the yombo.ini file for reading.

        Import the configuration items into the database, also prime the configs for reading.
        """
        self.exit_config_file = None  # Holds a complete configuration file to save when exiting.
        self.cache_dirty = False
        self.configs = {}  # Holds actual config data
        self.cfg_loaded = False
        self.yombo_ini_last_modified = 0
        self.working_dir = settings.arguments["working_dir"]
        ini_norestore = settings.arguments["norestoreini"]
        self.yombo_ini_path = f"{self.working_dir}/yombo.ini"
        if os.path.exists(self.yombo_ini_path):
            if os.path.isfile(self.yombo_ini_path) is False:
                try:
                    os.remove(self.yombo_ini_path)
                except Exception as e:
                    logger.error(
                        "'yombo.ini' file exists, but it's not a file and it can't be deleted!"
                    )
                    reactor.stop()
                    return
                if ini_norestore:
                    self.restore_backup_yombi_ini()
            else:
                if os.path.getsize(self.yombo_ini_path) < 2:
                    logger.warn(
                        "yombo.ini appears corrupt, attempting to restore from backup."
                    )
                    if ini_norestore:
                        self.restore_backup_yombi_ini()
        else:
            if ini_norestore:
                self.restore_backup_yombi_ini()

        self.loading_yombo_ini = True
        if settings.yombo_ini is False:
            self._Loader.operating_mode = "first_run"
        else:
            for section, options in settings.yombo_ini.items():
                for option, value in options.items():
                    try:
                        value = yield self._GPG.decrypt(value)
                    except:
                        pass
                    self.set(section, option, value, ignore_case=True)

        self.get("core", "rand_seed", random_string(length=128))
        logger.debug(
            "done parsing yombo.ini. Now about to parse yombo.ini.info.")
        try:
            config_parser = configparser.ConfigParser()
            config_parser.read(f"{self.working_dir}/etc/yombo.ini.info")
            logger.debug("yombo.ini.info file read into memory.")
            for section in config_parser.sections():
                if section not in self.configs:
                    continue
                for option in config_parser.options(section):
                    if option not in self.configs[section]:
                        continue
                    values = msgpack.loads(
                        b64decode(config_parser.get(section, option)))
                    self.configs[section][option] = dict_merge(
                        self.configs[section][option], values)
        except IOError as e:
            logger.warn(
                "CAUGHT IOError!!!!!!!!!!!!!!!!!!  In reading meta: {error}",
                error=e)
        except configparser.NoSectionError:
            logger.warn("CAUGHT ConfigParser.NoSectionError!!!!  IN saving. ")

        logger.debug("done parsing yombo.ini.info")

        #setup some defaults if we are new....
        self.get("core", "gwid", "local")
        self.get("core", "gwuuid", None)
        self.get("core", "is_master", 1)
        self.get("core", "master_gateway_id", "local")

        # Perform DB cleanup activites based on local section.
        if self.get("local", "deletedelayedmessages", False, False) is True:
            self._LocalDB.delete("sqldict",
                                 ["module = ?", "yombo.lib.messages"])
            self.set("local", "deletedelayedmessages", False)

        if self.get("local", "deletedevicehistory", False, False) is True:
            self._LocalDB.truncate("devicestatus")
            self.set("local", "deletedevicehistory", False)

        current_time = int(time())
        # Ask external services what they know about us.
        # detected_location states are based off this and is set in the locations library.
        # times uses this
        self.detected_location_info = self.get("core", "locationinfo", None,
                                               False)
        if self.detected_location_info is None or \
                self.get("core", "locationinfotime", 0, False) < current_time - 3600:
            self.detected_location_info = yield detect_location_info()
            self.set(
                "core", "locationinfo",
                data_pickle(self.detected_location_info,
                            encoder="msgpack_base64",
                            local=True))
            self.set("core", "locationinfotime", current_time)
        else:
            self.detected_location_info = data_unpickle(
                self.detected_location_info, encoder="msgpack_base64")
        self.set("core", "externalipaddress_v4",
                 self.detected_location_info["ip"])

        if self.get("core", "localipaddress_v4", False, False) is False or \
                self.get("core", "localipaddresstime", False, False) is False:
            address_info = get_local_network_info()
            self.set("core", "localipaddress_v4",
                     address_info["ipv4"]["address"])
            self.set("core", "localipaddress_netmask_v4",
                     address_info["ipv4"]["netmask"])
            self.set("core", "localipaddress_cidr_v4",
                     address_info["ipv4"]["cidr"])
            self.set("core", "localipaddress_network_v4",
                     address_info["ipv4"]["network"])
            self.set("core", "localipaddress_v6",
                     address_info["ipv6"]["address"])
            self.set("core", "localipaddress_netmask_v6",
                     address_info["ipv6"]["netmask"])
            # self.set("core", "localipaddress_cidr_v6", address_info["ipv6"]["cidr"])
            # self.set("core", "localipaddress_network_v6", address_info["ipv6"]["network"])
            self.set("core", "localipaddresstime", int(time()))
        else:
            if int(self.configs["core"]["localipaddresstime"]["value"]) < (
                    int(time()) - 180):
                address_info = get_local_network_info()
                self.set("core", "localipaddress_v4",
                         address_info["ipv4"]["address"])
                self.set("core", "localipaddress_netmask_v4",
                         address_info["ipv4"]["netmask"])
                self.set("core", "localipaddress_cidr_v4",
                         address_info["ipv4"]["cidr"])
                self.set("core", "localipaddress_network_v4",
                         address_info["ipv4"]["network"])
                self.set("core", "localipaddress_v6",
                         address_info["ipv6"]["address"])
                self.set("core", "localipaddress_netmask_v6",
                         address_info["ipv6"]["netmask"])
                # self.set("core", "localipaddress_cidr_v6", address_info["ipv6"]["cidr"])
                # self.set("core", "localipaddress_network_v6", address_info["ipv6"]["network"])
                self.set("core", "localipaddresstime", int(time()))

        self.save_loop = LoopingCall(self.save)
        self.save_loop.start(randint(12600, 14400), False)  # every 3.5-4 hours

        if self.get("core", "first_run", None, False) is None:
            self.set("core", "first_run", True)
        self.loading_yombo_ini = False

        # set system defaults. Reasons: 1) All in one place. 2) Somes values are needed before respective libraries
        # are loaded.
        self._Configs.get("mqtt", "client_enabled", True)
        self._Configs.get("mqtt", "server_enabled", True)
        self._Configs.get("mqtt", "server_max_connections", 1000)
        self._Configs.get("mqtt", "server_timeout_disconnect_delay", 2)
        self._Configs.get("mqtt", "server_listen_ip", "*")
        self._Configs.get("mqtt", "server_listen_port", 1883)
        self._Configs.get("mqtt", "server_listen_port_ss_ssl", 1884)
        self._Configs.get("mqtt", "server_listen_port_le_ssl", 1885)
        self._Configs.get("mqtt", "server_listen_port_websockets", 8081)
        self._Configs.get("mqtt", "server_listen_port_websockets_ss_ssl", 8444)
        self._Configs.get("mqtt", "server_listen_port_websockets_le_ssl", 8445)
        self._Configs.get("mqtt", "server_allow_anonymous", False)
        self._Configs.get("misc", "temperature_display", "f")
        self._Configs.get("misc", "length_display",
                          "imperial")  # will we ever get to metric?
        self.cfg_loaded = True
Example #5
0
    def _init_(self, **kwargs):
        """
        Open the yombo.ini file for reading.

        Import the configuration items into the database, also prime the configs for reading.
        """
        self.cache_dirty = False
        self.configs = {}
        self.automation_startup_check = []
        self._loaded = False
        self.yombo_ini_last_modified = 0

        ini_norestore = not os.path.exists('yombo.ini.norestore')

        if os.path.exists('yombo.ini'):
            if os.path.isfile('yombo.ini') is False:
                try:
                    os.remove('yombo.ini')
                except Exception as e:
                    logger.error(
                        "'yombo.ini' file exists, but it's not a file and it can't be deleted!"
                    )
                    reactor.stop()
                    return
                if ini_norestore:
                    self.restore_backup_yombi_ini()
            else:
                if os.path.getsize('yombo.ini') < 5:
                    logger.warn(
                        'yombo.ini appears corrupt, attempting to restore from backup.'
                    )
                    if ini_norestore:
                        self.restore_backup_yombi_ini()
        else:
            if ini_norestore:
                self.restore_backup_yombi_ini()

        self.loading_yombo_ini = True
        self.last_yombo_ini_read = self.read_yombo_ini()
        if self.last_yombo_ini_read is False:
            self._Loader.operating_mode = 'first_run'

        logger.debug(
            "done parsing yombo.ini. Now about to parse yombo.ini.info.")
        try:
            config_parser = configparser.ConfigParser()
            config_parser.read('usr/etc/yombo.ini.info')
            logger.debug("yombo.ini.info file read into memory.")
            for section in config_parser.sections():
                if section not in self.configs:
                    continue
                for option in config_parser.options(section):
                    if option not in self.configs[section]:
                        continue
                    values = msgpack.loads(
                        b64decode(config_parser.get(section, option)))
                    self.configs[section][option] = dict_merge(
                        self.configs[section][option], values)
        except IOError as e:
            logger.warn(
                "CAUGHT IOError!!!!!!!!!!!!!!!!!!  In reading meta: {error}",
                error=e)
        except configparser.NoSectionError:
            logger.warn("CAUGHT ConfigParser.NoSectionError!!!!  IN saving. ")

        logger.debug("done parsing yombo.ini.info")

        #setup some defaults if we are new....
        self.get('core', 'gwid', 'local')
        self.get('core', 'gwuuid', None)

        # Perform DB cleanup activites based on local section.
        if self.get('local', 'deletedelayedmessages', False, False) is True:
            self._Libraries['localdb'].delete(
                'sqldict', ['module = ?', 'yombo.gateway.lib.messages'])
            self.set('local', 'deletedelayedmessages', False)

        if self.get('local', 'deletedevicehistory', False, False) is True:
            self._Libraries['localdb'].truncate('devicestatus')
            self.set('local', 'deletedevicehistory', False)

        if self.get('core', 'externalipaddress_v4',
                    False, False) is False or self.get(
                        'core', 'externalipaddresstime', False,
                        False) is False:
            ipv4_external = yield get_external_ip_address_v4()
            self.set("core", "externalipaddress_v4", ipv4_external)
            self.set("core", "externalipaddresstime", int(time()))
        else:
            if int(self.configs['core']['externalipaddresstime']['value']) < (
                    int(time()) - 3600):
                ipv4_external = yield get_external_ip_address_v4()
                self.set("core", "externalipaddress_v4", ipv4_external)
                self.set("core", "externalipaddresstime", int(time()))

        if self.get('core',
                    'localipaddress_v4', False, False) is False or self.get(
                        'core', 'localipaddresstime', False, False) is False:
            address_info = get_local_network_info()
            self.set("core", "localipaddress_v4",
                     address_info['ipv4']['address'])
            self.set("core", "localipaddress_netmask_v4",
                     address_info['ipv4']['netmask'])
            self.set("core", "localipaddress_cidr_v4",
                     address_info['ipv4']['cidr'])
            self.set("core", "localipaddress_network_v4",
                     address_info['ipv4']['network'])
            self.set("core", "localipaddress_v6",
                     address_info['ipv6']['address'])
            self.set("core", "localipaddress_netmask_v6",
                     address_info['ipv6']['netmask'])
            # self.set("core", "localipaddress_cidr_v6", address_info['ipv6']['cidr'])
            # self.set("core", "localipaddress_network_v6", address_info['ipv6']['network'])
            self.set("core", "localipaddresstime", int(time()))
        else:
            if int(self.configs['core']['localipaddresstime']['value']) < (
                    int(time()) - 180):
                address_info = get_local_network_info()
                self.set("core", "localipaddress_v4",
                         address_info['ipv4']['address'])
                self.set("core", "localipaddress_netmask_v4",
                         address_info['ipv4']['netmask'])
                self.set("core", "localipaddress_cidr_v4",
                         address_info['ipv4']['cidr'])
                self.set("core", "localipaddress_network_v4",
                         address_info['ipv4']['network'])
                self.set("core", "localipaddress_v6",
                         address_info['ipv6']['address'])
                self.set("core", "localipaddress_netmask_v6",
                         address_info['ipv6']['netmask'])
                # self.set("core", "localipaddress_cidr_v6", address_info['ipv6']['cidr'])
                # self.set("core", "localipaddress_network_v6", address_info['ipv6']['network'])
                self.set("core", "localipaddresstime", int(time()))

        self.periodic_save_yombo_ini = LoopingCall(self.save)
        self.periodic_save_yombo_ini.start(randint(12600, 14400),
                                           False)  # every 3.5-4 hours
        # self.periodic_load_yombo_ini = LoopingCall(self.check_if_yombo_ini_modified)
        # self.periodic_load_yombo_ini.start(5)

        if self.get('core', 'first_run', None, False) is None:
            self.set('core', 'first_run', True)
        self.loading_yombo_ini = False

        # set system defaults. Reasons: 1) All in one place. 2) Somes values are needed before respective libraries
        # are loaded.
        self._Configs.get('mqtt', 'client_enabled', True)
        self._Configs.get('mqtt', 'server_enabled', True)
        self._Configs.get('mqtt', 'server_max_connections', 1000)
        self._Configs.get('mqtt', 'server_timeout_disconnect_delay', 2)
        self._Configs.get('mqtt', 'server_listen_ip', '*')
        self._Configs.get('mqtt', 'server_listen_port', 1883)
        self._Configs.get('mqtt', 'server_listen_port_ss_ssl', 1884)
        self._Configs.get('mqtt', 'server_listen_port_le_ssl', 1885)
        self._Configs.get('mqtt', 'server_listen_port_websockets', 8081)
        self._Configs.get('mqtt', 'server_listen_port_websockets_ss_ssl', 8444)
        self._Configs.get('mqtt', 'server_listen_port_websockets_le_ssl', 8445)
        self._Configs.get('mqtt', 'server_allow_anonymous', False)
        self._Configs.get('misc', 'temperature_display', 'f')
        self._Configs.get('misc', 'length_display',
                          'imperial')  # will we ever get to metric?